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