Added support for looking up symbols of other team to libdebug. The

debug_server uses this feature to print stack traces with symbols.



git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@13698 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold
2005-07-16 21:12:32 +00:00
parent 28e0d4cd19
commit 9a323d3533
6 changed files with 660 additions and 53 deletions
+18 -1
View File
@@ -13,12 +13,14 @@ extern "C" {
#endif
typedef struct debug_context {
team_id team;
port_id nub_port;
port_id reply_port;
} debug_context;
status_t init_debug_context(debug_context *context, port_id nubPort);
status_t init_debug_context(debug_context *context, team_id team,
port_id nubPort);
void destroy_debug_context(debug_context *context);
status_t send_debug_message(debug_context *context, int32 messageCode,
@@ -50,6 +52,21 @@ status_t debug_get_stack_frame(debug_context *context,
void *stackFrameAddress, debug_stack_frame_info *stackFrameInfo);
// symbol lookup support
typedef struct debug_symbol_lookup_context debug_symbol_lookup_context;
status_t debug_create_symbol_lookup_context(debug_context *debugContext,
debug_symbol_lookup_context **lookupContext);
void debug_delete_symbol_lookup_context(
debug_symbol_lookup_context *lookupContext);
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);
#ifdef __cplusplus
} // extern "C"
#endif
+5
View File
@@ -1,6 +1,9 @@
SubDir OBOS_TOP src kits debug ;
UseArchHeaders $(OBOS_ARCH) ;
UsePrivateHeaders debug ;
UsePrivateHeaders kernel ;
UsePrivateHeaders runtime_loader ;
UsePrivateHeaders shared ;
SubDirHdrs [ FDirName $(SUBDIR) arch ] ;
@@ -8,7 +11,9 @@ SEARCH_SOURCE += [ FDirName $(SUBDIR) arch $(OBOS_ARCH) ] ;
SharedLibrary debug :
debug_support.cpp
SymbolLookup.cpp
# architecture specific
arch_debug_support.cpp
;
+278
View File
@@ -0,0 +1,278 @@
/*
* Copyright 2005, Ingo Weinhold, bonefish@users.sf.net.
* Distributed under the terms of the MIT License.
*/
#include <string.h>
#include <runtime_loader.h>
#include "SymbolLookup.h"
using namespace BPrivate;
// PrepareAddress
const void *
Area::PrepareAddress(const void *address)
{
TRACE(("Area::PrepareAddress(%p): area: %ld\n", address, fRemoteID));
// clone the area, if not done already
if (fLocalID < 0) {
fLocalID = clone_area("cloned area", &fLocalAddress, B_ANY_ADDRESS,
B_READ_AREA, fRemoteID);
if (fLocalID < 0) {
TRACE(("Area::PrepareAddress(): Failed to clone area %ld: %s\n",
fRemoteID, strerror(fLocalID)));
throw Exception(fLocalID);
}
}
// translate the address
const void *result = (const void*)((addr_t)address - (addr_t)fRemoteAddress
+ (addr_t)fLocalAddress);
TRACE(("Area::PrepareAddress(%p) done: %p\n", address, result));
return result;
}
// #pragma mark -
// constructor
RemoteMemoryAccessor::RemoteMemoryAccessor(team_id team)
: fTeam(team),
fAreas()
{
}
// destructor
RemoteMemoryAccessor::~RemoteMemoryAccessor()
{
// delete the areas
while (Area *area = fAreas.Head()) {
fAreas.Remove(area);
delete area;
}
}
// Init
status_t
RemoteMemoryAccessor::Init()
{
// get a list of the team's areas
area_info areaInfo;
int32 cookie = 0;
status_t error;
while ((error = get_next_area_info(fTeam, &cookie, &areaInfo)) == B_OK) {
TRACE(("area %ld: address: %p, size: %ld, name: %s\n", areaInfo.area,
areaInfo.address, areaInfo.size, areaInfo.name));
Area *area = new(nothrow) Area(areaInfo.area, areaInfo.address,
areaInfo.size);
if (!area)
return B_NO_MEMORY;
fAreas.Add(area);
}
if (fAreas.IsEmpty())
return error;
return B_OK;
}
// PrepareAddress
const void *
RemoteMemoryAccessor::PrepareAddress(const void *remoteAddress, int32 size)
{
TRACE(("RemoteMemoryAccessor::PrepareAddress(%p, %ld)\n", remoteAddress,
size));
if (!remoteAddress) {
TRACE(("RemoteMemoryAccessor::PrepareAddress(): Got null address!\n"));
throw Exception(B_BAD_VALUE);
}
return _FindArea(remoteAddress, size).PrepareAddress(remoteAddress);
}
// _FindArea
Area &
RemoteMemoryAccessor::_FindArea(const void *address, int32 size)
{
TRACE(("RemoteMemoryAccessor::_FindArea(%p, %ld)\n", address, size));
for (AreaList::Iterator it = fAreas.GetIterator(); it.HasNext();) {
Area *area = it.Next();
if (area->ContainsAddress(address, size))
return *area;
}
TRACE(("RemoteMemoryAccessor::_FindArea(): No area found for address %p\n",
address));
throw Exception(B_ENTRY_NOT_FOUND);
}
// #pragma mark -
// constructor
SymbolLookup::SymbolLookup(team_id team)
: RemoteMemoryAccessor(team),
fDebugArea(NULL)
{
}
// destructor
SymbolLookup::~SymbolLookup()
{
}
// Init
status_t
SymbolLookup::Init()
{
TRACE(("SymbolLookup::Init()\n"));
status_t error = RemoteMemoryAccessor::Init();
if (error != B_OK)
return error;
TRACE(("SymbolLookup::Init(): searching debug area...\n"));
// find the runtime loader debug area
runtime_loader_debug_area *remoteDebugArea = NULL;
int32 cookie = 0;
area_info areaInfo;
while (get_next_area_info(fTeam, &cookie, &areaInfo) == B_OK) {
if (strcmp(areaInfo.name, RUNTIME_LOADER_DEBUG_AREA_NAME) == 0) {
remoteDebugArea = (runtime_loader_debug_area*)areaInfo.address;
break;
}
}
if (!remoteDebugArea) {
TRACE(("SymbolLookup::Init(): Couldn't find debug area!\n"));
return B_ERROR;
}
TRACE(("SymbolLookup::Init(): found debug area, translating address...\n"));
// translate the address
try {
fDebugArea = &Read(*remoteDebugArea);
TRACE(("SymbolLookup::Init(): translated debug area is at: %p, "
"loaded_images: %p\n", fDebugArea, fDebugArea->loaded_images));
} catch (Exception exception) {
return exception.Error();
}
return B_OK;
}
// LookupSymbolAddress
status_t
SymbolLookup::LookupSymbolAddress(addr_t address, addr_t *_baseAddress,
const char **_symbolName, const char **_imageName, bool *_exactMatch)
{
TRACE(("SymbolLookup::LookupSymbolAddress(%p)\n", (void*)address));
// get the image for the address
const image_t *image = _FindImageAtAddress(address);
if (!image)
return B_ENTRY_NOT_FOUND;
TRACE(("SymbolLookup::LookupSymbolAddress(): found image: ID: %ld, text: "
"address: %p, size: %ld\n",
image->id, (void*)image->regions[0].vmstart, image->regions[0].size));
// search the image for the symbol
const struct Elf32_Sym *symbolFound = NULL;
addr_t deltaFound = INT_MAX;
bool exactMatch = false;
const char *symbolName = NULL; // remote
int32 hashTabSize = Read(image->symhash[0]);
const uint32 *hashBuckets = image->symhash + 2; // remote
const uint32 *hashChains = image->symhash + 2 + hashTabSize; // remote
const elf_region_t *textRegion = image->regions; // local
for (int32 i = 0; i < hashTabSize; i++) {
for (int32 j = Read(hashBuckets[i]);
j != STN_UNDEF;
j = Read(hashChains[j])) {
const struct Elf32_Sym *symbol = &Read(image->syms[j]);
// skip invalid symbols
if (symbol->st_value == 0
|| symbol->st_value + symbol->st_size + textRegion->delta
> textRegion->vmstart + textRegion->size) {
continue;
}
// skip symbols starting after the given address
addr_t symbolAddress = symbol->st_value + textRegion->delta;
if (symbolAddress > address)
continue;
addr_t symbolDelta = address - symbolAddress;
if (!symbolFound || symbolDelta < deltaFound) {
deltaFound = symbolDelta;
symbolFound = symbol;
symbolName = SYMNAME(image, symbol);
if (symbolDelta >= 0 && symbolDelta < symbol->st_size) {
// exact match
exactMatch = true;
break;
}
}
}
}
TRACE(("SymbolLookup::LookupSymbolAddress(): done: symbol: %p, image name: "
"%s, exact match: %d\n", symbolFound, image->name, exactMatch));
if (_baseAddress) {
if (symbolFound)
*_baseAddress = symbolFound->st_value + textRegion->delta;
else
*_baseAddress = textRegion->vmstart;
}
if (_imageName)
*_imageName = image->name;
if (_symbolName)
*_symbolName = symbolName; // remote address
if (_exactMatch)
*_exactMatch = exactMatch;
return B_OK;
}
// _FindImageAtAddress
const image_t *
SymbolLookup::_FindImageAtAddress(addr_t address)
{
TRACE(("SymbolLookup::_FindImageAtAddress(%p)\n", (void*)address));
// iterate through the images
for (const image_t *image = &Read(*Read(fDebugArea->loaded_images->head));
image;
image = &Read(*image->next)) {
if (image->regions[0].vmstart <= address
&& address < image->regions[0].vmstart + image->regions[0].size) {
return image;
}
}
return NULL;
}
+135
View File
@@ -0,0 +1,135 @@
/*
* Copyright 2005, Ingo Weinhold, bonefish@users.sf.net.
* Distributed under the terms of the MIT License.
*/
#ifndef _SYMBOL_LOOKUP_H
#define _SYMBOL_LOOKUP_H
#include <stdio.h>
#include <OS.h>
#include <util/DoublyLinkedList.h>
//#define TRACE_DEBUG_SYMBOL_LOOKUP
#ifdef TRACE_DEBUG_SYMBOL_LOOKUP
# define TRACE(x) printf x
#else
# define TRACE(x) ;
#endif
struct image_t;
struct runtime_loader_debug_area;
namespace BPrivate {
// Exception
class Exception {
public:
Exception(status_t error)
: fError(error)
{
}
Exception(const Exception &other)
: fError(other.fError)
{
}
status_t Error() const { return fError; }
private:
status_t fError;
};
// Area
class Area : public DoublyLinkedListLinkImpl<Area> {
public:
Area(area_id id, const void *address, int32 size)
: fRemoteID(id),
fLocalID(-1),
fRemoteAddress(address),
fLocalAddress(NULL),
fSize(size)
{
}
~Area()
{
if (fLocalID >= 0)
delete_area(fLocalID);
}
const void* RemoteAddress() const { return fRemoteAddress; }
const void* LocalAddress() const { return fLocalAddress; }
int32 Size() const { return fSize; }
bool ContainsAddress(const void *address, int32 size) const
{
return ((addr_t)fRemoteAddress <= (addr_t)address
&& (addr_t)address + size <= (addr_t)fRemoteAddress + fSize);
}
const void *PrepareAddress(const void *address);
private:
area_id fRemoteID;
area_id fLocalID;
const void *fRemoteAddress;
void *fLocalAddress;
int32 fSize;
};
// RemoteMemoryAccessor
class RemoteMemoryAccessor {
public:
RemoteMemoryAccessor(team_id team);
~RemoteMemoryAccessor();
status_t Init();
const void *PrepareAddress(const void *remoteAddress, int32 size);
template<typename Type> inline const Type &Read(const Type &remoteData)
{
const void *remoteAddress = &remoteData;
const void *localAddress = PrepareAddress(remoteAddress,
sizeof(remoteData));
return *(const Type*)localAddress;
}
private:
Area &_FindArea(const void *address, int32 size);
typedef DoublyLinkedList<Area> AreaList;
protected:
team_id fTeam;
private:
AreaList fAreas;
};
// SymbolLookup
class SymbolLookup : private RemoteMemoryAccessor {
public:
SymbolLookup(team_id team);
~SymbolLookup();
status_t Init();
status_t LookupSymbolAddress(addr_t address, addr_t *_baseAddress,
const char **_symbolName, const char **_imageName, bool *_exactMatch);
private:
const image_t *_FindImageAtAddress(addr_t address);
const runtime_loader_debug_area *fDebugArea;
};
} // namespace BPrivate
using BPrivate::SymbolLookup;
#endif // _SYMBOL_LOOKUP_H
+113 -4
View File
@@ -3,21 +3,30 @@
* Distributed under the terms of the MIT License.
*/
#include <new>
#include <string.h>
#include <AutoDeleter.h>
#include <debug_support.h>
#include "arch_debug_support.h"
#include "SymbolLookup.h"
struct debug_symbol_lookup_context {
debug_context context;
SymbolLookup *lookup;
};
// init_debug_context
status_t
init_debug_context(debug_context *context, port_id nubPort)
init_debug_context(debug_context *context, team_id team, port_id nubPort)
{
if (!context || nubPort < 0)
if (!context || team < 0 || nubPort < 0)
return B_BAD_VALUE;
context->team = team;
context->nub_port = nubPort;
// create the reply port
@@ -183,7 +192,7 @@ debug_read_string(debug_context *context, const void *_address, char *buffer,
return sumRead;
}
// debug_get_cpu_state
status_t
debug_get_cpu_state(debug_context *context, thread_id thread,
debug_debugger_message *messageCode, debug_cpu_state *cpuState)
@@ -214,6 +223,9 @@ debug_get_cpu_state(debug_context *context, thread_id thread,
}
// #pragma mark -
// debug_get_instruction_pointer
status_t
debug_get_instruction_pointer(debug_context *context, thread_id thread,
void **ip, void **stackFrameAddress)
@@ -225,7 +237,7 @@ debug_get_instruction_pointer(debug_context *context, thread_id thread,
stackFrameAddress);
}
// debug_get_stack_frame
status_t
debug_get_stack_frame(debug_context *context, void *stackFrameAddress,
debug_stack_frame_info *stackFrameInfo)
@@ -236,3 +248,100 @@ debug_get_stack_frame(debug_context *context, void *stackFrameAddress,
return arch_debug_get_stack_frame(context, stackFrameAddress,
stackFrameInfo);
}
// #pragma mark -
// debug_create_symbol_lookup_context
status_t
debug_create_symbol_lookup_context(debug_context *debugContext,
debug_symbol_lookup_context **_lookupContext)
{
if (!debugContext || !_lookupContext)
return B_BAD_VALUE;
// create the lookup context
debug_symbol_lookup_context *lookupContext
= new(nothrow) debug_symbol_lookup_context;
lookupContext->context = *debugContext;
ObjectDeleter<debug_symbol_lookup_context> contextDeleter(lookupContext);
// create and init symbol lookup
SymbolLookup *lookup = new(nothrow) SymbolLookup(debugContext->team);
if (!lookup)
return B_NO_MEMORY;
status_t error = lookup->Init();
if (error != B_OK) {
delete lookup;
return error;
}
// everything went fine: return the result
lookupContext->lookup = lookup;
*_lookupContext = lookupContext;
contextDeleter.Detach();
return B_OK;
}
// debug_delete_symbol_lookup_context
void
debug_delete_symbol_lookup_context(debug_symbol_lookup_context *lookupContext)
{
if (lookupContext) {
delete lookupContext->lookup;
delete lookupContext;
}
}
// debug_lookup_symbol_address
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)
{
if (!lookupContext || !lookupContext->lookup)
return B_BAD_VALUE;
SymbolLookup *lookup = lookupContext->lookup;
// find the symbol
addr_t _baseAddress;
const char *_symbolName;
const char *_imageName;
try {
status_t error = lookup->LookupSymbolAddress((addr_t)address, &_baseAddress,
&_symbolName, &_imageName, exactMatch);
if (error != B_OK)
return error;
} catch (BPrivate::Exception exception) {
return exception.Error();
}
// translate/copy the results
if (baseAddress)
*baseAddress = (void*)_baseAddress;
if (symbolName && symbolNameSize > 0) {
// _symbolName is a remote address: We read the string from the
// remote memory. The reason for not using the cloned area is that
// we don't trust that the data therein is valid (i.e. null-terminated)
// and thus strlcpy() could segfault when hitting the cloned area end.
if (_symbolName) {
ssize_t sizeRead = debug_read_string(&lookupContext->context,
_symbolName, symbolName, symbolNameSize);
if (sizeRead < 0)
return sizeRead;
} else
symbolName[0] = '\0';
}
if (imageName) {
if (imageNameSize > B_OS_NAME_LENGTH)
imageNameSize = B_OS_NAME_LENGTH;
strlcpy(imageName, _imageName, imageNameSize);
}
return B_OK;
}
+111 -48
View File
@@ -107,6 +107,10 @@ private:
bool _HandleMessage(DebugMessage *message);
void _LookupSymbolAddress(debug_symbol_lookup_context *lookupContext,
const void *address, char *buffer, int32 bufferSize);
void _PrintStackTrace(thread_id thread);
status_t _InitGUI();
static status_t _HandlerThreadEntry(void *data);
@@ -333,7 +337,7 @@ TeamDebugHandler::Init(port_id nubPort)
}
// init a debug context for the handler
error = init_debug_context(&fDebugContext, nubPort);
error = init_debug_context(&fDebugContext, fTeam, nubPort);
if (error != B_OK) {
printf("debug_server: TeamDebugHandler::Init(): Failed to init "
"debug context for team %ld, port %ld: %s\n", fTeam, nubPort,
@@ -536,53 +540,7 @@ TeamDebugHandler::_HandleMessage(DebugMessage *message)
printf("debug_server: Thread %ld entered the debugger: %s\n", thread,
buffer);
// TODO: Temporary solution. Remove when attaching gdb is working.
#if 1
// print a stacktrace
void *ip = NULL;
void *stackFrameAddress = NULL;
status_t error = debug_get_instruction_pointer(&fDebugContext, thread, &ip,
&stackFrameAddress);
if (error == B_OK) {
printf("stack trace, current PC %p:\n", ip);
for (int32 i = 0; i < 50; i++) {
debug_stack_frame_info stackFrameInfo;
error = debug_get_stack_frame(&fDebugContext, stackFrameAddress,
&stackFrameInfo);
if (error < B_OK || stackFrameInfo.parent_frame == NULL)
break;
// find area containing the IP
team_id team = fTeam;
bool useAreaInfo = false;
area_info info;
int32 cookie = 0;
while (get_next_area_info(team, &cookie, &info) == B_OK) {
if ((addr_t)info.address
<= (addr_t)stackFrameInfo.return_address
&& (addr_t)info.address + info.size
> (addr_t)stackFrameInfo.return_address) {
useAreaInfo = true;
break;
}
}
printf(" (%p) %p", stackFrameInfo.frame,
stackFrameInfo.return_address);
if (useAreaInfo) {
printf(" (%s + %#lx)\n", info.name,
(addr_t)stackFrameInfo.return_address
- (addr_t)info.address);
} else
putchar('\n');
stackFrameAddress = stackFrameInfo.parent_frame;
}
}
#endif
_PrintStackTrace(thread);
bool kill = true;
@@ -615,6 +573,111 @@ TeamDebugHandler::_HandleMessage(DebugMessage *message)
return kill;
}
// _LookupSymbolAddress
void
TeamDebugHandler::_LookupSymbolAddress(
debug_symbol_lookup_context *lookupContext, const void *address,
char *buffer, int32 bufferSize)
{
// lookup the symbol
void *baseAddress;
char symbolName[1024];
char imageName[B_OS_NAME_LENGTH];
bool exactMatch;
bool lookupSucceeded = false;
if (lookupContext) {
status_t error = debug_lookup_symbol_address(lookupContext, address,
&baseAddress, symbolName, sizeof(symbolName), imageName,
sizeof(imageName), &exactMatch);
lookupSucceeded = (error == B_OK);
}
if (lookupSucceeded) {
// we were able to look something up
if (strlen(symbolName) > 0) {
// we even got a symbol
snprintf(buffer, bufferSize, "%s + %#lx%s", symbolName,
(addr_t)address - (addr_t)baseAddress,
(exactMatch ? "" : " (closest symbol)"));
} else {
// no symbol: image relative address
snprintf(buffer, bufferSize, "(%s + %#lx)", symbolName,
(addr_t)address - (addr_t)baseAddress);
}
} else {
// lookup failed: find area containing the IP
bool useAreaInfo = false;
area_info info;
int32 cookie = 0;
while (get_next_area_info(fTeam, &cookie, &info) == B_OK) {
if ((addr_t)info.address <= (addr_t)address
&& (addr_t)info.address + info.size > (addr_t)address) {
useAreaInfo = true;
break;
}
}
if (useAreaInfo) {
snprintf(buffer, bufferSize, "(%s + %#lx)", info.name,
(addr_t)address - (addr_t)info.address);
} else if (bufferSize > 0)
buffer[0] = '\0';
}
}
// _PrintStackTrace
void
TeamDebugHandler::_PrintStackTrace(thread_id thread)
{
// print a stacktrace
void *ip = NULL;
void *stackFrameAddress = NULL;
status_t error = debug_get_instruction_pointer(&fDebugContext, thread, &ip,
&stackFrameAddress);
if (error == B_OK) {
// create a symbol lookup context
debug_symbol_lookup_context *lookupContext = NULL;
error = debug_create_symbol_lookup_context(&fDebugContext,
&lookupContext);
if (error != B_OK) {
printf("debug_server: Failed to create symbol lookup context: %s\n",
strerror(error));
}
// lookup the IP
char symbolBuffer[2048];
_LookupSymbolAddress(lookupContext, ip, symbolBuffer,
sizeof(symbolBuffer) - 1);
printf("stack trace, current PC %p %s:\n", ip, symbolBuffer);
for (int32 i = 0; i < 50; i++) {
debug_stack_frame_info stackFrameInfo;
error = debug_get_stack_frame(&fDebugContext, stackFrameAddress,
&stackFrameInfo);
if (error < B_OK || stackFrameInfo.parent_frame == NULL)
break;
// lookup the return address
_LookupSymbolAddress(lookupContext, stackFrameInfo.return_address,
symbolBuffer, sizeof(symbolBuffer) - 1);
printf(" (%p) %p %s\n", stackFrameInfo.frame,
stackFrameInfo.return_address, symbolBuffer);
stackFrameAddress = stackFrameInfo.parent_frame;
}
// delete the symbol lookup context
if (lookupContext)
debug_delete_symbol_lookup_context(lookupContext);
}
}
// _InitGUI
status_t
TeamDebugHandler::_InitGUI()