Mercurial > repos > blastem
comparison gdb_remote.c @ 525:62860044337d
Support single stepping in gdb remote debugger
author | Mike Pavone <pavone@retrodev.com> |
---|---|
date | Tue, 11 Feb 2014 22:38:47 -0800 |
parents | 1495179d6737 |
children | 6fe73296938a |
comparison
equal
deleted
inserted
replaced
524:fb39534b6604 | 525:62860044337d |
---|---|
2 Copyright 2013 Michael Pavone | 2 Copyright 2013 Michael Pavone |
3 This file is part of BlastEm. | 3 This file is part of BlastEm. |
4 BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text. | 4 BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text. |
5 */ | 5 */ |
6 #include "gdb_remote.h" | 6 #include "gdb_remote.h" |
7 #include "68kinst.h" | |
8 #include "debug.h" | |
7 #include <unistd.h> | 9 #include <unistd.h> |
8 #include <fcntl.h> | 10 #include <fcntl.h> |
9 #include <stddef.h> | 11 #include <stddef.h> |
10 #include <stdlib.h> | 12 #include <stdlib.h> |
11 #include <stdio.h> | 13 #include <stdio.h> |
12 #include <string.h> | 14 #include <string.h> |
13 | 15 |
14 #define INITIAL_BUFFER_SIZE (16*1024) | 16 #define INITIAL_BUFFER_SIZE (16*1024) |
17 | |
18 #ifdef DO_DEBUG_PRINT | |
19 #define dfprintf fprintf | |
20 #else | |
21 #define dfprintf | |
22 #endif | |
15 | 23 |
16 char * buf = NULL; | 24 char * buf = NULL; |
17 char * curbuf = NULL; | 25 char * curbuf = NULL; |
18 char * end = NULL; | 26 char * end = NULL; |
19 size_t bufsize; | 27 size_t bufsize; |
20 int cont = 0; | 28 int cont = 0; |
21 int expect_break_response=0; | 29 int expect_break_response=0; |
22 uint32_t resume_pc; | 30 uint32_t resume_pc; |
23 | 31 |
24 | 32 |
33 static uint16_t branch_t; | |
34 static uint16_t branch_f; | |
35 | |
36 static bp_def * breakpoints = NULL; | |
37 static uint32_t bp_index = 0; | |
38 | |
39 | |
25 void hex_32(uint32_t num, char * out) | 40 void hex_32(uint32_t num, char * out) |
26 { | 41 { |
27 for (int32_t shift = 28; shift >= 0; shift -= 4) | 42 for (int32_t shift = 28; shift >= 0; shift -= 4) |
28 { | 43 { |
29 uint8_t nibble = num >> shift & 0xF; | 44 uint8_t nibble = num >> shift & 0xF; |
72 write_or_die(STDOUT_FILENO, "$", 1); | 87 write_or_die(STDOUT_FILENO, "$", 1); |
73 write_or_die(STDOUT_FILENO, command, strlen(command)); | 88 write_or_die(STDOUT_FILENO, command, strlen(command)); |
74 end[0] = '#'; | 89 end[0] = '#'; |
75 gdb_calc_checksum(command, end+1); | 90 gdb_calc_checksum(command, end+1); |
76 write_or_die(STDOUT_FILENO, end, 3); | 91 write_or_die(STDOUT_FILENO, end, 3); |
77 fprintf(stderr, "Sent $%s#%c%c\n", command, end[1], end[2]); | 92 dfprintf(stderr, "Sent $%s#%c%c\n", command, end[1], end[2]); |
78 } | 93 } |
79 | 94 |
80 uint32_t calc_status(m68k_context * context) | 95 uint32_t calc_status(m68k_context * context) |
81 { | 96 { |
82 uint32_t status = context->status << 3; | 97 uint32_t status = context->status << 3; |
106 } | 121 } |
107 | 122 |
108 void gdb_run_command(m68k_context * context, uint32_t pc, char * command) | 123 void gdb_run_command(m68k_context * context, uint32_t pc, char * command) |
109 { | 124 { |
110 char send_buf[512]; | 125 char send_buf[512]; |
111 fprintf(stderr, "Received command %s\n", command); | 126 dfprintf(stderr, "Received command %s\n", command); |
112 switch(*command) | 127 switch(*command) |
113 { | 128 { |
114 | 129 |
115 case 'c': | 130 case 'c': |
116 if (*(command+1) != 0) { | 131 if (*(command+1) != 0) { |
118 goto not_impl; | 133 goto not_impl; |
119 } | 134 } |
120 cont = 1; | 135 cont = 1; |
121 expect_break_response = 1; | 136 expect_break_response = 1; |
122 break; | 137 break; |
138 case 's': { | |
139 if (*(command+1) != 0) { | |
140 //TODO: implement resuming at an arbitrary address | |
141 goto not_impl; | |
142 } | |
143 m68kinst inst; | |
144 uint16_t * pc_ptr; | |
145 if (pc < 0x400000) { | |
146 pc_ptr = cart + pc/2; | |
147 } else if(pc > 0xE00000) { | |
148 pc_ptr = ram + (pc & 0xFFFF)/2; | |
149 } else { | |
150 fprintf(stderr, "Entered gdb remote debugger stub at address %X\n", pc); | |
151 exit(1); | |
152 } | |
153 uint16_t * after_pc = m68k_decode(pc_ptr, &inst, pc & 0xFFFFFF); | |
154 uint32_t after = pc + (after_pc-pc_ptr)*2; | |
155 | |
156 if (inst.op == M68K_RTS) { | |
157 after = (read_dma_value(context->aregs[7]/2) << 16) | read_dma_value(context->aregs[7]/2 + 1); | |
158 } else if (inst.op == M68K_RTE || inst.op == M68K_RTR) { | |
159 after = (read_dma_value((context->aregs[7]+2)/2) << 16) | read_dma_value((context->aregs[7]+2)/2 + 1); | |
160 } else if(m68k_is_branch(&inst)) { | |
161 if (inst.op == M68K_BCC && inst.extra.cond != COND_TRUE) { | |
162 branch_f = after; | |
163 branch_t = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF; | |
164 insert_breakpoint(context, branch_t, (uint8_t *)gdb_debug_enter); | |
165 } else if(inst.op == M68K_DBCC && inst.extra.cond != COND_FALSE) { | |
166 branch_t = after; | |
167 branch_f = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF; | |
168 insert_breakpoint(context, branch_f, (uint8_t *)gdb_debug_enter); | |
169 } else { | |
170 after = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF; | |
171 } | |
172 } | |
173 insert_breakpoint(context, after, (uint8_t *)gdb_debug_enter); | |
174 | |
175 cont = 1; | |
176 expect_break_response = 1; | |
177 break; | |
178 } | |
123 case 'H': | 179 case 'H': |
124 if (command[1] == 'g' || command[1] == 'c') {; | 180 if (command[1] == 'g' || command[1] == 'c') {; |
125 //no thread suport, just acknowledge | 181 //no thread suport, just acknowledge |
126 gdb_send_command("OK"); | 182 gdb_send_command("OK"); |
127 } else { | 183 } else { |
131 case 'Z': { | 187 case 'Z': { |
132 uint8_t type = command[1]; | 188 uint8_t type = command[1]; |
133 if (type < '2') { | 189 if (type < '2') { |
134 uint32_t address = strtoul(command+3, NULL, 16); | 190 uint32_t address = strtoul(command+3, NULL, 16); |
135 insert_breakpoint(context, address, (uint8_t *)gdb_debug_enter); | 191 insert_breakpoint(context, address, (uint8_t *)gdb_debug_enter); |
192 bp_def *new_bp = malloc(sizeof(bp_def)); | |
193 new_bp->next = breakpoints; | |
194 new_bp->address = address; | |
195 new_bp->index = bp_index++; | |
196 breakpoints = new_bp; | |
136 gdb_send_command("OK"); | 197 gdb_send_command("OK"); |
137 } else { | 198 } else { |
138 //watchpoints are not currently supported | 199 //watchpoints are not currently supported |
139 gdb_send_command(""); | 200 gdb_send_command(""); |
140 } | 201 } |
143 case 'z': { | 204 case 'z': { |
144 uint8_t type = command[1]; | 205 uint8_t type = command[1]; |
145 if (type < '2') { | 206 if (type < '2') { |
146 uint32_t address = strtoul(command+3, NULL, 16); | 207 uint32_t address = strtoul(command+3, NULL, 16); |
147 remove_breakpoint(context, address); | 208 remove_breakpoint(context, address); |
209 bp_def **found = find_breakpoint(&breakpoints, address); | |
210 if (*found) | |
211 { | |
212 bp_def * to_remove = *found; | |
213 *found = to_remove->next; | |
214 free(to_remove); | |
215 } | |
148 gdb_send_command("OK"); | 216 gdb_send_command("OK"); |
149 } else { | 217 } else { |
150 //watchpoints are not currently supported | 218 //watchpoints are not currently supported |
151 gdb_send_command(""); | 219 gdb_send_command(""); |
152 } | 220 } |
247 //trap exception or something, but for no we'll treat it as | 315 //trap exception or something, but for no we'll treat it as |
248 //a normal continue | 316 //a normal continue |
249 cont = 1; | 317 cont = 1; |
250 expect_break_response = 1; | 318 expect_break_response = 1; |
251 break; | 319 break; |
320 case 's': | |
321 case 'S': { | |
322 m68kinst inst; | |
323 uint16_t * pc_ptr; | |
324 if (pc < 0x400000) { | |
325 pc_ptr = cart + pc/2; | |
326 } else if(pc > 0xE00000) { | |
327 pc_ptr = ram + (pc & 0xFFFF)/2; | |
328 } else { | |
329 fprintf(stderr, "Entered gdb remote debugger stub at address %X\n", pc); | |
330 exit(1); | |
331 } | |
332 uint16_t * after_pc = m68k_decode(pc_ptr, &inst, pc & 0xFFFFFF); | |
333 uint32_t after = pc + (after_pc-pc_ptr)*2; | |
334 | |
335 if (inst.op == M68K_RTS) { | |
336 after = (read_dma_value(context->aregs[7]/2) << 16) | read_dma_value(context->aregs[7]/2 + 1); | |
337 } else if (inst.op == M68K_RTE || inst.op == M68K_RTR) { | |
338 after = (read_dma_value((context->aregs[7]+2)/2) << 16) | read_dma_value((context->aregs[7]+2)/2 + 1); | |
339 } else if(m68k_is_branch(&inst)) { | |
340 if (inst.op == M68K_BCC && inst.extra.cond != COND_TRUE) { | |
341 branch_f = after; | |
342 branch_t = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF; | |
343 insert_breakpoint(context, branch_t, (uint8_t *)gdb_debug_enter); | |
344 } else if(inst.op == M68K_DBCC && inst.extra.cond != COND_FALSE) { | |
345 branch_t = after; | |
346 branch_f = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF; | |
347 insert_breakpoint(context, branch_f, (uint8_t *)gdb_debug_enter); | |
348 } else { | |
349 after = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF; | |
350 } | |
351 } | |
352 insert_breakpoint(context, after, (uint8_t *)gdb_debug_enter); | |
353 | |
354 cont = 1; | |
355 expect_break_response = 1; | |
356 break; | |
357 } | |
252 default: | 358 default: |
253 goto not_impl; | 359 goto not_impl; |
254 } | 360 } |
255 } else { | 361 } else { |
256 goto not_impl; | 362 goto not_impl; |
269 exit(1); | 375 exit(1); |
270 } | 376 } |
271 | 377 |
272 m68k_context * gdb_debug_enter(m68k_context * context, uint32_t pc) | 378 m68k_context * gdb_debug_enter(m68k_context * context, uint32_t pc) |
273 { | 379 { |
274 fprintf(stderr, "Entered debugger at address %X\n", pc); | 380 dfprintf(stderr, "Entered debugger at address %X\n", pc); |
275 if (expect_break_response) { | 381 if (expect_break_response) { |
276 gdb_send_command("S05"); | 382 gdb_send_command("S05"); |
277 expect_break_response = 0; | 383 expect_break_response = 0; |
384 } | |
385 if ((pc & 0xFFFFFF) == branch_t) { | |
386 bp_def ** f_bp = find_breakpoint(&breakpoints, branch_f); | |
387 if (!*f_bp) { | |
388 remove_breakpoint(context, branch_f); | |
389 } | |
390 branch_t = branch_f = 0; | |
391 } else if((pc & 0xFFFFFF) == branch_f) { | |
392 bp_def ** t_bp = find_breakpoint(&breakpoints, branch_t); | |
393 if (!*t_bp) { | |
394 remove_breakpoint(context, branch_t); | |
395 } | |
396 branch_t = branch_f = 0; | |
397 } | |
398 //Check if this is a user set breakpoint, or just a temporary one | |
399 bp_def ** this_bp = find_breakpoint(&breakpoints, pc & 0xFFFFFF); | |
400 if (!*this_bp) { | |
401 remove_breakpoint(context, pc & 0xFFFFFF); | |
278 } | 402 } |
279 resume_pc = pc; | 403 resume_pc = pc; |
280 cont = 0; | 404 cont = 0; |
281 uint8_t partial = 0; | 405 uint8_t partial = 0; |
282 while(!cont) | 406 while(!cont) |
321 curbuf--; | 445 curbuf--; |
322 partial = 1; | 446 partial = 1; |
323 break; | 447 break; |
324 } | 448 } |
325 } else { | 449 } else { |
326 fprintf(stderr, "Ignoring character %c\n", *curbuf); | 450 dfprintf(stderr, "Ignoring character %c\n", *curbuf); |
327 } | 451 } |
328 } | 452 } |
329 if (curbuf == end) { | 453 if (curbuf == end) { |
330 curbuf = NULL; | 454 curbuf = NULL; |
331 } | 455 } |