Subversion Repositories HelenOS

Rev

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

  1. /*
  2.  * Copyright (c) 2008 Jiri Svoboda
  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 debug
  30.  * @{
  31.  */
  32. /** @file
  33.  */
  34.  
  35. #include <stdio.h>
  36. #include <stdlib.h>
  37. #include <assert.h>
  38. #include <sys/types.h>
  39. #include <errno.h>
  40. #include <udebug.h>
  41.  
  42. #include "../../../cons.h"
  43. #include "../../../main.h"
  44. #include "../../../breakpoint.h"
  45. #include "../../../include/arch.h"
  46.  
  47. #define OPCODE_BREAK        0x0000000d
  48.  
  49. static istate_t istate;
  50.  
  51. typedef enum {
  52.     OP_J,
  53.     OP_JAL,
  54.     OP_JALR,
  55.     OP_JR
  56. } op_t;
  57.  
  58. typedef struct {
  59.     uint32_t mask;
  60.     uint32_t value;
  61.     op_t op;
  62. } instr_desc_t;
  63.  
  64. static instr_desc_t decoding_table[] = {
  65.     { 0xfc000000, 0x08000000, OP_J },
  66.     { 0xfc000000, 0x0c000000, OP_JAL },
  67.     { 0xfc1f07ff, 0x00000009, OP_JALR },
  68.     { 0xfc1fffff, 0x00000008, OP_JR },
  69.     { 0, 0, -1 }
  70. };
  71.  
  72. int arch_breakpoint_set(breakpoint_t *b)
  73. {
  74.     return bstore_push(&b->arch.bs, b->addr, OPCODE_BREAK);
  75. }
  76.  
  77. int arch_breakpoint_remove(breakpoint_t *b)
  78. {
  79.     return bstore_pop(&b->arch.bs);
  80. }
  81.  
  82. static int islot_read(uintptr_t addr, uint32_t *instr)
  83. {
  84.     int rc;
  85.  
  86.     rc = udebug_mem_read(app_phone, instr, addr, sizeof(uint32_t));
  87.     if (rc != EOK) {
  88.         cons_printf("Error reading memory address 0x%zx\n", addr);
  89.     }
  90.  
  91.     return rc;
  92. }
  93.  
  94. static op_t instr_decode(uint32_t instr)
  95. {
  96.     instr_desc_t *idesc;
  97.  
  98.     idesc = &decoding_table[0];
  99.     while (idesc->op >= 0) {
  100.         if ((instr & idesc->mask) == idesc->value)
  101.             return idesc->op;
  102.         ++idesc;
  103.     }
  104.  
  105.     return -1;
  106. }
  107.  
  108. static int get_reg(int reg_no, uint32_t *value)
  109. {
  110.     int rc;
  111.  
  112.     cons_printf("get_reg...\n");
  113.  
  114.     if (reg_no == 0) {
  115.         *value = 0;
  116.         return 0;
  117.     }
  118.  
  119.     /* FIXME: ugly */
  120.     *value = ((uint32_t *)&istate)[reg_no - 1];
  121.     printf("get_reg ok (0x%08x)\n", *value);
  122.  
  123.     return 0;
  124. }
  125.  
  126. /** Get address of the instruction that will be executed after the current one.
  127.  *
  128.  * Assumptions: addr == PC, *addr is not covered by a BREAK.
  129.  *
  130.  * @param addr  Address of an instruction.
  131.  * @return  Address of the instruction that will be executed afterwards.
  132.  */
  133. static int get_next_addr(uintptr_t addr, uintptr_t *next_addr)
  134. {
  135.     /* TODO: J[AL]R, branches and delay slots */
  136.     uint32_t instr;
  137.     op_t op;
  138.     int rc;
  139.  
  140.     rc = islot_read(addr, &instr);
  141.     if (rc != 0) return rc;
  142.  
  143.     op = instr_decode(instr);
  144.  
  145.     switch (op) {
  146.     case OP_J:
  147.     case OP_JAL:
  148.         *next_addr =
  149.             ((addr + 4) & 0xf0000000) |
  150.             ((instr & 0x03ffffff) << 2);
  151.         break;
  152.     case OP_JR:
  153.     case OP_JALR:
  154.         rc = get_reg((instr >> 21) & 0x1f, next_addr);
  155.         break;
  156.     default:
  157.         /* Regular instruction */  
  158.         *next_addr = addr + 4;
  159.         break;
  160.     }
  161.  
  162.     return 0;  
  163. }
  164.  
  165. static void _ev_breakpoint(thash_t thread_hash)
  166. {
  167.     breakpoint_t *b;
  168.     dthread_t *dt;
  169.     int rc;
  170.     uint32_t epc;
  171.     uintptr_t brk_addr;
  172.     uintptr_t next_addr;
  173.     uint32_t brkp;
  174.  
  175.     brkp = OPCODE_BREAK;
  176.  
  177.     cons_printf("arch_event_breakpoint\n");
  178.  
  179.     rc = udebug_regs_read(app_phone, thread_hash, &istate);
  180.     cons_printf("udebug_regs_read -> %d\n", rc);
  181.     epc = istate_get_pc(&istate);
  182.     cons_printf("EPC was 0x%08x\n", epc);
  183.     brk_addr = epc;
  184.  
  185.     dt = dthread_get();
  186.  
  187.     if (active_bkpt != NULL) {
  188.         assert(active_bkpt->arch.bs.address == brk_addr);
  189.         b = active_bkpt;
  190.  
  191.         /* A breakpoint-clearing BRK has been hit */
  192.         cons_printf("restoring breakpoint %d\n", b->id);
  193.         rc = bstore_pop(&b->arch.bs);
  194.         if (rc != 0) return;
  195.         rc = bstore_push(&b->arch.bs, b->addr, OPCODE_BREAK);
  196.         if (rc != 0) return;
  197.         active_bkpt = NULL;
  198.         return;
  199.     }
  200.  
  201.     b = breakpoint_find_by_addr(brk_addr);
  202.     if (b == NULL) {
  203.         cons_printf("Unrecognized breakpoint at 0x%lx\n", brk_addr);
  204.     }
  205.  
  206.     /* A breakpoint has been hit */
  207.     cons_printf("breakpoint_hit...\n");
  208.     breakpoint_hit(b);
  209.  
  210.     /* While in breakpoint_hit(), singlestep was activated */
  211.     if (dt->arch.singlestep) return;
  212.  
  213.     cons_printf("move breakpoint\b");
  214.     rc = bstore_pop(&b->arch.bs);
  215.     if (rc != 0) return;
  216.  
  217.     rc = get_next_addr(brk_addr, &next_addr);
  218.     if (rc != 0) return;
  219.  
  220.     /*
  221.      * There could be another breakpoint at next_addr,
  222.      * but that's okay. We'll pop the active breakpoint bs
  223.      * before doing anything else.
  224.      */
  225.     rc = bstore_push(&b->arch.bs, next_addr, OPCODE_BREAK);
  226.     if (rc != 0) return;
  227.  
  228.     active_bkpt = b;
  229.     b->active = true;
  230.  
  231.     cons_printf("end_hit...\n");
  232. }
  233.  
  234.  
  235. static void _ev_singlestep(thash_t thread_hash)
  236. {
  237.     dthread_t *dt;
  238.     int rc;
  239.     uint32_t epc;
  240.     int brk_addr;
  241.     uint32_t brkp;
  242.  
  243.     dt = dthread_get();
  244.  
  245.     assert(active_bkpt == NULL);
  246.     assert(dt->arch.singlestep);
  247.     brkp = OPCODE_BREAK;
  248.  
  249.     cons_printf("arch_event_breakpoint\n");
  250.  
  251.     rc = udebug_regs_read(app_phone, thread_hash, &istate);
  252.     cons_printf("udebug_regs_read -> %d\n", rc);
  253.     epc = istate_get_pc(&istate);
  254.     cons_printf("EPC was 0x%08x\n", epc);
  255.     brk_addr = epc;
  256.  
  257.     if (dt->arch.cur.valid) {
  258.         cons_printf("restore breakpoint BRK\n");
  259.         rc = bstore_pop(&dt->arch.cur);
  260.     }
  261.  
  262.     cons_printf("clear singlestep BRK\n");
  263.     rc = bstore_pop(&dt->arch.next);
  264.  
  265.     dt->arch.singlestep = false;
  266.  
  267.     singlestep_hit();
  268. }
  269.  
  270.  
  271. void arch_event_breakpoint(thash_t thread_hash)
  272. {
  273.     dthread_t *dt;
  274.  
  275.     dt = dthread_get();
  276.     if (dt->arch.singlestep) {
  277.         _ev_singlestep(thread_hash);
  278.     } else {
  279.         _ev_breakpoint(thread_hash);
  280.     }
  281. }
  282.  
  283. void arch_event_trap(dthread_t *dt)
  284. {
  285.     /* Unused */
  286.     (void)dt;
  287. }
  288.  
  289. void arch_dump_regs(thash_t thash)
  290. {
  291.     /* TODO */
  292. }
  293.  
  294. void arch_singlestep(dthread_t *dt)
  295. {
  296.     int rc;
  297.     uint32_t epc;
  298.     breakpoint_t *b;
  299.     uint32_t old_instr;
  300.     uintptr_t next_addr;
  301.  
  302.     assert(active_bkpt == NULL);
  303.     assert(dt->arch.singlestep == false);
  304.  
  305.     cons_printf("arch_singlestep(dt)\n");
  306.     rc = udebug_regs_read(app_phone, dt->hash, &istate);
  307.     cons_printf("udebug_regs_read -> %d\n", rc);
  308.     epc = istate_get_pc(&istate);
  309.     cons_printf("EPC was 0x%08x\n", epc);
  310.  
  311.     cons_printf("initial set singlestep\n");
  312.     b = breakpoint_find_by_addr(epc);
  313.     if (b != NULL) {
  314.         /* Cover breakpoint with old instruction */
  315.         old_instr = b->arch.bs.value;
  316.         rc = bstore_push(&dt->arch.cur, epc, old_instr);
  317.         if (rc < 0) return;
  318.     }
  319.  
  320.     rc = get_next_addr(epc, &next_addr);
  321.     if (rc != 0) return;
  322.  
  323.     /* Cover next instruction with BREAK */
  324.     rc = bstore_push(&dt->arch.next, next_addr, OPCODE_BREAK);
  325.     if (rc != 0) return;
  326.  
  327.     dt->arch.singlestep = true;
  328.     dthread_resume(dt);
  329. }
  330.  
  331. /** @}
  332.  */
  333.