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