Subversion Repositories HelenOS

Rev

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

  1. /*
  2.  * Copyright (c) 2005 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 mips32debug
  30.  * @{
  31.  */
  32. /** @file
  33.  */
  34.  
  35. #include <arch/debugger.h>
  36. #include <memstr.h>
  37. #include <console/kconsole.h>
  38. #include <console/cmd.h>
  39. #include <symtab.h>
  40. #include <print.h>
  41. #include <panic.h>
  42. #include <arch.h>
  43. #include <arch/cp0.h>
  44. #include <func.h>
  45.  
  46. bpinfo_t breakpoints[BKPOINTS_MAX];
  47. SPINLOCK_INITIALIZE(bkpoint_lock);
  48.  
  49. static int cmd_print_breakpoints(cmd_arg_t *argv);
  50. static cmd_info_t bkpts_info = {
  51.     .name = "bkpts",
  52.     .description = "Print breakpoint table.",
  53.     .func = cmd_print_breakpoints,
  54.     .argc = 0,
  55. };
  56.  
  57. static int cmd_del_breakpoint(cmd_arg_t *argv);
  58. static cmd_arg_t del_argv = {
  59.     .type = ARG_TYPE_INT
  60. };
  61. static cmd_info_t delbkpt_info = {
  62.     .name = "delbkpt",
  63.     .description = "delbkpt <number> - Delete breakpoint.",
  64.     .func = cmd_del_breakpoint,
  65.     .argc = 1,
  66.     .argv = &del_argv
  67. };
  68.  
  69. static int cmd_add_breakpoint(cmd_arg_t *argv);
  70. static cmd_arg_t add_argv = {
  71.     .type = ARG_TYPE_INT
  72. };
  73. static cmd_info_t addbkpt_info = {
  74.     .name = "addbkpt",
  75.     .description = "addbkpt <&symbol> - new bkpoint. Break on J/Branch insts unsupported.",
  76.     .func = cmd_add_breakpoint,
  77.     .argc = 1,
  78.     .argv = &add_argv
  79. };
  80.  
  81. static cmd_arg_t adde_argv[] = {
  82.     { .type = ARG_TYPE_INT },
  83.     { .type = ARG_TYPE_INT }
  84. };
  85. static cmd_info_t addbkpte_info = {
  86.     .name = "addbkpte",
  87.     .description = "addebkpte <&symbol> <&func> - new bkpoint. Call func(or Nothing if 0).",
  88.     .func = cmd_add_breakpoint,
  89.     .argc = 2,
  90.     .argv = adde_argv
  91. };
  92.  
  93. static struct {
  94.     uint32_t andmask;
  95.     uint32_t value;
  96. }jmpinstr[] = {
  97.     {0xf3ff0000, 0x41000000}, /* BCzF */
  98.     {0xf3ff0000, 0x41020000}, /* BCzFL */
  99.     {0xf3ff0000, 0x41010000}, /* BCzT */
  100.     {0xf3ff0000, 0x41030000}, /* BCzTL */
  101.     {0xfc000000, 0x10000000}, /* BEQ */
  102.     {0xfc000000, 0x50000000}, /* BEQL */
  103.     {0xfc1f0000, 0x04010000}, /* BEQL */
  104.     {0xfc1f0000, 0x04110000}, /* BGEZAL */
  105.     {0xfc1f0000, 0x04130000}, /* BGEZALL */
  106.     {0xfc1f0000, 0x04030000}, /* BGEZL */
  107.     {0xfc1f0000, 0x1c000000}, /* BGTZ */
  108.     {0xfc1f0000, 0x5c000000}, /* BGTZL */
  109.     {0xfc1f0000, 0x18000000}, /* BLEZ */
  110.     {0xfc1f0000, 0x58000000}, /* BLEZL */
  111.     {0xfc1f0000, 0x04000000}, /* BLTZ */
  112.     {0xfc1f0000, 0x04100000}, /* BLTZAL */
  113.     {0xfc1f0000, 0x04120000}, /* BLTZALL */
  114.     {0xfc1f0000, 0x04020000}, /* BLTZL */
  115.     {0xfc000000, 0x14000000}, /* BNE */
  116.     {0xfc000000, 0x54000000}, /* BNEL */
  117.     {0xfc000000, 0x08000000}, /* J */
  118.     {0xfc000000, 0x0c000000}, /* JAL */
  119.     {0xfc1f07ff, 0x00000009}, /* JALR */
  120.     {0,0} /* EndOfTable */
  121. };
  122.  
  123. /** Test, if the given instruction is a jump or branch instruction
  124.  *
  125.  * @param instr Instruction code
  126.  * @return true - it is jump instruction, false otherwise
  127.  */
  128. static bool is_jump(unative_t instr)
  129. {
  130.     int i;
  131.  
  132.     for (i=0;jmpinstr[i].andmask;i++) {
  133.         if ((instr & jmpinstr[i].andmask) == jmpinstr[i].value)
  134.             return true;
  135.     }
  136.  
  137.     return false;
  138. }
  139.  
  140. /** Add new breakpoint to table */
  141. int cmd_add_breakpoint(cmd_arg_t *argv)
  142. {
  143.     bpinfo_t *cur = NULL;
  144.     ipl_t ipl;
  145.     int i;
  146.  
  147.     if (argv->intval & 0x3) {
  148.         printf("Not aligned instruction, forgot to use &symbol?\n");
  149.         return 1;
  150.     }
  151.     ipl = interrupts_disable();
  152.     spinlock_lock(&bkpoint_lock);
  153.  
  154.     /* Check, that the breakpoints do not conflict */
  155.     for (i=0; i<BKPOINTS_MAX; i++) {
  156.         if (breakpoints[i].address == (uintptr_t)argv->intval) {
  157.             printf("Duplicate breakpoint %d.\n", i);
  158.             spinlock_unlock(&bkpoints_lock);
  159.             return 0;
  160.         } else if (breakpoints[i].address == (uintptr_t)argv->intval + sizeof(unative_t) || \
  161.                breakpoints[i].address == (uintptr_t)argv->intval - sizeof(unative_t)) {
  162.             printf("Adjacent breakpoints not supported, conflict with %d.\n", i);
  163.             spinlock_unlock(&bkpoints_lock);
  164.             return 0;
  165.         }
  166.            
  167.     }
  168.  
  169.     for (i=0; i<BKPOINTS_MAX; i++)
  170.         if (!breakpoints[i].address) {
  171.             cur = &breakpoints[i];
  172.             break;
  173.         }
  174.     if (!cur) {
  175.         printf("Too many breakpoints.\n");
  176.         spinlock_unlock(&bkpoint_lock);
  177.         interrupts_restore(ipl);
  178.         return 0;
  179.     }
  180.     cur->address = (uintptr_t) argv->intval;
  181.     printf("Adding breakpoint on address: %p\n", argv->intval);
  182.     cur->instruction = ((unative_t *)cur->address)[0];
  183.     cur->nextinstruction = ((unative_t *)cur->address)[1];
  184.     if (argv == &add_argv) {
  185.         cur->flags = 0;
  186.     } else { /* We are add extended */
  187.         cur->flags = BKPOINT_FUNCCALL;
  188.         cur->bkfunc =   (void (*)(void *, istate_t *)) argv[1].intval;
  189.     }
  190.     if (is_jump(cur->instruction))
  191.         cur->flags |= BKPOINT_ONESHOT;
  192.     cur->counter = 0;
  193.  
  194.     /* Set breakpoint */
  195.     *((unative_t *)cur->address) = 0x0d;
  196.  
  197.     spinlock_unlock(&bkpoint_lock);
  198.     interrupts_restore(ipl);
  199.  
  200.     return 1;
  201. }
  202.  
  203.  
  204.  
  205. /** Remove breakpoint from table */
  206. int cmd_del_breakpoint(cmd_arg_t *argv)
  207. {
  208.     bpinfo_t *cur;
  209.     ipl_t ipl;
  210.  
  211.     if (argv->intval > BKPOINTS_MAX) {
  212.         printf("Invalid breakpoint number.\n");
  213.         return 0;
  214.     }
  215.     ipl = interrupts_disable();
  216.     spinlock_lock(&bkpoint_lock);
  217.  
  218.     cur = &breakpoints[argv->intval];
  219.     if (!cur->address) {
  220.         printf("Breakpoint does not exist.\n");
  221.         spinlock_unlock(&bkpoint_lock);
  222.         interrupts_restore(ipl);
  223.         return 0;
  224.     }
  225.     if ((cur->flags & BKPOINT_INPROG) && (cur->flags & BKPOINT_ONESHOT)) {
  226.         printf("Cannot remove one-shot breakpoint in-progress\n");
  227.         spinlock_unlock(&bkpoint_lock);
  228.         interrupts_restore(ipl);
  229.         return 0;
  230.     }
  231.     ((uint32_t *)cur->address)[0] = cur->instruction;
  232.     ((uint32_t *)cur->address)[1] = cur->nextinstruction;
  233.  
  234.     cur->address = NULL;
  235.  
  236.     spinlock_unlock(&bkpoint_lock);
  237.     interrupts_restore(ipl);
  238.     return 1;
  239. }
  240.  
  241. /** Print table of active breakpoints */
  242. int cmd_print_breakpoints(cmd_arg_t *argv)
  243. {
  244.     unsigned int i;
  245.     char *symbol;
  246.    
  247.     printf("#  Count Address    INPROG ONESHOT FUNCCALL In symbol\n");
  248.     printf("-- ----- ---------- ------ ------- -------- ---------\n");
  249.    
  250.     for (i = 0; i < BKPOINTS_MAX; i++)
  251.         if (breakpoints[i].address) {
  252.             symbol = get_symtab_entry(breakpoints[i].address);
  253.            
  254.             printf("%-2u %-5d %#10zx %-6s %-7s %-8s %s\n", i,
  255.                 breakpoints[i].counter, breakpoints[i].address,
  256.                 ((breakpoints[i].flags & BKPOINT_INPROG) ? "true" : "false"),
  257.                 ((breakpoints[i].flags & BKPOINT_ONESHOT) ? "true" : "false"),
  258.                 ((breakpoints[i].flags & BKPOINT_FUNCCALL) ? "true" : "false"),
  259.                 symbol);
  260.         }
  261.     return 1;
  262. }
  263.  
  264. /** Initialize debugger */
  265. void debugger_init()
  266. {
  267.     int i;
  268.  
  269.     for (i=0; i<BKPOINTS_MAX; i++)
  270.         breakpoints[i].address = NULL;
  271.    
  272.     cmd_initialize(&bkpts_info);
  273.     if (!cmd_register(&bkpts_info))
  274.         panic("could not register command %s\n", bkpts_info.name);
  275.  
  276.     cmd_initialize(&delbkpt_info);
  277.     if (!cmd_register(&delbkpt_info))
  278.         panic("could not register command %s\n", delbkpt_info.name);
  279.  
  280.     cmd_initialize(&addbkpt_info);
  281.     if (!cmd_register(&addbkpt_info))
  282.         panic("could not register command %s\n", addbkpt_info.name);
  283.  
  284.     cmd_initialize(&addbkpte_info);
  285.     if (!cmd_register(&addbkpte_info))
  286.         panic("could not register command %s\n", addbkpte_info.name);
  287. }
  288.  
  289. /** Handle breakpoint
  290.  *
  291.  * Find breakpoint in breakpoint table.
  292.  * If found, call kconsole, set break on next instruction and reexecute.
  293.  * If we are on "next instruction", set it back on the first and reexecute.
  294.  * If breakpoint not found in breakpoint table, call kconsole and start
  295.  * next instruction.
  296.  */
  297. void debugger_bpoint(istate_t *istate)
  298. {
  299.     bpinfo_t *cur = NULL;
  300.     uintptr_t fireaddr = istate->epc;
  301.     int i;
  302.  
  303.     /* test branch delay slot */
  304.     if (cp0_cause_read() & 0x80000000)
  305.         panic("Breakpoint in branch delay slot not supported.\n");
  306.  
  307.     spinlock_lock(&bkpoint_lock);
  308.     for (i=0; i<BKPOINTS_MAX; i++) {
  309.         /* Normal breakpoint */
  310.         if (fireaddr == breakpoints[i].address \
  311.             && !(breakpoints[i].flags & BKPOINT_REINST)) {
  312.             cur = &breakpoints[i];
  313.             break;
  314.         }
  315.         /* Reinst only breakpoint */
  316.         if ((breakpoints[i].flags & BKPOINT_REINST) \
  317.             && (fireaddr ==breakpoints[i].address+sizeof(unative_t))) {
  318.             cur = &breakpoints[i];
  319.             break;
  320.         }
  321.     }
  322.     if (cur) {
  323.         if (cur->flags & BKPOINT_REINST) {
  324.             /* Set breakpoint on first instruction */
  325.             ((uint32_t *)cur->address)[0] = 0x0d;
  326.             /* Return back the second */
  327.             ((uint32_t *)cur->address)[1] = cur->nextinstruction;
  328.             cur->flags &= ~BKPOINT_REINST;
  329.             spinlock_unlock(&bkpoint_lock);
  330.             return;
  331.         }
  332.         if (cur->flags & BKPOINT_INPROG)
  333.             printf("Warning: breakpoint recursion\n");
  334.        
  335.         if (!(cur->flags & BKPOINT_FUNCCALL))
  336.             printf("***Breakpoint %d: %p in %s.\n", i,
  337.                    fireaddr, get_symtab_entry(istate->epc));
  338.  
  339.         /* Return first instruction back */
  340.         ((uint32_t *)cur->address)[0] = cur->instruction;
  341.  
  342.         if (! (cur->flags & BKPOINT_ONESHOT)) {
  343.             /* Set Breakpoint on next instruction */
  344.             ((uint32_t *)cur->address)[1] = 0x0d;
  345.             cur->flags |= BKPOINT_REINST;
  346.         }
  347.         cur->flags |= BKPOINT_INPROG;
  348.     } else {
  349.         printf("***Breakpoint %p in %s.\n", fireaddr,
  350.                get_symtab_entry(fireaddr));
  351.         /* Move on to next instruction */
  352.         istate->epc += 4;
  353.     }
  354.     if (cur)
  355.         cur->counter++;
  356.     if (cur && (cur->flags & BKPOINT_FUNCCALL)) {
  357.         /* Allow zero bkfunc, just for counting */
  358.         if (cur->bkfunc)
  359.             cur->bkfunc(cur, istate);
  360.     } else {
  361.         printf("***Type 'exit' to exit kconsole.\n");
  362.         /* This disables all other processors - we are not SMP,
  363.          * actually this gets us to cpu_halt, if scheduler() is run
  364.          * - we generally do not want scheduler to be run from debug,
  365.          *   so this is a good idea
  366.          */
  367.         atomic_set(&haltstate,1);
  368.         spinlock_unlock(&bkpoint_lock);
  369.  
  370.         kconsole("debug");
  371.  
  372.         spinlock_lock(&bkpoint_lock);
  373.         atomic_set(&haltstate,0);
  374.     }
  375.     if (cur && cur->address == fireaddr && (cur->flags & BKPOINT_INPROG)) {
  376.         /* Remove one-shot breakpoint */
  377.         if ((cur->flags & BKPOINT_ONESHOT))
  378.             cur->address = NULL;
  379.         /* Remove in-progress flag */
  380.         cur->flags &= ~BKPOINT_INPROG;
  381.     }
  382.     spinlock_unlock(&bkpoint_lock);
  383. }
  384.  
  385. /** @}
  386.  */
  387.