in xmon/xmon.c [492:738]
static int xmon_core(struct pt_regs *regs, volatile int fromipi)
{
volatile int cmd = 0;
struct bpt *volatile bp;
long recurse_jmp[JMP_BUF_LEN];
bool locked_down;
unsigned long offset;
unsigned long flags;
#ifdef CONFIG_SMP
int cpu;
int secondary;
#endif
local_irq_save(flags);
hard_irq_disable();
locked_down = xmon_is_locked_down();
if (!fromipi) {
tracing_enabled = tracing_is_on();
tracing_off();
}
bp = in_breakpoint_table(regs->nip, &offset);
if (bp != NULL) {
regs_set_return_ip(regs, bp->address + offset);
atomic_dec(&bp->ref_count);
}
remove_cpu_bpts();
#ifdef CONFIG_SMP
cpu = smp_processor_id();
if (cpumask_test_cpu(cpu, &cpus_in_xmon)) {
/*
* We catch SPR read/write faults here because the 0x700, 0xf60
* etc. handlers don't call debugger_fault_handler().
*/
if (catch_spr_faults)
longjmp(bus_error_jmp, 1);
get_output_lock();
excprint(regs);
printf("cpu 0x%x: Exception %lx %s in xmon, "
"returning to main loop\n",
cpu, regs->trap, getvecname(TRAP(regs)));
release_output_lock();
longjmp(xmon_fault_jmp[cpu], 1);
}
if (setjmp(recurse_jmp) != 0) {
if (!in_xmon || !xmon_gate) {
get_output_lock();
printf("xmon: WARNING: bad recursive fault "
"on cpu 0x%x\n", cpu);
release_output_lock();
goto waiting;
}
secondary = !(xmon_taken && cpu == xmon_owner);
goto cmdloop;
}
xmon_fault_jmp[cpu] = recurse_jmp;
bp = NULL;
if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT))
bp = at_breakpoint(regs->nip);
if (bp || regs_is_unrecoverable(regs))
fromipi = 0;
if (!fromipi) {
get_output_lock();
if (!locked_down)
excprint(regs);
if (bp) {
printf("cpu 0x%x stopped at breakpoint 0x%tx (",
cpu, BP_NUM(bp));
xmon_print_symbol(regs->nip, " ", ")\n");
}
if (regs_is_unrecoverable(regs))
printf("WARNING: exception is not recoverable, "
"can't continue\n");
release_output_lock();
}
cpumask_set_cpu(cpu, &cpus_in_xmon);
waiting:
secondary = 1;
spin_begin();
while (secondary && !xmon_gate) {
if (in_xmon == 0) {
if (fromipi) {
spin_end();
goto leave;
}
secondary = test_and_set_bit(0, &in_xmon);
}
spin_cpu_relax();
touch_nmi_watchdog();
}
spin_end();
if (!secondary && !xmon_gate) {
/* we are the first cpu to come in */
/* interrupt other cpu(s) */
int ncpus = num_online_cpus();
xmon_owner = cpu;
mb();
if (ncpus > 1) {
/*
* A system reset (trap == 0x100) can be triggered on
* all CPUs, so when we come in via 0x100 try waiting
* for the other CPUs to come in before we send the
* debugger break (IPI). This is similar to
* crash_kexec_secondary().
*/
if (TRAP(regs) != INTERRUPT_SYSTEM_RESET || !wait_for_other_cpus(ncpus))
smp_send_debugger_break();
wait_for_other_cpus(ncpus);
}
remove_bpts();
disable_surveillance();
if (!locked_down) {
/* for breakpoint or single step, print curr insn */
if (bp || TRAP(regs) == INTERRUPT_TRACE)
ppc_inst_dump(regs->nip, 1, 0);
printf("enter ? for help\n");
}
mb();
xmon_gate = 1;
barrier();
touch_nmi_watchdog();
}
cmdloop:
while (in_xmon) {
if (secondary) {
spin_begin();
if (cpu == xmon_owner) {
if (!test_and_set_bit(0, &xmon_taken)) {
secondary = 0;
spin_end();
continue;
}
/* missed it */
while (cpu == xmon_owner)
spin_cpu_relax();
}
spin_cpu_relax();
touch_nmi_watchdog();
} else {
cmd = 1;
#ifdef CONFIG_SMP
if (xmon_batch)
cmd = batch_cmds(regs);
#endif
if (!locked_down && cmd)
cmd = cmds(regs);
if (locked_down || cmd != 0) {
/* exiting xmon */
insert_bpts();
xmon_gate = 0;
wmb();
in_xmon = 0;
break;
}
/* have switched to some other cpu */
secondary = 1;
}
}
leave:
cpumask_clear_cpu(cpu, &cpus_in_xmon);
xmon_fault_jmp[cpu] = NULL;
#else
/* UP is simple... */
if (in_xmon) {
printf("Exception %lx %s in xmon, returning to main loop\n",
regs->trap, getvecname(TRAP(regs)));
longjmp(xmon_fault_jmp[0], 1);
}
if (setjmp(recurse_jmp) == 0) {
xmon_fault_jmp[0] = recurse_jmp;
in_xmon = 1;
excprint(regs);
bp = at_breakpoint(regs->nip);
if (bp) {
printf("Stopped at breakpoint %tx (", BP_NUM(bp));
xmon_print_symbol(regs->nip, " ", ")\n");
}
if (regs_is_unrecoverable(regs))
printf("WARNING: exception is not recoverable, "
"can't continue\n");
remove_bpts();
disable_surveillance();
if (!locked_down) {
/* for breakpoint or single step, print current insn */
if (bp || TRAP(regs) == INTERRUPT_TRACE)
ppc_inst_dump(regs->nip, 1, 0);
printf("enter ? for help\n");
}
}
if (!locked_down)
cmd = cmds(regs);
insert_bpts();
in_xmon = 0;
#endif
#ifdef CONFIG_BOOKE
if (regs->msr & MSR_DE) {
bp = at_breakpoint(regs->nip);
if (bp != NULL) {
regs_set_return_ip(regs, (unsigned long) &bp->instr[0]);
atomic_inc(&bp->ref_count);
}
}
#else
if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) {
bp = at_breakpoint(regs->nip);
if (bp != NULL) {
int stepped = emulate_step(regs, ppc_inst_read(bp->instr));
if (stepped == 0) {
regs_set_return_ip(regs, (unsigned long) &bp->instr[0]);
atomic_inc(&bp->ref_count);
} else if (stepped < 0) {
printf("Couldn't single-step %s instruction\n",
IS_RFID(ppc_inst_read(bp->instr))? "rfid": "mtmsrd");
}
}
}
#endif
if (locked_down)
clear_all_bpt();
else
insert_cpu_bpts();
xmon_touch_watchdogs();
local_irq_restore(flags);
return cmd != 'X' && cmd != EOF;
}