Rev 3093 | Rev 3100 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
| Rev 3093 | Rev 3099 | ||
|---|---|---|---|
| Line 34... | Line 34... | ||
| 34 | 34 | ||
| 35 | #include <stdio.h> |
35 | #include <stdio.h> |
| 36 | #include <stdlib.h> |
36 | #include <stdlib.h> |
| 37 | #include <assert.h> |
37 | #include <assert.h> |
| 38 | #include <sys/types.h> |
38 | #include <sys/types.h> |
| - | 39 | #include <errno.h> |
|
| 39 | #include <udebug.h> |
40 | #include <udebug.h> |
| 40 | 41 | ||
| 41 | #include "../../../cons.h" |
42 | #include "../../../cons.h" |
| 42 | #include "../../../main.h" |
43 | #include "../../../main.h" |
| 43 | #include "../../../breakpoint.h" |
44 | #include "../../../breakpoint.h" |
| Line 45... | Line 46... | ||
| 45 | 46 | ||
| 46 | #define OPCODE_BREAK 0x0000000d |
47 | #define OPCODE_BREAK 0x0000000d |
| 47 | 48 | ||
| 48 | static istate_t istate; |
49 | static istate_t istate; |
| 49 | 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 | ||
| 50 | int arch_breakpoint_set(breakpoint_t *b) |
72 | int arch_breakpoint_set(breakpoint_t *b) |
| 51 | { |
73 | { |
| 52 | return bstore_push(&b->arch.bs, b->addr, OPCODE_BREAK); |
74 | return bstore_push(&b->arch.bs, b->addr, OPCODE_BREAK); |
| 53 | } |
75 | } |
| 54 | 76 | ||
| 55 | int arch_breakpoint_remove(breakpoint_t *b) |
77 | int arch_breakpoint_remove(breakpoint_t *b) |
| 56 | { |
78 | { |
| 57 | return bstore_pop(&b->arch.bs); |
79 | return bstore_pop(&b->arch.bs); |
| 58 | } |
80 | } |
| 59 | 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 | ||
| 60 | static void _ev_breakpoint(thash_t thread_hash) |
165 | static void _ev_breakpoint(thash_t thread_hash) |
| 61 | { |
166 | { |
| 62 | breakpoint_t *b; |
167 | breakpoint_t *b; |
| 63 | dthread_t *dt; |
168 | dthread_t *dt; |
| 64 | int rc; |
169 | int rc; |
| 65 | uint32_t epc; |
170 | uint32_t epc; |
| 66 | int brk_addr; |
171 | uintptr_t brk_addr; |
| - | 172 | uintptr_t next_addr; |
|
| 67 | uint32_t brkp; |
173 | uint32_t brkp; |
| 68 | 174 | ||
| 69 | brkp = OPCODE_BREAK; |
175 | brkp = OPCODE_BREAK; |
| 70 | 176 | ||
| 71 | cons_printf("arch_event_breakpoint\n"); |
177 | cons_printf("arch_event_breakpoint\n"); |
| Line 78... | Line 184... | ||
| 78 | 184 | ||
| 79 | dt = dthread_get(); |
185 | dt = dthread_get(); |
| 80 | 186 | ||
| 81 | if (active_bkpt != NULL) { |
187 | if (active_bkpt != NULL) { |
| 82 | assert(active_bkpt->arch.bs.address == brk_addr); |
188 | assert(active_bkpt->arch.bs.address == brk_addr); |
| - | 189 | b = active_bkpt; |
|
| 83 | 190 | ||
| 84 | /* A breakpoint-clearing BRK has been hit */ |
191 | /* A breakpoint-clearing BRK has been hit */ |
| 85 | cons_printf("restoring breakpoint %d\n", b->id); |
192 | cons_printf("restoring breakpoint %d\n", b->id); |
| 86 | rc = bstore_pop(&b->arch.bs); |
193 | rc = bstore_pop(&b->arch.bs); |
| 87 | if (rc != 0) return; |
194 | if (rc != 0) return; |
| 88 | rc = bstore_push(&b->arch.bs, brk_addr - 4, OPCODE_BREAK); |
195 | rc = bstore_push(&b->arch.bs, b->addr, OPCODE_BREAK); |
| 89 | if (rc != 0) return; |
196 | if (rc != 0) return; |
| 90 | active_bkpt = NULL; |
197 | active_bkpt = NULL; |
| 91 | return; |
198 | return; |
| 92 | } |
199 | } |
| 93 | 200 | ||
| Line 105... | Line 212... | ||
| 105 | 212 | ||
| 106 | cons_printf("move breakpoint\b"); |
213 | cons_printf("move breakpoint\b"); |
| 107 | rc = bstore_pop(&b->arch.bs); |
214 | rc = bstore_pop(&b->arch.bs); |
| 108 | if (rc != 0) return; |
215 | if (rc != 0) return; |
| 109 | 216 | ||
| - | 217 | rc = get_next_addr(brk_addr, &next_addr); |
|
| - | 218 | if (rc != 0) return; |
|
| - | 219 | ||
| 110 | /* |
220 | /* |
| 111 | * There could be another breakpoint at brk_addr + 4, |
221 | * There could be another breakpoint at next_addr, |
| 112 | * but that's okay. We'll pop the active breakpoint bs |
222 | * but that's okay. We'll pop the active breakpoint bs |
| 113 | * before doing anything else. |
223 | * before doing anything else. |
| 114 | */ |
224 | */ |
| 115 | rc = bstore_push(&b->arch.bs, brk_addr + 4, OPCODE_BREAK); |
225 | rc = bstore_push(&b->arch.bs, next_addr, OPCODE_BREAK); |
| 116 | if (rc != 0) return; |
226 | if (rc != 0) return; |
| 117 | 227 | ||
| 118 | active_bkpt = b; |
228 | active_bkpt = b; |
| 119 | b->active = true; |
229 | b->active = true; |
| 120 | 230 | ||
| Line 185... | Line 295... | ||
| 185 | { |
295 | { |
| 186 | int rc; |
296 | int rc; |
| 187 | uint32_t epc; |
297 | uint32_t epc; |
| 188 | breakpoint_t *b; |
298 | breakpoint_t *b; |
| 189 | uint32_t old_instr; |
299 | uint32_t old_instr; |
| - | 300 | uintptr_t next_addr; |
|
| 190 | 301 | ||
| 191 | assert(active_bkpt == NULL); |
302 | assert(active_bkpt == NULL); |
| 192 | assert(dt->arch.singlestep == false); |
303 | assert(dt->arch.singlestep == false); |
| 193 | 304 | ||
| 194 | cons_printf("arch_singlestep(dt)\n"); |
305 | cons_printf("arch_singlestep(dt)\n"); |
| Line 204... | Line 315... | ||
| 204 | old_instr = b->arch.bs.value; |
315 | old_instr = b->arch.bs.value; |
| 205 | rc = bstore_push(&dt->arch.cur, epc, old_instr); |
316 | rc = bstore_push(&dt->arch.cur, epc, old_instr); |
| 206 | if (rc < 0) return; |
317 | if (rc < 0) return; |
| 207 | } |
318 | } |
| 208 | 319 | ||
| - | 320 | rc = get_next_addr(epc, &next_addr); |
|
| - | 321 | if (rc != 0) return; |
|
| - | 322 | ||
| 209 | /* Cover next instruction with BREAK */ |
323 | /* Cover next instruction with BREAK */ |
| 210 | rc = bstore_push(&dt->arch.next, epc + 4, OPCODE_BREAK); |
324 | rc = bstore_push(&dt->arch.next, next_addr, OPCODE_BREAK); |
| 211 | if (rc < 0) return; |
325 | if (rc != 0) return; |
| 212 | 326 | ||
| 213 | dt->arch.singlestep = true; |
327 | dt->arch.singlestep = true; |
| 214 | dthread_resume(dt); |
328 | dthread_resume(dt); |
| 215 | } |
329 | } |
| 216 | 330 | ||