1 /* 2 * Copyright 2005, Ingo Weinhold, bonefish@users.sf.net. 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 using std::nothrow; 17 18 struct debug_symbol_lookup_context { 19 debug_context context; 20 SymbolLookup *lookup; 21 }; 22 23 24 // init_debug_context 25 status_t 26 init_debug_context(debug_context *context, team_id team, port_id nubPort) 27 { 28 if (!context || team < 0 || nubPort < 0) 29 return B_BAD_VALUE; 30 31 context->team = team; 32 context->nub_port = nubPort; 33 34 // create the reply port 35 context->reply_port = create_port(1, "debug reply port"); 36 if (context->reply_port < 0) 37 return context->reply_port; 38 39 return B_OK; 40 } 41 42 // destroy_debug_context 43 void 44 destroy_debug_context(debug_context *context) 45 { 46 if (context) { 47 if (context->reply_port >= 0) 48 delete_port(context->reply_port); 49 50 context->team = -1; 51 context->nub_port = -1; 52 context->reply_port = -1; 53 } 54 } 55 56 // send_debug_message 57 status_t 58 send_debug_message(debug_context *context, int32 messageCode, 59 const void *message, int32 messageSize, void *reply, int32 replySize) 60 { 61 if (!context) 62 return B_BAD_VALUE; 63 64 // send message 65 while (true) { 66 status_t result = write_port(context->nub_port, messageCode, message, 67 messageSize); 68 if (result == B_OK) 69 break; 70 if (result != B_INTERRUPTED) 71 return result; 72 } 73 74 if (!reply) 75 return B_OK; 76 77 // read reply 78 while (true) { 79 int32 code; 80 ssize_t bytesRead = read_port(context->reply_port, &code, reply, 81 replySize); 82 if (bytesRead > 0) 83 return B_OK; 84 if (bytesRead != B_INTERRUPTED) 85 return bytesRead; 86 } 87 } 88 89 // debug_read_memory_partial 90 ssize_t 91 debug_read_memory_partial(debug_context *context, const void *address, 92 void *buffer, size_t size) 93 { 94 if (!context) 95 return B_BAD_VALUE; 96 97 if (size == 0) 98 return 0; 99 if (size > B_MAX_READ_WRITE_MEMORY_SIZE) 100 size = B_MAX_READ_WRITE_MEMORY_SIZE; 101 102 // prepare the message 103 debug_nub_read_memory message; 104 message.reply_port = context->reply_port; 105 message.address = (void*)address; 106 message.size = size; 107 108 // send the message 109 debug_nub_read_memory_reply reply; 110 status_t error = send_debug_message(context, B_DEBUG_MESSAGE_READ_MEMORY, 111 &message, sizeof(message), &reply, sizeof(reply)); 112 113 if (error != B_OK) 114 return error; 115 if (reply.error != B_OK) 116 return reply.error; 117 118 // copy the read data 119 memcpy(buffer, reply.data, reply.size); 120 return reply.size; 121 } 122 123 // debug_read_memory 124 ssize_t 125 debug_read_memory(debug_context *context, const void *_address, void *_buffer, 126 size_t size) 127 { 128 const char *address = (const char *)_address; 129 char *buffer = (char*)_buffer; 130 131 // check parameters 132 if (!context || !address || !buffer) 133 return B_BAD_VALUE; 134 if (size == 0) 135 return 0; 136 137 // read as long as we can read data 138 ssize_t sumRead = 0; 139 while (size > 0) { 140 ssize_t bytesRead = debug_read_memory_partial(context, address, buffer, 141 size); 142 if (bytesRead < 0) { 143 if (sumRead > 0) 144 return sumRead; 145 return bytesRead; 146 } 147 148 address += bytesRead; 149 buffer += bytesRead; 150 sumRead += bytesRead; 151 size -= bytesRead; 152 } 153 154 return sumRead; 155 } 156 157 // debug_read_string 158 ssize_t 159 debug_read_string(debug_context *context, const void *_address, char *buffer, 160 size_t size) 161 { 162 const char *address = (const char *)_address; 163 164 // check parameters 165 if (!context || !address || !buffer || size == 0) 166 return B_BAD_VALUE; 167 168 // read as long as we can read data 169 ssize_t sumRead = 0; 170 while (size > 0) { 171 ssize_t bytesRead = debug_read_memory_partial(context, address, buffer, 172 size); 173 if (bytesRead < 0) { 174 // always null-terminate what we have (even, if it is an empty 175 // string) and be done 176 *buffer = '\0'; 177 return (sumRead > 0 ? sumRead : bytesRead); 178 } 179 180 int chunkSize = strnlen(buffer, bytesRead); 181 if (chunkSize < bytesRead) { 182 // we found a terminating null 183 sumRead += chunkSize; 184 return sumRead; 185 } 186 187 address += bytesRead; 188 buffer += bytesRead; 189 sumRead += bytesRead; 190 size -= bytesRead; 191 } 192 193 // We filled the complete buffer without encountering a terminating null 194 // replace the last char. But nevertheless return the full size to indicate 195 // that the buffer was too small. 196 buffer[-1] = '\0'; 197 198 return sumRead; 199 } 200 201 // debug_get_cpu_state 202 status_t 203 debug_get_cpu_state(debug_context *context, thread_id thread, 204 debug_debugger_message *messageCode, debug_cpu_state *cpuState) 205 { 206 if (!context || !cpuState) 207 return B_BAD_VALUE; 208 209 // prepare message 210 debug_nub_get_cpu_state message; 211 message.reply_port = context->reply_port; 212 message.thread = thread; 213 214 // send message 215 debug_nub_get_cpu_state_reply reply; 216 status_t error = send_debug_message(context, B_DEBUG_MESSAGE_GET_CPU_STATE, 217 &message, sizeof(message), &reply, sizeof(reply)); 218 if (error == B_OK) 219 error = reply.error; 220 221 // get state 222 if (error == B_OK) { 223 *cpuState = reply.cpu_state; 224 if (messageCode) 225 *messageCode = reply.message; 226 } 227 228 return error; 229 } 230 231 232 // #pragma mark - 233 234 // debug_get_instruction_pointer 235 status_t 236 debug_get_instruction_pointer(debug_context *context, thread_id thread, 237 void **ip, void **stackFrameAddress) 238 { 239 if (!context || !ip || !stackFrameAddress) 240 return B_BAD_VALUE; 241 242 return arch_debug_get_instruction_pointer(context, thread, ip, 243 stackFrameAddress); 244 } 245 246 // debug_get_stack_frame 247 status_t 248 debug_get_stack_frame(debug_context *context, void *stackFrameAddress, 249 debug_stack_frame_info *stackFrameInfo) 250 { 251 if (!context || !stackFrameAddress || !stackFrameInfo) 252 return B_BAD_VALUE; 253 254 return arch_debug_get_stack_frame(context, stackFrameAddress, 255 stackFrameInfo); 256 } 257 258 259 // #pragma mark - 260 261 // debug_create_symbol_lookup_context 262 status_t 263 debug_create_symbol_lookup_context(debug_context *debugContext, 264 debug_symbol_lookup_context **_lookupContext) 265 { 266 if (!debugContext || !_lookupContext) 267 return B_BAD_VALUE; 268 269 // create the lookup context 270 debug_symbol_lookup_context *lookupContext 271 = new(nothrow) debug_symbol_lookup_context; 272 lookupContext->context = *debugContext; 273 ObjectDeleter<debug_symbol_lookup_context> contextDeleter(lookupContext); 274 275 // create and init symbol lookup 276 SymbolLookup *lookup = new(nothrow) SymbolLookup(debugContext->team); 277 if (!lookup) 278 return B_NO_MEMORY; 279 280 status_t error = lookup->Init(); 281 if (error != B_OK) { 282 delete lookup; 283 return error; 284 } 285 286 // everything went fine: return the result 287 lookupContext->lookup = lookup; 288 *_lookupContext = lookupContext; 289 contextDeleter.Detach(); 290 291 return B_OK; 292 } 293 294 // debug_delete_symbol_lookup_context 295 void 296 debug_delete_symbol_lookup_context(debug_symbol_lookup_context *lookupContext) 297 { 298 if (lookupContext) { 299 delete lookupContext->lookup; 300 delete lookupContext; 301 } 302 } 303 304 // debug_lookup_symbol_address 305 status_t 306 debug_lookup_symbol_address(debug_symbol_lookup_context *lookupContext, 307 const void *address, void **baseAddress, char *symbolName, 308 int32 symbolNameSize, char *imageName, int32 imageNameSize, 309 bool *exactMatch) 310 { 311 if (!lookupContext || !lookupContext->lookup) 312 return B_BAD_VALUE; 313 SymbolLookup *lookup = lookupContext->lookup; 314 315 // find the symbol 316 addr_t _baseAddress; 317 const char *_symbolName; 318 const char *_imageName; 319 try { 320 status_t error = lookup->LookupSymbolAddress((addr_t)address, &_baseAddress, 321 &_symbolName, &_imageName, exactMatch); 322 if (error != B_OK) 323 return error; 324 } catch (BPrivate::Exception exception) { 325 return exception.Error(); 326 } 327 328 // translate/copy the results 329 if (baseAddress) 330 *baseAddress = (void*)_baseAddress; 331 332 if (symbolName && symbolNameSize > 0) { 333 // _symbolName is a remote address: We read the string from the 334 // remote memory. The reason for not using the cloned area is that 335 // we don't trust that the data therein is valid (i.e. null-terminated) 336 // and thus strlcpy() could segfault when hitting the cloned area end. 337 if (_symbolName) { 338 ssize_t sizeRead = debug_read_string(&lookupContext->context, 339 _symbolName, symbolName, symbolNameSize); 340 if (sizeRead < 0) 341 return sizeRead; 342 } else 343 symbolName[0] = '\0'; 344 } 345 346 if (imageName) { 347 if (imageNameSize > B_PATH_NAME_LENGTH) 348 imageNameSize = B_PATH_NAME_LENGTH; 349 strlcpy(imageName, _imageName, imageNameSize); 350 } 351 352 return B_OK; 353 } 354