Subversion Repositories HelenOS

Rev

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