kdb_dbtrap_t kdba_db_trap(struct pt_regs *regs, int error_unused) { kdb_machreg_t dr6; kdb_machreg_t dr7; int rw, reg; int i; kdb_dbtrap_t rv = KDB_DB_BPT; kdb_bp_t *bp; if (KDB_NULL_REGS(regs)) return KDB_DB_NOBPT; dr6 = kdba_getdr6(); dr7 = kdba_getdr7(); if (KDB_DEBUG(BP)) kdb_printf("kdb: dr6 0x%lx dr7 0x%lx\n", dr6, dr7); if (dr6 & DR6_BS) { if (KDB_STATE(SSBPT)) { if (KDB_DEBUG(BP)) kdb_printf("ssbpt\n"); KDB_STATE_CLEAR(SSBPT); for(i=0,bp=kdb_breakpoints; i < KDB_MAXBPT; i++, bp++) { if (KDB_DEBUG(BP)) kdb_printf("bp 0x%p enabled %d delayed %d global %d cpu %d\n", bp, bp->bp_enabled, bp->bp_delayed, bp->bp_global, bp->bp_cpu); if (!bp->bp_enabled) continue; if (!bp->bp_global && bp->bp_cpu != smp_processor_id()) continue; if (KDB_DEBUG(BP)) kdb_printf("bp for this cpu\n"); if (bp->bp_delayed) { bp->bp_delayed = 0; if (KDB_DEBUG(BP)) kdb_printf("kdba_installbp\n"); kdba_installbp(regs, bp); if (!KDB_STATE(DOING_SS)) { regs->eflags &= ~EF_TF; return(KDB_DB_SSBPT); } break; } } if (i == KDB_MAXBPT) { kdb_printf("kdb: Unable to find delayed breakpoint\n"); } if (!KDB_STATE(DOING_SS)) { regs->eflags &= ~EF_TF; return(KDB_DB_NOBPT); } /* FALLTHROUGH */ } /* * KDB_STATE_DOING_SS is set when the kernel debugger is using * the processor trap flag to single-step a processor. If a * single step trap occurs and this flag is clear, the SS trap * will be ignored by KDB and the kernel will be allowed to deal * with it as necessary (e.g. for ptrace). */ if (!KDB_STATE(DOING_SS)) goto unknown; /* single step */ rv = KDB_DB_SS; /* Indicate single step */ if (KDB_STATE(DOING_SSB)) { unsigned char instruction[2]; kdb_id1(regs->rip); if (kdb_getarea(instruction, regs->rip) || (instruction[0]&0xf0) == 0xe0 || /* short disp jumps */ (instruction[0]&0xf0) == 0x70 || /* Misc. jumps */ instruction[0] == 0xc2 || /* ret */ instruction[0] == 0x9a || /* call */ (instruction[0]&0xf8) == 0xc8 || /* enter, leave, iret, int, */ ((instruction[0] == 0x0f) && ((instruction[1]&0xf0)== 0x80)) ) { /* * End the ssb command here. */ KDB_STATE_CLEAR(DOING_SSB); KDB_STATE_CLEAR(DOING_SS); } else { rv = KDB_DB_SSB; /* Indicate ssb - dismiss immediately */ } } else { /* * Print current insn */ kdb_printf("SS trap at "); kdb_symbol_print(regs->rip, NULL, KDB_SP_DEFAULT|KDB_SP_NEWLINE); kdb_id1(regs->rip); KDB_STATE_CLEAR(DOING_SS); } if (rv != KDB_DB_SSB) regs->eflags &= ~EF_TF; } if (dr6 & DR6_B0) { rw = DR7_RW0(dr7); reg = 0; goto handle; } if (dr6 & DR6_B1) { rw = DR7_RW1(dr7); reg = 1; goto handle; } if (dr6 & DR6_B2) { rw = DR7_RW2(dr7); reg = 2; goto handle; } if (dr6 & DR6_B3) { rw = DR7_RW3(dr7); reg = 3; goto handle; } if (rv > 0) goto handled; goto unknown; /* dismiss */ handle: /* * Set Resume Flag */ regs->eflags |= EF_RF; /* * Determine which breakpoint was encountered. */ for(i=0, bp=kdb_breakpoints; i<KDB_MAXBPT; i++, bp++) { if (!(bp->bp_free) && (bp->bp_global || bp->bp_cpu == smp_processor_id()) && (bp->bp_hard) && (bp->bp_hard->bph_reg == reg)) { /* * Hit this breakpoint. */ kdb_printf("%s breakpoint #%d at " kdb_bfd_vma_fmt "\n", kdba_rwtypes[rw], i, bp->bp_addr); /* * For an instruction breakpoint, disassemble * the current instruction. */ if (rw == 0) { kdb_id1(regs->rip); } goto handled; } } unknown: regs->eflags |= EF_RF; /* Supress further faults */ rv = KDB_DB_NOBPT; /* Cause kdb() to return */ handled: /* * Clear the pending exceptions. */ kdba_putdr6(0); return rv; }
int kdb_stub(struct kgdb_state *ks) { int error = 0; kdb_bp_t *bp; unsigned long addr = kgdb_arch_pc(ks->ex_vector, ks->linux_regs); kdb_reason_t reason = KDB_REASON_OOPS; kdb_dbtrap_t db_result = KDB_DB_NOBPT; int i; if (KDB_STATE(REENTRY)) { reason = KDB_REASON_SWITCH; KDB_STATE_CLEAR(REENTRY); addr = instruction_pointer(ks->linux_regs); } ks->pass_exception = 0; if (atomic_read(&kgdb_setting_breakpoint)) reason = KDB_REASON_KEYBOARD; for (i = 0, bp = kdb_breakpoints; i < KDB_MAXBPT; i++, bp++) { if ((bp->bp_enabled) && (bp->bp_addr == addr)) { reason = KDB_REASON_BREAK; db_result = KDB_DB_BPT; if (addr != instruction_pointer(ks->linux_regs)) kgdb_arch_set_pc(ks->linux_regs, addr); break; } } if (reason == KDB_REASON_BREAK || reason == KDB_REASON_SWITCH) { for (i = 0, bp = kdb_breakpoints; i < KDB_MAXBPT; i++, bp++) { if (bp->bp_free) continue; if (bp->bp_addr == addr) { bp->bp_delay = 1; bp->bp_delayed = 1; /* * SSBPT is set when the kernel debugger must single step a * task in order to re-establish an instruction breakpoint * which uses the instruction replacement mechanism. It is * cleared by any action that removes the need to single-step * the breakpoint. */ reason = KDB_REASON_BREAK; db_result = KDB_DB_BPT; KDB_STATE_SET(SSBPT); break; } } } if (reason != KDB_REASON_BREAK && ks->ex_vector == 0 && ks->signo == SIGTRAP) { reason = KDB_REASON_SSTEP; db_result = KDB_DB_BPT; } /* Set initial kdb state variables */ KDB_STATE_CLEAR(KGDB_TRANS); kdb_initial_cpu = ks->cpu; kdb_current_task = kgdb_info[ks->cpu].task; kdb_current_regs = kgdb_info[ks->cpu].debuggerinfo; /* Remove any breakpoints as needed by kdb and clear single step */ kdb_bp_remove(); KDB_STATE_CLEAR(DOING_SS); KDB_STATE_CLEAR(DOING_SSB); KDB_STATE_SET(PAGER); /* zero out any offline cpu data */ for_each_present_cpu(i) { if (!cpu_online(i)) { kgdb_info[i].debuggerinfo = NULL; kgdb_info[i].task = NULL; } } if (ks->err_code == DIE_OOPS || reason == KDB_REASON_OOPS) { ks->pass_exception = 1; KDB_FLAG_SET(CATASTROPHIC); } kdb_initial_cpu = ks->cpu; if (KDB_STATE(SSBPT) && reason == KDB_REASON_SSTEP) { KDB_STATE_CLEAR(SSBPT); KDB_STATE_CLEAR(DOING_SS); } else { /* Start kdb main loop */ error = kdb_main_loop(KDB_REASON_ENTER, reason, ks->err_code, db_result, ks->linux_regs); } /* * Upon exit from the kdb main loop setup break points and restart * the system based on the requested continue state */ kdb_initial_cpu = -1; kdb_current_task = NULL; kdb_current_regs = NULL; KDB_STATE_CLEAR(PAGER); kdbnearsym_cleanup(); if (error == KDB_CMD_KGDB) { if (KDB_STATE(DOING_KGDB) || KDB_STATE(DOING_KGDB2)) { /* * This inteface glue which allows kdb to transition in into * the gdb stub. In order to do this the '?' or '' gdb serial * packet response is processed here. And then control is * passed to the gdbstub. */ if (KDB_STATE(DOING_KGDB)) gdbstub_state(ks, "?"); else gdbstub_state(ks, ""); KDB_STATE_CLEAR(DOING_KGDB); KDB_STATE_CLEAR(DOING_KGDB2); } return DBG_PASS_EVENT; } kdb_bp_install(ks->linux_regs); dbg_activate_sw_breakpoints(); /* Set the exit state to a single step or a continue */ if (KDB_STATE(DOING_SS)) gdbstub_state(ks, "s"); else gdbstub_state(ks, "c"); KDB_FLAG_CLEAR(CATASTROPHIC); /* Invoke arch specific exception handling prior to system resume */ kgdb_info[ks->cpu].ret_state = gdbstub_state(ks, "e"); if (ks->pass_exception) kgdb_info[ks->cpu].ret_state = 1; if (error == KDB_CMD_CPU) { KDB_STATE_SET(REENTRY); /* * Force clear the single step bit because kdb emulates this * differently vs the gdbstub */ kgdb_single_step = 0; dbg_deactivate_sw_breakpoints(); return DBG_SWITCH_CPU_EVENT; } return kgdb_info[ks->cpu].ret_state; }
static int kdb_bc(int argc, const char **argv) { kdb_machreg_t addr; kdb_bp_t *bp = NULL; int lowbp = KDB_MAXBPT; int highbp = 0; int done = 0; int i; int diag; int cmd; /* KDBCMD_B? */ if (strcmp(argv[0], "be") == 0) { cmd = KDBCMD_BE; } else if (strcmp(argv[0], "bd") == 0) { cmd = KDBCMD_BD; } else cmd = KDBCMD_BC; if (argc != 1) return KDB_ARGCOUNT; if (strcmp(argv[1], "*") == 0) { lowbp = 0; highbp = KDB_MAXBPT; } else { diag = kdbgetularg(argv[1], &addr); if (diag) return diag; /* * For addresses less than the maximum breakpoint number, * assume that the breakpoint number is desired. */ if (addr < KDB_MAXBPT) { bp = &kdb_breakpoints[addr]; lowbp = highbp = addr; highbp++; } else { for(i=0, bp=kdb_breakpoints; i<KDB_MAXBPT; i++, bp++) { if (bp->bp_addr == addr) { lowbp = highbp = i; highbp++; break; } } } } /* * Now operate on the set of breakpoints matching the input * criteria (either '*' for all, or an individual breakpoint). */ for(bp=&kdb_breakpoints[lowbp], i=lowbp; i < highbp; i++, bp++) { if (bp->bp_free) continue; done++; switch (cmd) { case KDBCMD_BC: if (bp->bp_hardtype) kdba_free_hwbp(bp); bp->bp_enabled = 0; bp->bp_global = 0; kdb_printf("Breakpoint %d at " kdb_bfd_vma_fmt " cleared\n", i, bp->bp_addr); bp->bp_addr = 0; bp->bp_free = 1; break; case KDBCMD_BE: /* * Allocate a hardware breakpoint. If one is not * available, don't enable the breakpoint. */ if (!bp->bp_template.bph_free && !bp->bp_hardtype) { kdba_alloc_hwbp(bp, &diag); if (diag) { bp->bp_enabled = 0; bp->bp_hardtype = 0; kdba_free_hwbp(bp); return diag; } } bp->bp_enabled = 1; kdb_printf("Breakpoint %d at " kdb_bfd_vma_fmt " enabled", i, bp->bp_addr); kdb_printf("\n"); break; case KDBCMD_BD: if (!bp->bp_enabled) break; /* * Since this breakpoint is now disabled, we can * give up the hardware register which is allocated * to it. */ if (bp->bp_hardtype) kdba_free_hwbp(bp); bp->bp_enabled = 0; kdb_printf("Breakpoint %d at " kdb_bfd_vma_fmt " disabled\n", i, bp->bp_addr); break; } if (bp->bp_delay && (cmd == KDBCMD_BC || cmd == KDBCMD_BD)) { bp->bp_delay = 0; KDB_STATE_CLEAR(SSBPT); } } return (!done)?KDB_BPTNOTFOUND:0; }