Subversion Repositories HelenOS

Rev

Rev 2927 | Rev 4337 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Copyright (c) 2006 Ondrej Palkovsky
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  *
  9.  * - Redistributions of source code must retain the above copyright
  10.  *   notice, this list of conditions and the following disclaimer.
  11.  * - Redistributions in binary form must reproduce the above copyright
  12.  *   notice, this list of conditions and the following disclaimer in the
  13.  *   documentation and/or other materials provided with the distribution.
  14.  * - The name of the author may not be used to endorse or promote products
  15.  *   derived from this software without specific prior written permission.
  16.  *
  17.  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  18.  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  19.  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  20.  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  21.  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  22.  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  23.  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  24.  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  25.  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  26.  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  27.  */
  28.  
  29. /** @addtogroup amd64debug
  30.  * @{
  31.  */
  32. /** @file
  33.  */
  34.  
  35. #include <arch/debugger.h>
  36. #include <console/kconsole.h>
  37. #include <console/cmd.h>
  38. #include <symtab.h>
  39. #include <print.h>
  40. #include <panic.h>
  41. #include <interrupt.h>
  42. #include <arch/asm.h>
  43. #include <arch/cpu.h>
  44. #include <debug.h>
  45. #include <func.h>
  46. #include <smp/ipi.h>
  47.  
  48. typedef struct  {
  49.     uintptr_t address;      /**< Breakpoint address */
  50.     int flags;              /**< Flags regarding breakpoint */
  51.     int counter;            /**< How many times the exception occured */
  52. } bpinfo_t;
  53.  
  54. static bpinfo_t breakpoints[BKPOINTS_MAX];
  55. SPINLOCK_INITIALIZE(bkpoint_lock);
  56.  
  57. static int cmd_print_breakpoints(cmd_arg_t *argv);
  58. static cmd_info_t bkpts_info = {
  59.     .name = "bkpts",
  60.     .description = "Print breakpoint table.",
  61.     .func = cmd_print_breakpoints,
  62.     .argc = 0,
  63. };
  64.  
  65. #ifndef CONFIG_DEBUG_AS_WATCHPOINT
  66.  
  67. static int cmd_del_breakpoint(cmd_arg_t *argv);
  68. static cmd_arg_t del_argv = {
  69.     .type = ARG_TYPE_INT
  70. };
  71. static cmd_info_t delbkpt_info = {
  72.     .name = "delbkpt",
  73.     .description = "delbkpt <number> - Delete breakpoint.",
  74.     .func = cmd_del_breakpoint,
  75.     .argc = 1,
  76.     .argv = &del_argv
  77. };
  78.  
  79. static int cmd_add_breakpoint(cmd_arg_t *argv);
  80. static cmd_arg_t add_argv = {
  81.     .type = ARG_TYPE_INT
  82. };
  83. static cmd_info_t addbkpt_info = {
  84.     .name = "addbkpt",
  85.     .description = "addbkpt <&symbol> - new breakpoint.",
  86.     .func = cmd_add_breakpoint,
  87.     .argc = 1,
  88.     .argv = &add_argv
  89. };
  90.  
  91. static cmd_arg_t addw_argv = {
  92.     .type = ARG_TYPE_INT
  93. };
  94. static cmd_info_t addwatchp_info = {
  95.     .name = "addwatchp",
  96.     .description = "addbwatchp <&symbol> - new write watchpoint.",
  97.     .func = cmd_add_breakpoint,
  98.     .argc = 1,
  99.     .argv = &addw_argv
  100. };
  101.  
  102. #endif
  103.  
  104. /** Print table of active breakpoints */
  105. int cmd_print_breakpoints(cmd_arg_t *argv __attribute__((unused)))
  106. {
  107.     unsigned int i;
  108.     char *symbol;
  109.  
  110. #ifdef __32_BITS__ 
  111.     printf("#  Count Address    In symbol\n");
  112.     printf("-- ----- ---------- ---------\n");
  113. #endif
  114.  
  115. #ifdef __64_BITS__
  116.     printf("#  Count Address            In symbol\n");
  117.     printf("-- ----- ------------------ ---------\n");
  118. #endif
  119.    
  120.     for (i = 0; i < BKPOINTS_MAX; i++)
  121.         if (breakpoints[i].address) {
  122.             symbol = get_symtab_entry(breakpoints[i].address);
  123.  
  124. #ifdef __32_BITS__
  125.             printf("%-2u %-5d %#10zx %s\n", i, breakpoints[i].counter,
  126.                 breakpoints[i].address, symbol);
  127. #endif
  128.  
  129. #ifdef __64_BITS__
  130.             printf("%-2u %-5d %#18zx %s\n", i, breakpoints[i].counter,
  131.                 breakpoints[i].address, symbol);
  132. #endif
  133.  
  134.         }
  135.     return 1;
  136. }
  137.  
  138. /* Setup DR register according to table */
  139. static void setup_dr(int curidx)
  140. {
  141.     unative_t dr7;
  142.     bpinfo_t *cur = &breakpoints[curidx];
  143.     int flags = breakpoints[curidx].flags;
  144.  
  145.     /* Disable breakpoint in DR7 */
  146.     dr7 = read_dr7();
  147.     dr7 &= ~(0x2 << (curidx*2));
  148.  
  149.     if (cur->address) { /* Setup DR register */
  150.         /* Set breakpoint to debug registers */
  151.         switch (curidx) {
  152.         case 0:
  153.             write_dr0(cur->address);
  154.             break;
  155.         case 1:
  156.             write_dr1(cur->address);
  157.             break;
  158.         case 2:
  159.             write_dr2(cur->address);
  160.             break;
  161.         case 3:
  162.             write_dr3(cur->address);
  163.             break;
  164.         }
  165.         /* Set type to requested breakpoint & length*/
  166.         dr7 &= ~ (0x3 << (16 + 4*curidx));
  167.         dr7 &= ~ (0x3 << (18 + 4*curidx));
  168.         if ((flags & BKPOINT_INSTR)) {
  169.             ;
  170.         } else {
  171.        
  172. #ifdef __32_BITS__
  173.             dr7 |= ((unative_t) 0x3) << (18 + 4 * curidx);
  174. #endif
  175.  
  176. #ifdef __64_BITS__
  177.             dr7 |= ((unative_t) 0x2) << (18 + 4 * curidx);
  178. #endif
  179.            
  180.             if ((flags & BKPOINT_WRITE))
  181.                 dr7 |= ((unative_t) 0x1) << (16 + 4 * curidx);
  182.             else if ((flags & BKPOINT_READ_WRITE))
  183.                 dr7 |= ((unative_t) 0x3) << (16 + 4 * curidx);
  184.         }
  185.  
  186.         /* Enable global breakpoint */
  187.         dr7 |= 0x2 << (curidx*2);
  188.  
  189.         write_dr7(dr7);
  190.        
  191.     }
  192. }
  193.    
  194. /** Enable hardware breakpoint
  195.  *
  196.  * @param where Address of HW breakpoint
  197.  * @param flags Type of breakpoint (EXECUTE, WRITE)
  198.  * @return Debug slot on success, -1 - no available HW breakpoint
  199.  */
  200. int breakpoint_add(const void *where, const int flags, int curidx)
  201. {
  202.     ipl_t ipl;
  203.     int i;
  204.     bpinfo_t *cur;
  205.  
  206.     ASSERT(flags & (BKPOINT_INSTR | BKPOINT_WRITE | BKPOINT_READ_WRITE));
  207.  
  208.     ipl = interrupts_disable();
  209.     spinlock_lock(&bkpoint_lock);
  210.    
  211.     if (curidx == -1) {
  212.         /* Find free space in slots */
  213.         for (i = 0; i < BKPOINTS_MAX; i++)
  214.             if (!breakpoints[i].address) {
  215.                 curidx = i;
  216.                 break;
  217.             }
  218.         if (curidx == -1) {
  219.             /* Too many breakpoints */
  220.             spinlock_unlock(&bkpoint_lock);
  221.             interrupts_restore(ipl);
  222.             return -1;
  223.         }
  224.     }
  225.     cur = &breakpoints[curidx];
  226.  
  227.     cur->address = (uintptr_t) where;
  228.     cur->flags = flags;
  229.     cur->counter = 0;
  230.  
  231.     setup_dr(curidx);
  232.  
  233.     spinlock_unlock(&bkpoint_lock);
  234.     interrupts_restore(ipl);
  235.  
  236.     /* Send IPI */
  237. #ifdef CONFIG_SMP
  238. //  ipi_broadcast(VECTOR_DEBUG_IPI);   
  239. #endif 
  240.  
  241.     return curidx;
  242. }
  243.  
  244. #ifdef amd64
  245. #   define getip(x) ((x)->rip)
  246. #else
  247. #   define getip(x) ((x)->eip)
  248. #endif
  249.  
  250. static void handle_exception(int slot, istate_t *istate)
  251. {
  252.     ASSERT(breakpoints[slot].address);
  253.  
  254.     /* Handle zero checker */
  255.     if (! (breakpoints[slot].flags & BKPOINT_INSTR)) {
  256.         if ((breakpoints[slot].flags & BKPOINT_CHECK_ZERO)) {
  257.             if (*((unative_t *) breakpoints[slot].address) != 0)
  258.                 return;
  259.             printf("**** Found ZERO on address %lx (slot %d) ****\n",
  260.                 breakpoints[slot].address, slot);
  261.         } else {
  262.             printf("Data watchpoint - new data: %lx\n",
  263.                    *((unative_t *) breakpoints[slot].address));
  264.         }
  265.     }
  266.     printf("Reached breakpoint %d:%lx(%s)\n", slot, getip(istate),
  267.            get_symtab_entry(getip(istate)));
  268.     printf("***Type 'exit' to exit kconsole.\n");
  269.     atomic_set(&haltstate,1);
  270.     kconsole((void *) "debug");
  271.     atomic_set(&haltstate,0);
  272. }
  273.  
  274. void breakpoint_del(int slot)
  275. {
  276.     bpinfo_t *cur;
  277.     ipl_t ipl;
  278.  
  279.     ipl = interrupts_disable();
  280.     spinlock_lock(&bkpoint_lock);
  281.  
  282.     cur = &breakpoints[slot];
  283.     if (!cur->address) {
  284.         spinlock_unlock(&bkpoint_lock);
  285.         interrupts_restore(ipl);
  286.         return;
  287.     }
  288.  
  289.     cur->address = NULL;
  290.  
  291.     setup_dr(slot);
  292.  
  293.     spinlock_unlock(&bkpoint_lock);
  294.     interrupts_restore(ipl);
  295. #ifdef CONFIG_SMP
  296. //  ipi_broadcast(VECTOR_DEBUG_IPI);   
  297. #endif
  298. }
  299.  
  300. #ifndef CONFIG_DEBUG_AS_WATCHPOINT
  301.  
  302. /** Remove breakpoint from table */
  303. int cmd_del_breakpoint(cmd_arg_t *argv)
  304. {
  305.     unative_t bpno = argv->intval;
  306.     if (bpno > BKPOINTS_MAX) {
  307.         printf("Invalid breakpoint number.\n");
  308.         return 0;
  309.     }
  310.     breakpoint_del(argv->intval);
  311.     return 1;
  312. }
  313.  
  314. /** Add new breakpoint to table */
  315. static int cmd_add_breakpoint(cmd_arg_t *argv)
  316. {
  317.     int flags;
  318.     int id;
  319.  
  320.     if (argv == &add_argv) {
  321.         flags = BKPOINT_INSTR;
  322.     } else { /* addwatchp */
  323.         flags = BKPOINT_WRITE;
  324.     }
  325.     printf("Adding breakpoint on address: %p\n", argv->intval);
  326.     id = breakpoint_add((void *)argv->intval, flags, -1);
  327.     if (id < 0)
  328.         printf("Add breakpoint failed.\n");
  329.     else
  330.         printf("Added breakpoint %d.\n", id);
  331.    
  332.     return 1;
  333. }
  334. #endif
  335.  
  336. static void debug_exception(int n __attribute__((unused)), istate_t *istate)
  337. {
  338.     unative_t dr6;
  339.     int i;
  340.    
  341.     /* Set RF to restart the instruction  */
  342. #ifdef amd64      
  343.     istate->rflags |= RFLAGS_RF;
  344. #else
  345.     istate->eflags |= EFLAGS_RF;
  346. #endif
  347.  
  348.     dr6 = read_dr6();
  349.     for (i=0; i < BKPOINTS_MAX; i++) {
  350.         if (dr6 & (1 << i)) {
  351.             dr6 &= ~ (1 << i);
  352.             write_dr6(dr6);
  353.            
  354.             handle_exception(i, istate);
  355.         }
  356.     }
  357. }
  358.  
  359. #ifdef CONFIG_SMP
  360. static void debug_ipi(int n __attribute__((unused)), istate_t *istate __attribute__((unused)))
  361. {
  362.     int i;
  363.  
  364.     spinlock_lock(&bkpoint_lock);
  365.     for (i = 0; i < BKPOINTS_MAX; i++)
  366.         setup_dr(i);
  367.     spinlock_unlock(&bkpoint_lock);
  368. }
  369. #endif
  370.  
  371. /** Initialize debugger */
  372. void debugger_init()
  373. {
  374.     int i;
  375.  
  376.     for (i=0; i<BKPOINTS_MAX; i++)
  377.         breakpoints[i].address = NULL;
  378.    
  379.     cmd_initialize(&bkpts_info);
  380.     if (!cmd_register(&bkpts_info))
  381.         panic("could not register command %s\n", bkpts_info.name);
  382.  
  383. #ifndef CONFIG_DEBUG_AS_WATCHPOINT
  384.     cmd_initialize(&delbkpt_info);
  385.     if (!cmd_register(&delbkpt_info))
  386.         panic("could not register command %s\n", delbkpt_info.name);
  387.  
  388.     cmd_initialize(&addbkpt_info);
  389.     if (!cmd_register(&addbkpt_info))
  390.         panic("could not register command %s\n", addbkpt_info.name);
  391.  
  392.     cmd_initialize(&addwatchp_info);
  393.     if (!cmd_register(&addwatchp_info))
  394.         panic("could not register command %s\n", addwatchp_info.name);
  395. #endif
  396.    
  397.     exc_register(VECTOR_DEBUG, "debugger",
  398.              debug_exception);
  399. #ifdef CONFIG_SMP
  400.     exc_register(VECTOR_DEBUG_IPI, "debugger_smp",
  401.              debug_ipi);
  402. #endif
  403. }
  404.  
  405. /** @}
  406.  */
  407.