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/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 #if 0 232 int cpu; 233 234 // command 'g' is used for reading the register 235 // file. Faked by now. 236 // 237 // For x86 the register order is: 238 // 239 // eax, ebx, ecx, edx, 240 // esp, ebp, esi, edi, 241 // eip, eflags, 242 // cs, ss, ds, es 243 // 244 // Note that even thought the segment descriptors 245 // are actually 16 bits wide, gdb requires them 246 // as 32 bit integers. Note also that for some 247 // reason (unknown to me) gdb wants the register 248 // dump in *big endian* format. 249 cpu = smp_get_current_cpu(); 250 gdb_regreply(dbg_register_file[cpu], 14); 251 #else 252 (void)gdb_regreply; 253 gdb_reply("E01"); 254 #endif 255 256 break; 257 } 258 259 case 'G': 260 // write registers 261 // TODO: Implement! 262 gdb_reply("E01"); 263 break; 264 265 266 case 'm': 267 { 268 char* ptr; 269 unsigned address; 270 unsigned len; 271 272 // The 'm' command has the form mAAA,LLL 273 // where AAA is the address and LLL is the 274 // number of bytes. 275 ptr = sCommand + 1; 276 address = 0; 277 len = 0; 278 while (ptr && *ptr && (*ptr != ',')) { 279 address <<= 4; 280 address += parse_nibble(*ptr); 281 ptr += 1; 282 } 283 if (*ptr == ',') 284 ptr += 1; 285 286 while (ptr && *ptr) { 287 len <<= 4; 288 len += parse_nibble(*ptr); 289 ptr += 1; 290 } 291 292 if (len > 128) 293 len = 128; 294 295 // We cannot directly access the requested memory 296 // for gdb may be trying to access an stray pointer 297 // We copy the memory to a safe buffer using 298 // the bulletproof debug_memcpy(). 299 if (debug_memcpy(B_CURRENT_TEAM, sSafeMemory, (char*)address, len) 300 < 0) { 301 gdb_reply("E02"); 302 } else 303 gdb_memreply(sSafeMemory, len); 304 305 break; 306 } 307 308 case 'D': 309 // detach 310 return QUIT; 311 312 case 'k': 313 // Command 'k' actual semantics is 'kill the damn thing'. 314 // However gdb sends that command when you disconnect 315 // from a debug session. I guess that 'kill' for the 316 // kernel would map to reboot... however that's a 317 // a very mean thing to do, instead we just quit 318 // the gdb state machine and fallback to the regular 319 // kernel debugger command prompt. 320 return QUIT; 321 322 case 's': 323 // "step" -- resume (?) at address 324 // TODO: Implement! 325 gdb_reply("E01"); 326 break; 327 328 default: 329 gdb_reply(""); 330 break; 331 } 332 333 return WAITACK; 334 } 335 336 337 // #pragma mark - protocol state machine 338 339 340 static int 341 gdb_init_handler(int input) 342 { 343 switch (input) { 344 case '$': 345 memset(sCommand, 0, sizeof(sCommand)); 346 sCommandIndex = 0; 347 return CMDREAD; 348 349 default: 350 #if 0 351 gdb_nak(); 352 #else 353 // looks to me like we should send 354 // a NAK here but it kinda works 355 // better if we just gobble all 356 // junk chars silently 357 #endif 358 return INIT; 359 } 360 } 361 362 363 static int 364 gdb_cmdread_handler(int input) 365 { 366 switch (input) { 367 case '#': 368 return CKSUM1; 369 370 default: 371 sCommand[sCommandIndex] = input; 372 sCommandIndex += 1; 373 return CMDREAD; 374 } 375 } 376 377 378 static int 379 gdb_cksum1_handler(int input) 380 { 381 int nibble = parse_nibble(input); 382 383 if (nibble == 0xff) { 384 #if 0 385 gdb_nak(); 386 return INIT; 387 #else 388 // looks to me like we should send 389 // a NAK here but it kinda works 390 // better if we just gobble all 391 // junk chars silently 392 #endif 393 } 394 395 sCheckSum = nibble << 4; 396 397 return CKSUM2; 398 } 399 400 401 static int 402 gdb_cksum2_handler(int input) 403 { 404 int nibble = parse_nibble(input); 405 406 if (nibble == 0xff) { 407 #if 0 408 gdb_nak(); 409 return INIT; 410 #else 411 // looks to me like we should send 412 // a NAK here but it kinda works 413 // better if we just gobble all 414 // junk chars silently 415 #endif 416 } 417 418 sCheckSum += nibble; 419 420 return gdb_parse_command(); 421 } 422 423 424 static int 425 gdb_waitack_handler(int input) 426 { 427 switch (input) { 428 case '+': 429 return INIT; 430 case '-': 431 gdb_resend_reply(); 432 return WAITACK; 433 434 default: 435 // looks like gdb and us are out of sync, 436 // send a NAK and retry from INIT state. 437 gdb_nak(); 438 return INIT; 439 } 440 } 441 442 443 static int 444 gdb_quit_handler(int input) 445 { 446 (void)(input); 447 448 // actually we should never be here 449 return QUIT; 450 } 451 452 453 static int (*dispatch_table[GDBSTATES])(int) = { 454 &gdb_init_handler, 455 &gdb_cmdread_handler, 456 &gdb_cksum1_handler, 457 &gdb_cksum2_handler, 458 &gdb_waitack_handler, 459 &gdb_quit_handler 460 }; 461 462 463 static int 464 gdb_state_dispatch(int curr, int input) 465 { 466 if (curr < INIT || curr >= GDBSTATES) 467 return QUIT; 468 469 return dispatch_table[curr](input); 470 } 471 472 473 static int 474 gdb_state_machine(void) 475 { 476 int state = INIT; 477 int c; 478 479 while (state != QUIT) { 480 c = arch_debug_serial_getchar(); 481 state = gdb_state_dispatch(state, c); 482 } 483 484 return 0; 485 } 486 487 488 // #pragma mark - 489 490 491 int 492 cmd_gdb(int argc, char** argv) 493 { 494 (void)(argc); 495 (void)(argv); 496 497 return gdb_state_machine(); 498 } 499