Rev 3099 | Rev 3108 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 3099 | Rev 3100 | ||
---|---|---|---|
Line 47... | Line 47... | ||
47 | #define OPCODE_BREAK 0x0000000d |
47 | #define OPCODE_BREAK 0x0000000d |
48 | 48 | ||
49 | static istate_t istate; |
49 | static istate_t istate; |
50 | 50 | ||
51 | typedef enum { |
51 | typedef enum { |
- | 52 | /* Branches (conditional) */ |
|
- | 53 | OP_BCzF, |
|
- | 54 | OP_BCzFL, |
|
- | 55 | OP_BCzT, |
|
- | 56 | OP_BCzTL, |
|
- | 57 | OP_BEQ, |
|
- | 58 | OP_BEQL, |
|
- | 59 | OP_BGEZ, |
|
- | 60 | OP_BGEZAL, |
|
- | 61 | OP_BGEZALL, |
|
- | 62 | OP_BGEZL, |
|
- | 63 | OP_BGTZ, |
|
- | 64 | OP_BGTZL, |
|
- | 65 | OP_BLEZ, |
|
- | 66 | OP_BLEZL, |
|
- | 67 | OP_BLTZ, |
|
- | 68 | OP_BLTZAL, |
|
- | 69 | OP_BLTZALL, |
|
- | 70 | OP_BLTZL, |
|
- | 71 | OP_BNE, |
|
- | 72 | OP_BNEL, |
|
- | 73 | ||
- | 74 | /* Jumps (unconditional) */ |
|
52 | OP_J, |
75 | OP_J, |
53 | OP_JAL, |
76 | OP_JAL, |
54 | OP_JALR, |
77 | OP_JALR, |
55 | OP_JR |
78 | OP_JR |
56 | } op_t; |
79 | } op_t; |
Line 60... | Line 83... | ||
60 | uint32_t value; |
83 | uint32_t value; |
61 | op_t op; |
84 | op_t op; |
62 | } instr_desc_t; |
85 | } instr_desc_t; |
63 | 86 | ||
64 | static instr_desc_t decoding_table[] = { |
87 | static instr_desc_t decoding_table[] = { |
- | 88 | { 0xf3ff0000, 0x41000000, OP_BCzF }, |
|
- | 89 | { 0xf3ff0000, 0x41020000, OP_BCzFL }, |
|
- | 90 | { 0xf3ff0000, 0x41010000, OP_BCzT }, |
|
- | 91 | { 0xf3ff0000, 0x41030000, OP_BCzTL }, |
|
- | 92 | { 0xfc000000, 0x10000000, OP_BEQ }, |
|
- | 93 | { 0xfc000000, 0x50000000, OP_BEQL }, |
|
- | 94 | { 0xfc1f0000, 0x04010000, OP_BGEZ }, |
|
- | 95 | { 0xfc1f0000, 0x04110000, OP_BGEZAL }, |
|
- | 96 | { 0xfc1f0000, 0x04130000, OP_BGEZALL }, |
|
- | 97 | { 0xfc1f0000, 0x04030000, OP_BGEZL }, |
|
- | 98 | { 0xfc1f0000, 0x1c000000, OP_BGTZ }, |
|
- | 99 | { 0xfc1f0000, 0x5c000000, OP_BGTZL }, |
|
- | 100 | { 0xfc1f0000, 0x18000000, OP_BLEZ }, |
|
- | 101 | { 0xfc1f0000, 0x58000000, OP_BLEZL }, |
|
- | 102 | { 0xfc1f0000, 0x04000000, OP_BLTZ }, |
|
- | 103 | { 0xfc1f0000, 0x04100000, OP_BLTZAL }, |
|
- | 104 | { 0xfc1f0000, 0x04120000, OP_BLTZALL }, |
|
- | 105 | { 0xfc1f0000, 0x04020000, OP_BLTZL }, |
|
- | 106 | { 0xfc000000, 0x14000000, OP_BNE }, |
|
- | 107 | { 0xfc000000, 0x54000000, OP_BNEL }, |
|
- | 108 | ||
65 | { 0xfc000000, 0x08000000, OP_J }, |
109 | { 0xfc000000, 0x08000000, OP_J }, |
66 | { 0xfc000000, 0x0c000000, OP_JAL }, |
110 | { 0xfc000000, 0x0c000000, OP_JAL }, |
67 | { 0xfc1f07ff, 0x00000009, OP_JALR }, |
111 | { 0xfc1f07ff, 0x00000009, OP_JALR }, |
68 | { 0xfc1fffff, 0x00000008, OP_JR }, |
112 | { 0xfc1fffff, 0x00000008, OP_JR }, |
- | 113 | ||
69 | { 0, 0, -1 } |
114 | { 0, 0, -1 } |
70 | }; |
115 | }; |
71 | 116 | ||
- | 117 | void arch_dthread_initialize(dthread_t *dt) |
|
- | 118 | { |
|
- | 119 | dt->arch.singlestep = false; |
|
- | 120 | ||
- | 121 | bstore_initialize(&dt->arch.cur); |
|
- | 122 | bstore_initialize(&dt->arch.next[0]); |
|
- | 123 | bstore_initialize(&dt->arch.next[1]); |
|
- | 124 | } |
|
- | 125 | ||
72 | int arch_breakpoint_set(breakpoint_t *b) |
126 | int arch_breakpoint_set(breakpoint_t *b) |
73 | { |
127 | { |
- | 128 | bstore_initialize(&b->arch.bs); |
|
- | 129 | bstore_initialize(&b->arch.next_bs[0]); |
|
- | 130 | bstore_initialize(&b->arch.next_bs[1]); |
|
- | 131 | ||
74 | return bstore_push(&b->arch.bs, b->addr, OPCODE_BREAK); |
132 | return bstore_push(&b->arch.bs, b->addr, OPCODE_BREAK); |
75 | } |
133 | } |
76 | 134 | ||
77 | int arch_breakpoint_remove(breakpoint_t *b) |
135 | int arch_breakpoint_remove(breakpoint_t *b) |
78 | { |
136 | { |
Line 105... | Line 163... | ||
105 | return -1; |
163 | return -1; |
106 | } |
164 | } |
107 | 165 | ||
108 | static int get_reg(int reg_no, uint32_t *value) |
166 | static int get_reg(int reg_no, uint32_t *value) |
109 | { |
167 | { |
110 | int rc; |
- | |
111 | - | ||
112 | cons_printf("get_reg...\n"); |
168 | cons_printf("get_reg...\n"); |
113 | 169 | ||
114 | if (reg_no == 0) { |
170 | if (reg_no == 0) { |
115 | *value = 0; |
171 | *value = 0; |
116 | return 0; |
172 | return 0; |
Line 126... | Line 182... | ||
126 | /** Get address of the instruction that will be executed after the current one. |
182 | /** Get address of the instruction that will be executed after the current one. |
127 | * |
183 | * |
128 | * Assumptions: addr == PC, *addr is not covered by a BREAK. |
184 | * Assumptions: addr == PC, *addr is not covered by a BREAK. |
129 | * |
185 | * |
130 | * @param addr Address of an instruction. |
186 | * @param addr Address of an instruction. |
- | 187 | * @param buffer Buffer for storing up to 2 addresses. |
|
131 | * @return Address of the instruction that will be executed afterwards. |
188 | * @return Number of stored addresses or negative error code. |
132 | */ |
189 | */ |
133 | static int get_next_addr(uintptr_t addr, uintptr_t *next_addr) |
190 | static int get_next_addr(uintptr_t addr, uintptr_t *buffer) |
134 | { |
191 | { |
135 | /* TODO: J[AL]R, branches and delay slots */ |
192 | /* TODO: J[AL]R, branches and delay slots */ |
136 | uint32_t instr; |
193 | uint32_t instr; |
- | 194 | int32_t offset; |
|
137 | op_t op; |
195 | op_t op; |
138 | int rc; |
196 | int rc; |
- | 197 | int n; |
|
139 | 198 | ||
140 | rc = islot_read(addr, &instr); |
199 | rc = islot_read(addr, &instr); |
141 | if (rc != 0) return rc; |
200 | if (rc != 0) return rc; |
142 | 201 | ||
143 | op = instr_decode(instr); |
202 | op = instr_decode(instr); |
144 | 203 | ||
145 | switch (op) { |
204 | switch (op) { |
- | 205 | case OP_BCzF: |
|
- | 206 | case OP_BCzFL: |
|
- | 207 | case OP_BCzT: |
|
- | 208 | case OP_BCzTL: |
|
- | 209 | case OP_BEQ: |
|
- | 210 | case OP_BEQL: |
|
- | 211 | case OP_BGEZ: |
|
- | 212 | case OP_BGEZAL: |
|
- | 213 | case OP_BGEZALL: |
|
- | 214 | case OP_BGEZL: |
|
- | 215 | case OP_BGTZ: |
|
- | 216 | case OP_BGTZL: |
|
- | 217 | case OP_BLEZ: |
|
- | 218 | case OP_BLTZ: |
|
- | 219 | case OP_BLTZAL: |
|
- | 220 | case OP_BLTZALL: |
|
- | 221 | case OP_BLTZL: |
|
- | 222 | case OP_BNE: |
|
- | 223 | case OP_BNEL: |
|
- | 224 | /* Branch */ |
|
- | 225 | offset = (int32_t)(int16_t)(instr & 0x0000ffff) << 2; |
|
- | 226 | buffer[0] = (addr + 4) + offset; /* taken */ |
|
- | 227 | buffer[1] = addr + 8; /* not taken */ |
|
- | 228 | n = 2; |
|
- | 229 | break; |
|
- | 230 | ||
146 | case OP_J: |
231 | case OP_J: |
147 | case OP_JAL: |
232 | case OP_JAL: |
- | 233 | /* Immediate jump */ |
|
148 | *next_addr = |
234 | buffer[0] = |
149 | ((addr + 4) & 0xf0000000) | |
235 | ((addr + 4) & 0xf0000000) | |
150 | ((instr & 0x03ffffff) << 2); |
236 | ((instr & 0x03ffffff) << 2); |
- | 237 | n = 1; |
|
151 | break; |
238 | break; |
152 | case OP_JR: |
239 | case OP_JR: |
153 | case OP_JALR: |
240 | case OP_JALR: |
- | 241 | /* Register jump */ |
|
154 | rc = get_reg((instr >> 21) & 0x1f, next_addr); |
242 | rc = get_reg((instr >> 21) & 0x1f, &buffer[0]); |
- | 243 | n = 1; |
|
155 | break; |
244 | break; |
156 | default: |
245 | default: |
157 | /* Regular instruction */ |
246 | /* Regular instruction */ |
158 | *next_addr = addr + 4; |
247 | buffer[0] = addr + 4; |
- | 248 | n = 1; |
|
159 | break; |
249 | break; |
160 | } |
250 | } |
161 | 251 | ||
162 | return 0; |
252 | return n; |
163 | } |
253 | } |
164 | 254 | ||
165 | static void _ev_breakpoint(thash_t thread_hash) |
255 | static void _ev_breakpoint(thash_t thread_hash) |
166 | { |
256 | { |
167 | breakpoint_t *b; |
257 | breakpoint_t *b; |
168 | dthread_t *dt; |
258 | dthread_t *dt; |
169 | int rc; |
259 | int rc, n_next, i; |
170 | uint32_t epc; |
260 | uint32_t epc; |
171 | uintptr_t brk_addr; |
261 | uintptr_t brk_addr; |
172 | uintptr_t next_addr; |
262 | uintptr_t next_addr[2]; |
173 | uint32_t brkp; |
263 | uint32_t brkp; |
174 | 264 | ||
175 | brkp = OPCODE_BREAK; |
265 | brkp = OPCODE_BREAK; |
176 | 266 | ||
177 | cons_printf("arch_event_breakpoint\n"); |
267 | cons_printf("arch_event_breakpoint\n"); |
Line 186... | Line 276... | ||
186 | 276 | ||
187 | if (active_bkpt != NULL) { |
277 | if (active_bkpt != NULL) { |
188 | assert(active_bkpt->arch.bs.address == brk_addr); |
278 | assert(active_bkpt->arch.bs.address == brk_addr); |
189 | b = active_bkpt; |
279 | b = active_bkpt; |
190 | 280 | ||
191 | /* A breakpoint-clearing BRK has been hit */ |
281 | /* A breakpoint-restoring BRK has been hit */ |
192 | cons_printf("restoring breakpoint %d\n", b->id); |
282 | cons_printf("restoring breakpoint %d\n", b->id); |
- | 283 | for (i = 0; i < b->arch.n_next; ++i) { |
|
193 | rc = bstore_pop(&b->arch.bs); |
284 | rc = bstore_pop(&b->arch.next_bs[i]); |
194 | if (rc != 0) return; |
285 | if (rc != 0) return; |
- | 286 | } |
|
- | 287 | ||
195 | rc = bstore_push(&b->arch.bs, b->addr, OPCODE_BREAK); |
288 | rc = bstore_push(&b->arch.bs, b->addr, OPCODE_BREAK); |
196 | if (rc != 0) return; |
289 | if (rc != 0) return; |
197 | active_bkpt = NULL; |
290 | active_bkpt = NULL; |
198 | return; |
291 | return; |
199 | } |
292 | } |
Line 212... | Line 305... | ||
212 | 305 | ||
213 | cons_printf("move breakpoint\b"); |
306 | cons_printf("move breakpoint\b"); |
214 | rc = bstore_pop(&b->arch.bs); |
307 | rc = bstore_pop(&b->arch.bs); |
215 | if (rc != 0) return; |
308 | if (rc != 0) return; |
216 | 309 | ||
217 | rc = get_next_addr(brk_addr, &next_addr); |
310 | n_next = get_next_addr(brk_addr, next_addr); |
218 | if (rc != 0) return; |
311 | if (n_next < 0) return; |
219 | 312 | ||
220 | /* |
313 | /* |
221 | * There could be another breakpoint at next_addr, |
314 | * There could be another breakpoint at next_addr, |
222 | * but that's okay. We'll pop the active breakpoint bs |
315 | * but that's okay. We'll pop the active breakpoint bs |
223 | * before doing anything else. |
316 | * before doing anything else. |
224 | */ |
317 | */ |
- | 318 | for (i = 0; i < n_next; ++i) { |
|
225 | rc = bstore_push(&b->arch.bs, next_addr, OPCODE_BREAK); |
319 | rc = bstore_push(&b->arch.next_bs[i], next_addr[i], |
- | 320 | OPCODE_BREAK); |
|
226 | if (rc != 0) return; |
321 | if (rc != 0) return; |
- | 322 | } |
|
- | 323 | b->arch.n_next = n_next; |
|
227 | 324 | ||
228 | active_bkpt = b; |
325 | active_bkpt = b; |
229 | b->active = true; |
326 | b->active = true; |
230 | 327 | ||
231 | cons_printf("end_hit...\n"); |
328 | cons_printf("end_hit...\n"); |
Line 233... | Line 330... | ||
233 | 330 | ||
234 | 331 | ||
235 | static void _ev_singlestep(thash_t thread_hash) |
332 | static void _ev_singlestep(thash_t thread_hash) |
236 | { |
333 | { |
237 | dthread_t *dt; |
334 | dthread_t *dt; |
238 | int rc; |
335 | int rc, i; |
239 | uint32_t epc; |
336 | uint32_t epc; |
240 | int brk_addr; |
337 | int brk_addr; |
241 | uint32_t brkp; |
338 | uint32_t brkp; |
242 | 339 | ||
243 | dt = dthread_get(); |
340 | dt = dthread_get(); |
Line 253... | Line 350... | ||
253 | epc = istate_get_pc(&istate); |
350 | epc = istate_get_pc(&istate); |
254 | cons_printf("EPC was 0x%08x\n", epc); |
351 | cons_printf("EPC was 0x%08x\n", epc); |
255 | brk_addr = epc; |
352 | brk_addr = epc; |
256 | 353 | ||
257 | if (dt->arch.cur.valid) { |
354 | if (dt->arch.cur.valid) { |
258 | cons_printf("restore breakpoint BRK\n"); |
355 | cons_printf("restore breakpoint BREAK\n"); |
259 | rc = bstore_pop(&dt->arch.cur); |
356 | rc = bstore_pop(&dt->arch.cur); |
260 | } |
357 | } |
261 | 358 | ||
262 | cons_printf("clear singlestep BRK\n"); |
359 | cons_printf("\nclear singlestep BREAKs\n"); |
- | 360 | for (i = 0; i < dt->arch.n_next; ++i) { |
|
263 | rc = bstore_pop(&dt->arch.next); |
361 | rc = bstore_pop(&dt->arch.next[i]); |
- | 362 | if (rc != 0) return; |
|
- | 363 | } |
|
264 | 364 | ||
265 | dt->arch.singlestep = false; |
365 | dt->arch.singlestep = false; |
266 | 366 | ||
267 | singlestep_hit(); |
367 | singlestep_hit(); |
268 | } |
368 | } |
Line 291... | Line 391... | ||
291 | /* TODO */ |
391 | /* TODO */ |
292 | } |
392 | } |
293 | 393 | ||
294 | void arch_singlestep(dthread_t *dt) |
394 | void arch_singlestep(dthread_t *dt) |
295 | { |
395 | { |
296 | int rc; |
396 | int rc, i; |
297 | uint32_t epc; |
397 | uint32_t epc; |
298 | breakpoint_t *b; |
398 | breakpoint_t *b; |
299 | uint32_t old_instr; |
399 | uint32_t old_instr; |
300 | uintptr_t next_addr; |
400 | uintptr_t next_addr[2]; |
- | 401 | int n_next; |
|
301 | 402 | ||
302 | assert(active_bkpt == NULL); |
403 | assert(active_bkpt == NULL); |
303 | assert(dt->arch.singlestep == false); |
404 | assert(dt->arch.singlestep == false); |
304 | 405 | ||
305 | cons_printf("arch_singlestep(dt)\n"); |
406 | cons_printf("arch_singlestep(dt)\n"); |
Line 315... | Line 416... | ||
315 | old_instr = b->arch.bs.value; |
416 | old_instr = b->arch.bs.value; |
316 | rc = bstore_push(&dt->arch.cur, epc, old_instr); |
417 | rc = bstore_push(&dt->arch.cur, epc, old_instr); |
317 | if (rc < 0) return; |
418 | if (rc < 0) return; |
318 | } |
419 | } |
319 | 420 | ||
320 | rc = get_next_addr(epc, &next_addr); |
421 | n_next = get_next_addr(epc, next_addr); |
321 | if (rc != 0) return; |
422 | if (n_next < 0) return; |
322 | 423 | ||
323 | /* Cover next instruction with BREAK */ |
424 | /* Cover next instruction(s) with BREAK */ |
- | 425 | for (i = 0; i < n_next; ++i) { |
|
324 | rc = bstore_push(&dt->arch.next, next_addr, OPCODE_BREAK); |
426 | rc = bstore_push(&dt->arch.next[i], next_addr[i], OPCODE_BREAK); |
325 | if (rc != 0) return; |
427 | if (rc != 0) return; |
- | 428 | } |
|
- | 429 | dt->arch.n_next = n_next; |
|
326 | 430 | ||
327 | dt->arch.singlestep = true; |
431 | dt->arch.singlestep = true; |
328 | dthread_resume(dt); |
432 | dthread_resume(dt); |
329 | } |
433 | } |
330 | 434 |