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