debugger.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2006 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 <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 /* Setup DR register according to table */
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         /* Disable breakpoint in DR7 */
00130         dr7 = read_dr7();
00131         dr7 &= ~(0x2 << (curidx*2));
00132 
00133         if (cur->address) { /* Setup DR register */
00134                 /* Set breakpoint to debug registers */
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                 /* Set type to requested breakpoint & length*/
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 /* 8 */
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                 /* Enable global breakpoint */
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                 /* Find free space in slots */
00194                 for (i=0; i<BKPOINTS_MAX; i++)
00195                         if (!breakpoints[i].address) {
00196                                 curidx = i;
00197                                 break;
00198                         }
00199                 if (curidx == -1) {
00200                         /* Too many breakpoints */
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         /* Send IPI */
00218 #ifdef CONFIG_SMP
00219 //      ipi_broadcast(VECTOR_DEBUG_IPI);        
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         /* Handle zero checker */
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 //      ipi_broadcast(VECTOR_DEBUG_IPI);        
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 { /* addwatchp */
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         /* Set RF to restart the instruction  */
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 

Generated on Sun Jun 18 16:26:57 2006 for HelenOS Kernel (amd64) by  doxygen 1.4.6