1 /* 2 * Copyright 2005-2009, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Copyright 2010-2013, Rene Gollent, rene@gollent.com. 4 * Distributed under the terms of the MIT License. 5 */ 6 7 #include <new> 8 9 #include <string.h> 10 11 #include <AutoDeleter.h> 12 #include <debug_support.h> 13 14 #include "arch_debug_support.h" 15 #include "Image.h" 16 #include "SymbolLookup.h" 17 18 19 using std::nothrow; 20 21 22 struct debug_symbol_lookup_context { 23 SymbolLookup* lookup; 24 }; 25 26 struct debug_symbol_iterator : BPrivate::Debug::SymbolIterator { 27 bool ownsImage; 28 29 debug_symbol_iterator() 30 : 31 ownsImage(false) 32 { 33 } 34 35 ~debug_symbol_iterator() 36 { 37 if (ownsImage) 38 delete image; 39 } 40 }; 41 42 43 // init_debug_context 44 status_t 45 init_debug_context(debug_context *context, team_id team, port_id nubPort) 46 { 47 if (!context || team < 0 || nubPort < 0) 48 return B_BAD_VALUE; 49 50 context->team = team; 51 context->nub_port = nubPort; 52 53 // create the reply port 54 context->reply_port = create_port(1, "debug reply port"); 55 if (context->reply_port < 0) 56 return context->reply_port; 57 58 return B_OK; 59 } 60 61 // destroy_debug_context 62 void 63 destroy_debug_context(debug_context *context) 64 { 65 if (context) { 66 if (context->reply_port >= 0) 67 delete_port(context->reply_port); 68 69 context->team = -1; 70 context->nub_port = -1; 71 context->reply_port = -1; 72 } 73 } 74 75 // send_debug_message 76 status_t 77 send_debug_message(debug_context *context, int32 messageCode, 78 const void *message, int32 messageSize, void *reply, int32 replySize) 79 { 80 if (!context) 81 return B_BAD_VALUE; 82 83 // send message 84 while (true) { 85 status_t result = write_port(context->nub_port, messageCode, message, 86 messageSize); 87 if (result == B_OK) 88 break; 89 if (result != B_INTERRUPTED) 90 return result; 91 } 92 93 if (!reply) 94 return B_OK; 95 96 // read reply 97 while (true) { 98 int32 code; 99 ssize_t bytesRead = read_port(context->reply_port, &code, reply, 100 replySize); 101 if (bytesRead > 0) 102 return B_OK; 103 if (bytesRead != B_INTERRUPTED) 104 return bytesRead; 105 } 106 } 107 108 // debug_read_memory_partial 109 ssize_t 110 debug_read_memory_partial(debug_context *context, const void *address, 111 void *buffer, size_t size) 112 { 113 if (!context) 114 return B_BAD_VALUE; 115 116 if (size == 0) 117 return 0; 118 if (size > B_MAX_READ_WRITE_MEMORY_SIZE) 119 size = B_MAX_READ_WRITE_MEMORY_SIZE; 120 121 // prepare the message 122 debug_nub_read_memory message; 123 message.reply_port = context->reply_port; 124 message.address = (void*)address; 125 message.size = size; 126 127 // send the message 128 debug_nub_read_memory_reply reply; 129 status_t error = send_debug_message(context, B_DEBUG_MESSAGE_READ_MEMORY, 130 &message, sizeof(message), &reply, sizeof(reply)); 131 132 if (error != B_OK) 133 return error; 134 if (reply.error != B_OK) 135 return reply.error; 136 137 // copy the read data 138 memcpy(buffer, reply.data, reply.size); 139 return reply.size; 140 } 141 142 // debug_read_memory 143 ssize_t 144 debug_read_memory(debug_context *context, const void *_address, void *_buffer, 145 size_t size) 146 { 147 const char *address = (const char *)_address; 148 char *buffer = (char*)_buffer; 149 150 // check parameters 151 if (!context || !address || !buffer) 152 return B_BAD_VALUE; 153 if (size == 0) 154 return 0; 155 156 // read as long as we can read data 157 ssize_t sumRead = 0; 158 while (size > 0) { 159 ssize_t bytesRead = debug_read_memory_partial(context, address, buffer, 160 size); 161 if (bytesRead < 0) { 162 if (sumRead > 0) 163 return sumRead; 164 return bytesRead; 165 } 166 167 address += bytesRead; 168 buffer += bytesRead; 169 sumRead += bytesRead; 170 size -= bytesRead; 171 } 172 173 return sumRead; 174 } 175 176 // debug_read_string 177 ssize_t 178 debug_read_string(debug_context *context, const void *_address, char *buffer, 179 size_t size) 180 { 181 const char *address = (const char *)_address; 182 183 // check parameters 184 if (!context || !address || !buffer || size == 0) 185 return B_BAD_VALUE; 186 187 // read as long as we can read data 188 ssize_t sumRead = 0; 189 while (size > 0) { 190 ssize_t bytesRead = debug_read_memory_partial(context, address, buffer, 191 size); 192 if (bytesRead < 0) { 193 // always null-terminate what we have (even, if it is an empty 194 // string) and be done 195 *buffer = '\0'; 196 return (sumRead > 0 ? sumRead : bytesRead); 197 } 198 199 int chunkSize = strnlen(buffer, bytesRead); 200 if (chunkSize < bytesRead) { 201 // we found a terminating null 202 sumRead += chunkSize; 203 return sumRead; 204 } 205 206 address += bytesRead; 207 buffer += bytesRead; 208 sumRead += bytesRead; 209 size -= bytesRead; 210 } 211 212 // We filled the complete buffer without encountering a terminating null 213 // replace the last char. But nevertheless return the full size to indicate 214 // that the buffer was too small. 215 buffer[-1] = '\0'; 216 217 return sumRead; 218 } 219 220 // debug_write_memory_partial 221 ssize_t 222 debug_write_memory_partial(debug_context *context, const void *address, 223 void *buffer, size_t size) 224 { 225 if (!context) 226 return B_BAD_VALUE; 227 228 if (size == 0) 229 return 0; 230 if (size > B_MAX_READ_WRITE_MEMORY_SIZE) 231 size = B_MAX_READ_WRITE_MEMORY_SIZE; 232 233 // prepare the message 234 debug_nub_write_memory message; 235 message.reply_port = context->reply_port; 236 message.address = (void*)address; 237 message.size = size; 238 memcpy(message.data, buffer, size); 239 240 // send the message 241 debug_nub_write_memory_reply reply; 242 status_t error = send_debug_message(context, B_DEBUG_MESSAGE_WRITE_MEMORY, 243 &message, sizeof(message), &reply, sizeof(reply)); 244 245 if (error != B_OK) 246 return error; 247 if (reply.error != B_OK) 248 return reply.error; 249 250 return reply.size; 251 } 252 253 // debug_write_memory 254 ssize_t 255 debug_write_memory(debug_context *context, const void *_address, void *_buffer, 256 size_t size) 257 { 258 const char *address = (const char *)_address; 259 char *buffer = (char*)_buffer; 260 261 // check parameters 262 if (!context || !address || !buffer) 263 return B_BAD_VALUE; 264 if (size == 0) 265 return 0; 266 267 ssize_t sumWritten = 0; 268 while (size > 0) { 269 ssize_t bytesWritten = debug_write_memory_partial(context, address, buffer, 270 size); 271 if (bytesWritten < 0) { 272 if (sumWritten > 0) 273 return sumWritten; 274 return bytesWritten; 275 } 276 277 address += bytesWritten; 278 buffer += bytesWritten; 279 sumWritten += bytesWritten; 280 size -= bytesWritten; 281 } 282 283 return sumWritten; 284 } 285 286 // debug_get_cpu_state 287 status_t 288 debug_get_cpu_state(debug_context *context, thread_id thread, 289 debug_debugger_message *messageCode, debug_cpu_state *cpuState) 290 { 291 if (!context || !cpuState) 292 return B_BAD_VALUE; 293 294 // prepare message 295 debug_nub_get_cpu_state message; 296 message.reply_port = context->reply_port; 297 message.thread = thread; 298 299 // send message 300 debug_nub_get_cpu_state_reply reply; 301 status_t error = send_debug_message(context, B_DEBUG_MESSAGE_GET_CPU_STATE, 302 &message, sizeof(message), &reply, sizeof(reply)); 303 if (error == B_OK) 304 error = reply.error; 305 306 // get state 307 if (error == B_OK) { 308 *cpuState = reply.cpu_state; 309 if (messageCode) 310 *messageCode = reply.message; 311 } 312 313 return error; 314 } 315 316 317 // #pragma mark - 318 319 // debug_get_instruction_pointer 320 status_t 321 debug_get_instruction_pointer(debug_context *context, thread_id thread, 322 void **ip, void **stackFrameAddress) 323 { 324 if (!context || !ip || !stackFrameAddress) 325 return B_BAD_VALUE; 326 327 return arch_debug_get_instruction_pointer(context, thread, ip, 328 stackFrameAddress); 329 } 330 331 // debug_get_stack_frame 332 status_t 333 debug_get_stack_frame(debug_context *context, void *stackFrameAddress, 334 debug_stack_frame_info *stackFrameInfo) 335 { 336 if (!context || !stackFrameAddress || !stackFrameInfo) 337 return B_BAD_VALUE; 338 339 return arch_debug_get_stack_frame(context, stackFrameAddress, 340 stackFrameInfo); 341 } 342 343 344 // #pragma mark - 345 346 // debug_create_symbol_lookup_context 347 status_t 348 debug_create_symbol_lookup_context(team_id team, image_id image, 349 debug_symbol_lookup_context **_lookupContext) 350 { 351 if (team < 0 || !_lookupContext) 352 return B_BAD_VALUE; 353 354 // create the lookup context 355 debug_symbol_lookup_context *lookupContext 356 = new(std::nothrow) debug_symbol_lookup_context; 357 if (lookupContext == NULL) 358 return B_NO_MEMORY; 359 ObjectDeleter<debug_symbol_lookup_context> contextDeleter(lookupContext); 360 361 // create and init symbol lookup 362 SymbolLookup *lookup = new(std::nothrow) SymbolLookup(team, image); 363 if (lookup == NULL) 364 return B_NO_MEMORY; 365 ObjectDeleter<SymbolLookup> lookupDeleter(lookup); 366 367 try { 368 status_t error = lookup->Init(); 369 if (error != B_OK) 370 return error; 371 } catch (BPrivate::Debug::Exception exception) { 372 return exception.Error(); 373 } 374 375 // everything went fine: return the result 376 lookupContext->lookup = lookup; 377 *_lookupContext = lookupContext; 378 contextDeleter.Detach(); 379 lookupDeleter.Detach(); 380 381 return B_OK; 382 } 383 384 // debug_delete_symbol_lookup_context 385 void 386 debug_delete_symbol_lookup_context(debug_symbol_lookup_context *lookupContext) 387 { 388 if (lookupContext) { 389 delete lookupContext->lookup; 390 delete lookupContext; 391 } 392 } 393 394 395 // debug_get_symbol 396 status_t 397 debug_get_symbol(debug_symbol_lookup_context* lookupContext, image_id image, 398 const char* name, int32 symbolType, void** _symbolLocation, 399 size_t* _symbolSize, int32* _symbolType) 400 { 401 if (!lookupContext || !lookupContext->lookup) 402 return B_BAD_VALUE; 403 SymbolLookup* lookup = lookupContext->lookup; 404 405 return lookup->GetSymbol(image, name, symbolType, _symbolLocation, 406 _symbolSize, _symbolType); 407 } 408 409 410 // debug_lookup_symbol_address 411 status_t 412 debug_lookup_symbol_address(debug_symbol_lookup_context *lookupContext, 413 const void *address, void **baseAddress, char *symbolName, 414 int32 symbolNameSize, char *imageName, int32 imageNameSize, 415 bool *exactMatch) 416 { 417 if (!lookupContext || !lookupContext->lookup) 418 return B_BAD_VALUE; 419 SymbolLookup *lookup = lookupContext->lookup; 420 421 // find the symbol 422 addr_t _baseAddress; 423 const char *_symbolName; 424 size_t _symbolNameLen; 425 const char *_imageName; 426 try { 427 status_t error = lookup->LookupSymbolAddress((addr_t)address, 428 &_baseAddress, &_symbolName, &_symbolNameLen, &_imageName, 429 exactMatch); 430 if (error != B_OK) 431 return error; 432 } catch (BPrivate::Debug::Exception exception) { 433 return exception.Error(); 434 } 435 436 // translate/copy the results 437 if (baseAddress) 438 *baseAddress = (void*)_baseAddress; 439 440 if (symbolName && symbolNameSize > 0) { 441 if (_symbolName && _symbolNameLen > 0) { 442 strlcpy(symbolName, _symbolName, 443 min_c((size_t)symbolNameSize, _symbolNameLen + 1)); 444 } else 445 symbolName[0] = '\0'; 446 } 447 448 if (imageName) { 449 if (imageNameSize > B_PATH_NAME_LENGTH) 450 imageNameSize = B_PATH_NAME_LENGTH; 451 strlcpy(imageName, _imageName, imageNameSize); 452 } 453 454 return B_OK; 455 } 456 457 458 status_t 459 debug_create_image_symbol_iterator(debug_symbol_lookup_context* lookupContext, 460 image_id imageID, debug_symbol_iterator** _iterator) 461 { 462 if (!lookupContext || !lookupContext->lookup) 463 return B_BAD_VALUE; 464 SymbolLookup *lookup = lookupContext->lookup; 465 466 debug_symbol_iterator* iterator = new(std::nothrow) debug_symbol_iterator; 467 if (iterator == NULL) 468 return B_NO_MEMORY; 469 470 status_t error; 471 try { 472 error = lookup->InitSymbolIterator(imageID, *iterator); 473 } catch (BPrivate::Debug::Exception exception) { 474 error = exception.Error(); 475 } 476 477 // Work-around for a runtime loader problem. A freshly fork()ed child does 478 // still have image_t structures with the parent's image ID's, so we 479 // wouldn't find the image in this case. 480 if (error != B_OK) { 481 // Get the image info and re-try looking with the text base address. 482 // Note, that we can't easily check whether the image is part of the 483 // target team at all (there's no image_info::team, we'd have to 484 // iterate through all images). 485 image_info imageInfo; 486 error = get_image_info(imageID, &imageInfo); 487 if (error == B_OK) { 488 try { 489 error = lookup->InitSymbolIteratorByAddress( 490 (addr_t)imageInfo.text, *iterator); 491 } catch (BPrivate::Debug::Exception exception) { 492 error = exception.Error(); 493 } 494 } 495 } 496 497 if (error != B_OK) { 498 delete iterator; 499 return error; 500 } 501 502 *_iterator = iterator; 503 return B_OK; 504 } 505 506 507 status_t 508 debug_create_file_symbol_iterator(const char* path, 509 debug_symbol_iterator** _iterator) 510 { 511 if (path == NULL) 512 return B_BAD_VALUE; 513 514 // create the iterator 515 debug_symbol_iterator* iterator = new(std::nothrow) debug_symbol_iterator; 516 if (iterator == NULL) 517 return B_NO_MEMORY; 518 ObjectDeleter<debug_symbol_iterator> iteratorDeleter(iterator); 519 520 // create the image file 521 ImageFile* imageFile = new(std::nothrow) ImageFile; 522 if (imageFile == NULL) 523 return B_NO_MEMORY; 524 525 // init the iterator 526 iterator->image = imageFile; 527 iterator->ownsImage = true; 528 iterator->currentIndex = -1; 529 530 // init the image file 531 status_t error = imageFile->Init(path); 532 if (error != B_OK) 533 return error; 534 535 iteratorDeleter.Detach(); 536 *_iterator = iterator; 537 538 return B_OK; 539 } 540 541 542 void 543 debug_delete_symbol_iterator(debug_symbol_iterator* iterator) 544 { 545 delete iterator; 546 } 547 548 549 // debug_next_image_symbol 550 status_t 551 debug_next_image_symbol(debug_symbol_iterator* iterator, char* nameBuffer, 552 size_t nameBufferLength, int32* _symbolType, void** _symbolLocation, 553 size_t* _symbolSize) 554 { 555 if (iterator == NULL || iterator->image == NULL) 556 return B_BAD_VALUE; 557 558 const char* symbolName; 559 size_t symbolNameLen; 560 addr_t symbolLocation; 561 562 try { 563 status_t error = iterator->image->NextSymbol(iterator->currentIndex, 564 &symbolName, &symbolNameLen, &symbolLocation, _symbolSize, 565 _symbolType); 566 if (error != B_OK) 567 return error; 568 } catch (BPrivate::Debug::Exception exception) { 569 return exception.Error(); 570 } 571 572 *_symbolLocation = (void*)symbolLocation; 573 574 if (symbolName != NULL && symbolNameLen > 0) { 575 strlcpy(nameBuffer, symbolName, 576 min_c(nameBufferLength, symbolNameLen + 1)); 577 } else 578 nameBuffer[0] = '\0'; 579 580 return B_OK; 581 } 582 583 584 status_t 585 debug_get_symbol_iterator_image_info(debug_symbol_iterator* iterator, 586 image_info* info) 587 { 588 if (iterator == NULL || iterator->image == NULL || info == NULL) 589 return B_BAD_VALUE; 590 591 *info = iterator->image->Info(); 592 return B_OK; 593 } 594