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.
11 #include <AutoDeleter.h>
12 #include <debug_support.h>
14 #include "arch_debug_support.h"
16 #include "SymbolLookup.h"
22 struct debug_symbol_lookup_context
{
26 struct debug_symbol_iterator
: BPrivate::Debug::SymbolIterator
{
29 debug_symbol_iterator()
35 ~debug_symbol_iterator()
45 init_debug_context(debug_context
*context
, team_id team
, port_id nubPort
)
47 if (!context
|| team
< 0 || nubPort
< 0)
51 context
->nub_port
= nubPort
;
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
;
61 // destroy_debug_context
63 destroy_debug_context(debug_context
*context
)
66 if (context
->reply_port
>= 0)
67 delete_port(context
->reply_port
);
70 context
->nub_port
= -1;
71 context
->reply_port
= -1;
77 send_debug_message(debug_context
*context
, int32 messageCode
,
78 const void *message
, int32 messageSize
, void *reply
, int32 replySize
)
85 status_t result
= write_port(context
->nub_port
, messageCode
, message
,
89 if (result
!= B_INTERRUPTED
)
99 ssize_t bytesRead
= read_port(context
->reply_port
, &code
, reply
,
103 if (bytesRead
!= B_INTERRUPTED
)
108 // debug_read_memory_partial
110 debug_read_memory_partial(debug_context
*context
, const void *address
,
111 void *buffer
, size_t size
)
118 if (size
> B_MAX_READ_WRITE_MEMORY_SIZE
)
119 size
= B_MAX_READ_WRITE_MEMORY_SIZE
;
121 // prepare the message
122 debug_nub_read_memory message
;
123 message
.reply_port
= context
->reply_port
;
124 message
.address
= (void*)address
;
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
));
134 if (reply
.error
!= B_OK
)
137 // copy the read data
138 memcpy(buffer
, reply
.data
, reply
.size
);
144 debug_read_memory(debug_context
*context
, const void *_address
, void *_buffer
,
147 const char *address
= (const char *)_address
;
148 char *buffer
= (char*)_buffer
;
151 if (!context
|| !address
|| !buffer
)
156 // read as long as we can read data
159 ssize_t bytesRead
= debug_read_memory_partial(context
, address
, buffer
,
167 address
+= bytesRead
;
169 sumRead
+= bytesRead
;
178 debug_read_string(debug_context
*context
, const void *_address
, char *buffer
,
181 const char *address
= (const char *)_address
;
184 if (!context
|| !address
|| !buffer
|| size
== 0)
187 // read as long as we can read data
190 ssize_t bytesRead
= debug_read_memory_partial(context
, address
, buffer
,
193 // always null-terminate what we have (even, if it is an empty
194 // string) and be done
196 return (sumRead
> 0 ? sumRead
: bytesRead
);
199 int chunkSize
= strnlen(buffer
, bytesRead
);
200 if (chunkSize
< bytesRead
) {
201 // we found a terminating null
202 sumRead
+= chunkSize
;
206 address
+= bytesRead
;
208 sumRead
+= bytesRead
;
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.
220 // debug_write_memory_partial
222 debug_write_memory_partial(debug_context
*context
, const void *address
,
223 void *buffer
, size_t size
)
230 if (size
> B_MAX_READ_WRITE_MEMORY_SIZE
)
231 size
= B_MAX_READ_WRITE_MEMORY_SIZE
;
233 // prepare the message
234 debug_nub_write_memory message
;
235 message
.reply_port
= context
->reply_port
;
236 message
.address
= (void*)address
;
238 memcpy(message
.data
, buffer
, size
);
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
));
247 if (reply
.error
!= B_OK
)
253 // debug_write_memory
255 debug_write_memory(debug_context
*context
, const void *_address
, void *_buffer
,
258 const char *address
= (const char *)_address
;
259 char *buffer
= (char*)_buffer
;
262 if (!context
|| !address
|| !buffer
)
267 ssize_t sumWritten
= 0;
269 ssize_t bytesWritten
= debug_write_memory_partial(context
, address
, buffer
,
271 if (bytesWritten
< 0) {
277 address
+= bytesWritten
;
278 buffer
+= bytesWritten
;
279 sumWritten
+= bytesWritten
;
280 size
-= bytesWritten
;
286 // debug_get_cpu_state
288 debug_get_cpu_state(debug_context
*context
, thread_id thread
,
289 debug_debugger_message
*messageCode
, debug_cpu_state
*cpuState
)
291 if (!context
|| !cpuState
)
295 debug_nub_get_cpu_state message
;
296 message
.reply_port
= context
->reply_port
;
297 message
.thread
= thread
;
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
));
308 *cpuState
= reply
.cpu_state
;
310 *messageCode
= reply
.message
;
319 // debug_get_instruction_pointer
321 debug_get_instruction_pointer(debug_context
*context
, thread_id thread
,
322 void **ip
, void **stackFrameAddress
)
324 if (!context
|| !ip
|| !stackFrameAddress
)
327 return arch_debug_get_instruction_pointer(context
, thread
, ip
,
331 // debug_get_stack_frame
333 debug_get_stack_frame(debug_context
*context
, void *stackFrameAddress
,
334 debug_stack_frame_info
*stackFrameInfo
)
336 if (!context
|| !stackFrameAddress
|| !stackFrameInfo
)
339 return arch_debug_get_stack_frame(context
, stackFrameAddress
,
346 // debug_create_symbol_lookup_context
348 debug_create_symbol_lookup_context(team_id team
, image_id image
,
349 debug_symbol_lookup_context
**_lookupContext
)
351 if (team
< 0 || !_lookupContext
)
354 // create the lookup context
355 debug_symbol_lookup_context
*lookupContext
356 = new(std::nothrow
) debug_symbol_lookup_context
;
357 if (lookupContext
== NULL
)
359 ObjectDeleter
<debug_symbol_lookup_context
> contextDeleter(lookupContext
);
361 // create and init symbol lookup
362 SymbolLookup
*lookup
= new(std::nothrow
) SymbolLookup(team
, image
);
365 ObjectDeleter
<SymbolLookup
> lookupDeleter(lookup
);
368 status_t error
= lookup
->Init();
371 } catch (BPrivate::Debug::Exception exception
) {
372 return exception
.Error();
375 // everything went fine: return the result
376 lookupContext
->lookup
= lookup
;
377 *_lookupContext
= lookupContext
;
378 contextDeleter
.Detach();
379 lookupDeleter
.Detach();
384 // debug_delete_symbol_lookup_context
386 debug_delete_symbol_lookup_context(debug_symbol_lookup_context
*lookupContext
)
389 delete lookupContext
->lookup
;
390 delete lookupContext
;
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
)
401 if (!lookupContext
|| !lookupContext
->lookup
)
403 SymbolLookup
* lookup
= lookupContext
->lookup
;
405 return lookup
->GetSymbol(image
, name
, symbolType
, _symbolLocation
,
406 _symbolSize
, _symbolType
);
410 // debug_lookup_symbol_address
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
,
417 if (!lookupContext
|| !lookupContext
->lookup
)
419 SymbolLookup
*lookup
= lookupContext
->lookup
;
423 const char *_symbolName
;
424 size_t _symbolNameLen
;
425 const char *_imageName
;
427 status_t error
= lookup
->LookupSymbolAddress((addr_t
)address
,
428 &_baseAddress
, &_symbolName
, &_symbolNameLen
, &_imageName
,
432 } catch (BPrivate::Debug::Exception exception
) {
433 return exception
.Error();
436 // translate/copy the results
438 *baseAddress
= (void*)_baseAddress
;
440 if (symbolName
&& symbolNameSize
> 0) {
441 if (_symbolName
&& _symbolNameLen
> 0) {
442 strlcpy(symbolName
, _symbolName
,
443 min_c((size_t)symbolNameSize
, _symbolNameLen
+ 1));
445 symbolName
[0] = '\0';
449 if (imageNameSize
> B_PATH_NAME_LENGTH
)
450 imageNameSize
= B_PATH_NAME_LENGTH
;
451 strlcpy(imageName
, _imageName
, imageNameSize
);
459 debug_create_image_symbol_iterator(debug_symbol_lookup_context
* lookupContext
,
460 image_id imageID
, debug_symbol_iterator
** _iterator
)
462 if (!lookupContext
|| !lookupContext
->lookup
)
464 SymbolLookup
*lookup
= lookupContext
->lookup
;
466 debug_symbol_iterator
* iterator
= new(std::nothrow
) debug_symbol_iterator
;
467 if (iterator
== NULL
)
472 error
= lookup
->InitSymbolIterator(imageID
, *iterator
);
473 } catch (BPrivate::Debug::Exception exception
) {
474 error
= exception
.Error();
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.
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
);
489 error
= lookup
->InitSymbolIteratorByAddress(
490 (addr_t
)imageInfo
.text
, *iterator
);
491 } catch (BPrivate::Debug::Exception exception
) {
492 error
= exception
.Error();
502 *_iterator
= iterator
;
508 debug_create_file_symbol_iterator(const char* path
,
509 debug_symbol_iterator
** _iterator
)
514 // create the iterator
515 debug_symbol_iterator
* iterator
= new(std::nothrow
) debug_symbol_iterator
;
516 if (iterator
== NULL
)
518 ObjectDeleter
<debug_symbol_iterator
> iteratorDeleter(iterator
);
520 // create the image file
521 ImageFile
* imageFile
= new(std::nothrow
) ImageFile
;
522 if (imageFile
== NULL
)
526 iterator
->image
= imageFile
;
527 iterator
->ownsImage
= true;
528 iterator
->currentIndex
= -1;
530 // init the image file
531 status_t error
= imageFile
->Init(path
);
535 iteratorDeleter
.Detach();
536 *_iterator
= iterator
;
543 debug_delete_symbol_iterator(debug_symbol_iterator
* iterator
)
549 // debug_next_image_symbol
551 debug_next_image_symbol(debug_symbol_iterator
* iterator
, char* nameBuffer
,
552 size_t nameBufferLength
, int32
* _symbolType
, void** _symbolLocation
,
555 if (iterator
== NULL
|| iterator
->image
== NULL
)
558 const char* symbolName
;
559 size_t symbolNameLen
;
560 addr_t symbolLocation
;
563 status_t error
= iterator
->image
->NextSymbol(iterator
->currentIndex
,
564 &symbolName
, &symbolNameLen
, &symbolLocation
, _symbolSize
,
568 } catch (BPrivate::Debug::Exception exception
) {
569 return exception
.Error();
572 *_symbolLocation
= (void*)symbolLocation
;
574 if (symbolName
!= NULL
&& symbolNameLen
> 0) {
575 strlcpy(nameBuffer
, symbolName
,
576 min_c(nameBufferLength
, symbolNameLen
+ 1));
578 nameBuffer
[0] = '\0';
585 debug_get_symbol_iterator_image_info(debug_symbol_iterator
* iterator
,
588 if (iterator
== NULL
|| iterator
->image
== NULL
|| info
== NULL
)
591 *info
= iterator
->image
->Info();