36,7 → 36,6 |
#include <stdlib.h> |
#include <assert.h> |
#include <sys/types.h> |
#include <errno.h> |
#include <udebug.h> |
|
#include "../../../cons.h" |
48,27 → 47,6 |
|
static istate_t istate; |
|
typedef enum { |
OP_J, |
OP_JAL, |
OP_JALR, |
OP_JR |
} op_t; |
|
typedef struct { |
uint32_t mask; |
uint32_t value; |
op_t op; |
} instr_desc_t; |
|
static instr_desc_t decoding_table[] = { |
{ 0xfc000000, 0x08000000, OP_J }, |
{ 0xfc000000, 0x0c000000, OP_JAL }, |
{ 0xfc1f07ff, 0x00000009, OP_JALR }, |
{ 0xfc1fffff, 0x00000008, OP_JR }, |
{ 0, 0, -1 } |
}; |
|
int arch_breakpoint_set(breakpoint_t *b) |
{ |
return bstore_push(&b->arch.bs, b->addr, OPCODE_BREAK); |
79,89 → 57,6 |
return bstore_pop(&b->arch.bs); |
} |
|
static int islot_read(uintptr_t addr, uint32_t *instr) |
{ |
int rc; |
|
rc = udebug_mem_read(app_phone, instr, addr, sizeof(uint32_t)); |
if (rc != EOK) { |
cons_printf("Error reading memory address 0x%zx\n", addr); |
} |
|
return rc; |
} |
|
static op_t instr_decode(uint32_t instr) |
{ |
instr_desc_t *idesc; |
|
idesc = &decoding_table[0]; |
while (idesc->op >= 0) { |
if ((instr & idesc->mask) == idesc->value) |
return idesc->op; |
++idesc; |
} |
|
return -1; |
} |
|
static int get_reg(int reg_no, uint32_t *value) |
{ |
int rc; |
|
cons_printf("get_reg...\n"); |
|
if (reg_no == 0) { |
*value = 0; |
return 0; |
} |
|
/* FIXME: ugly */ |
*value = ((uint32_t *)&istate)[reg_no - 1]; |
printf("get_reg ok (0x%08x)\n", *value); |
|
return 0; |
} |
|
/** Get address of the instruction that will be executed after the current one. |
* |
* Assumptions: addr == PC, *addr is not covered by a BREAK. |
* |
* @param addr Address of an instruction. |
* @return Address of the instruction that will be executed afterwards. |
*/ |
static int get_next_addr(uintptr_t addr, uintptr_t *next_addr) |
{ |
/* TODO: J[AL]R, branches and delay slots */ |
uint32_t instr; |
op_t op; |
int rc; |
|
rc = islot_read(addr, &instr); |
if (rc != 0) return rc; |
|
op = instr_decode(instr); |
|
switch (op) { |
case OP_J: |
case OP_JAL: |
*next_addr = |
((addr + 4) & 0xf0000000) | |
((instr & 0x03ffffff) << 2); |
break; |
case OP_JR: |
case OP_JALR: |
rc = get_reg((instr >> 21) & 0x1f, next_addr); |
break; |
default: |
/* Regular instruction */ |
*next_addr = addr + 4; |
break; |
} |
|
return 0; |
} |
|
static void _ev_breakpoint(thash_t thread_hash) |
{ |
breakpoint_t *b; |
168,8 → 63,7 |
dthread_t *dt; |
int rc; |
uint32_t epc; |
uintptr_t brk_addr; |
uintptr_t next_addr; |
int brk_addr; |
uint32_t brkp; |
|
brkp = OPCODE_BREAK; |
186,13 → 80,12 |
|
if (active_bkpt != NULL) { |
assert(active_bkpt->arch.bs.address == brk_addr); |
b = active_bkpt; |
|
/* A breakpoint-clearing BRK has been hit */ |
cons_printf("restoring breakpoint %d\n", b->id); |
rc = bstore_pop(&b->arch.bs); |
if (rc != 0) return; |
rc = bstore_push(&b->arch.bs, b->addr, OPCODE_BREAK); |
rc = bstore_push(&b->arch.bs, brk_addr - 4, OPCODE_BREAK); |
if (rc != 0) return; |
active_bkpt = NULL; |
return; |
214,15 → 107,12 |
rc = bstore_pop(&b->arch.bs); |
if (rc != 0) return; |
|
rc = get_next_addr(brk_addr, &next_addr); |
if (rc != 0) return; |
|
/* |
* There could be another breakpoint at next_addr, |
* There could be another breakpoint at brk_addr + 4, |
* but that's okay. We'll pop the active breakpoint bs |
* before doing anything else. |
*/ |
rc = bstore_push(&b->arch.bs, next_addr, OPCODE_BREAK); |
rc = bstore_push(&b->arch.bs, brk_addr + 4, OPCODE_BREAK); |
if (rc != 0) return; |
|
active_bkpt = b; |
297,7 → 187,6 |
uint32_t epc; |
breakpoint_t *b; |
uint32_t old_instr; |
uintptr_t next_addr; |
|
assert(active_bkpt == NULL); |
assert(dt->arch.singlestep == false); |
317,12 → 206,9 |
if (rc < 0) return; |
} |
|
rc = get_next_addr(epc, &next_addr); |
if (rc != 0) return; |
|
/* Cover next instruction with BREAK */ |
rc = bstore_push(&dt->arch.next, next_addr, OPCODE_BREAK); |
if (rc != 0) return; |
rc = bstore_push(&dt->arch.next, epc + 4, OPCODE_BREAK); |
if (rc < 0) return; |
|
dt->arch.singlestep = true; |
dthread_resume(dt); |