/* Breakpoint currently in use for each BRP. */ static DEFINE_PER_CPU(struct perf_event *, bp_on_reg[LOONGARCH_MAX_BRP]);
/* Watchpoint currently in use for each WRP. */ static DEFINE_PER_CPU(struct perf_event *, wp_on_reg[LOONGARCH_MAX_WRP]);
int hw_breakpoint_slots(int type)
{ /* * We can be called early, so don't rely on * our static variables being initialised.
*/ switch (type) { case TYPE_INST: return get_num_brps(); case TYPE_DATA: return get_num_wrps(); default:
pr_warn("unknown slot type: %d\n", type); return 0;
}
}
#define READ_WB_REG_CASE(OFF, N, REG, T, VAL) \ case (OFF + N): \
LOONGARCH_CSR_WATCH_READ(N, REG, T, VAL); \ break
#define WRITE_WB_REG_CASE(OFF, N, REG, T, VAL) \ case (OFF + N): \
LOONGARCH_CSR_WATCH_WRITE(N, REG, T, VAL); \ break
/* * hw_breakpoint_slot_setup - Find and setup a perf slot according to operations * * @slots: pointer to array of slots * @max_slots: max number of slots * @bp: perf_event to setup * @ops: operation to be carried out on the slot * * Return: * slot index on success * -ENOSPC if no slot is available/matches * -EINVAL on wrong operations parameter
*/
staticint hw_breakpoint_slot_setup(struct perf_event **slots, int max_slots, struct perf_event *bp, enum hw_breakpoint_ops ops)
{ int i; struct perf_event **slot;
for (i = 0; i < max_slots; ++i) {
slot = &slots[i]; switch (ops) { case HW_BREAKPOINT_INSTALL: if (!*slot) {
*slot = bp; return i;
} break; case HW_BREAKPOINT_UNINSTALL: if (*slot == bp) {
*slot = NULL; return i;
} break; default:
pr_warn_once("Unhandled hw breakpoint ops %d\n", ops); return -EINVAL;
}
}
/* * Unregister breakpoints from this task and reset the pointers in the thread_struct.
*/ void flush_ptrace_hw_breakpoint(struct task_struct *tsk)
{ int i; struct thread_struct *t = &tsk->thread;
for (i = 0; i < LOONGARCH_MAX_BRP; i++) { if (t->hbp_break[i]) {
unregister_hw_breakpoint(t->hbp_break[i]);
t->hbp_break[i] = NULL;
}
}
for (i = 0; i < LOONGARCH_MAX_WRP; i++) { if (t->hbp_watch[i]) {
unregister_hw_breakpoint(t->hbp_watch[i]);
t->hbp_watch[i] = NULL;
}
}
}
/* * Extract generic type and length encodings from an arch_hw_breakpoint_ctrl. * Hopefully this will disappear when ptrace can bypass the conversion * to generic breakpoint descriptions.
*/ int arch_bp_generic_fields(struct arch_hw_breakpoint_ctrl ctrl, int *gen_len, int *gen_type)
{ /* Type */ switch (ctrl.type) { case LOONGARCH_BREAKPOINT_EXECUTE:
*gen_type = HW_BREAKPOINT_X; break; case LOONGARCH_BREAKPOINT_LOAD:
*gen_type = HW_BREAKPOINT_R; break; case LOONGARCH_BREAKPOINT_STORE:
*gen_type = HW_BREAKPOINT_W; break; case LOONGARCH_BREAKPOINT_LOAD | LOONGARCH_BREAKPOINT_STORE:
*gen_type = HW_BREAKPOINT_RW; break; default: return -EINVAL;
}
/* Len */ switch (ctrl.len) { case LOONGARCH_BREAKPOINT_LEN_1:
*gen_len = HW_BREAKPOINT_LEN_1; break; case LOONGARCH_BREAKPOINT_LEN_2:
*gen_len = HW_BREAKPOINT_LEN_2; break; case LOONGARCH_BREAKPOINT_LEN_4:
*gen_len = HW_BREAKPOINT_LEN_4; break; case LOONGARCH_BREAKPOINT_LEN_8:
*gen_len = HW_BREAKPOINT_LEN_8; break; default: return -EINVAL;
}
return 0;
}
/* * Construct an arch_hw_breakpoint from a perf_event.
*/ staticint arch_build_bp_info(struct perf_event *bp, conststruct perf_event_attr *attr, struct arch_hw_breakpoint *hw)
{ /* Type */ switch (attr->bp_type) { case HW_BREAKPOINT_X:
hw->ctrl.type = LOONGARCH_BREAKPOINT_EXECUTE; break; case HW_BREAKPOINT_R:
hw->ctrl.type = LOONGARCH_BREAKPOINT_LOAD; break; case HW_BREAKPOINT_W:
hw->ctrl.type = LOONGARCH_BREAKPOINT_STORE; break; case HW_BREAKPOINT_RW:
hw->ctrl.type = LOONGARCH_BREAKPOINT_LOAD | LOONGARCH_BREAKPOINT_STORE; break; default: return -EINVAL;
}
/* Len */ switch (attr->bp_len) { case HW_BREAKPOINT_LEN_1:
hw->ctrl.len = LOONGARCH_BREAKPOINT_LEN_1; break; case HW_BREAKPOINT_LEN_2:
hw->ctrl.len = LOONGARCH_BREAKPOINT_LEN_2; break; case HW_BREAKPOINT_LEN_4:
hw->ctrl.len = LOONGARCH_BREAKPOINT_LEN_4; break; case HW_BREAKPOINT_LEN_8:
hw->ctrl.len = LOONGARCH_BREAKPOINT_LEN_8; break; default: return -EINVAL;
}
/* Address */
hw->address = attr->bp_addr;
return 0;
}
/* * Validate the arch-specific HW Breakpoint register settings.
*/ int hw_breakpoint_arch_parse(struct perf_event *bp, conststruct perf_event_attr *attr, struct arch_hw_breakpoint *hw)
{ int ret;
u64 alignment_mask;
/* Build the arch_hw_breakpoint. */
ret = arch_build_bp_info(bp, attr, hw); if (ret) return ret;
staticvoid update_bp_registers(struct pt_regs *regs, int enable, int type)
{
u32 ctrl; int i, max_slots; struct perf_event **slots; struct arch_hw_breakpoint *info;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.