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:
@@ -13,12 +13,14 @@ extern "C" {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef struct debug_context {
|
typedef struct debug_context {
|
||||||
|
team_id team;
|
||||||
port_id nub_port;
|
port_id nub_port;
|
||||||
port_id reply_port;
|
port_id reply_port;
|
||||||
} debug_context;
|
} 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);
|
void destroy_debug_context(debug_context *context);
|
||||||
|
|
||||||
status_t send_debug_message(debug_context *context, int32 messageCode,
|
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);
|
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
|
#ifdef __cplusplus
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
SubDir OBOS_TOP src kits debug ;
|
SubDir OBOS_TOP src kits debug ;
|
||||||
|
|
||||||
|
UseArchHeaders $(OBOS_ARCH) ;
|
||||||
UsePrivateHeaders debug ;
|
UsePrivateHeaders debug ;
|
||||||
|
UsePrivateHeaders kernel ;
|
||||||
|
UsePrivateHeaders runtime_loader ;
|
||||||
UsePrivateHeaders shared ;
|
UsePrivateHeaders shared ;
|
||||||
SubDirHdrs [ FDirName $(SUBDIR) arch ] ;
|
SubDirHdrs [ FDirName $(SUBDIR) arch ] ;
|
||||||
|
|
||||||
@@ -8,7 +11,9 @@ SEARCH_SOURCE += [ FDirName $(SUBDIR) arch $(OBOS_ARCH) ] ;
|
|||||||
|
|
||||||
SharedLibrary debug :
|
SharedLibrary debug :
|
||||||
debug_support.cpp
|
debug_support.cpp
|
||||||
|
SymbolLookup.cpp
|
||||||
|
|
||||||
|
# architecture specific
|
||||||
arch_debug_support.cpp
|
arch_debug_support.cpp
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,278 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2005, Ingo Weinhold, [email protected].
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,135 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2005, Ingo Weinhold, [email protected].
|
||||||
|
* 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
|
||||||
@@ -3,21 +3,30 @@
|
|||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <new>
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <AutoDeleter.h>
|
||||||
#include <debug_support.h>
|
#include <debug_support.h>
|
||||||
|
|
||||||
#include "arch_debug_support.h"
|
#include "arch_debug_support.h"
|
||||||
|
#include "SymbolLookup.h"
|
||||||
|
|
||||||
|
struct debug_symbol_lookup_context {
|
||||||
|
debug_context context;
|
||||||
|
SymbolLookup *lookup;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
// init_debug_context
|
// init_debug_context
|
||||||
status_t
|
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;
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
context->team = team;
|
||||||
context->nub_port = nubPort;
|
context->nub_port = nubPort;
|
||||||
|
|
||||||
// create the reply port
|
// create the reply port
|
||||||
@@ -183,7 +192,7 @@ debug_read_string(debug_context *context, const void *_address, char *buffer,
|
|||||||
return sumRead;
|
return sumRead;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// debug_get_cpu_state
|
||||||
status_t
|
status_t
|
||||||
debug_get_cpu_state(debug_context *context, thread_id thread,
|
debug_get_cpu_state(debug_context *context, thread_id thread,
|
||||||
debug_debugger_message *messageCode, debug_cpu_state *cpuState)
|
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
|
status_t
|
||||||
debug_get_instruction_pointer(debug_context *context, thread_id thread,
|
debug_get_instruction_pointer(debug_context *context, thread_id thread,
|
||||||
void **ip, void **stackFrameAddress)
|
void **ip, void **stackFrameAddress)
|
||||||
@@ -225,7 +237,7 @@ debug_get_instruction_pointer(debug_context *context, thread_id thread,
|
|||||||
stackFrameAddress);
|
stackFrameAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// debug_get_stack_frame
|
||||||
status_t
|
status_t
|
||||||
debug_get_stack_frame(debug_context *context, void *stackFrameAddress,
|
debug_get_stack_frame(debug_context *context, void *stackFrameAddress,
|
||||||
debug_stack_frame_info *stackFrameInfo)
|
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,
|
return arch_debug_get_stack_frame(context, stackFrameAddress,
|
||||||
stackFrameInfo);
|
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;
|
||||||
|
}
|
||||||
|
|||||||
@@ -107,6 +107,10 @@ private:
|
|||||||
|
|
||||||
bool _HandleMessage(DebugMessage *message);
|
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();
|
status_t _InitGUI();
|
||||||
|
|
||||||
static status_t _HandlerThreadEntry(void *data);
|
static status_t _HandlerThreadEntry(void *data);
|
||||||
@@ -333,7 +337,7 @@ TeamDebugHandler::Init(port_id nubPort)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// init a debug context for the handler
|
// init a debug context for the handler
|
||||||
error = init_debug_context(&fDebugContext, nubPort);
|
error = init_debug_context(&fDebugContext, fTeam, nubPort);
|
||||||
if (error != B_OK) {
|
if (error != B_OK) {
|
||||||
printf("debug_server: TeamDebugHandler::Init(): Failed to init "
|
printf("debug_server: TeamDebugHandler::Init(): Failed to init "
|
||||||
"debug context for team %ld, port %ld: %s\n", fTeam, nubPort,
|
"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,
|
printf("debug_server: Thread %ld entered the debugger: %s\n", thread,
|
||||||
buffer);
|
buffer);
|
||||||
|
|
||||||
// TODO: Temporary solution. Remove when attaching gdb is working.
|
_PrintStackTrace(thread);
|
||||||
#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
|
|
||||||
|
|
||||||
bool kill = true;
|
bool kill = true;
|
||||||
|
|
||||||
@@ -615,6 +573,111 @@ TeamDebugHandler::_HandleMessage(DebugMessage *message)
|
|||||||
return kill;
|
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
|
// _InitGUI
|
||||||
status_t
|
status_t
|
||||||
TeamDebugHandler::_InitGUI()
|
TeamDebugHandler::_InitGUI()
|
||||||
|
|||||||
Reference in New Issue
Block a user