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 <memstr.h>
00037 #include <console/kconsole.h>
00038 #include <console/cmd.h>
00039 #include <symtab.h>
00040 #include <print.h>
00041 #include <panic.h>
00042 #include <arch.h>
00043 #include <arch/cp0.h>
00044 #include <func.h>
00045
00046 bpinfo_t breakpoints[BKPOINTS_MAX];
00047 SPINLOCK_INITIALIZE(bkpoint_lock);
00048
00049 static int cmd_print_breakpoints(cmd_arg_t *argv);
00050 static cmd_info_t bkpts_info = {
00051 .name = "bkpts",
00052 .description = "Print breakpoint table.",
00053 .func = cmd_print_breakpoints,
00054 .argc = 0,
00055 };
00056
00057 static int cmd_del_breakpoint(cmd_arg_t *argv);
00058 static cmd_arg_t del_argv = {
00059 .type = ARG_TYPE_INT
00060 };
00061 static cmd_info_t delbkpt_info = {
00062 .name = "delbkpt",
00063 .description = "delbkpt <number> - Delete breakpoint.",
00064 .func = cmd_del_breakpoint,
00065 .argc = 1,
00066 .argv = &del_argv
00067 };
00068
00069 static int cmd_add_breakpoint(cmd_arg_t *argv);
00070 static cmd_arg_t add_argv = {
00071 .type = ARG_TYPE_INT
00072 };
00073 static cmd_info_t addbkpt_info = {
00074 .name = "addbkpt",
00075 .description = "addbkpt <&symbol> - new bkpoint. Break on J/Branch insts unsupported.",
00076 .func = cmd_add_breakpoint,
00077 .argc = 1,
00078 .argv = &add_argv
00079 };
00080
00081 static cmd_arg_t adde_argv[] = {
00082 { .type = ARG_TYPE_INT },
00083 { .type = ARG_TYPE_INT }
00084 };
00085 static cmd_info_t addbkpte_info = {
00086 .name = "addbkpte",
00087 .description = "addebkpte <&symbol> <&func> - new bkpoint. Call func(or Nothing if 0).",
00088 .func = cmd_add_breakpoint,
00089 .argc = 2,
00090 .argv = adde_argv
00091 };
00092
00093 static struct {
00094 __u32 andmask;
00095 __u32 value;
00096 }jmpinstr[] = {
00097 {0xf3ff0000, 0x41000000},
00098 {0xf3ff0000, 0x41020000},
00099 {0xf3ff0000, 0x41010000},
00100 {0xf3ff0000, 0x41030000},
00101 {0xfc000000, 0x10000000},
00102 {0xfc000000, 0x50000000},
00103 {0xfc1f0000, 0x04010000},
00104 {0xfc1f0000, 0x04110000},
00105 {0xfc1f0000, 0x04130000},
00106 {0xfc1f0000, 0x04030000},
00107 {0xfc1f0000, 0x1c000000},
00108 {0xfc1f0000, 0x5c000000},
00109 {0xfc1f0000, 0x18000000},
00110 {0xfc1f0000, 0x58000000},
00111 {0xfc1f0000, 0x04000000},
00112 {0xfc1f0000, 0x04100000},
00113 {0xfc1f0000, 0x04120000},
00114 {0xfc1f0000, 0x04020000},
00115 {0xfc000000, 0x14000000},
00116 {0xfc000000, 0x54000000},
00117 {0xfc000000, 0x08000000},
00118 {0xfc000000, 0x0c000000},
00119 {0xfc1f07ff, 0x00000009},
00120 {0,0}
00121 };
00122
00128 static bool is_jump(__native instr)
00129 {
00130 int i;
00131
00132 for (i=0;jmpinstr[i].andmask;i++) {
00133 if ((instr & jmpinstr[i].andmask) == jmpinstr[i].value)
00134 return true;
00135 }
00136
00137 return false;
00138 }
00139
00141 int cmd_add_breakpoint(cmd_arg_t *argv)
00142 {
00143 bpinfo_t *cur = NULL;
00144 ipl_t ipl;
00145 int i;
00146
00147 if (argv->intval & 0x3) {
00148 printf("Not aligned instruction, forgot to use &symbol?\n");
00149 return 1;
00150 }
00151 ipl = interrupts_disable();
00152 spinlock_lock(&bkpoint_lock);
00153
00154
00155 for (i=0; i<BKPOINTS_MAX; i++) {
00156 if (breakpoints[i].address == (__address)argv->intval) {
00157 printf("Duplicate breakpoint %d.\n", i);
00158 spinlock_unlock(&bkpoints_lock);
00159 return 0;
00160 } else if (breakpoints[i].address == (__address)argv->intval + sizeof(__native) || \
00161 breakpoints[i].address == (__address)argv->intval - sizeof(__native)) {
00162 printf("Adjacent breakpoints not supported, conflict with %d.\n", i);
00163 spinlock_unlock(&bkpoints_lock);
00164 return 0;
00165 }
00166
00167 }
00168
00169 for (i=0; i<BKPOINTS_MAX; i++)
00170 if (!breakpoints[i].address) {
00171 cur = &breakpoints[i];
00172 break;
00173 }
00174 if (!cur) {
00175 printf("Too many breakpoints.\n");
00176 spinlock_unlock(&bkpoint_lock);
00177 interrupts_restore(ipl);
00178 return 0;
00179 }
00180 cur->address = (__address) argv->intval;
00181 printf("Adding breakpoint on address: %p\n", argv->intval);
00182 cur->instruction = ((__native *)cur->address)[0];
00183 cur->nextinstruction = ((__native *)cur->address)[1];
00184 if (argv == &add_argv) {
00185 cur->flags = 0;
00186 } else {
00187 cur->flags = BKPOINT_FUNCCALL;
00188 cur->bkfunc = (void (*)(void *, istate_t *)) argv[1].intval;
00189 }
00190 if (is_jump(cur->instruction))
00191 cur->flags |= BKPOINT_ONESHOT;
00192 cur->counter = 0;
00193
00194
00195 *((__native *)cur->address) = 0x0d;
00196
00197 spinlock_unlock(&bkpoint_lock);
00198 interrupts_restore(ipl);
00199
00200 return 1;
00201 }
00202
00203
00204
00206 int cmd_del_breakpoint(cmd_arg_t *argv)
00207 {
00208 bpinfo_t *cur;
00209 ipl_t ipl;
00210
00211 if (argv->intval < 0 || argv->intval > BKPOINTS_MAX) {
00212 printf("Invalid breakpoint number.\n");
00213 return 0;
00214 }
00215 ipl = interrupts_disable();
00216 spinlock_lock(&bkpoint_lock);
00217
00218 cur = &breakpoints[argv->intval];
00219 if (!cur->address) {
00220 printf("Breakpoint does not exist.\n");
00221 spinlock_unlock(&bkpoint_lock);
00222 interrupts_restore(ipl);
00223 return 0;
00224 }
00225 if ((cur->flags & BKPOINT_INPROG) && (cur->flags & BKPOINT_ONESHOT)) {
00226 printf("Cannot remove one-shot breakpoint in-progress\n");
00227 spinlock_unlock(&bkpoint_lock);
00228 interrupts_restore(ipl);
00229 return 0;
00230 }
00231 ((__u32 *)cur->address)[0] = cur->instruction;
00232 ((__u32 *)cur->address)[1] = cur->nextinstruction;
00233
00234 cur->address = NULL;
00235
00236 spinlock_unlock(&bkpoint_lock);
00237 interrupts_restore(ipl);
00238 return 1;
00239 }
00240
00242 int cmd_print_breakpoints(cmd_arg_t *argv)
00243 {
00244 int i;
00245 char *symbol;
00246
00247 printf("Breakpoint table.\n");
00248 for (i=0; i < BKPOINTS_MAX; i++)
00249 if (breakpoints[i].address) {
00250 symbol = get_symtab_entry(breakpoints[i].address);
00251 printf("%d. %p in %s\n",i,
00252 breakpoints[i].address, symbol);
00253 printf(" Count(%d) ", breakpoints[i].counter);
00254 if (breakpoints[i].flags & BKPOINT_INPROG)
00255 printf("INPROG ");
00256 if (breakpoints[i].flags & BKPOINT_ONESHOT)
00257 printf("ONESHOT ");
00258 if (breakpoints[i].flags & BKPOINT_FUNCCALL)
00259 printf("FUNCCALL ");
00260 printf("\n");
00261 }
00262 return 1;
00263 }
00264
00266 void debugger_init()
00267 {
00268 int i;
00269
00270 for (i=0; i<BKPOINTS_MAX; i++)
00271 breakpoints[i].address = NULL;
00272
00273 cmd_initialize(&bkpts_info);
00274 if (!cmd_register(&bkpts_info))
00275 panic("could not register command %s\n", bkpts_info.name);
00276
00277 cmd_initialize(&delbkpt_info);
00278 if (!cmd_register(&delbkpt_info))
00279 panic("could not register command %s\n", delbkpt_info.name);
00280
00281 cmd_initialize(&addbkpt_info);
00282 if (!cmd_register(&addbkpt_info))
00283 panic("could not register command %s\n", addbkpt_info.name);
00284
00285 cmd_initialize(&addbkpte_info);
00286 if (!cmd_register(&addbkpte_info))
00287 panic("could not register command %s\n", addbkpte_info.name);
00288 }
00289
00298 void debugger_bpoint(istate_t *istate)
00299 {
00300 bpinfo_t *cur = NULL;
00301 __address fireaddr = istate->epc;
00302 int i;
00303
00304
00305 if (cp0_cause_read() & 0x80000000)
00306 panic("Breakpoint in branch delay slot not supported.\n");
00307
00308 spinlock_lock(&bkpoint_lock);
00309 for (i=0; i<BKPOINTS_MAX; i++) {
00310
00311 if (fireaddr == breakpoints[i].address \
00312 && !(breakpoints[i].flags & BKPOINT_REINST)) {
00313 cur = &breakpoints[i];
00314 break;
00315 }
00316
00317 if ((breakpoints[i].flags & BKPOINT_REINST) \
00318 && (fireaddr ==breakpoints[i].address+sizeof(__native))) {
00319 cur = &breakpoints[i];
00320 break;
00321 }
00322 }
00323 if (cur) {
00324 if (cur->flags & BKPOINT_REINST) {
00325
00326 ((__u32 *)cur->address)[0] = 0x0d;
00327
00328 ((__u32 *)cur->address)[1] = cur->nextinstruction;
00329 cur->flags &= ~BKPOINT_REINST;
00330 spinlock_unlock(&bkpoint_lock);
00331 return;
00332 }
00333 if (cur->flags & BKPOINT_INPROG)
00334 printf("Warning: breakpoint recursion\n");
00335
00336 if (!(cur->flags & BKPOINT_FUNCCALL))
00337 printf("***Breakpoint %d: %p in %s.\n", i,
00338 fireaddr, get_symtab_entry(istate->epc));
00339
00340
00341 ((__u32 *)cur->address)[0] = cur->instruction;
00342
00343 if (! (cur->flags & BKPOINT_ONESHOT)) {
00344
00345 ((__u32 *)cur->address)[1] = 0x0d;
00346 cur->flags |= BKPOINT_REINST;
00347 }
00348 cur->flags |= BKPOINT_INPROG;
00349 } else {
00350 printf("***Breakpoint %p in %s.\n", fireaddr,
00351 get_symtab_entry(fireaddr));
00352
00353 istate->epc += 4;
00354 }
00355 if (cur)
00356 cur->counter++;
00357 if (cur && (cur->flags & BKPOINT_FUNCCALL)) {
00358
00359 if (cur->bkfunc)
00360 cur->bkfunc(cur, istate);
00361 } else {
00362 printf("***Type 'exit' to exit kconsole.\n");
00363
00364
00365
00366
00367
00368 atomic_set(&haltstate,1);
00369 spinlock_unlock(&bkpoint_lock);
00370
00371 kconsole("debug");
00372
00373 spinlock_lock(&bkpoint_lock);
00374 atomic_set(&haltstate,0);
00375 }
00376 if (cur && cur->address == fireaddr && (cur->flags & BKPOINT_INPROG)) {
00377
00378 if ((cur->flags & BKPOINT_ONESHOT))
00379 cur->address = NULL;
00380
00381 cur->flags &= ~BKPOINT_INPROG;
00382 }
00383 spinlock_unlock(&bkpoint_lock);
00384 }
00385