1 /* 2 * Copyright 2005-2007, Axel Dörfler, axeld@pinc-software.de. 3 * Distributed under the terms of the MIT License. 4 * 5 * Copyright 2002, Manuel J. Petit. All rights reserved. 6 * Distributed under the terms of the NewOS License. 7 */ 8 9 /** Contains the code to interface with a remote GDB */ 10 11 #include "gdb.h" 12 13 #include <string.h> 14 #include <stdarg.h> 15 #include <stdio.h> 16 17 #include <ByteOrder.h> 18 19 #include <arch/debug_console.h> 20 #include <debug.h> 21 #include <elf.h> 22 #include <elf_priv.h> 23 #include <smp.h> 24 #include <vm.h> 25 26 27 enum { INIT = 0, CMDREAD, CKSUM1, CKSUM2, WAITACK, QUIT, GDBSTATES }; 28 29 30 static char sCommand[512]; 31 static int sCommandIndex; 32 static int sCheckSum; 33 34 static char sReply[512]; 35 static char sSafeMemory[512]; 36 37 38 // utility functions 39 40 41 static int 42 parse_nibble(int input) 43 { 44 int nibble = 0xff; 45 46 if (input >= '0' && input <= '9') 47 nibble = input - '0'; 48 49 if (input >= 'A' && input <= 'F') 50 nibble = 0x0a + input - 'A'; 51 52 if (input >= 'a' && input <= 'f') 53 nibble = 0x0a + input - 'a'; 54 55 return nibble; 56 } 57 58 59 // #pragma mark - GDB protocol 60 61 62 static void 63 gdb_ack(void) 64 { 65 arch_debug_serial_putchar('+'); 66 } 67 68 69 static void 70 gdb_nak(void) 71 { 72 arch_debug_serial_putchar('-'); 73 } 74 75 76 static void 77 gdb_resend_reply(void) 78 { 79 arch_debug_serial_puts(sReply); 80 } 81 82 83 static void 84 gdb_reply(char const* format, ...) 85 { 86 int i; 87 int len; 88 int sum; 89 va_list args; 90 91 va_start(args, format); 92 sReply[0] = '$'; 93 vsprintf(sReply + 1, format, args); 94 va_end(args); 95 96 len = strlen(sReply); 97 sum = 0; 98 for (i = 1; i < len; i++) { 99 sum += sReply[i]; 100 } 101 sum %= 256; 102 103 sprintf(sReply + len, "#%02x", sum); 104 105 gdb_resend_reply(); 106 } 107 108 109 static void 110 gdb_regreply(int const* regs, int numregs) 111 { 112 int i; 113 int len; 114 int sum; 115 116 sReply[0] = '$'; 117 for (i = 0; i < numregs; i++) 118 sprintf(sReply + 1 + 8 * i, "%08lx", B_HOST_TO_BENDIAN_INT32(regs[i])); 119 120 len = strlen(sReply); 121 sum = 0; 122 for (i = 1; i < len; i++) 123 sum += sReply[i]; 124 sum %= 256; 125 126 sprintf(sReply + len, "#%02x", sum); 127 128 gdb_resend_reply(); 129 } 130 131 132 static void 133 gdb_memreply(char const* bytes, int numbytes) 134 { 135 int i; 136 int len; 137 int sum; 138 139 sReply[0] = '$'; 140 for (i = 0; i < numbytes; i++) 141 sprintf(sReply + 1 + 2 * i, "%02x", (uint8)bytes[i]); 142 143 len = strlen(sReply); 144 sum = 0; 145 for (i = 1; i < len; i++) 146 sum += sReply[i]; 147 sum %= 256; 148 149 sprintf(sReply + len, "#%02x", sum); 150 151 gdb_resend_reply(); 152 } 153 154 155 // #pragma mark - checksum verification 156 157 158 static int 159 gdb_verify_checksum(void) 160 { 161 int i; 162 int len; 163 int sum; 164 165 len = strlen(sCommand); 166 sum = 0; 167 for (i = 0; i < len; i++) 168 sum += sCommand[i]; 169 sum %= 256; 170 171 return (sum == sCheckSum) ? 1 : 0; 172 } 173 174 175 // #pragma mark - command parsing 176 177 178 static int 179 gdb_parse_command(void) 180 { 181 if (!gdb_verify_checksum()) { 182 gdb_nak(); 183 return INIT; 184 } else 185 gdb_ack(); 186 187 switch (sCommand[0]) { 188 case '?': 189 // command '?' is used for retrieving the signal 190 // that stopped the program. Fully implemeting 191 // this command requires help from the debugger, 192 // by now we just fake a SIGKILL 193 gdb_reply("S09"); /* SIGKILL = 9 */ 194 break; 195 196 case 'H': 197 // Command H (actually Hct) is used to select 198 // the current thread (-1 meaning all threads) 199 // We just fake we recognize the the command 200 // and send an 'OK' response. 201 gdb_reply("OK"); 202 break; 203 204 case 'q': 205 { 206 // query commands 207 208 if (strcmp(sCommand + 1, "Supported") == 0) { 209 // get the supported features 210 gdb_reply(""); 211 } else if (strcmp(sCommand + 1, "Offsets") == 0) { 212 // get the segment offsets 213 elf_image_info* kernelImage = elf_get_kernel_image(); 214 gdb_reply("Text=%lx;Data=%lx;Bss=%lx", 215 kernelImage->text_region.delta, 216 kernelImage->data_region.delta, 217 kernelImage->data_region.delta); 218 } else 219 gdb_reply(""); 220 221 break; 222 } 223 224 case 'c': 225 // continue at address 226 // TODO: Parse the address and resume there! 227 return QUIT; 228 229 case 'g': 230 { 231 int cpu; 232 233 // command 'g' is used for reading the register 234 // file. Faked by now. 235 // 236 // For x86 the register order is: 237 // 238 // eax, ebx, ecx, edx, 239 // esp, ebp, esi, edi, 240 // eip, eflags, 241 // cs, ss, ds, es 242 // 243 // Note that even thought the segment descriptors 244 // are actually 16 bits wide, gdb requires them 245 // as 32 bit integers. Note also that for some 246 // reason (unknown to me) gdb wants the register 247 // dump in *big endian* format. 248 cpu = smp_get_current_cpu(); 249 gdb_regreply(dbg_register_file[cpu], 14); 250 251 break; 252 } 253 254 case 'G': 255 // write registers 256 // TODO: Implement! 257 gdb_reply("E01"); 258 break; 259 260 261 case 'm': 262 { 263 char* ptr; 264 unsigned address; 265 unsigned len; 266 267 // The 'm' command has the form mAAA,LLL 268 // where AAA is the address and LLL is the 269 // number of bytes. 270 ptr = sCommand + 1; 271 address = 0; 272 len = 0; 273 while (ptr && *ptr && (*ptr != ',')) { 274 address <<= 4; 275 address += parse_nibble(*ptr); 276 ptr += 1; 277 } 278 if (*ptr == ',') 279 ptr += 1; 280 281 while (ptr && *ptr) { 282 len <<= 4; 283 len += parse_nibble(*ptr); 284 ptr += 1; 285 } 286 287 if (len > 128) 288 len = 128; 289 290 // We cannot directly access the requested memory 291 // for gdb may be trying to access an stray pointer 292 // We copy the memory to a safe buffer using 293 // the bulletproof debug_memcpy(). 294 if (debug_memcpy(sSafeMemory, (char*)address, len) < 0) 295 gdb_reply("E02"); 296 else 297 gdb_memreply(sSafeMemory, len); 298 299 break; 300 } 301 302 case 'D': 303 // detach 304 return QUIT; 305 306 case 'k': 307 // Command 'k' actual semantics is 'kill the damn thing'. 308 // However gdb sends that command when you disconnect 309 // from a debug session. I guess that 'kill' for the 310 // kernel would map to reboot... however that's a 311 // a very mean thing to do, instead we just quit 312 // the gdb state machine and fallback to the regular 313 // kernel debugger command prompt. 314 return QUIT; 315 316 case 's': 317 // "step" -- resume (?) at address 318 // TODO: Implement! 319 gdb_reply("E01"); 320 break; 321 322 default: 323 gdb_reply(""); 324 break; 325 } 326 327 return WAITACK; 328 } 329 330 331 // #pragma mark - protocol state machine 332 333 334 static int 335 gdb_init_handler(int input) 336 { 337 switch (input) { 338 case '$': 339 memset(sCommand, 0, sizeof(sCommand)); 340 sCommandIndex = 0; 341 return CMDREAD; 342 343 default: 344 #if 0 345 gdb_nak(); 346 #else 347 // looks to me like we should send 348 // a NAK here but it kinda works 349 // better if we just gobble all 350 // junk chars silently 351 #endif 352 return INIT; 353 } 354 } 355 356 357 static int 358 gdb_cmdread_handler(int input) 359 { 360 switch (input) { 361 case '#': 362 return CKSUM1; 363 364 default: 365 sCommand[sCommandIndex] = input; 366 sCommandIndex += 1; 367 return CMDREAD; 368 } 369 } 370 371 372 static int 373 gdb_cksum1_handler(int input) 374 { 375 int nibble = parse_nibble(input); 376 377 if (nibble == 0xff) { 378 #if 0 379 gdb_nak(); 380 return INIT; 381 #else 382 // looks to me like we should send 383 // a NAK here but it kinda works 384 // better if we just gobble all 385 // junk chars silently 386 #endif 387 } 388 389 sCheckSum = nibble << 4; 390 391 return CKSUM2; 392 } 393 394 395 static int 396 gdb_cksum2_handler(int input) 397 { 398 int nibble = parse_nibble(input); 399 400 if (nibble == 0xff) { 401 #if 0 402 gdb_nak(); 403 return INIT; 404 #else 405 // looks to me like we should send 406 // a NAK here but it kinda works 407 // better if we just gobble all 408 // junk chars silently 409 #endif 410 } 411 412 sCheckSum += nibble; 413 414 return gdb_parse_command(); 415 } 416 417 418 static int 419 gdb_waitack_handler(int input) 420 { 421 switch (input) { 422 case '+': 423 return INIT; 424 case '-': 425 gdb_resend_reply(); 426 return WAITACK; 427 428 default: 429 // looks like gdb and us are out of sync, 430 // send a NAK and retry from INIT state. 431 gdb_nak(); 432 return INIT; 433 } 434 } 435 436 437 static int 438 gdb_quit_handler(int input) 439 { 440 (void)(input); 441 442 // actually we should never be here 443 return QUIT; 444 } 445 446 447 static int (*dispatch_table[GDBSTATES])(int) = { 448 &gdb_init_handler, 449 &gdb_cmdread_handler, 450 &gdb_cksum1_handler, 451 &gdb_cksum2_handler, 452 &gdb_waitack_handler, 453 &gdb_quit_handler 454 }; 455 456 457 static int 458 gdb_state_dispatch(int curr, int input) 459 { 460 if (curr < INIT || curr >= GDBSTATES) 461 return QUIT; 462 463 return dispatch_table[curr](input); 464 } 465 466 467 static int 468 gdb_state_machine(void) 469 { 470 int state = INIT; 471 int c; 472 473 while (state != QUIT) { 474 c = arch_debug_serial_getchar(); 475 state = gdb_state_dispatch(state, c); 476 } 477 478 return 0; 479 } 480 481 482 // #pragma mark - 483 484 485 int 486 cmd_gdb(int argc, char** argv) 487 { 488 (void)(argc); 489 (void)(argv); 490 491 return gdb_state_machine(); 492 } 493