Subversion Repositories HelenOS

Rev

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