Subversion Repositories HelenOS

Rev

Rev 3124 | 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. #include "../../../include/arch/arch.h"
  47. #include "../../../genarch/idec/idec.h"
  48.  
  49. static istate_t istate;
  50.  
  51. typedef enum {
  52.     /* Branch */
  53.     OP_B,
  54.     OP_BL,
  55.     OP_BLX1,
  56.     OP_BLX2,
  57.     OP_BX,
  58.  
  59.     OP_MOV_PC_LR
  60. } op_t;
  61.  
  62. typedef struct {
  63.     uint32_t mask;
  64.     uint32_t value;
  65.     op_t op;
  66. } instr_desc_t;
  67.  
  68. static instr_desc_t decoding_table[] = {
  69.     /* Unconditional branch (link) and exchange */
  70.     { 0xfe000000, 0xfa000000, OP_BLX1 },
  71.     { 0x0ffffff0, 0x012fff30, OP_BLX2 },
  72.     { 0x0ffffff0, 0x012fff10, OP_BX },
  73.  
  74.     /*
  75.      * Order is significant here, as the condition code for B, BL
  76.      * (the top 4 bits) must not be 0xf, which is caught by BLX, BX
  77.      */
  78.  
  79.     /* Branch (and link) */
  80.     { 0x0f000000, 0x0a000000, OP_B },
  81.     { 0x0f000000, 0x0b000000, OP_BL },
  82.  
  83.     /* mov pc, lr */
  84.     { 0xffffffff, 0xe1a0f00e, OP_MOV_PC_LR },
  85.  
  86.     { 0, 0, -1 }
  87. };
  88.  
  89. /** Sign-extend a value to 32 bits.
  90.  *
  91.  * @param val   A signed value (of limited width)
  92.  * @param bits  Bit-width of value.
  93.  * @return The value extended to a 32-bit signed integer.
  94.  */
  95. #define EXTS(val, bits) ((int32_t)(val) << (32 - (bits)) >> (32 - (bits)))
  96.  
  97. void arch_dthread_initialize(dthread_t *dt)
  98. {
  99.     dt->arch.singlestep = false;
  100.  
  101.     bstore_initialize(&dt->arch.cur);
  102.     bstore_initialize(&dt->arch.next[0]);
  103.     bstore_initialize(&dt->arch.next[1]);
  104. }
  105.  
  106. int arch_breakpoint_set(breakpoint_t *b)
  107. {
  108.     int rc;
  109.  
  110.     rc = idec_breakpoint_set(b);
  111.     if (rc != 0) return rc;
  112.  
  113.     return 0;
  114. }
  115.  
  116. int arch_breakpoint_remove(breakpoint_t *b)
  117. {
  118.     return idec_breakpoint_remove(b);
  119. }
  120.  
  121. static int islot_read(uintptr_t addr, uint32_t *instr)
  122. {
  123.     int rc;
  124.  
  125.     rc = udebug_mem_read(app_phone, instr, addr, sizeof(uint32_t));
  126.     if (rc != EOK) {
  127.         cons_printf("Error reading memory address 0x%zx\n", addr);
  128.     }
  129.  
  130.     return rc;
  131. }
  132.  
  133. static int get_reg(dthread_t *dt, int reg_no, uint32_t *value)
  134. {
  135.     int rc;
  136.  
  137.     cons_printf("get_reg...\n");
  138.  
  139.     if (reg_no == 0) {
  140.         *value = 0;
  141.         return 0;
  142.     }
  143.  
  144.     rc = udebug_regs_read(app_phone, dt->hash, &istate);
  145.     if (rc < 0) return rc;
  146.  
  147.     switch (reg_no) {
  148.  
  149.     case 0: *value = istate.r0; break;
  150.     case 1: *value = istate.r1; break;
  151.     case 2: *value = istate.r2; break;
  152.     case 3: *value = istate.r3; break;
  153.     case 4: *value = istate.r4; break;
  154.     case 5: *value = istate.r5; break;
  155.     case 6: *value = istate.r6; break;
  156.     case 7: *value = istate.r7; break;
  157.     case 8: *value = istate.r8; break;
  158.     case 9: *value = istate.r9; break;
  159.     case 10: *value = istate.r10; break;
  160.     case 11: *value = istate.r11; break;
  161.     case 12: *value = istate.r12; break;
  162.     case 13: *value = istate.sp; break;
  163.     case 14: *value = istate.lr; break;
  164.     case 15: *value = istate.pc; break;
  165.  
  166.     }
  167.     printf("get_reg ok (0x%08x)\n", *value);
  168.  
  169.     return 0;
  170. }
  171.  
  172. static op_t instr_decode(uint32_t instr)
  173. {
  174.     instr_desc_t *idesc;
  175.  
  176.     idesc = &decoding_table[0];
  177.     while (idesc->op >= 0) {
  178.         if ((instr & idesc->mask) == idesc->value)
  179.             return idesc->op;
  180.         ++idesc;
  181.     }
  182.  
  183.     return -1;
  184. }
  185.  
  186. /** Get address of the instruction that will be executed after the current one.
  187.  *
  188.  * Assumptions: addr == PC, *addr is not covered by a BREAK.
  189.  *
  190.  * @param dt        Dthread on which to operate.
  191.  * @param addr      Address of an instruction.
  192.  * @param buffer    Buffer for storing up to 2 addresses.
  193.  * @return      Number of stored addresses or negative error code.
  194.  */
  195. int get_next_addr(dthread_t *dt, uintptr_t addr, uintptr_t *buffer)
  196. {
  197.     uint32_t instr;
  198.     int32_t imm, h;
  199.     uint32_t regv;
  200.     op_t op;
  201.     int rc;
  202.     int n;
  203.  
  204.     rc = islot_read(addr, &instr);
  205.     if (rc != 0) return rc;
  206.  
  207.     op = instr_decode(instr);
  208.  
  209.     switch (op) {
  210.     /* Branch (and link) */
  211.     case OP_B:
  212.     case OP_BL:
  213.         /* imm is a 24-bit signed integer */
  214.         imm = EXTS(instr & 0x00ffffff, 24);
  215.         buffer[0] = (addr + 8) + (imm << 2);
  216.         buffer[1] = addr + 4;
  217.         n = 2;
  218.         break;
  219.  
  220.     /* Unconditional branch, link and exchange */
  221.     case OP_BLX1:
  222.         /* imm is a 24-bit signed integer */
  223.         imm = EXTS(instr & 0x00ffffff, 24);
  224.         h = (instr & 0x01000000) ? 1 : 0;
  225.         buffer[0] = (addr + 8) + (imm << 2) + (h << 1);
  226.         n = 1;
  227.         break;
  228.  
  229.     case OP_BLX2:
  230.     case OP_BX:
  231.         /* BLX (2), BX */
  232.         rc = get_reg(dt, instr & 0xf, &regv);
  233.         if (rc != 0) return rc;
  234.  
  235.         buffer[0] = regv & ~0x1;
  236.         buffer[1] = addr + 4;
  237.         n = 2;
  238.         break;
  239.  
  240.     case OP_MOV_PC_LR:
  241.         /* mov pc, lr - this is typically used as 'return' */
  242.         rc = get_reg(dt, 14 /* lr */, &regv);
  243.         if (rc != 0) return rc;
  244.  
  245.         buffer[0] = regv & ~0x1;
  246.         printf("mov pc, lr ---> 0x%x\n", buffer[0]);
  247.         n = 1;
  248.         break;
  249.  
  250.     /* TODO: handle general case of instructions writing r15(pc) */
  251.  
  252.     default:
  253.         /* Regular instruction */  
  254.         buffer[0] = addr + 4;
  255.         n = 1;
  256.         break;
  257.     }
  258.  
  259.     return n;
  260. }
  261.  
  262. void arch_event_breakpoint(thash_t thread_hash)
  263. {
  264.     idec_event_breakpoint(thread_hash);
  265. }
  266.  
  267. void arch_event_trap(dthread_t *dt)
  268. {
  269.     /* Unused */
  270.     (void)dt;
  271. }
  272.  
  273. void arch_dump_regs(thash_t thash)
  274. {
  275.     /* TODO */
  276. }
  277.  
  278. void arch_singlestep(dthread_t *dt)
  279. {
  280.     idec_singlestep(dt);
  281. }
  282.  
  283. /** @}
  284.  */
  285.