Very much work in progress, not in a particularly working state. Haiku munged
a good part of the source tree, so I rather get those changes into the repository before continuing. The general aim of the work is to deal with multiple instances of the same function, e.g. inlined or non-inlined inline functions or those weird duplicates gcc (4 at least) seems to be generating for no apparent reason. * Added classes FunctionInstance (wrapping FunctionDebugInfo) and Function. FunctionInstance represents a physical instance of a function (e.g. inlined function at a particular address). A Function collects all FunctionInstances referring to the same source code location. * Moved the SourceCode property from FunctionDebugInfo to Function accordingly. * Since SourceCode is no longer associated with a concrete function instance, several methods dealing with statements have been removed and the functionality has been provided through other means (e.g. TeamDebugModel or SpecificImageDebugModel). This part is not yet completed. * Introduced UserBreakpoint and UserBreakpointInstance. The user sets a breakpoint at a source code location, which is represented by a UserBreakpoint. Since that source location can be mapped to one address per instance of the respective function, UserBreakpoint has a UserBreakpointInstance per such function instance, which in turn refers to a Breakpoint (an actual breakpoint at an address). * Adjusted Breakpoint, BreakpointManager, and TeamDebugger accordingly. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@31447 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
ccf28e4dd1
commit
f66bd6256a
@ -38,108 +38,179 @@ BreakpointManager::Init()
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
BreakpointManager::InstallUserBreakpoint(target_addr_t address,
|
BreakpointManager::InstallUserBreakpoint(UserBreakpoint* userBreakpoint,
|
||||||
bool enabled)
|
bool enabled)
|
||||||
{
|
{
|
||||||
user_breakpoint_state state = enabled
|
printf("BreakpointManager::InstallUserBreakpoint(%p, %d)\n", userBreakpoint, enabled);
|
||||||
? USER_BREAKPOINT_ENABLED : USER_BREAKPOINT_DISABLED;
|
AutoLocker<BLocker> installLocker(fLock);
|
||||||
|
|
||||||
AutoLocker<TeamDebugModel> modelLocker(fDebugModel);
|
AutoLocker<TeamDebugModel> modelLocker(fDebugModel);
|
||||||
|
|
||||||
// If there already is a breakpoint, it might already have the requested
|
bool oldEnabled = userBreakpoint->IsEnabled();
|
||||||
// state.
|
if (userBreakpoint->IsValid() && enabled == oldEnabled)
|
||||||
Breakpoint* breakpoint = fDebugModel->BreakpointAtAddress(address);
|
{
|
||||||
if (breakpoint != NULL && breakpoint->UserState() == state)
|
printf(" user breakpoint already valid and with same enabled state\n");
|
||||||
return B_OK;
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
// create a breakpoint, if it doesn't exist yet
|
// get/create the breakpoints for all instances
|
||||||
if (breakpoint == NULL) {
|
printf(" creating breakpoints for breakpoint instances\n");
|
||||||
Image* image = fDebugModel->GetTeam()->ImageByAddress(address);
|
status_t error = B_OK;
|
||||||
if (image == NULL)
|
for (int32 i = 0;
|
||||||
return B_BAD_ADDRESS;
|
UserBreakpointInstance* instance = userBreakpoint->InstanceAt(i); i++) {
|
||||||
|
printf(" breakpoint instance %p\n", instance);
|
||||||
|
if (instance->GetBreakpoint() != NULL)
|
||||||
|
{
|
||||||
|
printf(" -> already has breakpoint\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
breakpoint = new(std::nothrow) Breakpoint(image, address);
|
target_addr_t address = instance->Address();
|
||||||
if (breakpoint == NULL)
|
Breakpoint* breakpoint = fDebugModel->BreakpointAtAddress(address);
|
||||||
return B_NO_MEMORY;
|
if (breakpoint == NULL) {
|
||||||
|
printf(" -> no breakpoint at that address yet\n");
|
||||||
|
Image* image = fDebugModel->GetTeam()->ImageByAddress(address);
|
||||||
|
if (image == NULL) {
|
||||||
|
printf(" -> no image at that address\n");
|
||||||
|
error = B_BAD_ADDRESS;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (!fDebugModel->AddBreakpoint(breakpoint))
|
breakpoint = new(std::nothrow) Breakpoint(image, address);
|
||||||
return B_NO_MEMORY;
|
if (breakpoint == NULL) {
|
||||||
|
error = B_NO_MEMORY;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fDebugModel->AddBreakpoint(breakpoint)) {
|
||||||
|
error = B_NO_MEMORY;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf(" -> adding instance to breakpoint %p\n", breakpoint);
|
||||||
|
breakpoint->AddUserBreakpoint(instance);
|
||||||
|
instance->SetBreakpoint(breakpoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
user_breakpoint_state oldState = breakpoint->UserState();
|
// If everything looks good so far mark the user breakpoint according to
|
||||||
|
// its new state.
|
||||||
|
if (error == B_OK)
|
||||||
|
userBreakpoint->SetEnabled(enabled);
|
||||||
|
|
||||||
// set the breakpoint state
|
// notify user breakpoint listeners
|
||||||
breakpoint->SetUserState(state);
|
if (error == B_OK) {
|
||||||
fDebugModel->NotifyUserBreakpointChanged(breakpoint);
|
for (int32 i = 0;
|
||||||
|
UserBreakpointInstance* instance = userBreakpoint->InstanceAt(i);
|
||||||
|
i++) {
|
||||||
|
fDebugModel->NotifyUserBreakpointChanged(instance->GetBreakpoint());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
AutoLocker<BLocker> installLocker(fLock);
|
|
||||||
// We need to make the installation decision with both locks held, and
|
|
||||||
// we keep this lock until we have the breakpoint installed/uninstalled.
|
|
||||||
|
|
||||||
bool install = breakpoint->ShouldBeInstalled();
|
|
||||||
if (breakpoint->IsInstalled() == install)
|
|
||||||
return B_OK;
|
|
||||||
|
|
||||||
// The breakpoint needs to be installed/uninstalled.
|
|
||||||
Reference<Breakpoint> breakpointReference(breakpoint);
|
|
||||||
modelLocker.Unlock();
|
modelLocker.Unlock();
|
||||||
|
|
||||||
status_t error = install
|
// install/uninstall the breakpoints as needed
|
||||||
? fDebuggerInterface->InstallBreakpoint(address)
|
printf(" updating breakpoints\n");
|
||||||
: fDebuggerInterface->UninstallBreakpoint(address);
|
|
||||||
|
|
||||||
// Mark the breakpoint installed/uninstalled, if everything went fine.
|
|
||||||
if (error == B_OK) {
|
if (error == B_OK) {
|
||||||
breakpoint->SetInstalled(install);
|
for (int32 i = 0;
|
||||||
return B_OK;
|
UserBreakpointInstance* instance = userBreakpoint->InstanceAt(i);
|
||||||
|
i++) {
|
||||||
|
printf(" breakpoint instance %p\n", instance);
|
||||||
|
error = _UpdateBreakpointInstallation(instance->GetBreakpoint());
|
||||||
|
if (error != B_OK)
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// revert on error
|
if (error == B_OK) {
|
||||||
installLocker. Unlock();
|
printf(" success, marking user breakpoint valid\n");
|
||||||
modelLocker.Lock();
|
// everything went fine -- mark the user breakpoint valid
|
||||||
|
if (!userBreakpoint->IsValid()) {
|
||||||
|
modelLocker.Lock();
|
||||||
|
userBreakpoint->SetValid(true);
|
||||||
|
userBreakpoint->AcquireReference();
|
||||||
|
// TODO: Put the user breakpoint some place?
|
||||||
|
modelLocker.Unlock();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// something went wrong -- revert the situation
|
||||||
|
printf(" error, reverting\n");
|
||||||
|
modelLocker.Lock();
|
||||||
|
userBreakpoint->SetEnabled(oldEnabled);
|
||||||
|
modelLocker.Unlock();
|
||||||
|
|
||||||
breakpoint->SetUserState(oldState);
|
if (!oldEnabled || !userBreakpoint->IsValid()) {
|
||||||
fDebugModel->NotifyUserBreakpointChanged(breakpoint);
|
for (int32 i = 0; UserBreakpointInstance* instance
|
||||||
|
= userBreakpoint->InstanceAt(i);
|
||||||
|
i++) {
|
||||||
|
Breakpoint* breakpoint = instance->GetBreakpoint();
|
||||||
|
if (breakpoint == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
if (breakpoint->IsUnused())
|
if (!userBreakpoint->IsValid()) {
|
||||||
fDebugModel->RemoveBreakpoint(breakpoint);
|
instance->SetBreakpoint(NULL);
|
||||||
|
breakpoint->RemoveUserBreakpoint(instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
_UpdateBreakpointInstallation(breakpoint);
|
||||||
|
|
||||||
|
modelLocker.Lock();
|
||||||
|
fDebugModel->NotifyUserBreakpointChanged(breakpoint);
|
||||||
|
|
||||||
|
if (breakpoint->IsUnused())
|
||||||
|
fDebugModel->RemoveBreakpoint(breakpoint);
|
||||||
|
modelLocker.Unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
installLocker.Unlock();
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
BreakpointManager::UninstallUserBreakpoint(target_addr_t address)
|
BreakpointManager::UninstallUserBreakpoint(UserBreakpoint* userBreakpoint)
|
||||||
{
|
{
|
||||||
|
AutoLocker<BLocker> installLocker(fLock);
|
||||||
AutoLocker<TeamDebugModel> modelLocker(fDebugModel);
|
AutoLocker<TeamDebugModel> modelLocker(fDebugModel);
|
||||||
|
|
||||||
Breakpoint* breakpoint = fDebugModel->BreakpointAtAddress(address);
|
if (!userBreakpoint->IsValid())
|
||||||
if (breakpoint == NULL || breakpoint->UserState() == USER_BREAKPOINT_NONE)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// set the breakpoint state
|
userBreakpoint->SetValid(false);
|
||||||
breakpoint->SetUserState(USER_BREAKPOINT_NONE);
|
userBreakpoint->SetEnabled(false);
|
||||||
fDebugModel->NotifyUserBreakpointChanged(breakpoint);
|
|
||||||
|
|
||||||
AutoLocker<BLocker> installLocker(fLock);
|
|
||||||
// We need to make the uninstallation decision with both locks held, and
|
|
||||||
// we keep this lock until we have the breakpoint uninstalled.
|
|
||||||
|
|
||||||
// check whether the breakpoint needs to be uninstalled
|
|
||||||
bool uninstall = !breakpoint->ShouldBeInstalled()
|
|
||||||
&& breakpoint->IsInstalled();
|
|
||||||
|
|
||||||
// if unused remove it
|
|
||||||
Reference<Breakpoint> breakpointReference(breakpoint);
|
|
||||||
if (breakpoint->IsUnused())
|
|
||||||
fDebugModel->RemoveBreakpoint(breakpoint);
|
|
||||||
|
|
||||||
modelLocker.Unlock();
|
modelLocker.Unlock();
|
||||||
|
|
||||||
if (uninstall) {
|
// uninstall the breakpoints as needed
|
||||||
fDebuggerInterface->UninstallBreakpoint(address);
|
for (int32 i = 0;
|
||||||
breakpoint->SetInstalled(false);
|
UserBreakpointInstance* instance = userBreakpoint->InstanceAt(i); i++) {
|
||||||
|
if (Breakpoint* breakpoint = instance->GetBreakpoint())
|
||||||
|
_UpdateBreakpointInstallation(breakpoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
modelLocker.Lock();
|
||||||
|
|
||||||
|
// detach the breakpoints from the user breakpoint instances
|
||||||
|
for (int32 i = 0;
|
||||||
|
UserBreakpointInstance* instance = userBreakpoint->InstanceAt(i); i++) {
|
||||||
|
if (Breakpoint* breakpoint = instance->GetBreakpoint()) {
|
||||||
|
instance->SetBreakpoint(NULL);
|
||||||
|
breakpoint->RemoveUserBreakpoint(instance);
|
||||||
|
|
||||||
|
fDebugModel->NotifyUserBreakpointChanged(breakpoint);
|
||||||
|
|
||||||
|
if (breakpoint->IsUnused())
|
||||||
|
fDebugModel->RemoveBreakpoint(breakpoint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
modelLocker.Unlock();
|
||||||
|
installLocker.Unlock();
|
||||||
|
|
||||||
|
// release the reference from InstallUserBreakpoint()
|
||||||
|
userBreakpoint->ReleaseReference();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -147,6 +218,7 @@ status_t
|
|||||||
BreakpointManager::InstallTemporaryBreakpoint(target_addr_t address,
|
BreakpointManager::InstallTemporaryBreakpoint(target_addr_t address,
|
||||||
BreakpointClient* client)
|
BreakpointClient* client)
|
||||||
{
|
{
|
||||||
|
AutoLocker<BLocker> installLocker(fLock);
|
||||||
AutoLocker<TeamDebugModel> modelLocker(fDebugModel);
|
AutoLocker<TeamDebugModel> modelLocker(fDebugModel);
|
||||||
|
|
||||||
// create a breakpoint, if it doesn't exist yet
|
// create a breakpoint, if it doesn't exist yet
|
||||||
@ -169,10 +241,6 @@ BreakpointManager::InstallTemporaryBreakpoint(target_addr_t address,
|
|||||||
// add the client
|
// add the client
|
||||||
status_t error;
|
status_t error;
|
||||||
if (breakpoint->AddClient(client)) {
|
if (breakpoint->AddClient(client)) {
|
||||||
AutoLocker<BLocker> installLocker(fLock);
|
|
||||||
// We need to make the installation decision with both locks held,
|
|
||||||
// and we keep this lock until we have the breakpoint installed.
|
|
||||||
|
|
||||||
if (breakpoint->IsInstalled())
|
if (breakpoint->IsInstalled())
|
||||||
return B_OK;
|
return B_OK;
|
||||||
|
|
||||||
@ -185,7 +253,6 @@ BreakpointManager::InstallTemporaryBreakpoint(target_addr_t address,
|
|||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
installLocker.Unlock();
|
|
||||||
modelLocker.Lock();
|
modelLocker.Lock();
|
||||||
|
|
||||||
breakpoint->RemoveClient(client);
|
breakpoint->RemoveClient(client);
|
||||||
@ -204,6 +271,7 @@ void
|
|||||||
BreakpointManager::UninstallTemporaryBreakpoint(target_addr_t address,
|
BreakpointManager::UninstallTemporaryBreakpoint(target_addr_t address,
|
||||||
BreakpointClient* client)
|
BreakpointClient* client)
|
||||||
{
|
{
|
||||||
|
AutoLocker<BLocker> installLocker(fLock);
|
||||||
AutoLocker<TeamDebugModel> modelLocker(fDebugModel);
|
AutoLocker<TeamDebugModel> modelLocker(fDebugModel);
|
||||||
|
|
||||||
Breakpoint* breakpoint = fDebugModel->BreakpointAtAddress(address);
|
Breakpoint* breakpoint = fDebugModel->BreakpointAtAddress(address);
|
||||||
@ -213,10 +281,6 @@ BreakpointManager::UninstallTemporaryBreakpoint(target_addr_t address,
|
|||||||
// remove the client
|
// remove the client
|
||||||
breakpoint->RemoveClient(client);
|
breakpoint->RemoveClient(client);
|
||||||
|
|
||||||
AutoLocker<BLocker> installLocker(fLock);
|
|
||||||
// We need to make the uninstallation decision with both locks held, and
|
|
||||||
// we keep this lock until we have the breakpoint uninstalled.
|
|
||||||
|
|
||||||
// check whether the breakpoint needs to be uninstalled
|
// check whether the breakpoint needs to be uninstalled
|
||||||
bool uninstall = !breakpoint->ShouldBeInstalled()
|
bool uninstall = !breakpoint->ShouldBeInstalled()
|
||||||
&& breakpoint->IsInstalled();
|
&& breakpoint->IsInstalled();
|
||||||
@ -233,3 +297,30 @@ BreakpointManager::UninstallTemporaryBreakpoint(target_addr_t address,
|
|||||||
breakpoint->SetInstalled(false);
|
breakpoint->SetInstalled(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
BreakpointManager::_UpdateBreakpointInstallation(Breakpoint* breakpoint)
|
||||||
|
{
|
||||||
|
bool shouldBeInstalled = breakpoint->ShouldBeInstalled();
|
||||||
|
printf("BreakpointManager::_UpdateBreakpointInstallation(%p): should be installed: %d, is installed: %d\n", breakpoint, shouldBeInstalled, breakpoint->IsInstalled());
|
||||||
|
if (shouldBeInstalled == breakpoint->IsInstalled())
|
||||||
|
return B_OK;
|
||||||
|
|
||||||
|
if (shouldBeInstalled) {
|
||||||
|
// install
|
||||||
|
status_t error = fDebuggerInterface->InstallBreakpoint(
|
||||||
|
breakpoint->Address());
|
||||||
|
if (error != B_OK)
|
||||||
|
return error;
|
||||||
|
printf("BREAKPOINT at %#llx installed: %s\n", breakpoint->Address(), strerror(error));
|
||||||
|
breakpoint->SetInstalled(true);
|
||||||
|
} else {
|
||||||
|
// uninstall
|
||||||
|
fDebuggerInterface->UninstallBreakpoint(breakpoint->Address());
|
||||||
|
printf("BREAKPOINT at %#llx uninstalled\n", breakpoint->Address());
|
||||||
|
breakpoint->SetInstalled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
@ -22,9 +22,15 @@ public:
|
|||||||
|
|
||||||
status_t Init();
|
status_t Init();
|
||||||
|
|
||||||
status_t InstallUserBreakpoint(target_addr_t address,
|
// status_t InstallUserBreakpoint(target_addr_t address,
|
||||||
|
// bool enabled);
|
||||||
|
// void UninstallUserBreakpoint(target_addr_t address);
|
||||||
|
|
||||||
|
status_t InstallUserBreakpoint(
|
||||||
|
UserBreakpoint* userBreakpoint,
|
||||||
bool enabled);
|
bool enabled);
|
||||||
void UninstallUserBreakpoint(target_addr_t address);
|
void UninstallUserBreakpoint(
|
||||||
|
UserBreakpoint* userBreakpoint);
|
||||||
|
|
||||||
status_t InstallTemporaryBreakpoint(
|
status_t InstallTemporaryBreakpoint(
|
||||||
target_addr_t address,
|
target_addr_t address,
|
||||||
@ -33,6 +39,11 @@ public:
|
|||||||
target_addr_t address,
|
target_addr_t address,
|
||||||
BreakpointClient* client);
|
BreakpointClient* client);
|
||||||
|
|
||||||
|
private:
|
||||||
|
status_t _UpdateBreakpointInstallation(
|
||||||
|
Breakpoint* breakpoint);
|
||||||
|
// fLock must be held
|
||||||
|
|
||||||
private:
|
private:
|
||||||
BLocker fLock; // used to synchronize un-/installing
|
BLocker fLock; // used to synchronize un-/installing
|
||||||
TeamDebugModel* fDebugModel;
|
TeamDebugModel* fDebugModel;
|
||||||
|
@ -56,7 +56,9 @@ Application Debugger :
|
|||||||
DwarfFunctionDebugInfo.cpp
|
DwarfFunctionDebugInfo.cpp
|
||||||
DwarfImageDebugInfo.cpp
|
DwarfImageDebugInfo.cpp
|
||||||
DwarfTeamDebugInfo.cpp
|
DwarfTeamDebugInfo.cpp
|
||||||
|
Function.cpp
|
||||||
FunctionDebugInfo.cpp
|
FunctionDebugInfo.cpp
|
||||||
|
FunctionInstance.cpp
|
||||||
ImageDebugInfo.cpp
|
ImageDebugInfo.cpp
|
||||||
ImageDebugInfoProvider.cpp
|
ImageDebugInfoProvider.cpp
|
||||||
SpecificImageDebugInfo.cpp
|
SpecificImageDebugInfo.cpp
|
||||||
@ -97,6 +99,7 @@ Application Debugger :
|
|||||||
StackTrace.cpp
|
StackTrace.cpp
|
||||||
Statement.cpp
|
Statement.cpp
|
||||||
SymbolInfo.cpp
|
SymbolInfo.cpp
|
||||||
|
UserBreakpoint.cpp
|
||||||
Team.cpp
|
Team.cpp
|
||||||
TeamDebugModel.cpp
|
TeamDebugModel.cpp
|
||||||
TeamMemory.cpp
|
TeamMemory.cpp
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
#include "Architecture.h"
|
#include "Architecture.h"
|
||||||
#include "CpuState.h"
|
#include "CpuState.h"
|
||||||
#include "DebuggerInterface.h"
|
#include "DebuggerInterface.h"
|
||||||
#include "FunctionDebugInfo.h"
|
#include "Function.h"
|
||||||
#include "Image.h"
|
#include "Image.h"
|
||||||
#include "ImageDebugInfo.h"
|
#include "ImageDebugInfo.h"
|
||||||
#include "SourceCode.h"
|
#include "SourceCode.h"
|
||||||
@ -258,7 +258,7 @@ LoadImageDebugInfoJob::Do()
|
|||||||
// set the result
|
// set the result
|
||||||
locker.Lock();
|
locker.Lock();
|
||||||
if (error == B_OK) {
|
if (error == B_OK) {
|
||||||
fImage->SetImageDebugInfo(debugInfo, IMAGE_DEBUG_INFO_LOADED);
|
error = fImage->SetImageDebugInfo(debugInfo, IMAGE_DEBUG_INFO_LOADED);
|
||||||
debugInfo->RemoveReference();
|
debugInfo->RemoveReference();
|
||||||
} else {
|
} else {
|
||||||
fImage->SetImageDebugInfo(NULL, IMAGE_DEBUG_INFO_UNAVAILABLE);
|
fImage->SetImageDebugInfo(NULL, IMAGE_DEBUG_INFO_UNAVAILABLE);
|
||||||
@ -319,7 +319,7 @@ LoadImageDebugInfoJob::ScheduleIfNecessary(Worker* worker, Image* image,
|
|||||||
|
|
||||||
LoadSourceCodeJob::LoadSourceCodeJob(
|
LoadSourceCodeJob::LoadSourceCodeJob(
|
||||||
DebuggerInterface* debuggerInterface, Architecture* architecture,
|
DebuggerInterface* debuggerInterface, Architecture* architecture,
|
||||||
Team* team, FunctionDebugInfo* function)
|
Team* team, Function* function)
|
||||||
:
|
:
|
||||||
fDebuggerInterface(debuggerInterface),
|
fDebuggerInterface(debuggerInterface),
|
||||||
fArchitecture(architecture),
|
fArchitecture(architecture),
|
||||||
@ -346,13 +346,29 @@ LoadSourceCodeJob::Key() const
|
|||||||
status_t
|
status_t
|
||||||
LoadSourceCodeJob::Do()
|
LoadSourceCodeJob::Do()
|
||||||
{
|
{
|
||||||
|
// Get the function debug info for an instance which we can use to load the
|
||||||
|
// source code.
|
||||||
|
AutoLocker<Team> locker(fTeam);
|
||||||
|
|
||||||
|
status_t error = B_OK;
|
||||||
|
FunctionDebugInfo* functionDebugInfo = NULL;
|
||||||
|
if (FunctionInstance* instance = fFunction->FirstInstance()) {
|
||||||
|
functionDebugInfo = instance->GetFunctionDebugInfo();
|
||||||
|
} else
|
||||||
|
error = B_ENTRY_NOT_FOUND;
|
||||||
|
Reference<FunctionDebugInfo> functionDebugInfoReference(functionDebugInfo);
|
||||||
|
|
||||||
|
locker.Unlock();
|
||||||
|
|
||||||
// load the source code, if we can
|
// load the source code, if we can
|
||||||
SourceCode* sourceCode = NULL;
|
SourceCode* sourceCode = NULL;
|
||||||
status_t error = fFunction->GetSpecificImageDebugInfo()->LoadSourceCode(
|
if (error == B_OK) {
|
||||||
fFunction, sourceCode);
|
error = functionDebugInfo->GetSpecificImageDebugInfo()->LoadSourceCode(
|
||||||
|
functionDebugInfo, sourceCode);
|
||||||
|
}
|
||||||
|
|
||||||
// set the result
|
// set the result
|
||||||
AutoLocker<Team> locker(fTeam);
|
locker.Lock();
|
||||||
if (error == B_OK) {
|
if (error == B_OK) {
|
||||||
fFunction->SetSourceCode(sourceCode, FUNCTION_SOURCE_LOADED);
|
fFunction->SetSourceCode(sourceCode, FUNCTION_SOURCE_LOADED);
|
||||||
sourceCode->RemoveReference();
|
sourceCode->RemoveReference();
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
class Architecture;
|
class Architecture;
|
||||||
class CpuState;
|
class CpuState;
|
||||||
class DebuggerInterface;
|
class DebuggerInterface;
|
||||||
class FunctionDebugInfo;
|
class Function;
|
||||||
class Image;
|
class Image;
|
||||||
class StackFrame;
|
class StackFrame;
|
||||||
class Team;
|
class Team;
|
||||||
@ -112,8 +112,8 @@ class LoadSourceCodeJob : public Job {
|
|||||||
public:
|
public:
|
||||||
LoadSourceCodeJob(
|
LoadSourceCodeJob(
|
||||||
DebuggerInterface* debuggerInterface,
|
DebuggerInterface* debuggerInterface,
|
||||||
Architecture* architecture,
|
Architecture* architecture, Team* team,
|
||||||
Team* team, FunctionDebugInfo* function);
|
Function* function);
|
||||||
virtual ~LoadSourceCodeJob();
|
virtual ~LoadSourceCodeJob();
|
||||||
|
|
||||||
virtual JobKey Key() const;
|
virtual JobKey Key() const;
|
||||||
@ -123,7 +123,7 @@ private:
|
|||||||
DebuggerInterface* fDebuggerInterface;
|
DebuggerInterface* fDebuggerInterface;
|
||||||
Architecture* fArchitecture;
|
Architecture* fArchitecture;
|
||||||
Team* fTeam;
|
Team* fTeam;
|
||||||
FunctionDebugInfo* fFunction;
|
Function* fFunction;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -21,11 +21,15 @@
|
|||||||
#include "CpuState.h"
|
#include "CpuState.h"
|
||||||
#include "DebuggerInterface.h"
|
#include "DebuggerInterface.h"
|
||||||
#include "FileManager.h"
|
#include "FileManager.h"
|
||||||
|
#include "Function.h"
|
||||||
|
#include "ImageDebugInfo.h"
|
||||||
#include "Jobs.h"
|
#include "Jobs.h"
|
||||||
#include "LocatableFile.h"
|
#include "LocatableFile.h"
|
||||||
#include "MessageCodes.h"
|
#include "MessageCodes.h"
|
||||||
#include "SymbolInfo.h"
|
#include "SourceCode.h"
|
||||||
|
#include "SpecificImageDebugInfo.h"
|
||||||
#include "Statement.h"
|
#include "Statement.h"
|
||||||
|
#include "SymbolInfo.h"
|
||||||
#include "TeamDebugInfo.h"
|
#include "TeamDebugInfo.h"
|
||||||
#include "TeamDebugModel.h"
|
#include "TeamDebugModel.h"
|
||||||
|
|
||||||
@ -479,8 +483,10 @@ TeamDebugger::MessageReceived(BMessage* message)
|
|||||||
|
|
||||||
void
|
void
|
||||||
TeamDebugger::FunctionSourceCodeRequested(TeamWindow* window,
|
TeamDebugger::FunctionSourceCodeRequested(TeamWindow* window,
|
||||||
FunctionDebugInfo* function)
|
FunctionInstance* functionInstance)
|
||||||
{
|
{
|
||||||
|
Function* function = functionInstance->GetFunction();
|
||||||
|
|
||||||
// mark loading
|
// mark loading
|
||||||
AutoLocker< ::Team> locker(fTeam);
|
AutoLocker< ::Team> locker(fTeam);
|
||||||
if (function->SourceCodeState() != FUNCTION_SOURCE_NOT_LOADED)
|
if (function->SourceCodeState() != FUNCTION_SOURCE_NOT_LOADED)
|
||||||
@ -821,6 +827,8 @@ TeamDebugger::_HandleImageDeleted(ImageDeletedEvent* event)
|
|||||||
imageHandler->ReleaseReference();
|
imageHandler->ReleaseReference();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Remove breakpoints in the image!
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -837,7 +845,114 @@ void
|
|||||||
TeamDebugger::_HandleSetUserBreakpoint(target_addr_t address, bool enabled)
|
TeamDebugger::_HandleSetUserBreakpoint(target_addr_t address, bool enabled)
|
||||||
{
|
{
|
||||||
printf("TeamDebugger::_HandleSetUserBreakpoint(%#llx, %d)\n", address, enabled);
|
printf("TeamDebugger::_HandleSetUserBreakpoint(%#llx, %d)\n", address, enabled);
|
||||||
status_t error = fBreakpointManager->InstallUserBreakpoint(address,
|
// check whether there already is a breakpoint
|
||||||
|
AutoLocker< ::Team> locker(fTeam);
|
||||||
|
|
||||||
|
Breakpoint* breakpoint = fDebugModel->BreakpointAtAddress(address);
|
||||||
|
UserBreakpoint* userBreakpoint = NULL;
|
||||||
|
if (breakpoint != NULL && breakpoint->FirstUserBreakpoint() != NULL)
|
||||||
|
userBreakpoint = breakpoint->FirstUserBreakpoint()->GetUserBreakpoint();
|
||||||
|
Reference<UserBreakpoint> userBreakpointReference(userBreakpoint);
|
||||||
|
|
||||||
|
if (userBreakpoint == NULL) {
|
||||||
|
printf(" no breakpoint yet\n");
|
||||||
|
// get the function at the address
|
||||||
|
Image* image = fTeam->ImageByAddress(address);
|
||||||
|
printf(" image: %p\n", image);
|
||||||
|
if (image == NULL)
|
||||||
|
return;
|
||||||
|
ImageDebugInfo* imageDebugInfo = image->GetImageDebugInfo();
|
||||||
|
printf(" image debug info: %p\n", imageDebugInfo);
|
||||||
|
if (imageDebugInfo == NULL)
|
||||||
|
return;
|
||||||
|
// TODO: Handle this case by loading the debug info, if possible!
|
||||||
|
FunctionInstance* functionInstance
|
||||||
|
= imageDebugInfo->FunctionAtAddress(address);
|
||||||
|
printf(" function instance: %p\n", functionInstance);
|
||||||
|
if (functionInstance == NULL)
|
||||||
|
return;
|
||||||
|
Function* function = functionInstance->GetFunction();
|
||||||
|
printf(" function: %p\n", function);
|
||||||
|
|
||||||
|
// get the source location for the address
|
||||||
|
FunctionDebugInfo* functionDebugInfo
|
||||||
|
= functionInstance->GetFunctionDebugInfo();
|
||||||
|
SourceLocation sourceLocation;
|
||||||
|
Statement* breakpointStatement = NULL;
|
||||||
|
// if (SourceCode* sourceCode = functionDebugInfo->GetSourceCode()) {
|
||||||
|
// breakpointStatement = sourceCode->StatementAtAddress(address);
|
||||||
|
// if (breakpointStatement != NULL)
|
||||||
|
// sourceLocation = breakpointStatement->StartSourceLocation();
|
||||||
|
// }
|
||||||
|
|
||||||
|
if (breakpointStatement == NULL
|
||||||
|
&& functionDebugInfo->GetSpecificImageDebugInfo()->GetStatement(
|
||||||
|
functionDebugInfo, address, breakpointStatement) != B_OK) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceLocation = breakpointStatement->StartSourceLocation();
|
||||||
|
breakpointStatement->ReleaseReference();
|
||||||
|
|
||||||
|
target_addr_t relativeAddress = address - functionInstance->Address();
|
||||||
|
printf(" relative address: %#llx, source location: (%ld, %ld)\n", relativeAddress, sourceLocation.Line(), sourceLocation.Column());
|
||||||
|
|
||||||
|
// create the user breakpoint
|
||||||
|
userBreakpoint = new(std::nothrow) UserBreakpoint(function);
|
||||||
|
if (userBreakpoint == NULL)
|
||||||
|
return;
|
||||||
|
userBreakpointReference.SetTo(userBreakpoint, true);
|
||||||
|
printf(" created user breakpoint: %p\n", userBreakpoint);
|
||||||
|
|
||||||
|
// iterate through all function instances and create
|
||||||
|
// UserBreakpointInstances
|
||||||
|
for (FunctionInstanceList::ConstIterator it
|
||||||
|
= function->Instances().GetIterator();
|
||||||
|
FunctionInstance* instance = it.Next();) {
|
||||||
|
printf(" function instance %p: range: %#llx - %#llx\n", instance, instance->Address(), instance->Address() + instance->Size());
|
||||||
|
// get the breakpoint address for the instance
|
||||||
|
target_addr_t instanceAddress = 0;
|
||||||
|
if (instance == functionInstance) {
|
||||||
|
instanceAddress = address;
|
||||||
|
} else if (functionInstance->SourceFile() != NULL) {
|
||||||
|
// We have a source file, so get the address for the source
|
||||||
|
// location.
|
||||||
|
Statement* statement = NULL;
|
||||||
|
functionDebugInfo = instance->GetFunctionDebugInfo();
|
||||||
|
functionDebugInfo->GetSpecificImageDebugInfo()
|
||||||
|
->GetStatementForSourceLocation(functionDebugInfo,
|
||||||
|
sourceLocation, statement);
|
||||||
|
if (statement != NULL) {
|
||||||
|
instanceAddress = statement->CoveringAddressRange().Start();
|
||||||
|
// TODO: What about BreakpointAllowed()?
|
||||||
|
statement->ReleaseReference();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf(" breakpoint address using source info: %llx\n", instanceAddress);
|
||||||
|
|
||||||
|
if (instanceAddress == 0) {
|
||||||
|
// No source file (or we failed getting the statement), so try
|
||||||
|
// to use the same relative address.
|
||||||
|
if (relativeAddress > instance->Size())
|
||||||
|
continue;
|
||||||
|
instanceAddress = instance->Address() + relativeAddress;
|
||||||
|
}
|
||||||
|
printf(" final breakpoint address: %llx\n", instanceAddress);
|
||||||
|
|
||||||
|
UserBreakpointInstance* breakpointInstance = new(std::nothrow)
|
||||||
|
UserBreakpointInstance(userBreakpoint, instanceAddress);
|
||||||
|
if (breakpointInstance == NULL
|
||||||
|
|| !userBreakpoint->AddInstance(breakpointInstance)) {
|
||||||
|
delete breakpointInstance;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
printf(" breakpoint instance: %p\n", breakpointInstance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
locker.Unlock();
|
||||||
|
|
||||||
|
status_t error = fBreakpointManager->InstallUserBreakpoint(userBreakpoint,
|
||||||
enabled);
|
enabled);
|
||||||
if (error != B_OK) {
|
if (error != B_OK) {
|
||||||
_NotifyUser("Install Breakpoint", "Failed to install breakpoint: %s",
|
_NotifyUser("Install Breakpoint", "Failed to install breakpoint: %s",
|
||||||
@ -850,7 +965,19 @@ void
|
|||||||
TeamDebugger::_HandleClearUserBreakpoint(target_addr_t address)
|
TeamDebugger::_HandleClearUserBreakpoint(target_addr_t address)
|
||||||
{
|
{
|
||||||
printf("TeamDebugger::_HandleClearUserBreakpoint(%#llx)\n", address);
|
printf("TeamDebugger::_HandleClearUserBreakpoint(%#llx)\n", address);
|
||||||
fBreakpointManager->UninstallUserBreakpoint(address);
|
|
||||||
|
AutoLocker< ::Team> locker(fTeam);
|
||||||
|
|
||||||
|
Breakpoint* breakpoint = fDebugModel->BreakpointAtAddress(address);
|
||||||
|
if (breakpoint == NULL || breakpoint->FirstUserBreakpoint() == NULL)
|
||||||
|
return;
|
||||||
|
UserBreakpoint* userBreakpoint
|
||||||
|
= breakpoint->FirstUserBreakpoint()->GetUserBreakpoint();
|
||||||
|
Reference<UserBreakpoint> userBreakpointReference(userBreakpoint);
|
||||||
|
|
||||||
|
locker.Unlock();
|
||||||
|
|
||||||
|
fBreakpointManager->UninstallUserBreakpoint(userBreakpoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
// TeamWindow::Listener
|
// TeamWindow::Listener
|
||||||
virtual void FunctionSourceCodeRequested(TeamWindow* window,
|
virtual void FunctionSourceCodeRequested(TeamWindow* window,
|
||||||
FunctionDebugInfo* function);
|
FunctionInstance* function);
|
||||||
virtual void ImageDebugInfoRequested(TeamWindow* window,
|
virtual void ImageDebugInfoRequested(TeamWindow* window,
|
||||||
Image* image);
|
Image* image);
|
||||||
virtual void ThreadActionRequested(TeamWindow* window,
|
virtual void ThreadActionRequested(TeamWindow* window,
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
#include "BreakpointManager.h"
|
#include "BreakpointManager.h"
|
||||||
#include "CpuState.h"
|
#include "CpuState.h"
|
||||||
#include "DebuggerInterface.h"
|
#include "DebuggerInterface.h"
|
||||||
#include "FunctionDebugInfo.h"
|
#include "FunctionInstance.h"
|
||||||
#include "ImageDebugInfo.h"
|
#include "ImageDebugInfo.h"
|
||||||
#include "InstructionInfo.h"
|
#include "InstructionInfo.h"
|
||||||
#include "Jobs.h"
|
#include "Jobs.h"
|
||||||
@ -126,7 +126,7 @@ ThreadHandler::HandleBreakpointHit(BreakpointHitEvent* event)
|
|||||||
// spurious breakpoint -- might be a temporary breakpoint, that has
|
// spurious breakpoint -- might be a temporary breakpoint, that has
|
||||||
// already been uninstalled
|
// already been uninstalled
|
||||||
continueThread = true;
|
continueThread = true;
|
||||||
} else if (breakpoint->UserState() != USER_BREAKPOINT_ENABLED) {
|
} else if (breakpoint->HasEnabledUserBreakpoint()) {
|
||||||
// breakpoint of another thread or one that has been disabled in
|
// breakpoint of another thread or one that has been disabled in
|
||||||
// the meantime
|
// the meantime
|
||||||
continueThread = true;
|
continueThread = true;
|
||||||
@ -382,20 +382,21 @@ ThreadHandler::_GetStatementAtInstructionPointer(StackFrame* frame)
|
|||||||
{
|
{
|
||||||
AutoLocker<TeamDebugModel> locker(fDebugModel);
|
AutoLocker<TeamDebugModel> locker(fDebugModel);
|
||||||
|
|
||||||
FunctionDebugInfo* function = frame->Function();
|
FunctionInstance* functionInstance = frame->Function();
|
||||||
if (function == NULL)
|
if (functionInstance == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
FunctionDebugInfo* function = functionInstance->GetFunctionDebugInfo();
|
||||||
|
|
||||||
// If there's source code attached to the function, we can just get the
|
// If there's source code attached to the function, we can just get the
|
||||||
// statement.
|
// statement.
|
||||||
SourceCode* sourceCode = function->GetSourceCode();
|
// SourceCode* sourceCode = function->GetSourceCode();
|
||||||
if (sourceCode != NULL) {
|
// if (sourceCode != NULL) {
|
||||||
Statement* statement = sourceCode->StatementAtAddress(
|
// Statement* statement = sourceCode->StatementAtAddress(
|
||||||
frame->InstructionPointer());
|
// frame->InstructionPointer());
|
||||||
if (statement != NULL)
|
// if (statement != NULL)
|
||||||
statement->AddReference();
|
// statement->AddReference();
|
||||||
return statement;
|
// return statement;
|
||||||
}
|
// }
|
||||||
|
|
||||||
locker.Unlock();
|
locker.Unlock();
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
#include <AutoLocker.h>
|
#include <AutoLocker.h>
|
||||||
|
|
||||||
#include "CpuState.h"
|
#include "CpuState.h"
|
||||||
#include "FunctionDebugInfo.h"
|
#include "FunctionInstance.h"
|
||||||
#include "Image.h"
|
#include "Image.h"
|
||||||
#include "ImageDebugInfo.h"
|
#include "ImageDebugInfo.h"
|
||||||
#include "ImageDebugInfoProvider.h"
|
#include "ImageDebugInfoProvider.h"
|
||||||
@ -75,31 +75,38 @@ Architecture::CreateStackTrace(Team* team,
|
|||||||
|
|
||||||
// get the function
|
// get the function
|
||||||
teamLocker.Lock();
|
teamLocker.Lock();
|
||||||
FunctionDebugInfo* function = NULL;
|
FunctionInstance* function = NULL;
|
||||||
if (imageDebugInfo != NULL)
|
FunctionDebugInfo* functionDebugInfo = NULL;
|
||||||
|
if (imageDebugInfo != NULL) {
|
||||||
function = imageDebugInfo->FunctionAtAddress(instructionPointer);
|
function = imageDebugInfo->FunctionAtAddress(instructionPointer);
|
||||||
Reference<FunctionDebugInfo> functionReference(function);
|
if (function != NULL)
|
||||||
|
functionDebugInfo = function->GetFunctionDebugInfo();
|
||||||
|
}
|
||||||
|
Reference<FunctionInstance> functionReference(function);
|
||||||
teamLocker.Unlock();
|
teamLocker.Unlock();
|
||||||
|
|
||||||
// If the last frame had been created by the architecture, we update the
|
// If the last frame had been created by the architecture, we update the
|
||||||
// CPU state.
|
// CPU state.
|
||||||
if (architectureFrame)
|
if (architectureFrame) {
|
||||||
UpdateStackFrameCpuState(frame, image, function, cpuState);
|
UpdateStackFrameCpuState(frame, image,
|
||||||
|
functionDebugInfo, cpuState);
|
||||||
|
}
|
||||||
|
|
||||||
// create the frame using the debug info
|
// create the frame using the debug info
|
||||||
StackFrame* previousFrame = NULL;
|
StackFrame* previousFrame = NULL;
|
||||||
CpuState* previousCpuState = NULL;
|
CpuState* previousCpuState = NULL;
|
||||||
if (function != NULL) {
|
if (function != NULL) {
|
||||||
status_t error = function->GetSpecificImageDebugInfo()->CreateFrame(
|
status_t error = functionDebugInfo->GetSpecificImageDebugInfo()
|
||||||
image, function, cpuState, previousFrame, previousCpuState);
|
->CreateFrame(image, functionDebugInfo, cpuState, previousFrame,
|
||||||
|
previousCpuState);
|
||||||
if (error != B_OK && error != B_UNSUPPORTED)
|
if (error != B_OK && error != B_UNSUPPORTED)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we have no frame yet, let the architecture create it.
|
// If we have no frame yet, let the architecture create it.
|
||||||
if (previousFrame == NULL) {
|
if (previousFrame == NULL) {
|
||||||
status_t error = CreateStackFrame(image, function, cpuState,
|
status_t error = CreateStackFrame(image, functionDebugInfo,
|
||||||
frame == NULL, previousFrame, previousCpuState);
|
cpuState, frame == NULL, previousFrame, previousCpuState);
|
||||||
if (error != B_OK)
|
if (error != B_OK)
|
||||||
break;
|
break;
|
||||||
architectureFrame = true;
|
architectureFrame = true;
|
||||||
|
@ -296,8 +296,9 @@ ArchitectureX86::DisassembleCode(FunctionDebugInfo* function,
|
|||||||
bool breakpointAllowed;
|
bool breakpointAllowed;
|
||||||
while (disassembler.GetNextInstruction(line, instructionAddress,
|
while (disassembler.GetNextInstruction(line, instructionAddress,
|
||||||
instructionSize, breakpointAllowed) == B_OK) {
|
instructionSize, breakpointAllowed) == B_OK) {
|
||||||
|
// TODO: Respect breakpointAllowed!
|
||||||
if (!source->AddInstructionLine(line, instructionAddress,
|
if (!source->AddInstructionLine(line, instructionAddress,
|
||||||
instructionSize, breakpointAllowed)) {
|
instructionSize)) {
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -320,9 +321,7 @@ ArchitectureX86::GetStatement(FunctionDebugInfo* function,
|
|||||||
|
|
||||||
// create a statement
|
// create a statement
|
||||||
ContiguousStatement* statement = new(std::nothrow) ContiguousStatement(
|
ContiguousStatement* statement = new(std::nothrow) ContiguousStatement(
|
||||||
SourceLocation(0), SourceLocation(1),
|
SourceLocation(0), TargetAddressRange(info.Address(), info.Size()));
|
||||||
TargetAddressRange(info.Address(), info.Size()),
|
|
||||||
info.IsBreakpointAllowed());
|
|
||||||
if (statement == NULL)
|
if (statement == NULL)
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
@ -49,17 +49,17 @@ BasicFunctionDebugInfo::Size() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const char*
|
const BString&
|
||||||
BasicFunctionDebugInfo::Name() const
|
BasicFunctionDebugInfo::Name() const
|
||||||
{
|
{
|
||||||
return fName.String();
|
return fName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const char*
|
const BString&
|
||||||
BasicFunctionDebugInfo::PrettyName() const
|
BasicFunctionDebugInfo::PrettyName() const
|
||||||
{
|
{
|
||||||
return fPrettyName.String();
|
return fPrettyName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -23,8 +23,8 @@ public:
|
|||||||
virtual SpecificImageDebugInfo* GetSpecificImageDebugInfo() const;
|
virtual SpecificImageDebugInfo* GetSpecificImageDebugInfo() const;
|
||||||
virtual target_addr_t Address() const;
|
virtual target_addr_t Address() const;
|
||||||
virtual target_size_t Size() const;
|
virtual target_size_t Size() const;
|
||||||
virtual const char* Name() const;
|
virtual const BString& Name() const;
|
||||||
virtual const char* PrettyName() const;
|
virtual const BString& PrettyName() const;
|
||||||
|
|
||||||
virtual LocatableFile* SourceFile() const;
|
virtual LocatableFile* SourceFile() const;
|
||||||
virtual SourceLocation SourceStartLocation() const;
|
virtual SourceLocation SourceStartLocation() const;
|
||||||
|
@ -118,6 +118,15 @@ DebuggerImageDebugInfo::GetStatement(FunctionDebugInfo* function,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
DebuggerImageDebugInfo::GetStatementForSourceLocation(
|
||||||
|
FunctionDebugInfo* function, const SourceLocation& sourceLocation,
|
||||||
|
Statement*& _statement)
|
||||||
|
{
|
||||||
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*static*/ int
|
/*static*/ int
|
||||||
DebuggerImageDebugInfo::_CompareSymbols(const SymbolInfo* a,
|
DebuggerImageDebugInfo::_CompareSymbols(const SymbolInfo* a,
|
||||||
const SymbolInfo* b)
|
const SymbolInfo* b)
|
||||||
|
@ -36,6 +36,10 @@ public:
|
|||||||
virtual status_t GetStatement(FunctionDebugInfo* function,
|
virtual status_t GetStatement(FunctionDebugInfo* function,
|
||||||
target_addr_t address,
|
target_addr_t address,
|
||||||
Statement*& _statement);
|
Statement*& _statement);
|
||||||
|
virtual status_t GetStatementForSourceLocation(
|
||||||
|
FunctionDebugInfo* function,
|
||||||
|
const SourceLocation& sourceLocation,
|
||||||
|
Statement*& _statement);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static int _CompareSymbols(const SymbolInfo* a,
|
static int _CompareSymbols(const SymbolInfo* a,
|
||||||
|
@ -63,17 +63,17 @@ DwarfFunctionDebugInfo::Size() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const char*
|
const BString&
|
||||||
DwarfFunctionDebugInfo::Name() const
|
DwarfFunctionDebugInfo::Name() const
|
||||||
{
|
{
|
||||||
return fName.String();
|
return fName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const char*
|
const BString&
|
||||||
DwarfFunctionDebugInfo::PrettyName() const
|
DwarfFunctionDebugInfo::PrettyName() const
|
||||||
{
|
{
|
||||||
return fName.String();
|
return fName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -32,8 +32,8 @@ public:
|
|||||||
virtual SpecificImageDebugInfo* GetSpecificImageDebugInfo() const;
|
virtual SpecificImageDebugInfo* GetSpecificImageDebugInfo() const;
|
||||||
virtual target_addr_t Address() const;
|
virtual target_addr_t Address() const;
|
||||||
virtual target_size_t Size() const;
|
virtual target_size_t Size() const;
|
||||||
virtual const char* Name() const;
|
virtual const BString& Name() const;
|
||||||
virtual const char* PrettyName() const;
|
virtual const BString& PrettyName() const;
|
||||||
|
|
||||||
virtual LocatableFile* SourceFile() const;
|
virtual LocatableFile* SourceFile() const;
|
||||||
virtual SourceLocation SourceStartLocation() const;
|
virtual SourceLocation SourceStartLocation() const;
|
||||||
|
@ -320,11 +320,179 @@ DwarfImageDebugInfo::LoadSourceCode(FunctionDebugInfo* function,
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
DwarfImageDebugInfo::GetStatement(FunctionDebugInfo* function,
|
DwarfImageDebugInfo::GetStatement(FunctionDebugInfo* _function,
|
||||||
target_addr_t address, Statement*& _statement)
|
target_addr_t address, Statement*& _statement)
|
||||||
{
|
{
|
||||||
// TODO:...
|
DwarfFunctionDebugInfo* function
|
||||||
return fArchitecture->GetStatement(function, address, _statement);
|
= dynamic_cast<DwarfFunctionDebugInfo*>(_function);
|
||||||
|
if (function == NULL)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
AutoLocker<BLocker> locker(fLock);
|
||||||
|
|
||||||
|
// get the source file
|
||||||
|
LocatableFile* file = function->SourceFile();
|
||||||
|
if (file == NULL)
|
||||||
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
|
||||||
|
// maybe the source code is already loaded -- this will simplify things
|
||||||
|
CompilationUnit* unit = function->GetCompilationUnit();
|
||||||
|
// FileSourceCode* sourceCode = _LookupSourceCode(unit, file);
|
||||||
|
// if (sourceCode) {
|
||||||
|
// Statement* statement = sourceCode->StatementAtAddress(address);
|
||||||
|
// if (statement == NULL)
|
||||||
|
// return B_ENTRY_NOT_FOUND;
|
||||||
|
//
|
||||||
|
// statement->AcquireReference();
|
||||||
|
// _statement = statement;
|
||||||
|
// return B_OK;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// get the index of the source file in the compilation unit for cheaper
|
||||||
|
// comparison below
|
||||||
|
int32 fileIndex = _GetSourceFileIndex(unit, file);
|
||||||
|
|
||||||
|
// Get the statement by executing the line number program for the
|
||||||
|
// compilation unit.
|
||||||
|
LineNumberProgram& program = unit->GetLineNumberProgram();
|
||||||
|
if (!program.IsValid())
|
||||||
|
return B_BAD_DATA;
|
||||||
|
|
||||||
|
LineNumberProgram::State state;
|
||||||
|
program.GetInitialState(state);
|
||||||
|
|
||||||
|
target_addr_t statementAddress = 0;
|
||||||
|
int32 statementLine = -1;
|
||||||
|
int32 statementColumn = -1;
|
||||||
|
while (program.GetNextRow(state)) {
|
||||||
|
bool isOurFile = state.file == fileIndex;
|
||||||
|
|
||||||
|
if (statementAddress != 0
|
||||||
|
&& (!isOurFile || state.isStatement || state.isSequenceEnd)) {
|
||||||
|
target_addr_t endAddress = state.address;
|
||||||
|
if (address >= statementAddress && address < endAddress) {
|
||||||
|
ContiguousStatement* statement = new(std::nothrow)
|
||||||
|
ContiguousStatement(
|
||||||
|
SourceLocation(statementLine, statementColumn),
|
||||||
|
TargetAddressRange(fRelocationDelta + statementAddress,
|
||||||
|
endAddress - statementAddress));
|
||||||
|
if (statement == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
_statement = statement;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
statementAddress = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// skip statements of other files
|
||||||
|
if (!isOurFile)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (state.isStatement) {
|
||||||
|
statementAddress = state.address;
|
||||||
|
statementLine = state.line - 1;
|
||||||
|
statementColumn = state.column - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
DwarfImageDebugInfo::GetStatementForSourceLocation(FunctionDebugInfo* _function,
|
||||||
|
const SourceLocation& sourceLocation, Statement*& _statement)
|
||||||
|
{
|
||||||
|
DwarfFunctionDebugInfo* function
|
||||||
|
= dynamic_cast<DwarfFunctionDebugInfo*>(_function);
|
||||||
|
if (function == NULL)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
target_addr_t functionStartAddress = function->Address();
|
||||||
|
target_addr_t functionEndAddress = functionStartAddress + function->Size();
|
||||||
|
printf("DwarfImageDebugInfo::GetStatementForSourceLocation(%p): function range: %#llx - %#llx\n",
|
||||||
|
function, functionStartAddress, functionEndAddress);
|
||||||
|
|
||||||
|
AutoLocker<BLocker> locker(fLock);
|
||||||
|
|
||||||
|
// get the source file
|
||||||
|
LocatableFile* file = function->SourceFile();
|
||||||
|
if (file == NULL)
|
||||||
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
|
||||||
|
// maybe the source code is already loaded -- this will simplify things
|
||||||
|
CompilationUnit* unit = function->GetCompilationUnit();
|
||||||
|
FileSourceCode* sourceCode = _LookupSourceCode(unit, file);
|
||||||
|
if (sourceCode) {
|
||||||
|
// TODO: This is not precise enough -- columns are ignored!
|
||||||
|
Statement* statement = sourceCode->StatementAtLine(
|
||||||
|
sourceLocation.Line());
|
||||||
|
if (statement == NULL)
|
||||||
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
|
||||||
|
statement->AcquireReference();
|
||||||
|
_statement = statement;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the index of the source file in the compilation unit for cheaper
|
||||||
|
// comparison below
|
||||||
|
int32 fileIndex = _GetSourceFileIndex(unit, file);
|
||||||
|
|
||||||
|
// target_addr_t functionStartAddress = function->Address();
|
||||||
|
// target_addr_t functionEndAddress = functionStartAddress + function->Size();
|
||||||
|
|
||||||
|
// Get the statement by executing the line number program for the
|
||||||
|
// compilation unit.
|
||||||
|
LineNumberProgram& program = unit->GetLineNumberProgram();
|
||||||
|
if (!program.IsValid())
|
||||||
|
return B_BAD_DATA;
|
||||||
|
|
||||||
|
LineNumberProgram::State state;
|
||||||
|
program.GetInitialState(state);
|
||||||
|
|
||||||
|
target_addr_t statementAddress = 0;
|
||||||
|
int32 statementLine = -1;
|
||||||
|
int32 statementColumn = -1;
|
||||||
|
while (program.GetNextRow(state)) {
|
||||||
|
bool isOurFile = state.file == fileIndex;
|
||||||
|
|
||||||
|
if (statementAddress != 0
|
||||||
|
&& (!isOurFile || state.isStatement || state.isSequenceEnd)) {
|
||||||
|
target_addr_t endAddress = state.address;
|
||||||
|
if (statementAddress < endAddress
|
||||||
|
&& statementAddress >= functionStartAddress
|
||||||
|
&& statementAddress < functionEndAddress
|
||||||
|
&& statementLine == (int32)sourceLocation.Line()
|
||||||
|
&& statementColumn == (int32)sourceLocation.Column()) {
|
||||||
|
ContiguousStatement* statement = new(std::nothrow)
|
||||||
|
ContiguousStatement(
|
||||||
|
SourceLocation(statementLine, statementColumn),
|
||||||
|
TargetAddressRange(fRelocationDelta + statementAddress,
|
||||||
|
endAddress - statementAddress));
|
||||||
|
if (statement == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
_statement = statement;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
statementAddress = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// skip statements of other files
|
||||||
|
if (!isOurFile)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (state.isStatement) {
|
||||||
|
statementAddress = state.address;
|
||||||
|
statementLine = state.line - 1;
|
||||||
|
statementColumn = state.column - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_ENTRY_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -353,26 +521,13 @@ DwarfImageDebugInfo::_LoadSourceCode(FunctionDebugInfo* _function,
|
|||||||
|
|
||||||
// get the index of the source file in the compilation unit for cheaper
|
// get the index of the source file in the compilation unit for cheaper
|
||||||
// comparison below
|
// comparison below
|
||||||
const char* directory;
|
int32 fileIndex = _GetSourceFileIndex(unit, function->SourceFile());
|
||||||
int32 fileIndex = -1;
|
|
||||||
for (int32 i = 0; const char* fileName = unit->FileAt(i, &directory); i++) {
|
|
||||||
LocatableFile* file = fFileManager->GetSourceFile(directory, fileName);
|
|
||||||
if (file != NULL) {
|
|
||||||
file->ReleaseReference();
|
|
||||||
if (file == function->SourceFile()) {
|
|
||||||
fileIndex = i + 1;
|
|
||||||
// indices are one-based
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
printf("DwarfImageDebugInfo::_LoadSourceCode(), file: %ld, function at: %#llx\n", fileIndex, function->Address());
|
printf("DwarfImageDebugInfo::_LoadSourceCode(), file: %ld, function at: %#llx\n", fileIndex, function->Address());
|
||||||
|
|
||||||
for (int32 i = 0; const char* fileName = unit->FileAt(i, &directory); i++) {
|
for (int32 i = 0; const char* fileName = unit->FileAt(i, NULL); i++) {
|
||||||
printf(" file %ld: %s\n", i, fileName);
|
printf(" file %ld: %s\n", i, fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// not loaded yet -- get the source file
|
// not loaded yet -- get the source file
|
||||||
SourceFile* sourceFile;
|
SourceFile* sourceFile;
|
||||||
status_t error = fFileManager->LoadSourceFile(file, sourceFile);
|
status_t error = fFileManager->LoadSourceFile(file, sourceFile);
|
||||||
@ -413,10 +568,9 @@ printf(" %#lx (%ld, %ld, %ld) %d\n", state.address, state.file, state.line, s
|
|||||||
// add the statement
|
// add the statement
|
||||||
ContiguousStatement* statement = new(std::nothrow)
|
ContiguousStatement* statement = new(std::nothrow)
|
||||||
ContiguousStatement(
|
ContiguousStatement(
|
||||||
SourceLocation(statementLine, statementColumn),
|
|
||||||
SourceLocation(statementLine, statementColumn),
|
SourceLocation(statementLine, statementColumn),
|
||||||
TargetAddressRange(fRelocationDelta + statementAddress,
|
TargetAddressRange(fRelocationDelta + statementAddress,
|
||||||
endAddress - statementAddress), true);
|
endAddress - statementAddress));
|
||||||
if (statement == NULL)
|
if (statement == NULL)
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
@ -463,3 +617,25 @@ DwarfImageDebugInfo::_LookupSourceCode(CompilationUnit* unit,
|
|||||||
SourceCodeEntry* entry = fSourceCodes->Lookup(SourceCodeKey(unit, file));
|
SourceCodeEntry* entry = fSourceCodes->Lookup(SourceCodeKey(unit, file));
|
||||||
return entry != NULL ? entry->sourceCode : NULL;
|
return entry != NULL ? entry->sourceCode : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int32
|
||||||
|
DwarfImageDebugInfo::_GetSourceFileIndex(CompilationUnit* unit,
|
||||||
|
LocatableFile* sourceFile) const
|
||||||
|
{
|
||||||
|
// get the index of the source file in the compilation unit for cheaper
|
||||||
|
// comparison below
|
||||||
|
const char* directory;
|
||||||
|
for (int32 i = 0; const char* fileName = unit->FileAt(i, &directory); i++) {
|
||||||
|
LocatableFile* file = fFileManager->GetSourceFile(directory, fileName);
|
||||||
|
if (file != NULL) {
|
||||||
|
file->ReleaseReference();
|
||||||
|
if (file == sourceFile) {
|
||||||
|
return i + 1;
|
||||||
|
// indices are one-based
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
@ -47,6 +47,10 @@ public:
|
|||||||
virtual status_t GetStatement(FunctionDebugInfo* function,
|
virtual status_t GetStatement(FunctionDebugInfo* function,
|
||||||
target_addr_t address,
|
target_addr_t address,
|
||||||
Statement*& _statement);
|
Statement*& _statement);
|
||||||
|
virtual status_t GetStatementForSourceLocation(
|
||||||
|
FunctionDebugInfo* function,
|
||||||
|
const SourceLocation& sourceLocation,
|
||||||
|
Statement*& _statement);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct SourceCodeKey;
|
struct SourceCodeKey;
|
||||||
@ -60,6 +64,8 @@ private:
|
|||||||
SourceCode*& _sourceCode);
|
SourceCode*& _sourceCode);
|
||||||
FileSourceCode* _LookupSourceCode(CompilationUnit* unit,
|
FileSourceCode* _LookupSourceCode(CompilationUnit* unit,
|
||||||
LocatableFile* file);
|
LocatableFile* file);
|
||||||
|
int32 _GetSourceFileIndex(CompilationUnit* unit,
|
||||||
|
LocatableFile* sourceFile) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
BLocker fLock;
|
BLocker fLock;
|
||||||
|
90
src/apps/debugger/debug_info/Function.cpp
Normal file
90
src/apps/debugger/debug_info/Function.cpp
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Function.h"
|
||||||
|
|
||||||
|
#include "SourceCode.h"
|
||||||
|
|
||||||
|
|
||||||
|
Function::Function()
|
||||||
|
:
|
||||||
|
fSourceCode(NULL),
|
||||||
|
fSourceCodeState(FUNCTION_SOURCE_NOT_LOADED)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Function::~Function()
|
||||||
|
{
|
||||||
|
SetSourceCode(NULL, FUNCTION_SOURCE_NOT_LOADED);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Function::SetSourceCode(SourceCode* source, function_source_state state)
|
||||||
|
{
|
||||||
|
if (source == fSourceCode && state == fSourceCodeState)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (fSourceCode != NULL)
|
||||||
|
fSourceCode->RemoveReference();
|
||||||
|
|
||||||
|
fSourceCode = source;
|
||||||
|
fSourceCodeState = state;
|
||||||
|
|
||||||
|
if (fSourceCode != NULL)
|
||||||
|
fSourceCode->AddReference();
|
||||||
|
|
||||||
|
// notify listeners
|
||||||
|
for (ListenerList::Iterator it = fListeners.GetIterator();
|
||||||
|
Listener* listener = it.Next();) {
|
||||||
|
listener->FunctionSourceCodeChanged(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Function::AddListener(Listener* listener)
|
||||||
|
{
|
||||||
|
fListeners.Add(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Function::RemoveListener(Listener* listener)
|
||||||
|
{
|
||||||
|
fListeners.Remove(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
void
|
||||||
|
Function::AddInstance(FunctionInstance* instance)
|
||||||
|
{
|
||||||
|
printf(" %p: added %p\n", this, instance);
|
||||||
|
fInstances.Add(instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Function::RemoveInstance(FunctionInstance* instance)
|
||||||
|
{
|
||||||
|
printf(" %p: removed %p\n", this, instance);
|
||||||
|
fInstances.Remove(instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - Listener
|
||||||
|
|
||||||
|
|
||||||
|
Function::Listener::~Listener()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Function::Listener::FunctionSourceCodeChanged(Function* function)
|
||||||
|
{
|
||||||
|
}
|
85
src/apps/debugger/debug_info/Function.h
Normal file
85
src/apps/debugger/debug_info/Function.h
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef FUNCTION_H
|
||||||
|
#define FUNCTION_H
|
||||||
|
|
||||||
|
#include <util/DoublyLinkedList.h>
|
||||||
|
#include <util/OpenHashTable.h>
|
||||||
|
|
||||||
|
#include "FunctionInstance.h"
|
||||||
|
|
||||||
|
|
||||||
|
enum function_source_state {
|
||||||
|
FUNCTION_SOURCE_NOT_LOADED,
|
||||||
|
FUNCTION_SOURCE_LOADING,
|
||||||
|
FUNCTION_SOURCE_LOADED,
|
||||||
|
FUNCTION_SOURCE_UNAVAILABLE
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class SourceCode;
|
||||||
|
|
||||||
|
|
||||||
|
class Function : public Referenceable, public HashTableLink<Function> {
|
||||||
|
public:
|
||||||
|
class Listener;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Function();
|
||||||
|
~Function();
|
||||||
|
|
||||||
|
// team must be locked ot access the instances
|
||||||
|
FunctionInstance* FirstInstance() const
|
||||||
|
{ return fInstances.Head(); }
|
||||||
|
FunctionInstance* LastInstance() const
|
||||||
|
{ return fInstances.Tail(); }
|
||||||
|
const FunctionInstanceList& Instances() const
|
||||||
|
{ return fInstances; }
|
||||||
|
|
||||||
|
const BString& Name() const
|
||||||
|
{ return FirstInstance()->Name(); }
|
||||||
|
const BString& PrettyName() const
|
||||||
|
{ return FirstInstance()->PrettyName(); }
|
||||||
|
LocatableFile* SourceFile() const
|
||||||
|
{ return FirstInstance()->SourceFile(); }
|
||||||
|
SourceLocation GetSourceLocation() const
|
||||||
|
{ return FirstInstance()
|
||||||
|
->GetSourceLocation(); }
|
||||||
|
|
||||||
|
// mutable attributes follow (locking required)
|
||||||
|
SourceCode* GetSourceCode() const { return fSourceCode; }
|
||||||
|
function_source_state SourceCodeState() const
|
||||||
|
{ return fSourceCodeState; }
|
||||||
|
void SetSourceCode(SourceCode* source,
|
||||||
|
function_source_state state);
|
||||||
|
|
||||||
|
void AddListener(Listener* listener);
|
||||||
|
void RemoveListener(Listener* listener);
|
||||||
|
|
||||||
|
// package private
|
||||||
|
void AddInstance(FunctionInstance* instance);
|
||||||
|
void RemoveInstance(FunctionInstance* instance);
|
||||||
|
|
||||||
|
private:
|
||||||
|
typedef DoublyLinkedList<Listener> ListenerList;
|
||||||
|
|
||||||
|
private:
|
||||||
|
FunctionInstanceList fInstances;
|
||||||
|
SourceCode* fSourceCode;
|
||||||
|
function_source_state fSourceCodeState;
|
||||||
|
ListenerList fListeners;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class Function::Listener : public DoublyLinkedListLinkImpl<Listener> {
|
||||||
|
public:
|
||||||
|
virtual ~Listener();
|
||||||
|
|
||||||
|
virtual void FunctionSourceCodeChanged(Function* function);
|
||||||
|
// called with lock held
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // FUNCTION_H
|
@ -5,71 +5,12 @@
|
|||||||
|
|
||||||
#include "FunctionDebugInfo.h"
|
#include "FunctionDebugInfo.h"
|
||||||
|
|
||||||
#include "SourceCode.h"
|
|
||||||
|
|
||||||
|
|
||||||
FunctionDebugInfo::FunctionDebugInfo()
|
FunctionDebugInfo::FunctionDebugInfo()
|
||||||
:
|
|
||||||
fSourceCode(NULL),
|
|
||||||
fSourceCodeState(FUNCTION_SOURCE_NOT_LOADED)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
FunctionDebugInfo::~FunctionDebugInfo()
|
FunctionDebugInfo::~FunctionDebugInfo()
|
||||||
{
|
|
||||||
SetSourceCode(NULL, FUNCTION_SOURCE_NOT_LOADED);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
FunctionDebugInfo::SetSourceCode(SourceCode* source,
|
|
||||||
function_source_state state)
|
|
||||||
{
|
|
||||||
if (source == fSourceCode && state == fSourceCodeState)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (fSourceCode != NULL)
|
|
||||||
fSourceCode->RemoveReference();
|
|
||||||
|
|
||||||
fSourceCode = source;
|
|
||||||
fSourceCodeState = state;
|
|
||||||
|
|
||||||
if (fSourceCode != NULL)
|
|
||||||
fSourceCode->AddReference();
|
|
||||||
|
|
||||||
// notify listeners
|
|
||||||
for (ListenerList::Iterator it = fListeners.GetIterator();
|
|
||||||
Listener* listener = it.Next();) {
|
|
||||||
listener->FunctionSourceCodeChanged(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
FunctionDebugInfo::AddListener(Listener* listener)
|
|
||||||
{
|
|
||||||
fListeners.Add(listener);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
FunctionDebugInfo::RemoveListener(Listener* listener)
|
|
||||||
{
|
|
||||||
fListeners.Remove(listener);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark - Listener
|
|
||||||
|
|
||||||
|
|
||||||
FunctionDebugInfo::Listener::~Listener()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
FunctionDebugInfo::Listener::FunctionSourceCodeChanged(
|
|
||||||
FunctionDebugInfo* function)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -6,29 +6,17 @@
|
|||||||
#define FUNCTION_DEBUG_INFO_H
|
#define FUNCTION_DEBUG_INFO_H
|
||||||
|
|
||||||
#include <Referenceable.h>
|
#include <Referenceable.h>
|
||||||
#include <util/DoublyLinkedList.h>
|
|
||||||
|
|
||||||
#include "SourceLocation.h"
|
#include "SourceLocation.h"
|
||||||
#include "Types.h"
|
#include "Types.h"
|
||||||
|
|
||||||
|
|
||||||
enum function_source_state {
|
class BString;
|
||||||
FUNCTION_SOURCE_NOT_LOADED,
|
|
||||||
FUNCTION_SOURCE_LOADING,
|
|
||||||
FUNCTION_SOURCE_LOADED,
|
|
||||||
FUNCTION_SOURCE_UNAVAILABLE
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class LocatableFile;
|
class LocatableFile;
|
||||||
class SourceCode;
|
|
||||||
class SpecificImageDebugInfo;
|
class SpecificImageDebugInfo;
|
||||||
|
|
||||||
|
|
||||||
class FunctionDebugInfo : public Referenceable {
|
class FunctionDebugInfo : public Referenceable {
|
||||||
public:
|
|
||||||
class Listener;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
FunctionDebugInfo();
|
FunctionDebugInfo();
|
||||||
virtual ~FunctionDebugInfo();
|
virtual ~FunctionDebugInfo();
|
||||||
@ -36,41 +24,12 @@ public:
|
|||||||
virtual SpecificImageDebugInfo* GetSpecificImageDebugInfo() const = 0;
|
virtual SpecificImageDebugInfo* GetSpecificImageDebugInfo() const = 0;
|
||||||
virtual target_addr_t Address() const = 0;
|
virtual target_addr_t Address() const = 0;
|
||||||
virtual target_size_t Size() const = 0;
|
virtual target_size_t Size() const = 0;
|
||||||
virtual const char* Name() const = 0;
|
virtual const BString& Name() const = 0;
|
||||||
virtual const char* PrettyName() const = 0;
|
virtual const BString& PrettyName() const = 0;
|
||||||
|
|
||||||
virtual LocatableFile* SourceFile() const = 0;
|
virtual LocatableFile* SourceFile() const = 0;
|
||||||
virtual SourceLocation SourceStartLocation() const = 0;
|
virtual SourceLocation SourceStartLocation() const = 0;
|
||||||
virtual SourceLocation SourceEndLocation() const = 0;
|
virtual SourceLocation SourceEndLocation() const = 0;
|
||||||
|
|
||||||
// mutable attributes follow (locking required)
|
|
||||||
SourceCode* GetSourceCode() const { return fSourceCode; }
|
|
||||||
function_source_state SourceCodeState() const
|
|
||||||
{ return fSourceCodeState; }
|
|
||||||
void SetSourceCode(SourceCode* source,
|
|
||||||
function_source_state state);
|
|
||||||
|
|
||||||
void AddListener(Listener* listener);
|
|
||||||
void RemoveListener(Listener* listener);
|
|
||||||
|
|
||||||
private:
|
|
||||||
typedef DoublyLinkedList<Listener> ListenerList;
|
|
||||||
|
|
||||||
private:
|
|
||||||
// mutable
|
|
||||||
SourceCode* fSourceCode;
|
|
||||||
function_source_state fSourceCodeState;
|
|
||||||
ListenerList fListeners;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class FunctionDebugInfo::Listener : public DoublyLinkedListLinkImpl<Listener> {
|
|
||||||
public:
|
|
||||||
virtual ~Listener();
|
|
||||||
|
|
||||||
virtual void FunctionSourceCodeChanged(
|
|
||||||
FunctionDebugInfo* function);
|
|
||||||
// called with lock held
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
41
src/apps/debugger/debug_info/FunctionInstance.cpp
Normal file
41
src/apps/debugger/debug_info/FunctionInstance.cpp
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "FunctionInstance.h"
|
||||||
|
|
||||||
|
#include "Function.h"
|
||||||
|
|
||||||
|
|
||||||
|
FunctionInstance::FunctionInstance(ImageDebugInfo* imageDebugInfo,
|
||||||
|
FunctionDebugInfo* functionDebugInfo)
|
||||||
|
:
|
||||||
|
fImageDebugInfo(imageDebugInfo),
|
||||||
|
fFunction(NULL),
|
||||||
|
fFunctionDebugInfo(functionDebugInfo)
|
||||||
|
{
|
||||||
|
fFunctionDebugInfo->AcquireReference();
|
||||||
|
// TODO: What about fImageDebugInfo? We must be careful regarding cyclic
|
||||||
|
// references.
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FunctionInstance::~FunctionInstance()
|
||||||
|
{
|
||||||
|
SetFunction(NULL);
|
||||||
|
fFunctionDebugInfo->ReleaseReference();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
FunctionInstance::SetFunction(Function* function)
|
||||||
|
{
|
||||||
|
if (fFunction != NULL)
|
||||||
|
fFunction->ReleaseReference();
|
||||||
|
|
||||||
|
fFunction = function;
|
||||||
|
|
||||||
|
if (fFunction != NULL)
|
||||||
|
fFunction->AcquireReference();
|
||||||
|
}
|
58
src/apps/debugger/debug_info/FunctionInstance.h
Normal file
58
src/apps/debugger/debug_info/FunctionInstance.h
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef FUNCTION_INSTANCE_H
|
||||||
|
#define FUNCTION_INSTANCE_H
|
||||||
|
|
||||||
|
#include <util/DoublyLinkedList.h>
|
||||||
|
|
||||||
|
#include "FunctionDebugInfo.h"
|
||||||
|
|
||||||
|
|
||||||
|
class Function;
|
||||||
|
class FunctionDebugInfo;
|
||||||
|
class ImageDebugInfo;
|
||||||
|
|
||||||
|
|
||||||
|
class FunctionInstance : public Referenceable,
|
||||||
|
public DoublyLinkedListLinkImpl<FunctionInstance> {
|
||||||
|
public:
|
||||||
|
FunctionInstance(ImageDebugInfo* imageDebugInfo,
|
||||||
|
FunctionDebugInfo* functionDebugInfo);
|
||||||
|
~FunctionInstance();
|
||||||
|
|
||||||
|
ImageDebugInfo* GetImageDebugInfo() const
|
||||||
|
{ return fImageDebugInfo; }
|
||||||
|
Function* GetFunction() const
|
||||||
|
{ return fFunction; }
|
||||||
|
FunctionDebugInfo* GetFunctionDebugInfo() const
|
||||||
|
{ return fFunctionDebugInfo; }
|
||||||
|
|
||||||
|
target_addr_t Address() const
|
||||||
|
{ return fFunctionDebugInfo->Address(); }
|
||||||
|
target_size_t Size() const
|
||||||
|
{ return fFunctionDebugInfo->Size(); }
|
||||||
|
const BString& Name() const
|
||||||
|
{ return fFunctionDebugInfo->Name(); }
|
||||||
|
const BString& PrettyName() const
|
||||||
|
{ return fFunctionDebugInfo->PrettyName(); }
|
||||||
|
LocatableFile* SourceFile() const
|
||||||
|
{ return fFunctionDebugInfo->SourceFile(); }
|
||||||
|
SourceLocation GetSourceLocation() const
|
||||||
|
{ return fFunctionDebugInfo
|
||||||
|
->SourceStartLocation(); }
|
||||||
|
|
||||||
|
void SetFunction(Function* function);
|
||||||
|
// package private
|
||||||
|
private:
|
||||||
|
ImageDebugInfo* fImageDebugInfo;
|
||||||
|
Function* fFunction;
|
||||||
|
FunctionDebugInfo* fFunctionDebugInfo;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
typedef DoublyLinkedList<FunctionInstance> FunctionInstanceList;
|
||||||
|
|
||||||
|
|
||||||
|
#endif // FUNCTION_INSTANCE_H
|
@ -8,6 +8,7 @@
|
|||||||
#include <new>
|
#include <new>
|
||||||
|
|
||||||
#include "FunctionDebugInfo.h"
|
#include "FunctionDebugInfo.h"
|
||||||
|
#include "FunctionInstance.h"
|
||||||
#include "SpecificImageDebugInfo.h"
|
#include "SpecificImageDebugInfo.h"
|
||||||
|
|
||||||
|
|
||||||
@ -20,8 +21,8 @@ ImageDebugInfo::ImageDebugInfo(const ImageInfo& imageInfo)
|
|||||||
|
|
||||||
ImageDebugInfo::~ImageDebugInfo()
|
ImageDebugInfo::~ImageDebugInfo()
|
||||||
{
|
{
|
||||||
for (int32 i = 0; FunctionDebugInfo* function = fFunctions.ItemAt(i); i++)
|
for (int32 i = 0; FunctionInstance* function = fFunctions.ItemAt(i); i++)
|
||||||
function->RemoveReference();
|
function->ReleaseReference();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -39,23 +40,35 @@ ImageDebugInfo::FinishInit()
|
|||||||
// missing functions from less expressive debug infos
|
// missing functions from less expressive debug infos
|
||||||
for (int32 i = 0; SpecificImageDebugInfo* specificInfo
|
for (int32 i = 0; SpecificImageDebugInfo* specificInfo
|
||||||
= fSpecificInfos.ItemAt(i); i++) {
|
= fSpecificInfos.ItemAt(i); i++) {
|
||||||
FunctionList functions;
|
BObjectList<FunctionDebugInfo> functions;
|
||||||
status_t error = specificInfo->GetFunctions(functions);
|
status_t error = specificInfo->GetFunctions(functions);
|
||||||
if (error != B_OK)
|
if (error != B_OK)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
for (int32 k = 0; FunctionDebugInfo* function = functions.ItemAt(k);
|
for (int32 k = 0; FunctionDebugInfo* function = functions.ItemAt(k);
|
||||||
k++) {
|
k++) {
|
||||||
if (FunctionAtAddress(function->Address()) == NULL) {
|
if (FunctionAtAddress(function->Address()) != NULL)
|
||||||
if (!fFunctions.BinaryInsert(function, &_CompareFunctions)) {
|
continue;
|
||||||
for (; (function = functions.ItemAt(k)); k++) {
|
|
||||||
function->RemoveReference();
|
FunctionInstance* instance = new(std::nothrow) FunctionInstance(
|
||||||
return B_NO_MEMORY;
|
this, function);
|
||||||
}
|
if (instance == NULL
|
||||||
}
|
|| !fFunctions.BinaryInsert(instance, &_CompareFunctions)) {
|
||||||
} else
|
delete instance;
|
||||||
function->RemoveReference();
|
error = B_NO_MEMORY;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove references returned by the specific debug info -- the
|
||||||
|
// FunctionInstance objects have references, now.
|
||||||
|
for (int32 k = 0; FunctionDebugInfo* function = functions.ItemAt(k);
|
||||||
|
k++) {
|
||||||
|
function->RemoveReference();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error != B_OK)
|
||||||
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
@ -69,14 +82,14 @@ ImageDebugInfo::CountFunctions() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
FunctionDebugInfo*
|
FunctionInstance*
|
||||||
ImageDebugInfo::FunctionAt(int32 index) const
|
ImageDebugInfo::FunctionAt(int32 index) const
|
||||||
{
|
{
|
||||||
return fFunctions.ItemAt(index);
|
return fFunctions.ItemAt(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
FunctionDebugInfo*
|
FunctionInstance*
|
||||||
ImageDebugInfo::FunctionAtAddress(target_addr_t address) const
|
ImageDebugInfo::FunctionAtAddress(target_addr_t address) const
|
||||||
{
|
{
|
||||||
return fFunctions.BinarySearchByKey(address, &_CompareAddressFunction);
|
return fFunctions.BinarySearchByKey(address, &_CompareAddressFunction);
|
||||||
@ -84,8 +97,8 @@ ImageDebugInfo::FunctionAtAddress(target_addr_t address) const
|
|||||||
|
|
||||||
|
|
||||||
/*static*/ int
|
/*static*/ int
|
||||||
ImageDebugInfo::_CompareFunctions(const FunctionDebugInfo* a,
|
ImageDebugInfo::_CompareFunctions(const FunctionInstance* a,
|
||||||
const FunctionDebugInfo* b)
|
const FunctionInstance* b)
|
||||||
{
|
{
|
||||||
return a->Address() < b->Address()
|
return a->Address() < b->Address()
|
||||||
? -1 : (a->Address() == b->Address() ? 0 : 1);
|
? -1 : (a->Address() == b->Address() ? 0 : 1);
|
||||||
@ -94,7 +107,7 @@ ImageDebugInfo::_CompareFunctions(const FunctionDebugInfo* a,
|
|||||||
|
|
||||||
/*static*/ int
|
/*static*/ int
|
||||||
ImageDebugInfo::_CompareAddressFunction(const target_addr_t* address,
|
ImageDebugInfo::_CompareAddressFunction(const target_addr_t* address,
|
||||||
const FunctionDebugInfo* function)
|
const FunctionInstance* function)
|
||||||
{
|
{
|
||||||
if (*address < function->Address())
|
if (*address < function->Address())
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
class Architecture;
|
class Architecture;
|
||||||
class DebuggerInterface;
|
class DebuggerInterface;
|
||||||
class FunctionDebugInfo;
|
class FunctionDebugInfo;
|
||||||
|
class FunctionInstance;
|
||||||
class SpecificImageDebugInfo;
|
class SpecificImageDebugInfo;
|
||||||
|
|
||||||
|
|
||||||
@ -29,19 +30,19 @@ public:
|
|||||||
status_t FinishInit();
|
status_t FinishInit();
|
||||||
|
|
||||||
int32 CountFunctions() const;
|
int32 CountFunctions() const;
|
||||||
FunctionDebugInfo* FunctionAt(int32 index) const;
|
FunctionInstance* FunctionAt(int32 index) const;
|
||||||
FunctionDebugInfo* FunctionAtAddress(target_addr_t address) const;
|
FunctionInstance* FunctionAtAddress(target_addr_t address) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef BObjectList<SpecificImageDebugInfo> SpecificInfoList;
|
typedef BObjectList<SpecificImageDebugInfo> SpecificInfoList;
|
||||||
typedef BObjectList<FunctionDebugInfo> FunctionList;
|
typedef BObjectList<FunctionInstance> FunctionList;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static int _CompareFunctions(const FunctionDebugInfo* a,
|
static int _CompareFunctions(const FunctionInstance* a,
|
||||||
const FunctionDebugInfo* b);
|
const FunctionInstance* b);
|
||||||
static int _CompareAddressFunction(
|
static int _CompareAddressFunction(
|
||||||
const target_addr_t* address,
|
const target_addr_t* address,
|
||||||
const FunctionDebugInfo* function);
|
const FunctionInstance* function);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ImageInfo fImageInfo;
|
ImageInfo fImageInfo;
|
||||||
|
@ -17,6 +17,7 @@ class DebuggerInterface;
|
|||||||
class FunctionDebugInfo;
|
class FunctionDebugInfo;
|
||||||
class Image;
|
class Image;
|
||||||
class SourceCode;
|
class SourceCode;
|
||||||
|
class SourceLocation;
|
||||||
class StackFrame;
|
class StackFrame;
|
||||||
class Statement;
|
class Statement;
|
||||||
|
|
||||||
@ -45,6 +46,11 @@ public:
|
|||||||
target_addr_t address,
|
target_addr_t address,
|
||||||
Statement*& _statement) = 0;
|
Statement*& _statement) = 0;
|
||||||
// returns reference
|
// returns reference
|
||||||
|
virtual status_t GetStatementForSourceLocation(
|
||||||
|
FunctionDebugInfo* function,
|
||||||
|
const SourceLocation& sourceLocation,
|
||||||
|
Statement*& _statement) = 0;
|
||||||
|
// returns reference
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -11,8 +11,62 @@
|
|||||||
|
|
||||||
#include "DebuggerTeamDebugInfo.h"
|
#include "DebuggerTeamDebugInfo.h"
|
||||||
#include "DwarfTeamDebugInfo.h"
|
#include "DwarfTeamDebugInfo.h"
|
||||||
|
#include "Function.h"
|
||||||
#include "ImageDebugInfo.h"
|
#include "ImageDebugInfo.h"
|
||||||
#include "SpecificImageDebugInfo.h"
|
#include "SpecificImageDebugInfo.h"
|
||||||
|
#include "StringUtils.h"
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - FunctionHashDefinition
|
||||||
|
|
||||||
|
|
||||||
|
struct TeamDebugInfo::FunctionHashDefinition {
|
||||||
|
typedef const FunctionInstance* KeyType;
|
||||||
|
typedef Function ValueType;
|
||||||
|
|
||||||
|
size_t HashKey(const FunctionInstance* key) const
|
||||||
|
{
|
||||||
|
// Instances without source file only equal themselves.
|
||||||
|
if (key->SourceFile() == NULL)
|
||||||
|
return (uint32)(addr_t)key;
|
||||||
|
|
||||||
|
uint32 hash = StringUtils::HashValue(key->Name());
|
||||||
|
hash = hash * 17 + (uint32)(addr_t)key->SourceFile();
|
||||||
|
SourceLocation location = key->GetSourceLocation();
|
||||||
|
hash = hash * 17 + location.Line();
|
||||||
|
hash = hash * 17 + location.Column();
|
||||||
|
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Hash(const Function* value) const
|
||||||
|
{
|
||||||
|
return HashKey(value->FirstInstance());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Compare(const FunctionInstance* key, const Function* value) const
|
||||||
|
{
|
||||||
|
// source file must be the same
|
||||||
|
if (key->SourceFile() != value->SourceFile())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Instances without source file only equal themselves.
|
||||||
|
if (key->SourceFile() == NULL)
|
||||||
|
return key == value->FirstInstance();
|
||||||
|
|
||||||
|
// Source location and function name must also match.
|
||||||
|
return key->GetSourceLocation() == value->GetSourceLocation()
|
||||||
|
&& key->Name() == value->Name();
|
||||||
|
}
|
||||||
|
|
||||||
|
HashTableLink<Function>* GetLink(Function* value) const
|
||||||
|
{
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - TeamDebugInfo
|
||||||
|
|
||||||
|
|
||||||
TeamDebugInfo::TeamDebugInfo(DebuggerInterface* debuggerInterface,
|
TeamDebugInfo::TeamDebugInfo(DebuggerInterface* debuggerInterface,
|
||||||
@ -21,19 +75,39 @@ TeamDebugInfo::TeamDebugInfo(DebuggerInterface* debuggerInterface,
|
|||||||
fDebuggerInterface(debuggerInterface),
|
fDebuggerInterface(debuggerInterface),
|
||||||
fArchitecture(architecture),
|
fArchitecture(architecture),
|
||||||
fFileManager(fileManager),
|
fFileManager(fileManager),
|
||||||
fSpecificInfos(10, true)
|
fSpecificInfos(10, true),
|
||||||
|
fFunctions(NULL)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TeamDebugInfo::~TeamDebugInfo()
|
TeamDebugInfo::~TeamDebugInfo()
|
||||||
{
|
{
|
||||||
|
if (fFunctions != NULL) {
|
||||||
|
Function* function = fFunctions->Clear(true);
|
||||||
|
while (function != NULL) {
|
||||||
|
Function* next = function->fNext;
|
||||||
|
function->ReleaseReference();
|
||||||
|
function = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete fFunctions;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
TeamDebugInfo::Init()
|
TeamDebugInfo::Init()
|
||||||
{
|
{
|
||||||
|
// create function hash table
|
||||||
|
fFunctions = new(std::nothrow) FunctionTable;
|
||||||
|
if (fFunctions == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
status_t error = fFunctions->Init();
|
||||||
|
if (error != B_OK)
|
||||||
|
return error;
|
||||||
|
|
||||||
// Create specific infos for all types of debug info we support, in
|
// Create specific infos for all types of debug info we support, in
|
||||||
// descending order of expressiveness.
|
// descending order of expressiveness.
|
||||||
|
|
||||||
@ -45,7 +119,7 @@ TeamDebugInfo::Init()
|
|||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
status_t error = dwarfInfo->Init();
|
error = dwarfInfo->Init();
|
||||||
if (error != B_OK)
|
if (error != B_OK)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
@ -98,3 +172,65 @@ TeamDebugInfo::LoadImageDebugInfo(const ImageInfo& imageInfo,
|
|||||||
_imageDebugInfo = imageDebugInfoDeleter.Detach();
|
_imageDebugInfo = imageDebugInfoDeleter.Detach();
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
status_t
|
||||||
|
TeamDebugInfo::AddImageDebugInfo(ImageDebugInfo* imageDebugInfo)
|
||||||
|
{
|
||||||
|
printf("TeamDebugInfo::AddImageDebugInfo(%p)\n", imageDebugInfo);
|
||||||
|
// Match all of the image debug info's functions instances with functions.
|
||||||
|
for (int32 i = 0;
|
||||||
|
FunctionInstance* instance = imageDebugInfo->FunctionAt(i); i++) {
|
||||||
|
// lookup the function or create it, if it doesn't exist yet
|
||||||
|
Function* function = fFunctions->Lookup(instance);
|
||||||
|
if (function != NULL) {
|
||||||
|
// TODO: Also update possible user breakpoints in this function!
|
||||||
|
printf(" adding instance %p to existing function %p\n", instance, function);
|
||||||
|
function->AddInstance(instance);
|
||||||
|
instance->SetFunction(function);
|
||||||
|
} else {
|
||||||
|
function = new(std::nothrow) Function;
|
||||||
|
if (function == NULL) {
|
||||||
|
RemoveImageDebugInfo(imageDebugInfo);
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
}
|
||||||
|
printf(" adding instance %p to new function %p\n", instance, function);
|
||||||
|
function->AddInstance(instance);
|
||||||
|
instance->SetFunction(function);
|
||||||
|
fFunctions->Insert(function);
|
||||||
|
// Insert after adding the instance. Otherwise the function
|
||||||
|
// wouldn't be hashable/comparable.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TeamDebugInfo::RemoveImageDebugInfo(ImageDebugInfo* imageDebugInfo)
|
||||||
|
{
|
||||||
|
// Remove the functions from all of the image debug info's functions
|
||||||
|
// instances.
|
||||||
|
for (int32 i = 0;
|
||||||
|
FunctionInstance* instance = imageDebugInfo->FunctionAt(i); i++) {
|
||||||
|
if (Function* function = instance->GetFunction()) {
|
||||||
|
// TODO: Also update possible user breakpoints in this function!
|
||||||
|
if (function->FirstInstance() == function->LastInstance()) {
|
||||||
|
// function unused -- remove it
|
||||||
|
// Note, that we have to remove it from the hash before removing
|
||||||
|
// the instance, since otherwise the function cannot be compared
|
||||||
|
// anymore.
|
||||||
|
fFunctions->Remove(function);
|
||||||
|
function->ReleaseReference();
|
||||||
|
// The instance still has a reference.
|
||||||
|
}
|
||||||
|
|
||||||
|
function->RemoveInstance(instance);
|
||||||
|
instance->SetFunction(NULL);
|
||||||
|
// If this was the last instance, it will remove the last
|
||||||
|
// reference to the function.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
#include <ObjectList.h>
|
#include <ObjectList.h>
|
||||||
#include <Referenceable.h>
|
#include <Referenceable.h>
|
||||||
|
#include <util/OpenHashTable.h>
|
||||||
|
|
||||||
#include "ImageInfo.h"
|
#include "ImageInfo.h"
|
||||||
|
|
||||||
@ -14,6 +15,8 @@
|
|||||||
class Architecture;
|
class Architecture;
|
||||||
class DebuggerInterface;
|
class DebuggerInterface;
|
||||||
class FileManager;
|
class FileManager;
|
||||||
|
class Function;
|
||||||
|
class FunctionInstance;
|
||||||
class ImageDebugInfo;
|
class ImageDebugInfo;
|
||||||
class ImageInfo;
|
class ImageInfo;
|
||||||
class LocatableFile;
|
class LocatableFile;
|
||||||
@ -34,14 +37,24 @@ public:
|
|||||||
LocatableFile* imageFile,
|
LocatableFile* imageFile,
|
||||||
ImageDebugInfo*& _imageDebugInfo);
|
ImageDebugInfo*& _imageDebugInfo);
|
||||||
|
|
||||||
|
// team is locked
|
||||||
|
status_t AddImageDebugInfo(
|
||||||
|
ImageDebugInfo* imageDebugInfo);
|
||||||
|
void RemoveImageDebugInfo(
|
||||||
|
ImageDebugInfo* imageDebugInfo);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
struct FunctionHashDefinition;
|
||||||
|
|
||||||
typedef BObjectList<SpecificTeamDebugInfo> SpecificInfoList;
|
typedef BObjectList<SpecificTeamDebugInfo> SpecificInfoList;
|
||||||
|
typedef OpenHashTable<FunctionHashDefinition> FunctionTable;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DebuggerInterface* fDebuggerInterface;
|
DebuggerInterface* fDebuggerInterface;
|
||||||
Architecture* fArchitecture;
|
Architecture* fArchitecture;
|
||||||
FileManager* fFileManager;
|
FileManager* fFileManager;
|
||||||
SpecificInfoList fSpecificInfos;
|
SpecificInfoList fSpecificInfos;
|
||||||
|
FunctionTable* fFunctions;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
#include "table/TableColumns.h"
|
#include "table/TableColumns.h"
|
||||||
|
|
||||||
#include "FunctionDebugInfo.h"
|
#include "FunctionInstance.h"
|
||||||
#include "Image.h"
|
#include "Image.h"
|
||||||
#include "ImageDebugInfo.h"
|
#include "ImageDebugInfo.h"
|
||||||
#include "LocatableFile.h"
|
#include "LocatableFile.h"
|
||||||
@ -63,11 +63,11 @@ public:
|
|||||||
|
|
||||||
// create an array with the functions
|
// create an array with the functions
|
||||||
int32 functionCount = fImageDebugInfo->CountFunctions();
|
int32 functionCount = fImageDebugInfo->CountFunctions();
|
||||||
FunctionDebugInfo** functions
|
FunctionInstance** functions
|
||||||
= new(std::nothrow) FunctionDebugInfo*[functionCount];
|
= new(std::nothrow) FunctionInstance*[functionCount];
|
||||||
if (functions == NULL)
|
if (functions == NULL)
|
||||||
return;
|
return;
|
||||||
ArrayDeleter<FunctionDebugInfo*> functionsDeleter(functions);
|
ArrayDeleter<FunctionInstance*> functionsDeleter(functions);
|
||||||
|
|
||||||
for (int32 i = 0; i < functionCount; i++)
|
for (int32 i = 0; i < functionCount; i++)
|
||||||
functions[i] = fImageDebugInfo->FunctionAt(i);
|
functions[i] = fImageDebugInfo->FunctionAt(i);
|
||||||
@ -170,12 +170,12 @@ public:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
FunctionDebugInfo* function = (FunctionDebugInfo*)object;
|
FunctionInstance* function = (FunctionInstance*)object;
|
||||||
value.SetTo(function->PrettyName(), B_VARIANT_DONT_COPY_DATA);
|
value.SetTo(function->PrettyName(), B_VARIANT_DONT_COPY_DATA);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GetFunctionPath(FunctionDebugInfo* function, TreeTablePath& _path)
|
bool GetFunctionPath(FunctionInstance* function, TreeTablePath& _path)
|
||||||
{
|
{
|
||||||
int32 index = -1;
|
int32 index = -1;
|
||||||
for (int32 i = 0; i < fFunctionCount; i++) {
|
for (int32 i = 0; i < fFunctionCount; i++) {
|
||||||
@ -198,7 +198,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool GetObjectForPath(const TreeTablePath& path,
|
bool GetObjectForPath(const TreeTablePath& path,
|
||||||
LocatableFile*& _sourceFile, FunctionDebugInfo*& _function)
|
LocatableFile*& _sourceFile, FunctionInstance*& _function)
|
||||||
{
|
{
|
||||||
int32 componentCount = path.CountComponents();
|
int32 componentCount = path.CountComponents();
|
||||||
if (componentCount == 0 || componentCount > 2)
|
if (componentCount == 0 || componentCount > 2)
|
||||||
@ -256,8 +256,8 @@ private:
|
|||||||
return pathA.Compare(pathB);
|
return pathA.Compare(pathB);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool _FunctionLess(const FunctionDebugInfo* a,
|
static bool _FunctionLess(const FunctionInstance* a,
|
||||||
const FunctionDebugInfo* b)
|
const FunctionInstance* b)
|
||||||
{
|
{
|
||||||
// compare source file name first
|
// compare source file name first
|
||||||
int compared = _CompareSourceFileNames(a->SourceFile(),
|
int compared = _CompareSourceFileNames(a->SourceFile(),
|
||||||
@ -271,7 +271,7 @@ private:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
ImageDebugInfo* fImageDebugInfo;
|
ImageDebugInfo* fImageDebugInfo;
|
||||||
FunctionDebugInfo** fFunctions;
|
FunctionInstance** fFunctions;
|
||||||
int32 fFunctionCount;
|
int32 fFunctionCount;
|
||||||
int32* fSourceFileIndices;
|
int32* fSourceFileIndices;
|
||||||
int32 fSourceFileCount;
|
int32 fSourceFileCount;
|
||||||
@ -357,7 +357,7 @@ printf("ImageFunctionsView::SetImageDebugInfo(%p) done\n", imageDebugInfo);
|
|||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
ImageFunctionsView::SetFunction(FunctionDebugInfo* function)
|
ImageFunctionsView::SetFunction(FunctionInstance* function)
|
||||||
{
|
{
|
||||||
printf("ImageFunctionsView::SetFunction(%p)\n", function);
|
printf("ImageFunctionsView::SetFunction(%p)\n", function);
|
||||||
TreeTablePath path;
|
TreeTablePath path;
|
||||||
@ -377,7 +377,7 @@ ImageFunctionsView::TreeTableSelectionChanged(TreeTable* table)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
LocatableFile* sourceFile = NULL;
|
LocatableFile* sourceFile = NULL;
|
||||||
FunctionDebugInfo* function = NULL;
|
FunctionInstance* function = NULL;
|
||||||
TreeTablePath path;
|
TreeTablePath path;
|
||||||
if (table->SelectionModel()->GetPathAt(0, path))
|
if (table->SelectionModel()->GetPathAt(0, path))
|
||||||
fFunctionsTableModel->GetObjectForPath(path, sourceFile, function);
|
fFunctionsTableModel->GetObjectForPath(path, sourceFile, function);
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
#include "Team.h"
|
#include "Team.h"
|
||||||
|
|
||||||
|
|
||||||
class FunctionDebugInfo;
|
class FunctionInstance;
|
||||||
|
|
||||||
|
|
||||||
class ImageFunctionsView : public BGroupView, private TreeTableListener {
|
class ImageFunctionsView : public BGroupView, private TreeTableListener {
|
||||||
@ -29,7 +29,7 @@ public:
|
|||||||
|
|
||||||
void SetImageDebugInfo(
|
void SetImageDebugInfo(
|
||||||
ImageDebugInfo* imageDebugInfo);
|
ImageDebugInfo* imageDebugInfo);
|
||||||
void SetFunction(FunctionDebugInfo* function);
|
void SetFunction(FunctionInstance* function);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class FunctionsTableModel;
|
class FunctionsTableModel;
|
||||||
@ -53,7 +53,7 @@ public:
|
|||||||
virtual ~Listener();
|
virtual ~Listener();
|
||||||
|
|
||||||
virtual void FunctionSelectionChanged(
|
virtual void FunctionSelectionChanged(
|
||||||
FunctionDebugInfo* function) = 0;
|
FunctionInstance* function) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#include <ObjectList.h>
|
#include <ObjectList.h>
|
||||||
|
|
||||||
#include "Breakpoint.h"
|
#include "Breakpoint.h"
|
||||||
|
#include "Function.h"
|
||||||
#include "SourceCode.h"
|
#include "SourceCode.h"
|
||||||
#include "StackTrace.h"
|
#include "StackTrace.h"
|
||||||
#include "Statement.h"
|
#include "Statement.h"
|
||||||
@ -519,8 +520,7 @@ SourceView::MarkerView::Draw(BRect updateRect)
|
|||||||
|
|
||||||
Statement* statement = fSourceCode->StatementAtLine(line);
|
Statement* statement = fSourceCode->StatementAtLine(line);
|
||||||
if (statement == NULL
|
if (statement == NULL
|
||||||
|| statement->StartSourceLocation().Line() != (uint32)line
|
|| statement->StartSourceLocation().Line() != (uint32)line) {
|
||||||
|| !statement->BreakpointAllowed()) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -543,8 +543,7 @@ SourceView::MarkerView::MouseDown(BPoint where)
|
|||||||
|
|
||||||
Statement* statement = fSourceCode->StatementAtLine(line);
|
Statement* statement = fSourceCode->StatementAtLine(line);
|
||||||
if (statement == NULL
|
if (statement == NULL
|
||||||
|| statement->StartSourceLocation().Line() != (uint32)line
|
|| statement->StartSourceLocation().Line() != (uint32)line) {
|
||||||
|| !statement->BreakpointAllowed()) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -595,15 +594,24 @@ SourceView::MarkerView::_UpdateIPMarkers()
|
|||||||
fIPMarkers.MakeEmpty();
|
fIPMarkers.MakeEmpty();
|
||||||
|
|
||||||
if (fSourceCode != NULL && fStackTrace != NULL) {
|
if (fSourceCode != NULL && fStackTrace != NULL) {
|
||||||
|
AutoLocker<TeamDebugModel> locker(fDebugModel);
|
||||||
|
|
||||||
for (int32 i = 0; StackFrame* frame = fStackTrace->FrameAt(i);
|
for (int32 i = 0; StackFrame* frame = fStackTrace->FrameAt(i);
|
||||||
i++) {
|
i++) {
|
||||||
target_addr_t ip = frame->InstructionPointer();
|
target_addr_t ip = frame->InstructionPointer();
|
||||||
Statement* statement = fSourceCode->StatementAtAddress(ip);
|
FunctionInstance* functionInstance;
|
||||||
if (statement == NULL)
|
Statement* statement;
|
||||||
|
if (fDebugModel->GetTeam()->GetStatementAtAddress(ip,
|
||||||
|
functionInstance, statement) != B_OK) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
Reference<Statement> statementReference(statement, true);
|
||||||
|
|
||||||
uint32 line = statement->StartSourceLocation().Line();
|
uint32 line = statement->StartSourceLocation().Line();
|
||||||
if (line >= (uint32)LineCount())
|
if (functionInstance->GetFunction()->GetSourceCode() != fSourceCode
|
||||||
|
|| line < 0 || line >= (uint32)LineCount()) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
bool isTopFrame = i == 0
|
bool isTopFrame = i == 0
|
||||||
&& frame->Type() != STACK_FRAME_TYPE_SYSCALL;
|
&& frame->Type() != STACK_FRAME_TYPE_SYSCALL;
|
||||||
@ -638,25 +646,30 @@ SourceView::MarkerView::_UpdateBreakpointMarkers()
|
|||||||
AutoLocker<TeamDebugModel> locker(fDebugModel);
|
AutoLocker<TeamDebugModel> locker(fDebugModel);
|
||||||
|
|
||||||
// get the breakpoints in our source code range
|
// get the breakpoints in our source code range
|
||||||
BObjectList<Breakpoint> breakpoints;
|
BObjectList<UserBreakpoint> breakpoints;
|
||||||
fDebugModel->GetBreakpointsInAddressRange(
|
fDebugModel->GetBreakpointsForSourceCode(fSourceCode, breakpoints);
|
||||||
fSourceCode->StatementAddressRange(), breakpoints);
|
|
||||||
|
|
||||||
for (int32 i = 0; Breakpoint* breakpoint = breakpoints.ItemAt(i); i++) {
|
for (int32 i = 0; UserBreakpoint* breakpoint = breakpoints.ItemAt(i);
|
||||||
if (breakpoint->UserState() == USER_BREAKPOINT_NONE)
|
i++) {
|
||||||
|
UserBreakpointInstance* breakpointInstance
|
||||||
|
= breakpoint->InstanceAt(0);
|
||||||
|
FunctionInstance* functionInstance;
|
||||||
|
Statement* statement;
|
||||||
|
if (fDebugModel->GetTeam()->GetStatementAtAddress(
|
||||||
|
breakpointInstance->Address(), functionInstance,
|
||||||
|
statement) != B_OK) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
Reference<Statement> statementReference(statement, true);
|
||||||
|
|
||||||
Statement* statement = fSourceCode->StatementAtAddress(
|
|
||||||
breakpoint->Address());
|
|
||||||
if (statement == NULL)
|
|
||||||
continue;
|
|
||||||
uint32 line = statement->StartSourceLocation().Line();
|
uint32 line = statement->StartSourceLocation().Line();
|
||||||
if (line >= (uint32)LineCount())
|
if (functionInstance->GetFunction()->GetSourceCode() != fSourceCode
|
||||||
|
|| line < 0 || line >= (uint32)LineCount()) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
BreakpointMarker* marker = new(std::nothrow) BreakpointMarker(
|
BreakpointMarker* marker = new(std::nothrow) BreakpointMarker(
|
||||||
line, breakpoint->Address(),
|
line, breakpointInstance->Address(), breakpoint->IsEnabled());
|
||||||
breakpoint->UserState() == USER_BREAKPOINT_ENABLED);
|
|
||||||
if (marker == NULL || !fBreakpointMarkers.AddItem(marker)) {
|
if (marker == NULL || !fBreakpointMarkers.AddItem(marker)) {
|
||||||
delete marker;
|
delete marker;
|
||||||
break;
|
break;
|
||||||
@ -995,9 +1008,15 @@ SourceView::ScrollToAddress(target_addr_t address)
|
|||||||
if (fSourceCode == NULL)
|
if (fSourceCode == NULL)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Statement* statement = fSourceCode->StatementAtAddress(address);
|
AutoLocker<TeamDebugModel> locker(fDebugModel);
|
||||||
if (statement == NULL)
|
|
||||||
|
FunctionInstance* functionInstance;
|
||||||
|
Statement* statement;
|
||||||
|
if (fDebugModel->GetTeam()->GetStatementAtAddress(address, functionInstance,
|
||||||
|
statement) != B_OK) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
Reference<Statement> statementReference(statement, true);
|
||||||
|
|
||||||
return ScrollToLine(statement->StartSourceLocation().Line());
|
return ScrollToLine(statement->StartSourceLocation().Line());
|
||||||
}
|
}
|
||||||
@ -1013,11 +1032,16 @@ SourceView::ScrollToLine(uint32 line)
|
|||||||
float bottom = top + fFontInfo.lineHeight - 1;
|
float bottom = top + fFontInfo.lineHeight - 1;
|
||||||
|
|
||||||
BRect visible = _VisibleRect();
|
BRect visible = _VisibleRect();
|
||||||
|
printf("SourceView::ScrollToLine(%ld)\n", line);
|
||||||
|
printf(" visible: (%f, %f) - (%f, %f), line: %f - %f\n", visible.left, visible.top, visible.right, visible.bottom, top, bottom);
|
||||||
|
|
||||||
// If not visible at all, scroll to the center, otherwise scroll so that at
|
// If not visible at all, scroll to the center, otherwise scroll so that at
|
||||||
// least one more line is visible.
|
// least one more line is visible.
|
||||||
if (top >= visible.bottom || bottom <= visible.top)
|
if (top >= visible.bottom || bottom <= visible.top)
|
||||||
|
{
|
||||||
|
printf(" -> scrolling to (%f, %f)\n", visible.left, top - (visible.Height() + 1) / 2);
|
||||||
ScrollTo(visible.left, top - (visible.Height() + 1) / 2);
|
ScrollTo(visible.left, top - (visible.Height() + 1) / 2);
|
||||||
|
}
|
||||||
else if (top - fFontInfo.lineHeight < visible.top)
|
else if (top - fFontInfo.lineHeight < visible.top)
|
||||||
ScrollBy(0, top - fFontInfo.lineHeight - visible.top);
|
ScrollBy(0, top - fFontInfo.lineHeight - visible.top);
|
||||||
else if (bottom + fFontInfo.lineHeight > visible.bottom)
|
else if (bottom + fFontInfo.lineHeight > visible.bottom)
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
#include "table/TableColumns.h"
|
#include "table/TableColumns.h"
|
||||||
|
|
||||||
#include "FunctionDebugInfo.h"
|
#include "FunctionInstance.h"
|
||||||
#include "Image.h"
|
#include "Image.h"
|
||||||
#include "StackTrace.h"
|
#include "StackTrace.h"
|
||||||
|
|
||||||
@ -105,7 +105,7 @@ public:
|
|||||||
case 2:
|
case 2:
|
||||||
{
|
{
|
||||||
Image* image = frame->GetImage();
|
Image* image = frame->GetImage();
|
||||||
FunctionDebugInfo* function = frame->Function();
|
FunctionInstance* function = frame->Function();
|
||||||
if (image == NULL && function == NULL) {
|
if (image == NULL && function == NULL) {
|
||||||
value.SetTo("?", B_VARIANT_DONT_COPY_DATA);
|
value.SetTo("?", B_VARIANT_DONT_COPY_DATA);
|
||||||
return true;
|
return true;
|
||||||
|
@ -215,7 +215,7 @@ TeamWindow::StackFrameSelectionChanged(StackFrame* frame)
|
|||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
TeamWindow::FunctionSelectionChanged(FunctionDebugInfo* function)
|
TeamWindow::FunctionSelectionChanged(FunctionInstance* function)
|
||||||
{
|
{
|
||||||
_SetActiveFunction(function);
|
_SetActiveFunction(function);
|
||||||
}
|
}
|
||||||
@ -281,7 +281,7 @@ TeamWindow::UserBreakpointChanged(const TeamDebugModel::BreakpointEvent& event)
|
|||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
TeamWindow::FunctionSourceCodeChanged(FunctionDebugInfo* function)
|
TeamWindow::FunctionSourceCodeChanged(Function* function)
|
||||||
{
|
{
|
||||||
printf("TeamWindow::FunctionSourceCodeChanged(%p): source: %p, state: %d\n",
|
printf("TeamWindow::FunctionSourceCodeChanged(%p): source: %p, state: %d\n",
|
||||||
function, function->GetSourceCode(), function->SourceCodeState());
|
function, function->GetSourceCode(), function->SourceCodeState());
|
||||||
@ -469,15 +469,15 @@ TeamWindow::_SetActiveStackFrame(StackFrame* frame)
|
|||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
TeamWindow::_SetActiveFunction(FunctionDebugInfo* function)
|
TeamWindow::_SetActiveFunction(FunctionInstance* functionInstance)
|
||||||
{
|
{
|
||||||
if (function == fActiveFunction)
|
if (functionInstance == fActiveFunction)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
AutoLocker<TeamDebugModel> locker(fDebugModel);
|
AutoLocker<TeamDebugModel> locker(fDebugModel);
|
||||||
|
|
||||||
if (fActiveFunction != NULL) {
|
if (fActiveFunction != NULL) {
|
||||||
fActiveFunction->RemoveListener(this);
|
fActiveFunction->GetFunction()->RemoveListener(this);
|
||||||
fActiveFunction->RemoveReference();
|
fActiveFunction->RemoveReference();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -487,12 +487,12 @@ TeamWindow::_SetActiveFunction(FunctionDebugInfo* function)
|
|||||||
|
|
||||||
fActiveFunction = NULL;
|
fActiveFunction = NULL;
|
||||||
|
|
||||||
if (function != NULL) {
|
if (functionInstance != NULL) {
|
||||||
_SetActiveImage(fDebugModel->GetTeam()->ImageByAddress(
|
_SetActiveImage(fDebugModel->GetTeam()->ImageByAddress(
|
||||||
function->Address()));
|
functionInstance->Address()));
|
||||||
}
|
}
|
||||||
|
|
||||||
fActiveFunction = function;
|
fActiveFunction = functionInstance;
|
||||||
|
|
||||||
locker.Lock();
|
locker.Lock();
|
||||||
|
|
||||||
@ -501,13 +501,14 @@ TeamWindow::_SetActiveFunction(FunctionDebugInfo* function)
|
|||||||
|
|
||||||
if (fActiveFunction != NULL) {
|
if (fActiveFunction != NULL) {
|
||||||
fActiveFunction->AddReference();
|
fActiveFunction->AddReference();
|
||||||
fActiveFunction->AddListener(this);
|
fActiveFunction->GetFunction()->AddListener(this);
|
||||||
|
|
||||||
sourceCode = fActiveFunction->GetSourceCode();
|
Function* function = fActiveFunction->GetFunction();
|
||||||
|
sourceCode = function->GetSourceCode();
|
||||||
sourceCodeReference.SetTo(sourceCode);
|
sourceCodeReference.SetTo(sourceCode);
|
||||||
|
|
||||||
// If the source code is not loaded yet, request it.
|
// If the source code is not loaded yet, request it.
|
||||||
if (fActiveFunction->SourceCodeState() == FUNCTION_SOURCE_NOT_LOADED)
|
if (function->SourceCodeState() == FUNCTION_SOURCE_NOT_LOADED)
|
||||||
fListener->FunctionSourceCodeRequested(this, fActiveFunction);
|
fListener->FunctionSourceCodeRequested(this, fActiveFunction);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -522,8 +523,10 @@ TeamWindow::_SetActiveFunction(FunctionDebugInfo* function)
|
|||||||
void
|
void
|
||||||
TeamWindow::_SetActiveSourceCode(SourceCode* sourceCode)
|
TeamWindow::_SetActiveSourceCode(SourceCode* sourceCode)
|
||||||
{
|
{
|
||||||
if (sourceCode == fActiveSourceCode)
|
if (sourceCode == fActiveSourceCode) {
|
||||||
|
_ScrollToActiveFunction();
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (fActiveSourceCode != NULL)
|
if (fActiveSourceCode != NULL)
|
||||||
fActiveSourceCode->RemoveReference();
|
fActiveSourceCode->RemoveReference();
|
||||||
@ -535,16 +538,9 @@ TeamWindow::_SetActiveSourceCode(SourceCode* sourceCode)
|
|||||||
|
|
||||||
fSourceView->SetSourceCode(fActiveSourceCode);
|
fSourceView->SetSourceCode(fActiveSourceCode);
|
||||||
|
|
||||||
// Scroll to the active function, if it doesn't match the stack frame (i.e.
|
_ScrollToActiveFunction();
|
||||||
// has been selected manually).
|
|
||||||
if (fActiveFunction != NULL && fActiveSourceCode != NULL
|
|
||||||
&& (fActiveStackFrame == NULL
|
|
||||||
|| fActiveStackFrame->Function() != fActiveFunction)) {
|
|
||||||
fSourceView->ScrollToAddress(fActiveFunction->Address());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
TeamWindow::_UpdateCpuState()
|
TeamWindow::_UpdateCpuState()
|
||||||
{
|
{
|
||||||
@ -601,6 +597,19 @@ TeamWindow::_UpdateRunButtons()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TeamWindow::_ScrollToActiveFunction()
|
||||||
|
{
|
||||||
|
// Scroll to the active function, if it doesn't match the stack frame (i.e.
|
||||||
|
// has been selected manually).
|
||||||
|
if (fActiveFunction != NULL && fActiveSourceCode != NULL
|
||||||
|
&& (fActiveStackFrame == NULL
|
||||||
|
|| fActiveStackFrame->Function() != fActiveFunction)) {
|
||||||
|
fSourceView->ScrollToAddress(fActiveFunction->Address());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
TeamWindow::_HandleThreadStateChanged(thread_id threadID)
|
TeamWindow::_HandleThreadStateChanged(thread_id threadID)
|
||||||
{
|
{
|
||||||
@ -693,7 +702,7 @@ TeamWindow::_HandleSourceCodeChanged()
|
|||||||
// get a reference to the source code
|
// get a reference to the source code
|
||||||
AutoLocker<TeamDebugModel> locker(fDebugModel);
|
AutoLocker<TeamDebugModel> locker(fDebugModel);
|
||||||
|
|
||||||
SourceCode* sourceCode = fActiveFunction->GetSourceCode();
|
SourceCode* sourceCode = fActiveFunction->GetFunction()->GetSourceCode();
|
||||||
Reference<SourceCode> sourceCodeReference(sourceCode);
|
Reference<SourceCode> sourceCodeReference(sourceCode);
|
||||||
|
|
||||||
locker.Unlock();
|
locker.Unlock();
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
#include <Window.h>
|
#include <Window.h>
|
||||||
|
|
||||||
#include "SourceView.h"
|
#include "SourceView.h"
|
||||||
#include "FunctionDebugInfo.h"
|
#include "Function.h"
|
||||||
#include "ImageFunctionsView.h"
|
#include "ImageFunctionsView.h"
|
||||||
#include "ImageListView.h"
|
#include "ImageListView.h"
|
||||||
#include "StackTraceView.h"
|
#include "StackTraceView.h"
|
||||||
@ -20,7 +20,6 @@
|
|||||||
|
|
||||||
class BButton;
|
class BButton;
|
||||||
class BTabView;
|
class BTabView;
|
||||||
class FunctionDebugInfo;
|
|
||||||
class Image;
|
class Image;
|
||||||
class RegisterView;
|
class RegisterView;
|
||||||
class SourceCode;
|
class SourceCode;
|
||||||
@ -30,7 +29,7 @@ class StackFrame;
|
|||||||
class TeamWindow : public BWindow, ThreadListView::Listener,
|
class TeamWindow : public BWindow, ThreadListView::Listener,
|
||||||
ImageListView::Listener, StackTraceView::Listener,
|
ImageListView::Listener, StackTraceView::Listener,
|
||||||
ImageFunctionsView::Listener, SourceView::Listener, Team::Listener,
|
ImageFunctionsView::Listener, SourceView::Listener, Team::Listener,
|
||||||
TeamDebugModel::Listener, FunctionDebugInfo::Listener {
|
TeamDebugModel::Listener, Function::Listener {
|
||||||
public:
|
public:
|
||||||
class Listener;
|
class Listener;
|
||||||
|
|
||||||
@ -58,7 +57,7 @@ private:
|
|||||||
|
|
||||||
// ImageFunctionsView::Listener
|
// ImageFunctionsView::Listener
|
||||||
virtual void FunctionSelectionChanged(
|
virtual void FunctionSelectionChanged(
|
||||||
FunctionDebugInfo* function);
|
FunctionInstance* function);
|
||||||
|
|
||||||
// SourceView::Listener
|
// SourceView::Listener
|
||||||
virtual void SetBreakpointRequested(target_addr_t address,
|
virtual void SetBreakpointRequested(target_addr_t address,
|
||||||
@ -80,9 +79,8 @@ private:
|
|||||||
const TeamDebugModel::BreakpointEvent&
|
const TeamDebugModel::BreakpointEvent&
|
||||||
event);
|
event);
|
||||||
|
|
||||||
// FunctionDebugInfo::Listener
|
// Function::Listener
|
||||||
virtual void FunctionSourceCodeChanged(
|
virtual void FunctionSourceCodeChanged(Function* function);
|
||||||
FunctionDebugInfo* function);
|
|
||||||
|
|
||||||
void _Init();
|
void _Init();
|
||||||
|
|
||||||
@ -90,10 +88,11 @@ private:
|
|||||||
void _SetActiveImage(Image* image);
|
void _SetActiveImage(Image* image);
|
||||||
void _SetActiveStackTrace(StackTrace* stackTrace);
|
void _SetActiveStackTrace(StackTrace* stackTrace);
|
||||||
void _SetActiveStackFrame(StackFrame* frame);
|
void _SetActiveStackFrame(StackFrame* frame);
|
||||||
void _SetActiveFunction(FunctionDebugInfo* function);
|
void _SetActiveFunction(FunctionInstance* function);
|
||||||
void _SetActiveSourceCode(SourceCode* sourceCode);
|
void _SetActiveSourceCode(SourceCode* sourceCode);
|
||||||
void _UpdateCpuState();
|
void _UpdateCpuState();
|
||||||
void _UpdateRunButtons();
|
void _UpdateRunButtons();
|
||||||
|
void _ScrollToActiveFunction();
|
||||||
|
|
||||||
void _HandleThreadStateChanged(thread_id threadID);
|
void _HandleThreadStateChanged(thread_id threadID);
|
||||||
void _HandleCpuStateChanged(thread_id threadID);
|
void _HandleCpuStateChanged(thread_id threadID);
|
||||||
@ -109,7 +108,7 @@ private:
|
|||||||
Image* fActiveImage;
|
Image* fActiveImage;
|
||||||
StackTrace* fActiveStackTrace;
|
StackTrace* fActiveStackTrace;
|
||||||
StackFrame* fActiveStackFrame;
|
StackFrame* fActiveStackFrame;
|
||||||
FunctionDebugInfo* fActiveFunction;
|
FunctionInstance* fActiveFunction;
|
||||||
SourceCode* fActiveSourceCode;
|
SourceCode* fActiveSourceCode;
|
||||||
Listener* fListener;
|
Listener* fListener;
|
||||||
BTabView* fTabView;
|
BTabView* fTabView;
|
||||||
@ -132,7 +131,7 @@ public:
|
|||||||
virtual ~Listener();
|
virtual ~Listener();
|
||||||
|
|
||||||
virtual void FunctionSourceCodeRequested(TeamWindow* window,
|
virtual void FunctionSourceCodeRequested(TeamWindow* window,
|
||||||
FunctionDebugInfo* function) = 0;
|
FunctionInstance* function) = 0;
|
||||||
virtual void ImageDebugInfoRequested(TeamWindow* window,
|
virtual void ImageDebugInfoRequested(TeamWindow* window,
|
||||||
Image* image) = 0;
|
Image* image) = 0;
|
||||||
virtual void ThreadActionRequested(TeamWindow* window,
|
virtual void ThreadActionRequested(TeamWindow* window,
|
||||||
|
@ -21,7 +21,6 @@ Breakpoint::Breakpoint(Image* image, target_addr_t address)
|
|||||||
:
|
:
|
||||||
fAddress(address),
|
fAddress(address),
|
||||||
fImage(image),
|
fImage(image),
|
||||||
fUserState(USER_BREAKPOINT_NONE),
|
|
||||||
fInstalled(false)
|
fInstalled(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -32,13 +31,6 @@ Breakpoint::~Breakpoint()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
Breakpoint::SetUserState(user_breakpoint_state state)
|
|
||||||
{
|
|
||||||
fUserState = state;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Breakpoint::SetInstalled(bool installed)
|
Breakpoint::SetInstalled(bool installed)
|
||||||
{
|
{
|
||||||
@ -49,14 +41,45 @@ Breakpoint::SetInstalled(bool installed)
|
|||||||
bool
|
bool
|
||||||
Breakpoint::ShouldBeInstalled() const
|
Breakpoint::ShouldBeInstalled() const
|
||||||
{
|
{
|
||||||
return fUserState == USER_BREAKPOINT_ENABLED || !fClients.IsEmpty();
|
if (!fClients.IsEmpty())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return !fClients.IsEmpty() || HasEnabledUserBreakpoint();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Breakpoint::IsUnused() const
|
Breakpoint::IsUnused() const
|
||||||
{
|
{
|
||||||
return fUserState == USER_BREAKPOINT_NONE && fClients.IsEmpty();
|
return fClients.IsEmpty() && fUserBreakpoints.IsEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
Breakpoint::HasEnabledUserBreakpoint() const
|
||||||
|
{
|
||||||
|
for (UserBreakpointInstanceList::ConstIterator it
|
||||||
|
= fUserBreakpoints.GetIterator();
|
||||||
|
UserBreakpointInstance* instance = it.Next();) {
|
||||||
|
if (instance->GetUserBreakpoint()->IsEnabled())
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Breakpoint::AddUserBreakpoint(UserBreakpointInstance* instance)
|
||||||
|
{
|
||||||
|
fUserBreakpoints.Add(instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Breakpoint::RemoveUserBreakpoint(UserBreakpointInstance* instance)
|
||||||
|
{
|
||||||
|
fUserBreakpoints.Remove(instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -5,17 +5,7 @@
|
|||||||
#ifndef BREAKPOINT_H
|
#ifndef BREAKPOINT_H
|
||||||
#define BREAKPOINT_H
|
#define BREAKPOINT_H
|
||||||
|
|
||||||
#include <ObjectList.h>
|
#include "UserBreakpoint.h"
|
||||||
#include <Referenceable.h>
|
|
||||||
|
|
||||||
#include "Types.h"
|
|
||||||
|
|
||||||
|
|
||||||
enum user_breakpoint_state {
|
|
||||||
USER_BREAKPOINT_NONE,
|
|
||||||
USER_BREAKPOINT_ENABLED,
|
|
||||||
USER_BREAKPOINT_DISABLED
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class Image;
|
class Image;
|
||||||
@ -35,14 +25,22 @@ public:
|
|||||||
Image* GetImage() const { return fImage; }
|
Image* GetImage() const { return fImage; }
|
||||||
target_addr_t Address() const { return fAddress; }
|
target_addr_t Address() const { return fAddress; }
|
||||||
|
|
||||||
user_breakpoint_state UserState() const { return fUserState; }
|
|
||||||
void SetUserState(user_breakpoint_state state);
|
|
||||||
|
|
||||||
bool IsInstalled() const { return fInstalled; }
|
bool IsInstalled() const { return fInstalled; }
|
||||||
void SetInstalled(bool installed);
|
void SetInstalled(bool installed);
|
||||||
|
|
||||||
bool ShouldBeInstalled() const;
|
bool ShouldBeInstalled() const;
|
||||||
bool IsUnused() const;
|
bool IsUnused() const;
|
||||||
|
bool HasEnabledUserBreakpoint() const;
|
||||||
|
|
||||||
|
UserBreakpointInstance* FirstUserBreakpoint() const
|
||||||
|
{ return fUserBreakpoints.Head(); }
|
||||||
|
UserBreakpointInstance* LastUserBreakpoint() const
|
||||||
|
{ return fUserBreakpoints.Tail(); }
|
||||||
|
|
||||||
|
void AddUserBreakpoint(
|
||||||
|
UserBreakpointInstance* instance);
|
||||||
|
void RemoveUserBreakpoint(
|
||||||
|
UserBreakpointInstance* instance);
|
||||||
|
|
||||||
bool AddClient(BreakpointClient* client);
|
bool AddClient(BreakpointClient* client);
|
||||||
void RemoveClient(BreakpointClient* client);
|
void RemoveClient(BreakpointClient* client);
|
||||||
@ -59,8 +57,8 @@ private:
|
|||||||
private:
|
private:
|
||||||
target_addr_t fAddress;
|
target_addr_t fAddress;
|
||||||
Image* fImage;
|
Image* fImage;
|
||||||
|
UserBreakpointInstanceList fUserBreakpoints;
|
||||||
ClientList fClients;
|
ClientList fClients;
|
||||||
user_breakpoint_state fUserState;
|
|
||||||
bool fInstalled;
|
bool fInstalled;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -57,20 +57,6 @@ DisassembledCode::LineAt(int32 index) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int32
|
|
||||||
DisassembledCode::CountStatements() const
|
|
||||||
{
|
|
||||||
return fStatements.CountItems();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Statement*
|
|
||||||
DisassembledCode::StatementAt(int32 index) const
|
|
||||||
{
|
|
||||||
return fStatements.ItemAt(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Statement*
|
Statement*
|
||||||
DisassembledCode::StatementAtLine(int32 index) const
|
DisassembledCode::StatementAtLine(int32 index) const
|
||||||
{
|
{
|
||||||
@ -79,25 +65,25 @@ DisassembledCode::StatementAtLine(int32 index) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Statement*
|
//Statement*
|
||||||
DisassembledCode::StatementAtAddress(target_addr_t address) const
|
//DisassembledCode::StatementAtAddress(target_addr_t address) const
|
||||||
{
|
//{
|
||||||
return fStatements.BinarySearchByKey(address, &_CompareAddressStatement);
|
// return fStatements.BinarySearchByKey(address, &_CompareAddressStatement);
|
||||||
}
|
//}
|
||||||
|
|
||||||
|
|
||||||
TargetAddressRange
|
//TargetAddressRange
|
||||||
DisassembledCode::StatementAddressRange() const
|
//DisassembledCode::StatementAddressRange() const
|
||||||
{
|
//{
|
||||||
if (fStatements.IsEmpty())
|
// if (fStatements.IsEmpty())
|
||||||
return TargetAddressRange();
|
// return TargetAddressRange();
|
||||||
|
//
|
||||||
ContiguousStatement* first = fStatements.ItemAt(0);
|
// ContiguousStatement* first = fStatements.ItemAt(0);
|
||||||
ContiguousStatement* last
|
// ContiguousStatement* last
|
||||||
= fStatements.ItemAt(fStatements.CountItems() - 1);
|
// = fStatements.ItemAt(fStatements.CountItems() - 1);
|
||||||
return TargetAddressRange(first->AddressRange().Start(),
|
// return TargetAddressRange(first->AddressRange().Start(),
|
||||||
last->AddressRange().End());
|
// last->AddressRange().End());
|
||||||
}
|
//}
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@ -109,13 +95,12 @@ DisassembledCode::AddCommentLine(const BString& line)
|
|||||||
|
|
||||||
bool
|
bool
|
||||||
DisassembledCode::AddInstructionLine(const BString& line, target_addr_t address,
|
DisassembledCode::AddInstructionLine(const BString& line, target_addr_t address,
|
||||||
target_size_t size, bool breakpointAllowed)
|
target_size_t size)
|
||||||
{
|
{
|
||||||
int32 lineIndex = fLines.CountItems();
|
int32 lineIndex = fLines.CountItems();
|
||||||
|
|
||||||
ContiguousStatement* statement = new(std::nothrow) ContiguousStatement(
|
ContiguousStatement* statement = new(std::nothrow) ContiguousStatement(
|
||||||
SourceLocation(lineIndex), SourceLocation(lineIndex + 1),
|
SourceLocation(lineIndex), TargetAddressRange(address, size));
|
||||||
TargetAddressRange(address, size), breakpointAllowed);
|
|
||||||
if (statement == NULL)
|
if (statement == NULL)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -22,18 +22,15 @@ public:
|
|||||||
virtual int32 CountLines() const;
|
virtual int32 CountLines() const;
|
||||||
virtual const char* LineAt(int32 index) const;
|
virtual const char* LineAt(int32 index) const;
|
||||||
|
|
||||||
virtual int32 CountStatements() const;
|
|
||||||
virtual Statement* StatementAt(int32 index) const;
|
|
||||||
virtual Statement* StatementAtLine(int32 index) const;
|
virtual Statement* StatementAtLine(int32 index) const;
|
||||||
virtual Statement* StatementAtAddress(target_addr_t address) const;
|
// Statement* StatementAtAddress(target_addr_t address) const;
|
||||||
|
|
||||||
virtual TargetAddressRange StatementAddressRange() const;
|
// TargetAddressRange StatementAddressRange() const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool AddCommentLine(const BString& line);
|
bool AddCommentLine(const BString& line);
|
||||||
bool AddInstructionLine(const BString& line,
|
bool AddInstructionLine(const BString& line,
|
||||||
target_addr_t address, target_size_t size,
|
target_addr_t address, target_size_t size);
|
||||||
bool breakpointAllowed);
|
|
||||||
// instructions must be added in
|
// instructions must be added in
|
||||||
// ascending address order
|
// ascending address order
|
||||||
|
|
||||||
|
@ -78,20 +78,6 @@ FileSourceCode::LineAt(int32 index) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int32
|
|
||||||
FileSourceCode::CountStatements() const
|
|
||||||
{
|
|
||||||
return fStatements.CountItems();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Statement*
|
|
||||||
FileSourceCode::StatementAt(int32 index) const
|
|
||||||
{
|
|
||||||
return fStatements.ItemAt(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Statement*
|
Statement*
|
||||||
FileSourceCode::StatementAtLine(int32 index) const
|
FileSourceCode::StatementAtLine(int32 index) const
|
||||||
{
|
{
|
||||||
@ -99,25 +85,25 @@ FileSourceCode::StatementAtLine(int32 index) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Statement*
|
//Statement*
|
||||||
FileSourceCode::StatementAtAddress(target_addr_t address) const
|
//FileSourceCode::StatementAtAddress(target_addr_t address) const
|
||||||
{
|
//{
|
||||||
return fStatements.BinarySearchByKey(address, &_CompareAddressStatement);
|
// return fStatements.BinarySearchByKey(address, &_CompareAddressStatement);
|
||||||
}
|
//}
|
||||||
|
|
||||||
|
|
||||||
TargetAddressRange
|
//TargetAddressRange
|
||||||
FileSourceCode::StatementAddressRange() const
|
//FileSourceCode::StatementAddressRange() const
|
||||||
{
|
//{
|
||||||
if (fStatements.IsEmpty())
|
// if (fStatements.IsEmpty())
|
||||||
return TargetAddressRange();
|
// return TargetAddressRange();
|
||||||
|
//
|
||||||
ContiguousStatement* first = fStatements.ItemAt(0);
|
// ContiguousStatement* first = fStatements.ItemAt(0);
|
||||||
ContiguousStatement* last
|
// ContiguousStatement* last
|
||||||
= fStatements.ItemAt(fStatements.CountItems() - 1);
|
// = fStatements.ItemAt(fStatements.CountItems() - 1);
|
||||||
return TargetAddressRange(first->AddressRange().Start(),
|
// return TargetAddressRange(first->AddressRange().Start(),
|
||||||
last->AddressRange().End());
|
// last->AddressRange().End());
|
||||||
}
|
//}
|
||||||
|
|
||||||
|
|
||||||
/*static*/ int
|
/*static*/ int
|
||||||
|
@ -25,12 +25,10 @@ public:
|
|||||||
virtual int32 CountLines() const;
|
virtual int32 CountLines() const;
|
||||||
virtual const char* LineAt(int32 index) const;
|
virtual const char* LineAt(int32 index) const;
|
||||||
|
|
||||||
virtual int32 CountStatements() const;
|
|
||||||
virtual Statement* StatementAt(int32 index) const;
|
|
||||||
virtual Statement* StatementAtLine(int32 index) const;
|
virtual Statement* StatementAtLine(int32 index) const;
|
||||||
virtual Statement* StatementAtAddress(target_addr_t address) const;
|
// Statement* StatementAtAddress(target_addr_t address) const;
|
||||||
|
|
||||||
virtual TargetAddressRange StatementAddressRange() const;
|
// virtual TargetAddressRange StatementAddressRange() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef BObjectList<ContiguousStatement> StatementList;
|
typedef BObjectList<ContiguousStatement> StatementList;
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include "ImageDebugInfo.h"
|
#include "ImageDebugInfo.h"
|
||||||
#include "LocatableFile.h"
|
#include "LocatableFile.h"
|
||||||
#include "Team.h"
|
#include "Team.h"
|
||||||
|
#include "TeamDebugInfo.h"
|
||||||
|
|
||||||
|
|
||||||
Image::Image(Team* team,const ImageInfo& imageInfo, LocatableFile* imageFile)
|
Image::Image(Team* team,const ImageInfo& imageInfo, LocatableFile* imageFile)
|
||||||
@ -49,22 +50,34 @@ Image::ContainsAddress(target_addr_t address) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
status_t
|
||||||
Image::SetImageDebugInfo(ImageDebugInfo* debugInfo,
|
Image::SetImageDebugInfo(ImageDebugInfo* debugInfo,
|
||||||
image_debug_info_state state)
|
image_debug_info_state state)
|
||||||
{
|
{
|
||||||
if (debugInfo == fDebugInfo && state == fDebugInfoState)
|
if (debugInfo == fDebugInfo && state == fDebugInfoState)
|
||||||
return;
|
return B_OK;
|
||||||
|
|
||||||
if (fDebugInfo != NULL)
|
if (fDebugInfo != NULL) {
|
||||||
|
fTeam->DebugInfo()->RemoveImageDebugInfo(fDebugInfo);
|
||||||
fDebugInfo->RemoveReference();
|
fDebugInfo->RemoveReference();
|
||||||
|
}
|
||||||
|
|
||||||
fDebugInfo = debugInfo;
|
fDebugInfo = debugInfo;
|
||||||
fDebugInfoState = state;
|
fDebugInfoState = state;
|
||||||
|
|
||||||
if (fDebugInfo != NULL)
|
status_t error = B_OK;
|
||||||
fDebugInfo->AddReference();
|
if (fDebugInfo != NULL) {
|
||||||
|
error = fTeam->DebugInfo()->AddImageDebugInfo(fDebugInfo);
|
||||||
|
if (error == B_OK) {
|
||||||
|
fDebugInfo->AddReference();
|
||||||
|
} else {
|
||||||
|
fDebugInfo = NULL;
|
||||||
|
fDebugInfoState = IMAGE_DEBUG_INFO_UNAVAILABLE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// notify listeners
|
// notify listeners
|
||||||
fTeam->NotifyImageDebugInfoChanged(this);
|
fTeam->NotifyImageDebugInfoChanged(this);
|
||||||
|
|
||||||
|
return error;
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,6 @@ public:
|
|||||||
|
|
||||||
status_t Init();
|
status_t Init();
|
||||||
|
|
||||||
|
|
||||||
Team* GetTeam() const { return fTeam; }
|
Team* GetTeam() const { return fTeam; }
|
||||||
image_id ID() const { return fInfo.ImageID(); }
|
image_id ID() const { return fInfo.ImageID(); }
|
||||||
const char* Name() const { return fInfo.Name(); }
|
const char* Name() const { return fInfo.Name(); }
|
||||||
@ -48,7 +47,7 @@ public:
|
|||||||
ImageDebugInfo* GetImageDebugInfo() const { return fDebugInfo; }
|
ImageDebugInfo* GetImageDebugInfo() const { return fDebugInfo; }
|
||||||
image_debug_info_state ImageDebugInfoState() const
|
image_debug_info_state ImageDebugInfoState() const
|
||||||
{ return fDebugInfoState; }
|
{ return fDebugInfoState; }
|
||||||
void SetImageDebugInfo(ImageDebugInfo* debugInfo,
|
status_t SetImageDebugInfo(ImageDebugInfo* debugInfo,
|
||||||
image_debug_info_state state);
|
image_debug_info_state state);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -20,13 +20,7 @@ public:
|
|||||||
virtual int32 CountLines() const = 0;
|
virtual int32 CountLines() const = 0;
|
||||||
virtual const char* LineAt(int32 index) const = 0;
|
virtual const char* LineAt(int32 index) const = 0;
|
||||||
|
|
||||||
virtual int32 CountStatements() const = 0;
|
|
||||||
virtual Statement* StatementAt(int32 index) const = 0;
|
|
||||||
virtual Statement* StatementAtLine(int32 index) const = 0;
|
virtual Statement* StatementAtLine(int32 index) const = 0;
|
||||||
virtual Statement* StatementAtAddress(target_addr_t address)
|
|
||||||
const = 0;
|
|
||||||
|
|
||||||
virtual TargetAddressRange StatementAddressRange() const = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
#include "StackFrame.h"
|
#include "StackFrame.h"
|
||||||
|
|
||||||
#include "CpuState.h"
|
#include "CpuState.h"
|
||||||
#include "FunctionDebugInfo.h"
|
#include "FunctionInstance.h"
|
||||||
#include "Image.h"
|
#include "Image.h"
|
||||||
|
|
||||||
|
|
||||||
@ -57,7 +57,7 @@ StackFrame::SetImage(Image* image)
|
|||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
StackFrame::SetFunction(FunctionDebugInfo* function)
|
StackFrame::SetFunction(FunctionInstance* function)
|
||||||
{
|
{
|
||||||
if (fFunction != NULL)
|
if (fFunction != NULL)
|
||||||
fFunction->RemoveReference();
|
fFunction->RemoveReference();
|
||||||
|
@ -22,7 +22,7 @@ enum stack_frame_type {
|
|||||||
|
|
||||||
class CpuState;
|
class CpuState;
|
||||||
class Image;
|
class Image;
|
||||||
class FunctionDebugInfo;
|
class FunctionInstance;
|
||||||
|
|
||||||
|
|
||||||
class StackFrame : public Referenceable {
|
class StackFrame : public Referenceable {
|
||||||
@ -46,8 +46,8 @@ public:
|
|||||||
Image* GetImage() const { return fImage; }
|
Image* GetImage() const { return fImage; }
|
||||||
void SetImage(Image* image);
|
void SetImage(Image* image);
|
||||||
|
|
||||||
FunctionDebugInfo* Function() const { return fFunction; }
|
FunctionInstance* Function() const { return fFunction; }
|
||||||
void SetFunction(FunctionDebugInfo* function);
|
void SetFunction(FunctionInstance* function);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
stack_frame_type fType;
|
stack_frame_type fType;
|
||||||
@ -56,7 +56,7 @@ private:
|
|||||||
target_addr_t fInstructionPointer;
|
target_addr_t fInstructionPointer;
|
||||||
target_addr_t fReturnAddress;
|
target_addr_t fReturnAddress;
|
||||||
Image* fImage;
|
Image* fImage;
|
||||||
FunctionDebugInfo* fFunction;
|
FunctionInstance* fFunction;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -17,12 +17,9 @@ Statement::~Statement()
|
|||||||
// #pragma mark - AbstractStatement
|
// #pragma mark - AbstractStatement
|
||||||
|
|
||||||
|
|
||||||
AbstractStatement::AbstractStatement(const SourceLocation& start,
|
AbstractStatement::AbstractStatement(const SourceLocation& start)
|
||||||
const SourceLocation& end, bool breakpointAllowed)
|
|
||||||
:
|
:
|
||||||
fStart(start),
|
fStart(start)
|
||||||
fEnd(end),
|
|
||||||
fBreakpointAllowed(breakpointAllowed)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,28 +31,13 @@ AbstractStatement::StartSourceLocation() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
SourceLocation
|
|
||||||
AbstractStatement::EndSourceLocation() const
|
|
||||||
{
|
|
||||||
return fEnd;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool
|
|
||||||
AbstractStatement::BreakpointAllowed() const
|
|
||||||
{
|
|
||||||
return fBreakpointAllowed;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark - ContiguousStatement
|
// #pragma mark - ContiguousStatement
|
||||||
|
|
||||||
|
|
||||||
ContiguousStatement::ContiguousStatement(const SourceLocation& start,
|
ContiguousStatement::ContiguousStatement(const SourceLocation& start,
|
||||||
const SourceLocation& end, const TargetAddressRange& range,
|
const TargetAddressRange& range)
|
||||||
bool breakpointAllowed)
|
|
||||||
:
|
:
|
||||||
AbstractStatement(start, end, breakpointAllowed),
|
AbstractStatement(start),
|
||||||
fRange(range)
|
fRange(range)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,6 @@ public:
|
|||||||
virtual ~Statement();
|
virtual ~Statement();
|
||||||
|
|
||||||
virtual SourceLocation StartSourceLocation() const = 0;
|
virtual SourceLocation StartSourceLocation() const = 0;
|
||||||
virtual SourceLocation EndSourceLocation() const = 0;
|
|
||||||
|
|
||||||
virtual TargetAddressRange CoveringAddressRange() const = 0;
|
virtual TargetAddressRange CoveringAddressRange() const = 0;
|
||||||
|
|
||||||
@ -26,35 +25,24 @@ public:
|
|||||||
|
|
||||||
virtual bool ContainsAddress(target_addr_t address)
|
virtual bool ContainsAddress(target_addr_t address)
|
||||||
const = 0;
|
const = 0;
|
||||||
|
|
||||||
virtual bool BreakpointAllowed() const = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class AbstractStatement : public Statement {
|
class AbstractStatement : public Statement {
|
||||||
public:
|
public:
|
||||||
AbstractStatement(const SourceLocation& start,
|
AbstractStatement(const SourceLocation& start);
|
||||||
const SourceLocation& end,
|
|
||||||
bool breakpointAllowed);
|
|
||||||
|
|
||||||
virtual SourceLocation StartSourceLocation() const;
|
virtual SourceLocation StartSourceLocation() const;
|
||||||
virtual SourceLocation EndSourceLocation() const;
|
|
||||||
|
|
||||||
virtual bool BreakpointAllowed() const;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
SourceLocation fStart;
|
SourceLocation fStart;
|
||||||
SourceLocation fEnd;
|
|
||||||
bool fBreakpointAllowed;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class ContiguousStatement : public AbstractStatement {
|
class ContiguousStatement : public AbstractStatement {
|
||||||
public:
|
public:
|
||||||
ContiguousStatement(const SourceLocation& start,
|
ContiguousStatement(const SourceLocation& start,
|
||||||
const SourceLocation& end,
|
const TargetAddressRange& range);
|
||||||
const TargetAddressRange& range,
|
|
||||||
bool breakpointAllowed);
|
|
||||||
|
|
||||||
const TargetAddressRange& AddressRange() const
|
const TargetAddressRange& AddressRange() const
|
||||||
{ return fRange; }
|
{ return fRange; }
|
||||||
|
@ -9,6 +9,9 @@
|
|||||||
|
|
||||||
#include <AutoLocker.h>
|
#include <AutoLocker.h>
|
||||||
|
|
||||||
|
#include "FunctionInstance.h"
|
||||||
|
#include "ImageDebugInfo.h"
|
||||||
|
#include "SpecificImageDebugInfo.h"
|
||||||
#include "TeamDebugInfo.h"
|
#include "TeamDebugInfo.h"
|
||||||
|
|
||||||
|
|
||||||
@ -201,6 +204,39 @@ Team::Images() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
Team::GetStatementAtAddress(target_addr_t address, FunctionInstance*& _function,
|
||||||
|
Statement*& _statement)
|
||||||
|
{
|
||||||
|
// get the image at the address
|
||||||
|
Image* image = ImageByAddress(address);
|
||||||
|
if (image == NULL)
|
||||||
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
|
||||||
|
ImageDebugInfo* imageDebugInfo = image->GetImageDebugInfo();
|
||||||
|
if (imageDebugInfo == NULL)
|
||||||
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
|
||||||
|
// get the function
|
||||||
|
FunctionInstance* functionInstance
|
||||||
|
= imageDebugInfo->FunctionAtAddress(address);
|
||||||
|
if (functionInstance == NULL)
|
||||||
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
|
||||||
|
// get the statement from the image debug info
|
||||||
|
FunctionDebugInfo* functionDebugInfo
|
||||||
|
= functionInstance->GetFunctionDebugInfo();
|
||||||
|
status_t error = functionDebugInfo->GetSpecificImageDebugInfo()
|
||||||
|
->GetStatement(functionDebugInfo, address, _statement);
|
||||||
|
// TODO: Provide the corresponding SourceCode, if available!
|
||||||
|
if (error != B_OK)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
_function = functionInstance;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Team::AddListener(Listener* listener)
|
Team::AddListener(Listener* listener)
|
||||||
{
|
{
|
||||||
|
@ -28,7 +28,9 @@ enum {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class FunctionInstance;
|
||||||
class LocatableFile;
|
class LocatableFile;
|
||||||
|
class Statement;
|
||||||
class TeamDebugInfo;
|
class TeamDebugInfo;
|
||||||
|
|
||||||
|
|
||||||
@ -68,6 +70,13 @@ public:
|
|||||||
Image* ImageByAddress(target_addr_t address) const;
|
Image* ImageByAddress(target_addr_t address) const;
|
||||||
const ImageList& Images() const;
|
const ImageList& Images() const;
|
||||||
|
|
||||||
|
status_t GetStatementAtAddress(target_addr_t address,
|
||||||
|
FunctionInstance*& _function,
|
||||||
|
Statement*& _statement);
|
||||||
|
// returns a reference to the statement,
|
||||||
|
// not to the functions instance, though,
|
||||||
|
// caller must lock
|
||||||
|
|
||||||
void AddListener(Listener* listener);
|
void AddListener(Listener* listener);
|
||||||
void RemoveListener(Listener* listener);
|
void RemoveListener(Listener* listener);
|
||||||
|
|
||||||
|
@ -10,6 +10,8 @@
|
|||||||
#include <AutoLocker.h>
|
#include <AutoLocker.h>
|
||||||
|
|
||||||
#include "Breakpoint.h"
|
#include "Breakpoint.h"
|
||||||
|
#include "Function.h"
|
||||||
|
#include "UserBreakpoint.h"
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark - BreakpointByAddressPredicate
|
// #pragma mark - BreakpointByAddressPredicate
|
||||||
@ -107,16 +109,36 @@ TeamDebugModel::BreakpointAtAddress(target_addr_t address) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//void
|
||||||
|
//TeamDebugModel::GetBreakpointsInAddressRange(TargetAddressRange range,
|
||||||
|
// BObjectList<Breakpoint>& breakpoints) const
|
||||||
|
//{
|
||||||
|
// int32 index = fBreakpoints.FindBinaryInsertionIndex(
|
||||||
|
// BreakpointByAddressPredicate(range.Start()));
|
||||||
|
// for (; Breakpoint* breakpoint = fBreakpoints.ItemAt(index); index++) {
|
||||||
|
// if (breakpoint->Address() > range.End())
|
||||||
|
// break;
|
||||||
|
// breakpoints.AddItem(breakpoint);
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
TeamDebugModel::GetBreakpointsInAddressRange(TargetAddressRange range,
|
TeamDebugModel::GetBreakpointsForSourceCode(SourceCode* sourceCode,
|
||||||
BObjectList<Breakpoint>& breakpoints) const
|
BObjectList<UserBreakpoint>& breakpoints) const
|
||||||
{
|
{
|
||||||
int32 index = fBreakpoints.FindBinaryInsertionIndex(
|
// TODO: This can probably be optimized. Maybe by registering the user
|
||||||
BreakpointByAddressPredicate(range.Start()));
|
// breakpoints with the team debug model and sorting them by source code.
|
||||||
for (; Breakpoint* breakpoint = fBreakpoints.ItemAt(index); index++) {
|
for (int32 i = 0; Breakpoint* breakpoint = fBreakpoints.ItemAt(i); i++) {
|
||||||
if (breakpoint->Address() > range.End())
|
UserBreakpointInstance* userBreakpointInstance
|
||||||
break;
|
= breakpoint->FirstUserBreakpoint();
|
||||||
breakpoints.AddItem(breakpoint);
|
if (userBreakpointInstance == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
UserBreakpoint* userBreakpoint
|
||||||
|
= userBreakpointInstance->GetUserBreakpoint();
|
||||||
|
if (userBreakpoint->GetFunction()->GetSourceCode() == sourceCode)
|
||||||
|
breakpoints.AddItem(userBreakpoint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,7 +22,9 @@ enum {
|
|||||||
|
|
||||||
class Architecture;
|
class Architecture;
|
||||||
class Breakpoint;
|
class Breakpoint;
|
||||||
|
class SourceCode;
|
||||||
class TeamMemory;
|
class TeamMemory;
|
||||||
|
class UserBreakpoint;
|
||||||
|
|
||||||
|
|
||||||
class TeamDebugModel {
|
class TeamDebugModel {
|
||||||
@ -56,9 +58,13 @@ public:
|
|||||||
Breakpoint* BreakpointAt(int32 index) const;
|
Breakpoint* BreakpointAt(int32 index) const;
|
||||||
Breakpoint* BreakpointAtAddress(
|
Breakpoint* BreakpointAtAddress(
|
||||||
target_addr_t address) const;
|
target_addr_t address) const;
|
||||||
void GetBreakpointsInAddressRange(
|
// void GetBreakpointsInAddressRange(
|
||||||
TargetAddressRange range,
|
// TargetAddressRange range,
|
||||||
BObjectList<Breakpoint>& breakpoints) const;
|
// BObjectList<Breakpoint>& breakpoints) const;
|
||||||
|
void GetBreakpointsForSourceCode(
|
||||||
|
SourceCode* sourceCode,
|
||||||
|
BObjectList<UserBreakpoint>& breakpoints)
|
||||||
|
const;
|
||||||
|
|
||||||
void AddListener(Listener* listener);
|
void AddListener(Listener* listener);
|
||||||
void RemoveListener(Listener* listener);
|
void RemoveListener(Listener* listener);
|
||||||
|
94
src/apps/debugger/model/UserBreakpoint.cpp
Normal file
94
src/apps/debugger/model/UserBreakpoint.cpp
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "UserBreakpoint.h"
|
||||||
|
|
||||||
|
#include "Function.h"
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - UserBreakpointInstance
|
||||||
|
|
||||||
|
|
||||||
|
UserBreakpointInstance::UserBreakpointInstance(UserBreakpoint* userBreakpoint,
|
||||||
|
target_addr_t address)
|
||||||
|
:
|
||||||
|
fAddress(address),
|
||||||
|
fUserBreakpoint(userBreakpoint),
|
||||||
|
fBreakpoint(NULL)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
UserBreakpointInstance::SetBreakpoint(Breakpoint* breakpoint)
|
||||||
|
{
|
||||||
|
fBreakpoint = breakpoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - UserBreakpoint
|
||||||
|
|
||||||
|
|
||||||
|
UserBreakpoint::UserBreakpoint(Function* function)
|
||||||
|
:
|
||||||
|
fFunction(function),
|
||||||
|
fValid(false),
|
||||||
|
fEnabled(false)
|
||||||
|
{
|
||||||
|
fFunction->AcquireReference();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
UserBreakpoint::~UserBreakpoint()
|
||||||
|
{
|
||||||
|
for (int32 i = 0; UserBreakpointInstance* instance = fInstances.ItemAt(i);
|
||||||
|
i++) {
|
||||||
|
delete instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
fFunction->ReleaseReference();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int32
|
||||||
|
UserBreakpoint::CountInstances() const
|
||||||
|
{
|
||||||
|
return fInstances.CountItems();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
UserBreakpointInstance*
|
||||||
|
UserBreakpoint::InstanceAt(int32 index) const
|
||||||
|
{
|
||||||
|
return fInstances.ItemAt(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
UserBreakpoint::AddInstance(UserBreakpointInstance* instance)
|
||||||
|
{
|
||||||
|
return fInstances.AddItem(instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
UserBreakpoint::RemoveInstance(UserBreakpointInstance* instance)
|
||||||
|
{
|
||||||
|
fInstances.RemoveItem(instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
UserBreakpoint::SetValid(bool valid)
|
||||||
|
{
|
||||||
|
fValid = valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
UserBreakpoint::SetEnabled(bool enabled)
|
||||||
|
{
|
||||||
|
fEnabled = enabled;
|
||||||
|
}
|
79
src/apps/debugger/model/UserBreakpoint.h
Normal file
79
src/apps/debugger/model/UserBreakpoint.h
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef USER_BREAKPOINT_H
|
||||||
|
#define USER_BREAKPOINT_H
|
||||||
|
|
||||||
|
#include <ObjectList.h>
|
||||||
|
#include <Referenceable.h>
|
||||||
|
#include <util/DoublyLinkedList.h>
|
||||||
|
|
||||||
|
#include "Types.h"
|
||||||
|
|
||||||
|
|
||||||
|
class Breakpoint;
|
||||||
|
class Function;
|
||||||
|
class UserBreakpoint;
|
||||||
|
|
||||||
|
|
||||||
|
class UserBreakpointInstance
|
||||||
|
: public DoublyLinkedListLinkImpl<UserBreakpointInstance> {
|
||||||
|
public:
|
||||||
|
UserBreakpointInstance(
|
||||||
|
UserBreakpoint* userBreakpoint,
|
||||||
|
target_addr_t address);
|
||||||
|
|
||||||
|
UserBreakpoint* GetUserBreakpoint() const
|
||||||
|
{ return fUserBreakpoint; }
|
||||||
|
target_addr_t Address() const { return fAddress; }
|
||||||
|
|
||||||
|
Breakpoint* GetBreakpoint() const { return fBreakpoint; }
|
||||||
|
void SetBreakpoint(Breakpoint* breakpoint);
|
||||||
|
|
||||||
|
private:
|
||||||
|
target_addr_t fAddress;
|
||||||
|
UserBreakpoint* fUserBreakpoint;
|
||||||
|
Breakpoint* fBreakpoint;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
typedef DoublyLinkedList<UserBreakpointInstance> UserBreakpointInstanceList;
|
||||||
|
|
||||||
|
|
||||||
|
class UserBreakpoint : public Referenceable {
|
||||||
|
public:
|
||||||
|
UserBreakpoint(Function* function);
|
||||||
|
~UserBreakpoint();
|
||||||
|
|
||||||
|
Function* GetFunction() const { return fFunction; }
|
||||||
|
|
||||||
|
int32 CountInstances() const;
|
||||||
|
UserBreakpointInstance* InstanceAt(int32 index) const;
|
||||||
|
|
||||||
|
// Note: After known to the BreakpointManager, those can only be
|
||||||
|
// invoked with the breakpoint manager lock held.
|
||||||
|
bool AddInstance(UserBreakpointInstance* instance);
|
||||||
|
void RemoveInstance(
|
||||||
|
UserBreakpointInstance* instance);
|
||||||
|
|
||||||
|
bool IsValid() const { return fValid; }
|
||||||
|
void SetValid(bool valid);
|
||||||
|
// BreakpointManager only
|
||||||
|
|
||||||
|
bool IsEnabled() const { return fEnabled; }
|
||||||
|
void SetEnabled(bool enabled);
|
||||||
|
// BreakpointManager only
|
||||||
|
|
||||||
|
private:
|
||||||
|
typedef BObjectList<UserBreakpointInstance> InstanceList;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Function* fFunction;
|
||||||
|
InstanceList fInstances;
|
||||||
|
bool fValid;
|
||||||
|
bool fEnabled;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // USER_BREAKPOINT_H
|
Loading…
Reference in New Issue
Block a user