00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00035 #include <arch/debugger.h>
00036 #include <console/kconsole.h>
00037 #include <console/cmd.h>
00038 #include <symtab.h>
00039 #include <print.h>
00040 #include <panic.h>
00041 #include <interrupt.h>
00042 #include <arch/asm.h>
00043 #include <arch/cpu.h>
00044 #include <debug.h>
00045 #include <func.h>
00046 #include <smp/ipi.h>
00047
00048 typedef struct {
00049 __address address;
00050 int flags;
00051 int counter;
00052 } bpinfo_t;
00053
00054 static bpinfo_t breakpoints[BKPOINTS_MAX];
00055 SPINLOCK_INITIALIZE(bkpoint_lock);
00056
00057 static int cmd_print_breakpoints(cmd_arg_t *argv);
00058 static cmd_info_t bkpts_info = {
00059 .name = "bkpts",
00060 .description = "Print breakpoint table.",
00061 .func = cmd_print_breakpoints,
00062 .argc = 0,
00063 };
00064
00065 #ifndef CONFIG_DEBUG_AS_WATCHPOINT
00066
00067 static int cmd_del_breakpoint(cmd_arg_t *argv);
00068 static cmd_arg_t del_argv = {
00069 .type = ARG_TYPE_INT
00070 };
00071 static cmd_info_t delbkpt_info = {
00072 .name = "delbkpt",
00073 .description = "delbkpt <number> - Delete breakpoint.",
00074 .func = cmd_del_breakpoint,
00075 .argc = 1,
00076 .argv = &del_argv
00077 };
00078
00079 static int cmd_add_breakpoint(cmd_arg_t *argv);
00080 static cmd_arg_t add_argv = {
00081 .type = ARG_TYPE_INT
00082 };
00083 static cmd_info_t addbkpt_info = {
00084 .name = "addbkpt",
00085 .description = "addbkpt <&symbol> - new breakpoint.",
00086 .func = cmd_add_breakpoint,
00087 .argc = 1,
00088 .argv = &add_argv
00089 };
00090
00091 static cmd_arg_t addw_argv = {
00092 .type = ARG_TYPE_INT
00093 };
00094 static cmd_info_t addwatchp_info = {
00095 .name = "addwatchp",
00096 .description = "addbwatchp <&symbol> - new write watchpoint.",
00097 .func = cmd_add_breakpoint,
00098 .argc = 1,
00099 .argv = &addw_argv
00100 };
00101
00102 #endif
00103
00105 int cmd_print_breakpoints(cmd_arg_t *argv)
00106 {
00107 int i;
00108 char *symbol;
00109
00110 printf("Breakpoint table.\n");
00111 for (i=0; i < BKPOINTS_MAX; i++)
00112 if (breakpoints[i].address) {
00113 symbol = get_symtab_entry(breakpoints[i].address);
00114 printf("%d. %p in %s\n",i,
00115 breakpoints[i].address, symbol);
00116 printf(" Count(%d) ", breakpoints[i].counter);
00117 printf("\n");
00118 }
00119 return 1;
00120 }
00121
00122
00123 static void setup_dr(int curidx)
00124 {
00125 __native dr7;
00126 bpinfo_t *cur = &breakpoints[curidx];
00127 int flags = breakpoints[curidx].flags;
00128
00129
00130 dr7 = read_dr7();
00131 dr7 &= ~(0x2 << (curidx*2));
00132
00133 if (cur->address) {
00134
00135 switch (curidx) {
00136 case 0:
00137 write_dr0(cur->address);
00138 break;
00139 case 1:
00140 write_dr1(cur->address);
00141 break;
00142 case 2:
00143 write_dr2(cur->address);
00144 break;
00145 case 3:
00146 write_dr3(cur->address);
00147 break;
00148 }
00149
00150 dr7 &= ~ (0x3 << (16 + 4*curidx));
00151 dr7 &= ~ (0x3 << (18 + 4*curidx));
00152 if ((flags & BKPOINT_INSTR)) {
00153 ;
00154 } else {
00155 if (sizeof(int) == 4)
00156 dr7 |= ((__native) 0x3) << (18 + 4*curidx);
00157 else
00158 dr7 |= ((__native) 0x2) << (18 + 4*curidx);
00159
00160 if ((flags & BKPOINT_WRITE))
00161 dr7 |= ((__native) 0x1) << (16 + 4*curidx);
00162 else if ((flags & BKPOINT_READ_WRITE))
00163 dr7 |= ((__native) 0x3) << (16 + 4*curidx);
00164 }
00165
00166
00167 dr7 |= 0x2 << (curidx*2);
00168
00169 write_dr7(dr7);
00170
00171 }
00172 }
00173
00181 int breakpoint_add(void * where, int flags, int curidx)
00182 {
00183 ipl_t ipl;
00184 int i;
00185 bpinfo_t *cur;
00186
00187 ASSERT( flags & (BKPOINT_INSTR | BKPOINT_WRITE | BKPOINT_READ_WRITE));
00188
00189 ipl = interrupts_disable();
00190 spinlock_lock(&bkpoint_lock);
00191
00192 if (curidx == -1) {
00193
00194 for (i=0; i<BKPOINTS_MAX; i++)
00195 if (!breakpoints[i].address) {
00196 curidx = i;
00197 break;
00198 }
00199 if (curidx == -1) {
00200
00201 spinlock_unlock(&bkpoint_lock);
00202 interrupts_restore(ipl);
00203 return -1;
00204 }
00205 }
00206 cur = &breakpoints[curidx];
00207
00208 cur->address = (__address) where;
00209 cur->flags = flags;
00210 cur->counter = 0;
00211
00212 setup_dr(curidx);
00213
00214 spinlock_unlock(&bkpoint_lock);
00215 interrupts_restore(ipl);
00216
00217
00218 #ifdef CONFIG_SMP
00219
00220 #endif
00221
00222 return curidx;
00223 }
00224
00225 #ifdef amd64
00226 # define getip(x) ((x)->rip)
00227 #else
00228 # define getip(x) ((x)->eip)
00229 #endif
00230
00231 static void handle_exception(int slot, istate_t *istate)
00232 {
00233 ASSERT(breakpoints[slot].address);
00234
00235
00236 if (! (breakpoints[slot].flags & BKPOINT_INSTR)) {
00237 if ((breakpoints[slot].flags & BKPOINT_CHECK_ZERO)) {
00238 if (*((__native *) breakpoints[slot].address) != 0)
00239 return;
00240 printf("**** Found ZERO on address %p ****\n",
00241 slot, breakpoints[slot].address);
00242 } else {
00243 printf("Data watchpoint - new data: %p\n",
00244 *((__native *) breakpoints[slot].address));
00245 }
00246 }
00247 printf("Reached breakpoint %d:%p(%s)\n", slot, getip(istate),
00248 get_symtab_entry(getip(istate)));
00249 printf("***Type 'exit' to exit kconsole.\n");
00250 atomic_set(&haltstate,1);
00251 kconsole("debug");
00252 atomic_set(&haltstate,0);
00253 }
00254
00255 void breakpoint_del(int slot)
00256 {
00257 bpinfo_t *cur;
00258 ipl_t ipl;
00259
00260 ipl = interrupts_disable();
00261 spinlock_lock(&bkpoint_lock);
00262
00263 cur = &breakpoints[slot];
00264 if (!cur->address) {
00265 spinlock_unlock(&bkpoint_lock);
00266 interrupts_restore(ipl);
00267 return;
00268 }
00269
00270 cur->address = NULL;
00271
00272 setup_dr(slot);
00273
00274 spinlock_unlock(&bkpoint_lock);
00275 interrupts_restore(ipl);
00276 #ifdef CONFIG_SMP
00277
00278 #endif
00279 }
00280
00281 #ifndef CONFIG_DEBUG_AS_WATCHPOINT
00282
00284 int cmd_del_breakpoint(cmd_arg_t *argv)
00285 {
00286 if (argv->intval < 0 || argv->intval > BKPOINTS_MAX) {
00287 printf("Invalid breakpoint number.\n");
00288 return 0;
00289 }
00290 breakpoint_del(argv->intval);
00291 return 1;
00292 }
00293
00295 static int cmd_add_breakpoint(cmd_arg_t *argv)
00296 {
00297 int flags;
00298 int id;
00299
00300 if (argv == &add_argv) {
00301 flags = BKPOINT_INSTR;
00302 } else {
00303 flags = BKPOINT_WRITE;
00304 }
00305 printf("Adding breakpoint on address: %p\n", argv->intval);
00306 id = breakpoint_add((void *)argv->intval, flags, -1);
00307 if (id < 0)
00308 printf("Add breakpoint failed.\n");
00309 else
00310 printf("Added breakpoint %d.\n", id);
00311
00312 return 1;
00313 }
00314 #endif
00315
00316 static void debug_exception(int n, istate_t *istate)
00317 {
00318 __native dr6;
00319 int i;
00320
00321
00322 #ifdef amd64
00323 istate->rflags |= RFLAGS_RF;
00324 #else
00325 istate->eflags |= EFLAGS_RF;
00326 #endif
00327
00328 dr6 = read_dr6();
00329 for (i=0; i < BKPOINTS_MAX; i++) {
00330 if (dr6 & (1 << i)) {
00331 dr6 &= ~ (1 << i);
00332 write_dr6(dr6);
00333
00334 handle_exception(i, istate);
00335 }
00336 }
00337 }
00338
00339 #ifdef CONFIG_SMP
00340 static void debug_ipi(int n, istate_t *istate)
00341 {
00342 int i;
00343
00344 spinlock_lock(&bkpoint_lock);
00345 for (i=0; i < BKPOINTS_MAX; i++)
00346 setup_dr(i);
00347 spinlock_unlock(&bkpoint_lock);
00348 }
00349 #endif
00350
00352 void debugger_init()
00353 {
00354 int i;
00355
00356 for (i=0; i<BKPOINTS_MAX; i++)
00357 breakpoints[i].address = NULL;
00358
00359 cmd_initialize(&bkpts_info);
00360 if (!cmd_register(&bkpts_info))
00361 panic("could not register command %s\n", bkpts_info.name);
00362
00363 #ifndef CONFIG_DEBUG_AS_WATCHPOINT
00364 cmd_initialize(&delbkpt_info);
00365 if (!cmd_register(&delbkpt_info))
00366 panic("could not register command %s\n", delbkpt_info.name);
00367
00368 cmd_initialize(&addbkpt_info);
00369 if (!cmd_register(&addbkpt_info))
00370 panic("could not register command %s\n", addbkpt_info.name);
00371
00372 cmd_initialize(&addwatchp_info);
00373 if (!cmd_register(&addwatchp_info))
00374 panic("could not register command %s\n", addwatchp_info.name);
00375 #endif
00376
00377 exc_register(VECTOR_DEBUG, "debugger",
00378 debug_exception);
00379 #ifdef CONFIG_SMP
00380 exc_register(VECTOR_DEBUG_IPI, "debugger_smp",
00381 debug_ipi);
00382 #endif
00383 }
00384