Blame view
kernel/debug/kdb/kdb_debugger.c
4.31 KB
5d5314d67
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
/* * Created by: Jason Wessel <jason.wessel@windriver.com> * * Copyright (c) 2009 Wind River Systems, Inc. All Rights Reserved. * * This file is licensed under the terms of the GNU General Public * License version 2. This program is licensed "as is" without any * warranty of any kind, whether express or implied. */ #include <linux/kgdb.h> #include <linux/kdb.h> #include <linux/kdebug.h> |
6e5fdeedc
|
14 |
#include <linux/export.h> |
b10d22d6e
|
15 |
#include <linux/hardirq.h> |
5d5314d67
|
16 17 18 19 20 21 22 23 24 |
#include "kdb_private.h" #include "../debug_core.h" /* * KDB interface to KGDB internals */ get_char_func kdb_poll_funcs[] = { dbg_io_get_char, NULL, |
f5316b4ae
|
25 26 27 28 |
NULL, NULL, NULL, NULL, |
5d5314d67
|
29 |
}; |
f5316b4ae
|
30 31 32 33 |
EXPORT_SYMBOL_GPL(kdb_poll_funcs); int kdb_poll_idx = 1; EXPORT_SYMBOL_GPL(kdb_poll_idx); |
5d5314d67
|
34 |
|
f679c4985
|
35 |
static struct kgdb_state *kdb_ks; |
5d5314d67
|
36 37 38 39 40 41 42 43 |
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; |
f679c4985
|
44 |
kdb_ks = ks; |
5d5314d67
|
45 46 47 48 49 50 51 52 |
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; |
b10d22d6e
|
53 54 |
if (in_nmi()) reason = KDB_REASON_NMI; |
5d5314d67
|
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
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); |
495363d38
|
93 |
kdb_initial_cpu = atomic_read(&kgdb_active); |
5d5314d67
|
94 95 96 97 98 99 |
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); |
f5316b4ae
|
100 |
KDB_STATE_SET(PAGER); |
5d5314d67
|
101 102 103 104 105 106 107 108 109 110 111 |
/* 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); } |
5d5314d67
|
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
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; |
f5316b4ae
|
127 |
KDB_STATE_CLEAR(PAGER); |
5d5314d67
|
128 129 |
kdbnearsym_cleanup(); if (error == KDB_CMD_KGDB) { |
d613d828e
|
130 |
if (KDB_STATE(DOING_KGDB)) |
5d5314d67
|
131 |
KDB_STATE_CLEAR(DOING_KGDB); |
5d5314d67
|
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 |
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; } |
f679c4985
|
160 161 162 163 |
void kdb_gdb_state_pass(char *buf) { gdbstub_state(kdb_ks, buf); } |