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
debug_symbol_iteratordebug_symbol_iterator29 debug_symbol_iterator()
30 :
31 ownsImage(false)
32 {
33 }
34
~debug_symbol_iteratordebug_symbol_iterator35 ~debug_symbol_iterator()
36 {
37 if (ownsImage)
38 delete image;
39 }
40 };
41
42
43 // init_debug_context
44 status_t
init_debug_context(debug_context * context,team_id team,port_id nubPort)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
destroy_debug_context(debug_context * context)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
send_debug_message(debug_context * context,int32 messageCode,const void * message,int32 messageSize,void * reply,int32 replySize)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
debug_read_memory_partial(debug_context * context,const void * address,void * buffer,size_t size)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
debug_read_memory(debug_context * context,const void * _address,void * _buffer,size_t size)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
debug_read_string(debug_context * context,const void * _address,char * buffer,size_t size)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
debug_write_memory_partial(debug_context * context,const void * address,void * buffer,size_t size)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
debug_write_memory(debug_context * context,const void * _address,void * _buffer,size_t size)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
debug_get_cpu_state(debug_context * context,thread_id thread,debug_debugger_message * messageCode,debug_cpu_state * cpuState)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
debug_get_instruction_pointer(debug_context * context,thread_id thread,void ** ip,void ** stackFrameAddress)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
debug_get_stack_frame(debug_context * context,void * stackFrameAddress,debug_stack_frame_info * stackFrameInfo)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
debug_create_symbol_lookup_context(team_id team,image_id image,debug_symbol_lookup_context ** _lookupContext)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
debug_delete_symbol_lookup_context(debug_symbol_lookup_context * lookupContext)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
debug_get_symbol(debug_symbol_lookup_context * lookupContext,image_id image,const char * name,int32 symbolType,void ** _symbolLocation,size_t * _symbolSize,int32 * _symbolType)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
debug_lookup_symbol_address(debug_symbol_lookup_context * lookupContext,const void * address,void ** baseAddress,char * symbolName,int32 symbolNameSize,char * imageName,int32 imageNameSize,bool * exactMatch)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
debug_create_image_symbol_iterator(debug_symbol_lookup_context * lookupContext,image_id imageID,debug_symbol_iterator ** _iterator)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
debug_create_file_symbol_iterator(const char * path,debug_symbol_iterator ** _iterator)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
debug_delete_symbol_iterator(debug_symbol_iterator * iterator)543 debug_delete_symbol_iterator(debug_symbol_iterator* iterator)
544 {
545 delete iterator;
546 }
547
548
549 // debug_next_image_symbol
550 status_t
debug_next_image_symbol(debug_symbol_iterator * iterator,char * nameBuffer,size_t nameBufferLength,int32 * _symbolType,void ** _symbolLocation,size_t * _symbolSize)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
debug_get_symbol_iterator_image_info(debug_symbol_iterator * iterator,image_info * info)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