debugger.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2005 Ondrej Palkovsky
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  *
00009  * - Redistributions of source code must retain the above copyright
00010  *   notice, this list of conditions and the following disclaimer.
00011  * - Redistributions in binary form must reproduce the above copyright
00012  *   notice, this list of conditions and the following disclaimer in the
00013  *   documentation and/or other materials provided with the distribution.
00014  * - The name of the author may not be used to endorse or promote products
00015  *   derived from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00018  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00019  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00020  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00021  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00022  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00023  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00024  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00025  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00026  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
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}, /* BCzF */
00098         {0xf3ff0000, 0x41020000}, /* BCzFL */
00099         {0xf3ff0000, 0x41010000}, /* BCzT */
00100         {0xf3ff0000, 0x41030000}, /* BCzTL */
00101         {0xfc000000, 0x10000000}, /* BEQ */
00102         {0xfc000000, 0x50000000}, /* BEQL */
00103         {0xfc1f0000, 0x04010000}, /* BEQL */
00104         {0xfc1f0000, 0x04110000}, /* BGEZAL */
00105         {0xfc1f0000, 0x04130000}, /* BGEZALL */
00106         {0xfc1f0000, 0x04030000}, /* BGEZL */
00107         {0xfc1f0000, 0x1c000000}, /* BGTZ */
00108         {0xfc1f0000, 0x5c000000}, /* BGTZL */
00109         {0xfc1f0000, 0x18000000}, /* BLEZ */
00110         {0xfc1f0000, 0x58000000}, /* BLEZL */
00111         {0xfc1f0000, 0x04000000}, /* BLTZ */
00112         {0xfc1f0000, 0x04100000}, /* BLTZAL */
00113         {0xfc1f0000, 0x04120000}, /* BLTZALL */
00114         {0xfc1f0000, 0x04020000}, /* BLTZL */
00115         {0xfc000000, 0x14000000}, /* BNE */
00116         {0xfc000000, 0x54000000}, /* BNEL */
00117         {0xfc000000, 0x08000000}, /* J */
00118         {0xfc000000, 0x0c000000}, /* JAL */
00119         {0xfc1f07ff, 0x00000009}, /* JALR */
00120         {0,0} /* EndOfTable */
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         /* Check, that the breakpoints do not conflict */
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 { /* We are add extended */
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         /* Set breakpoint */
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         /* test branch delay slot */
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                 /* Normal breakpoint */
00311                 if (fireaddr == breakpoints[i].address \
00312                     && !(breakpoints[i].flags & BKPOINT_REINST)) {
00313                         cur = &breakpoints[i];
00314                         break;
00315                 }
00316                 /* Reinst only breakpoint */
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                         /* Set breakpoint on first instruction */
00326                         ((__u32 *)cur->address)[0] = 0x0d;
00327                         /* Return back the second */
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                 /* Return first instruction back */
00341                 ((__u32 *)cur->address)[0] = cur->instruction;
00342 
00343                 if (! (cur->flags & BKPOINT_ONESHOT)) {
00344                         /* Set Breakpoint on next instruction */
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                 /* Move on to next instruction */
00353                 istate->epc += 4;
00354         }
00355         if (cur)
00356                 cur->counter++;
00357         if (cur && (cur->flags & BKPOINT_FUNCCALL)) {
00358                 /* Allow zero bkfunc, just for counting */
00359                 if (cur->bkfunc)
00360                         cur->bkfunc(cur, istate);
00361         } else {
00362                 printf("***Type 'exit' to exit kconsole.\n");
00363                 /* This disables all other processors - we are not SMP,
00364                  * actually this gets us to cpu_halt, if scheduler() is run
00365                  * - we generally do not want scheduler to be run from debug,
00366                  *   so this is a good idea
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                 /* Remove one-shot breakpoint */
00378                 if ((cur->flags & BKPOINT_ONESHOT))
00379                         cur->address = NULL;
00380                 /* Remove in-progress flag */
00381                 cur->flags &= ~BKPOINT_INPROG;
00382         } 
00383         spinlock_unlock(&bkpoint_lock);
00384 }
00385 

Generated on Sun Jun 18 17:01:57 2006 for HelenOS Kernel (mips32) by  doxygen 1.4.6