x86,kgdb: Implement early hardware breakpoint debugging
It is not possible to use the hw_breakpoint.c API prior to mm_init(), but it is possible to use hardware breakpoints with the kernel debugger. Prior to smp_init() it is possible to simply write to the dr registers of the boot cpu directly. This can be used up until the kgdb_arch_late() is invoked, at which point the standard hw_breakpoint.c API will get used. CC: Frederic Weisbecker <fweisbec@gmail.com> CC: Ingo Molnar <mingo@elte.hu> Signed-off-by: Jason Wessel <jason.wessel@windriver.com>
This commit is contained in:
@@ -199,6 +199,8 @@ static struct hw_breakpoint {
|
|||||||
struct perf_event **pev;
|
struct perf_event **pev;
|
||||||
} breakinfo[4];
|
} breakinfo[4];
|
||||||
|
|
||||||
|
static unsigned long early_dr7;
|
||||||
|
|
||||||
static void kgdb_correct_hw_break(void)
|
static void kgdb_correct_hw_break(void)
|
||||||
{
|
{
|
||||||
int breakno;
|
int breakno;
|
||||||
@@ -210,6 +212,14 @@ static void kgdb_correct_hw_break(void)
|
|||||||
int cpu = raw_smp_processor_id();
|
int cpu = raw_smp_processor_id();
|
||||||
if (!breakinfo[breakno].enabled)
|
if (!breakinfo[breakno].enabled)
|
||||||
continue;
|
continue;
|
||||||
|
if (dbg_is_early) {
|
||||||
|
set_debugreg(breakinfo[breakno].addr, breakno);
|
||||||
|
early_dr7 |= encode_dr7(breakno,
|
||||||
|
breakinfo[breakno].len,
|
||||||
|
breakinfo[breakno].type);
|
||||||
|
set_debugreg(early_dr7, 7);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
bp = *per_cpu_ptr(breakinfo[breakno].pev, cpu);
|
bp = *per_cpu_ptr(breakinfo[breakno].pev, cpu);
|
||||||
info = counter_arch_bp(bp);
|
info = counter_arch_bp(bp);
|
||||||
if (bp->attr.disabled != 1)
|
if (bp->attr.disabled != 1)
|
||||||
@@ -224,7 +234,8 @@ static void kgdb_correct_hw_break(void)
|
|||||||
if (!val)
|
if (!val)
|
||||||
bp->attr.disabled = 0;
|
bp->attr.disabled = 0;
|
||||||
}
|
}
|
||||||
hw_breakpoint_restore();
|
if (!dbg_is_early)
|
||||||
|
hw_breakpoint_restore();
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hw_break_reserve_slot(int breakno)
|
static int hw_break_reserve_slot(int breakno)
|
||||||
@@ -233,6 +244,9 @@ static int hw_break_reserve_slot(int breakno)
|
|||||||
int cnt = 0;
|
int cnt = 0;
|
||||||
struct perf_event **pevent;
|
struct perf_event **pevent;
|
||||||
|
|
||||||
|
if (dbg_is_early)
|
||||||
|
return 0;
|
||||||
|
|
||||||
for_each_online_cpu(cpu) {
|
for_each_online_cpu(cpu) {
|
||||||
cnt++;
|
cnt++;
|
||||||
pevent = per_cpu_ptr(breakinfo[breakno].pev, cpu);
|
pevent = per_cpu_ptr(breakinfo[breakno].pev, cpu);
|
||||||
@@ -258,6 +272,9 @@ static int hw_break_release_slot(int breakno)
|
|||||||
struct perf_event **pevent;
|
struct perf_event **pevent;
|
||||||
int cpu;
|
int cpu;
|
||||||
|
|
||||||
|
if (dbg_is_early)
|
||||||
|
return 0;
|
||||||
|
|
||||||
for_each_online_cpu(cpu) {
|
for_each_online_cpu(cpu) {
|
||||||
pevent = per_cpu_ptr(breakinfo[breakno].pev, cpu);
|
pevent = per_cpu_ptr(breakinfo[breakno].pev, cpu);
|
||||||
if (dbg_release_bp_slot(*pevent))
|
if (dbg_release_bp_slot(*pevent))
|
||||||
@@ -302,7 +319,11 @@ static void kgdb_remove_all_hw_break(void)
|
|||||||
bp = *per_cpu_ptr(breakinfo[i].pev, cpu);
|
bp = *per_cpu_ptr(breakinfo[i].pev, cpu);
|
||||||
if (bp->attr.disabled == 1)
|
if (bp->attr.disabled == 1)
|
||||||
continue;
|
continue;
|
||||||
arch_uninstall_hw_breakpoint(bp);
|
if (dbg_is_early)
|
||||||
|
early_dr7 &= ~encode_dr7(i, breakinfo[i].len,
|
||||||
|
breakinfo[i].type);
|
||||||
|
else
|
||||||
|
arch_uninstall_hw_breakpoint(bp);
|
||||||
bp->attr.disabled = 1;
|
bp->attr.disabled = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -379,6 +400,11 @@ void kgdb_disable_hw_debug(struct pt_regs *regs)
|
|||||||
for (i = 0; i < 4; i++) {
|
for (i = 0; i < 4; i++) {
|
||||||
if (!breakinfo[i].enabled)
|
if (!breakinfo[i].enabled)
|
||||||
continue;
|
continue;
|
||||||
|
if (dbg_is_early) {
|
||||||
|
early_dr7 &= ~encode_dr7(i, breakinfo[i].len,
|
||||||
|
breakinfo[i].type);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
bp = *per_cpu_ptr(breakinfo[i].pev, cpu);
|
bp = *per_cpu_ptr(breakinfo[i].pev, cpu);
|
||||||
if (bp->attr.disabled == 1)
|
if (bp->attr.disabled == 1)
|
||||||
continue;
|
continue;
|
||||||
|
Reference in New Issue
Block a user