Subversion Repositories HelenOS

Rev

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