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 |