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 }