Rev 3099 | Rev 3108 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 3099 | Rev 3100 | ||
---|---|---|---|
1 | /* |
1 | /* |
2 | * Copyright (c) 2008 Jiri Svoboda |
2 | * Copyright (c) 2008 Jiri Svoboda |
3 | * All rights reserved. |
3 | * All rights reserved. |
4 | * |
4 | * |
5 | * Redistribution and use in source and binary forms, with or without |
5 | * Redistribution and use in source and binary forms, with or without |
6 | * modification, are permitted provided that the following conditions |
6 | * modification, are permitted provided that the following conditions |
7 | * are met: |
7 | * are met: |
8 | * |
8 | * |
9 | * - Redistributions of source code must retain the above copyright |
9 | * - Redistributions of source code must retain the above copyright |
10 | * notice, this list of conditions and the following disclaimer. |
10 | * notice, this list of conditions and the following disclaimer. |
11 | * - Redistributions in binary form must reproduce the above copyright |
11 | * - Redistributions in binary form must reproduce the above copyright |
12 | * notice, this list of conditions and the following disclaimer in the |
12 | * notice, this list of conditions and the following disclaimer in the |
13 | * documentation and/or other materials provided with the distribution. |
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 |
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. |
15 | * derived from this software without specific prior written permission. |
16 | * |
16 | * |
17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
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 |
18 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
19 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
19 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
20 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
20 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
21 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
21 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
22 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
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 |
23 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
24 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
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 |
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. |
26 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27 | */ |
27 | */ |
28 | 28 | ||
29 | /** @addtogroup debug |
29 | /** @addtogroup debug |
30 | * @{ |
30 | * @{ |
31 | */ |
31 | */ |
32 | /** @file |
32 | /** @file |
33 | */ |
33 | */ |
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 <errno.h> |
40 | #include <udebug.h> |
40 | #include <udebug.h> |
41 | 41 | ||
42 | #include "../../../cons.h" |
42 | #include "../../../cons.h" |
43 | #include "../../../main.h" |
43 | #include "../../../main.h" |
44 | #include "../../../breakpoint.h" |
44 | #include "../../../breakpoint.h" |
45 | #include "../../../include/arch.h" |
45 | #include "../../../include/arch.h" |
46 | 46 | ||
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; |
57 | 80 | ||
58 | typedef struct { |
81 | typedef struct { |
59 | uint32_t mask; |
82 | uint32_t mask; |
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 | { |
79 | return bstore_pop(&b->arch.bs); |
137 | return bstore_pop(&b->arch.bs); |
80 | } |
138 | } |
81 | 139 | ||
82 | static int islot_read(uintptr_t addr, uint32_t *instr) |
140 | static int islot_read(uintptr_t addr, uint32_t *instr) |
83 | { |
141 | { |
84 | int rc; |
142 | int rc; |
85 | 143 | ||
86 | rc = udebug_mem_read(app_phone, instr, addr, sizeof(uint32_t)); |
144 | rc = udebug_mem_read(app_phone, instr, addr, sizeof(uint32_t)); |
87 | if (rc != EOK) { |
145 | if (rc != EOK) { |
88 | cons_printf("Error reading memory address 0x%zx\n", addr); |
146 | cons_printf("Error reading memory address 0x%zx\n", addr); |
89 | } |
147 | } |
90 | 148 | ||
91 | return rc; |
149 | return rc; |
92 | } |
150 | } |
93 | 151 | ||
94 | static op_t instr_decode(uint32_t instr) |
152 | static op_t instr_decode(uint32_t instr) |
95 | { |
153 | { |
96 | instr_desc_t *idesc; |
154 | instr_desc_t *idesc; |
97 | 155 | ||
98 | idesc = &decoding_table[0]; |
156 | idesc = &decoding_table[0]; |
99 | while (idesc->op >= 0) { |
157 | while (idesc->op >= 0) { |
100 | if ((instr & idesc->mask) == idesc->value) |
158 | if ((instr & idesc->mask) == idesc->value) |
101 | return idesc->op; |
159 | return idesc->op; |
102 | ++idesc; |
160 | ++idesc; |
103 | } |
161 | } |
104 | 162 | ||
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; |
117 | } |
173 | } |
118 | 174 | ||
119 | /* FIXME: ugly */ |
175 | /* FIXME: ugly */ |
120 | *value = ((uint32_t *)&istate)[reg_no - 1]; |
176 | *value = ((uint32_t *)&istate)[reg_no - 1]; |
121 | printf("get_reg ok (0x%08x)\n", *value); |
177 | printf("get_reg ok (0x%08x)\n", *value); |
122 | 178 | ||
123 | return 0; |
179 | return 0; |
124 | } |
180 | } |
125 | 181 | ||
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"); |
178 | 268 | ||
179 | rc = udebug_regs_read(app_phone, thread_hash, &istate); |
269 | rc = udebug_regs_read(app_phone, thread_hash, &istate); |
180 | cons_printf("udebug_regs_read -> %d\n", rc); |
270 | cons_printf("udebug_regs_read -> %d\n", rc); |
181 | epc = istate_get_pc(&istate); |
271 | epc = istate_get_pc(&istate); |
182 | cons_printf("EPC was 0x%08x\n", epc); |
272 | cons_printf("EPC was 0x%08x\n", epc); |
183 | brk_addr = epc; |
273 | brk_addr = epc; |
184 | 274 | ||
185 | dt = dthread_get(); |
275 | dt = dthread_get(); |
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 | } |
200 | 293 | ||
201 | b = breakpoint_find_by_addr(brk_addr); |
294 | b = breakpoint_find_by_addr(brk_addr); |
202 | if (b == NULL) { |
295 | if (b == NULL) { |
203 | cons_printf("Unrecognized breakpoint at 0x%lx\n", brk_addr); |
296 | cons_printf("Unrecognized breakpoint at 0x%lx\n", brk_addr); |
204 | } |
297 | } |
205 | 298 | ||
206 | /* A breakpoint has been hit */ |
299 | /* A breakpoint has been hit */ |
207 | cons_printf("breakpoint_hit...\n"); |
300 | cons_printf("breakpoint_hit...\n"); |
208 | breakpoint_hit(b); |
301 | breakpoint_hit(b); |
209 | 302 | ||
210 | /* While in breakpoint_hit(), singlestep was activated */ |
303 | /* While in breakpoint_hit(), singlestep was activated */ |
211 | if (dt->arch.singlestep) return; |
304 | if (dt->arch.singlestep) return; |
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"); |
232 | } |
329 | } |
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(); |
244 | 341 | ||
245 | assert(active_bkpt == NULL); |
342 | assert(active_bkpt == NULL); |
246 | assert(dt->arch.singlestep); |
343 | assert(dt->arch.singlestep); |
247 | brkp = OPCODE_BREAK; |
344 | brkp = OPCODE_BREAK; |
248 | 345 | ||
249 | cons_printf("arch_event_breakpoint\n"); |
346 | cons_printf("arch_event_breakpoint\n"); |
250 | 347 | ||
251 | rc = udebug_regs_read(app_phone, thread_hash, &istate); |
348 | rc = udebug_regs_read(app_phone, thread_hash, &istate); |
252 | cons_printf("udebug_regs_read -> %d\n", rc); |
349 | cons_printf("udebug_regs_read -> %d\n", rc); |
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 | } |
269 | 369 | ||
270 | 370 | ||
271 | void arch_event_breakpoint(thash_t thread_hash) |
371 | void arch_event_breakpoint(thash_t thread_hash) |
272 | { |
372 | { |
273 | dthread_t *dt; |
373 | dthread_t *dt; |
274 | 374 | ||
275 | dt = dthread_get(); |
375 | dt = dthread_get(); |
276 | if (dt->arch.singlestep) { |
376 | if (dt->arch.singlestep) { |
277 | _ev_singlestep(thread_hash); |
377 | _ev_singlestep(thread_hash); |
278 | } else { |
378 | } else { |
279 | _ev_breakpoint(thread_hash); |
379 | _ev_breakpoint(thread_hash); |
280 | } |
380 | } |
281 | } |
381 | } |
282 | 382 | ||
283 | void arch_event_trap(dthread_t *dt) |
383 | void arch_event_trap(dthread_t *dt) |
284 | { |
384 | { |
285 | /* Unused */ |
385 | /* Unused */ |
286 | (void)dt; |
386 | (void)dt; |
287 | } |
387 | } |
288 | 388 | ||
289 | void arch_dump_regs(thash_t thash) |
389 | void arch_dump_regs(thash_t thash) |
290 | { |
390 | { |
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"); |
306 | rc = udebug_regs_read(app_phone, dt->hash, &istate); |
407 | rc = udebug_regs_read(app_phone, dt->hash, &istate); |
307 | cons_printf("udebug_regs_read -> %d\n", rc); |
408 | cons_printf("udebug_regs_read -> %d\n", rc); |
308 | epc = istate_get_pc(&istate); |
409 | epc = istate_get_pc(&istate); |
309 | cons_printf("EPC was 0x%08x\n", epc); |
410 | cons_printf("EPC was 0x%08x\n", epc); |
310 | 411 | ||
311 | cons_printf("initial set singlestep\n"); |
412 | cons_printf("initial set singlestep\n"); |
312 | b = breakpoint_find_by_addr(epc); |
413 | b = breakpoint_find_by_addr(epc); |
313 | if (b != NULL) { |
414 | if (b != NULL) { |
314 | /* Cover breakpoint with old instruction */ |
415 | /* Cover breakpoint with old instruction */ |
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 | ||
331 | /** @} |
435 | /** @} |
332 | */ |
436 | */ |
333 | 437 |