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
|
||||
BreakpointManager::InstallUserBreakpoint(target_addr_t address,
|
||||
BreakpointManager::InstallUserBreakpoint(UserBreakpoint* userBreakpoint,
|
||||
bool enabled)
|
||||
{
|
||||
user_breakpoint_state state = enabled
|
||||
? USER_BREAKPOINT_ENABLED : USER_BREAKPOINT_DISABLED;
|
||||
|
||||
printf("BreakpointManager::InstallUserBreakpoint(%p, %d)\n", userBreakpoint, enabled);
|
||||
AutoLocker<BLocker> installLocker(fLock);
|
||||
AutoLocker<TeamDebugModel> modelLocker(fDebugModel);
|
||||
|
||||
// If there already is a breakpoint, it might already have the requested
|
||||
// state.
|
||||
Breakpoint* breakpoint = fDebugModel->BreakpointAtAddress(address);
|
||||
if (breakpoint != NULL && breakpoint->UserState() == state)
|
||||
bool oldEnabled = userBreakpoint->IsEnabled();
|
||||
if (userBreakpoint->IsValid() && enabled == oldEnabled)
|
||||
{
|
||||
printf(" user breakpoint already valid and with same enabled state\n");
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// create a breakpoint, if it doesn't exist yet
|
||||
// get/create the breakpoints for all instances
|
||||
printf(" creating breakpoints for breakpoint instances\n");
|
||||
status_t error = B_OK;
|
||||
for (int32 i = 0;
|
||||
UserBreakpointInstance* instance = userBreakpoint->InstanceAt(i); i++) {
|
||||
printf(" breakpoint instance %p\n", instance);
|
||||
if (instance->GetBreakpoint() != NULL)
|
||||
{
|
||||
printf(" -> already has breakpoint\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
target_addr_t address = instance->Address();
|
||||
Breakpoint* breakpoint = fDebugModel->BreakpointAtAddress(address);
|
||||
if (breakpoint == NULL) {
|
||||
printf(" -> no breakpoint at that address yet\n");
|
||||
Image* image = fDebugModel->GetTeam()->ImageByAddress(address);
|
||||
if (image == NULL)
|
||||
return B_BAD_ADDRESS;
|
||||
if (image == NULL) {
|
||||
printf(" -> no image at that address\n");
|
||||
error = B_BAD_ADDRESS;
|
||||
break;
|
||||
}
|
||||
|
||||
breakpoint = new(std::nothrow) Breakpoint(image, address);
|
||||
if (breakpoint == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
if (!fDebugModel->AddBreakpoint(breakpoint))
|
||||
return B_NO_MEMORY;
|
||||
if (breakpoint == NULL) {
|
||||
error = B_NO_MEMORY;
|
||||
break;
|
||||
}
|
||||
|
||||
user_breakpoint_state oldState = breakpoint->UserState();
|
||||
if (!fDebugModel->AddBreakpoint(breakpoint)) {
|
||||
error = B_NO_MEMORY;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// set the breakpoint state
|
||||
breakpoint->SetUserState(state);
|
||||
fDebugModel->NotifyUserBreakpointChanged(breakpoint);
|
||||
printf(" -> adding instance to breakpoint %p\n", breakpoint);
|
||||
breakpoint->AddUserBreakpoint(instance);
|
||||
instance->SetBreakpoint(breakpoint);
|
||||
}
|
||||
|
||||
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.
|
||||
// If everything looks good so far mark the user breakpoint according to
|
||||
// its new state.
|
||||
if (error == B_OK)
|
||||
userBreakpoint->SetEnabled(enabled);
|
||||
|
||||
bool install = breakpoint->ShouldBeInstalled();
|
||||
if (breakpoint->IsInstalled() == install)
|
||||
return B_OK;
|
||||
// notify user breakpoint listeners
|
||||
if (error == B_OK) {
|
||||
for (int32 i = 0;
|
||||
UserBreakpointInstance* instance = userBreakpoint->InstanceAt(i);
|
||||
i++) {
|
||||
fDebugModel->NotifyUserBreakpointChanged(instance->GetBreakpoint());
|
||||
}
|
||||
}
|
||||
|
||||
// The breakpoint needs to be installed/uninstalled.
|
||||
Reference<Breakpoint> breakpointReference(breakpoint);
|
||||
modelLocker.Unlock();
|
||||
|
||||
status_t error = install
|
||||
? fDebuggerInterface->InstallBreakpoint(address)
|
||||
: fDebuggerInterface->UninstallBreakpoint(address);
|
||||
|
||||
// Mark the breakpoint installed/uninstalled, if everything went fine.
|
||||
// install/uninstall the breakpoints as needed
|
||||
printf(" updating breakpoints\n");
|
||||
if (error == B_OK) {
|
||||
breakpoint->SetInstalled(install);
|
||||
return B_OK;
|
||||
for (int32 i = 0;
|
||||
UserBreakpointInstance* instance = userBreakpoint->InstanceAt(i);
|
||||
i++) {
|
||||
printf(" breakpoint instance %p\n", instance);
|
||||
error = _UpdateBreakpointInstallation(instance->GetBreakpoint());
|
||||
if (error != B_OK)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// revert on error
|
||||
installLocker. Unlock();
|
||||
if (error == B_OK) {
|
||||
printf(" success, marking user breakpoint valid\n");
|
||||
// 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()) {
|
||||
for (int32 i = 0; UserBreakpointInstance* instance
|
||||
= userBreakpoint->InstanceAt(i);
|
||||
i++) {
|
||||
Breakpoint* breakpoint = instance->GetBreakpoint();
|
||||
if (breakpoint == NULL)
|
||||
continue;
|
||||
|
||||
if (!userBreakpoint->IsValid()) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BreakpointManager::UninstallUserBreakpoint(target_addr_t address)
|
||||
BreakpointManager::UninstallUserBreakpoint(UserBreakpoint* userBreakpoint)
|
||||
{
|
||||
AutoLocker<BLocker> installLocker(fLock);
|
||||
AutoLocker<TeamDebugModel> modelLocker(fDebugModel);
|
||||
|
||||
Breakpoint* breakpoint = fDebugModel->BreakpointAtAddress(address);
|
||||
if (breakpoint == NULL || breakpoint->UserState() == USER_BREAKPOINT_NONE)
|
||||
if (!userBreakpoint->IsValid())
|
||||
return;
|
||||
|
||||
// set the breakpoint state
|
||||
breakpoint->SetUserState(USER_BREAKPOINT_NONE);
|
||||
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);
|
||||
userBreakpoint->SetValid(false);
|
||||
userBreakpoint->SetEnabled(false);
|
||||
|
||||
modelLocker.Unlock();
|
||||
|
||||
if (uninstall) {
|
||||
fDebuggerInterface->UninstallBreakpoint(address);
|
||||
breakpoint->SetInstalled(false);
|
||||
// uninstall the breakpoints as needed
|
||||
for (int32 i = 0;
|
||||
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,
|
||||
BreakpointClient* client)
|
||||
{
|
||||
AutoLocker<BLocker> installLocker(fLock);
|
||||
AutoLocker<TeamDebugModel> modelLocker(fDebugModel);
|
||||
|
||||
// create a breakpoint, if it doesn't exist yet
|
||||
@ -169,10 +241,6 @@ BreakpointManager::InstallTemporaryBreakpoint(target_addr_t address,
|
||||
// add the client
|
||||
status_t error;
|
||||
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())
|
||||
return B_OK;
|
||||
|
||||
@ -185,7 +253,6 @@ BreakpointManager::InstallTemporaryBreakpoint(target_addr_t address,
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
installLocker.Unlock();
|
||||
modelLocker.Lock();
|
||||
|
||||
breakpoint->RemoveClient(client);
|
||||
@ -204,6 +271,7 @@ void
|
||||
BreakpointManager::UninstallTemporaryBreakpoint(target_addr_t address,
|
||||
BreakpointClient* client)
|
||||
{
|
||||
AutoLocker<BLocker> installLocker(fLock);
|
||||
AutoLocker<TeamDebugModel> modelLocker(fDebugModel);
|
||||
|
||||
Breakpoint* breakpoint = fDebugModel->BreakpointAtAddress(address);
|
||||
@ -213,10 +281,6 @@ BreakpointManager::UninstallTemporaryBreakpoint(target_addr_t address,
|
||||
// remove the 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
|
||||
bool uninstall = !breakpoint->ShouldBeInstalled()
|
||||
&& breakpoint->IsInstalled();
|
||||
@ -233,3 +297,30 @@ BreakpointManager::UninstallTemporaryBreakpoint(target_addr_t address,
|
||||
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 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);
|
||||
void UninstallUserBreakpoint(target_addr_t address);
|
||||
void UninstallUserBreakpoint(
|
||||
UserBreakpoint* userBreakpoint);
|
||||
|
||||
status_t InstallTemporaryBreakpoint(
|
||||
target_addr_t address,
|
||||
@ -33,6 +39,11 @@ public:
|
||||
target_addr_t address,
|
||||
BreakpointClient* client);
|
||||
|
||||
private:
|
||||
status_t _UpdateBreakpointInstallation(
|
||||
Breakpoint* breakpoint);
|
||||
// fLock must be held
|
||||
|
||||
private:
|
||||
BLocker fLock; // used to synchronize un-/installing
|
||||
TeamDebugModel* fDebugModel;
|
||||
|
@ -56,7 +56,9 @@ Application Debugger :
|
||||
DwarfFunctionDebugInfo.cpp
|
||||
DwarfImageDebugInfo.cpp
|
||||
DwarfTeamDebugInfo.cpp
|
||||
Function.cpp
|
||||
FunctionDebugInfo.cpp
|
||||
FunctionInstance.cpp
|
||||
ImageDebugInfo.cpp
|
||||
ImageDebugInfoProvider.cpp
|
||||
SpecificImageDebugInfo.cpp
|
||||
@ -97,6 +99,7 @@ Application Debugger :
|
||||
StackTrace.cpp
|
||||
Statement.cpp
|
||||
SymbolInfo.cpp
|
||||
UserBreakpoint.cpp
|
||||
Team.cpp
|
||||
TeamDebugModel.cpp
|
||||
TeamMemory.cpp
|
||||
|
@ -12,7 +12,7 @@
|
||||
#include "Architecture.h"
|
||||
#include "CpuState.h"
|
||||
#include "DebuggerInterface.h"
|
||||
#include "FunctionDebugInfo.h"
|
||||
#include "Function.h"
|
||||
#include "Image.h"
|
||||
#include "ImageDebugInfo.h"
|
||||
#include "SourceCode.h"
|
||||
@ -258,7 +258,7 @@ LoadImageDebugInfoJob::Do()
|
||||
// set the result
|
||||
locker.Lock();
|
||||
if (error == B_OK) {
|
||||
fImage->SetImageDebugInfo(debugInfo, IMAGE_DEBUG_INFO_LOADED);
|
||||
error = fImage->SetImageDebugInfo(debugInfo, IMAGE_DEBUG_INFO_LOADED);
|
||||
debugInfo->RemoveReference();
|
||||
} else {
|
||||
fImage->SetImageDebugInfo(NULL, IMAGE_DEBUG_INFO_UNAVAILABLE);
|
||||
@ -319,7 +319,7 @@ LoadImageDebugInfoJob::ScheduleIfNecessary(Worker* worker, Image* image,
|
||||
|
||||
LoadSourceCodeJob::LoadSourceCodeJob(
|
||||
DebuggerInterface* debuggerInterface, Architecture* architecture,
|
||||
Team* team, FunctionDebugInfo* function)
|
||||
Team* team, Function* function)
|
||||
:
|
||||
fDebuggerInterface(debuggerInterface),
|
||||
fArchitecture(architecture),
|
||||
@ -346,13 +346,29 @@ LoadSourceCodeJob::Key() const
|
||||
status_t
|
||||
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
|
||||
SourceCode* sourceCode = NULL;
|
||||
status_t error = fFunction->GetSpecificImageDebugInfo()->LoadSourceCode(
|
||||
fFunction, sourceCode);
|
||||
if (error == B_OK) {
|
||||
error = functionDebugInfo->GetSpecificImageDebugInfo()->LoadSourceCode(
|
||||
functionDebugInfo, sourceCode);
|
||||
}
|
||||
|
||||
// set the result
|
||||
AutoLocker<Team> locker(fTeam);
|
||||
locker.Lock();
|
||||
if (error == B_OK) {
|
||||
fFunction->SetSourceCode(sourceCode, FUNCTION_SOURCE_LOADED);
|
||||
sourceCode->RemoveReference();
|
||||
|
@ -12,7 +12,7 @@
|
||||
class Architecture;
|
||||
class CpuState;
|
||||
class DebuggerInterface;
|
||||
class FunctionDebugInfo;
|
||||
class Function;
|
||||
class Image;
|
||||
class StackFrame;
|
||||
class Team;
|
||||
@ -112,8 +112,8 @@ class LoadSourceCodeJob : public Job {
|
||||
public:
|
||||
LoadSourceCodeJob(
|
||||
DebuggerInterface* debuggerInterface,
|
||||
Architecture* architecture,
|
||||
Team* team, FunctionDebugInfo* function);
|
||||
Architecture* architecture, Team* team,
|
||||
Function* function);
|
||||
virtual ~LoadSourceCodeJob();
|
||||
|
||||
virtual JobKey Key() const;
|
||||
@ -123,7 +123,7 @@ private:
|
||||
DebuggerInterface* fDebuggerInterface;
|
||||
Architecture* fArchitecture;
|
||||
Team* fTeam;
|
||||
FunctionDebugInfo* fFunction;
|
||||
Function* fFunction;
|
||||
};
|
||||
|
||||
|
||||
|
@ -21,11 +21,15 @@
|
||||
#include "CpuState.h"
|
||||
#include "DebuggerInterface.h"
|
||||
#include "FileManager.h"
|
||||
#include "Function.h"
|
||||
#include "ImageDebugInfo.h"
|
||||
#include "Jobs.h"
|
||||
#include "LocatableFile.h"
|
||||
#include "MessageCodes.h"
|
||||
#include "SymbolInfo.h"
|
||||
#include "SourceCode.h"
|
||||
#include "SpecificImageDebugInfo.h"
|
||||
#include "Statement.h"
|
||||
#include "SymbolInfo.h"
|
||||
#include "TeamDebugInfo.h"
|
||||
#include "TeamDebugModel.h"
|
||||
|
||||
@ -479,8 +483,10 @@ TeamDebugger::MessageReceived(BMessage* message)
|
||||
|
||||
void
|
||||
TeamDebugger::FunctionSourceCodeRequested(TeamWindow* window,
|
||||
FunctionDebugInfo* function)
|
||||
FunctionInstance* functionInstance)
|
||||
{
|
||||
Function* function = functionInstance->GetFunction();
|
||||
|
||||
// mark loading
|
||||
AutoLocker< ::Team> locker(fTeam);
|
||||
if (function->SourceCodeState() != FUNCTION_SOURCE_NOT_LOADED)
|
||||
@ -821,6 +827,8 @@ TeamDebugger::_HandleImageDeleted(ImageDeletedEvent* event)
|
||||
imageHandler->ReleaseReference();
|
||||
}
|
||||
|
||||
// TODO: Remove breakpoints in the image!
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -837,7 +845,114 @@ void
|
||||
TeamDebugger::_HandleSetUserBreakpoint(target_addr_t address, bool 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);
|
||||
if (error != B_OK) {
|
||||
_NotifyUser("Install Breakpoint", "Failed to install breakpoint: %s",
|
||||
@ -850,7 +965,19 @@ void
|
||||
TeamDebugger::_HandleClearUserBreakpoint(target_addr_t 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:
|
||||
// TeamWindow::Listener
|
||||
virtual void FunctionSourceCodeRequested(TeamWindow* window,
|
||||
FunctionDebugInfo* function);
|
||||
FunctionInstance* function);
|
||||
virtual void ImageDebugInfoRequested(TeamWindow* window,
|
||||
Image* image);
|
||||
virtual void ThreadActionRequested(TeamWindow* window,
|
||||
|
@ -15,7 +15,7 @@
|
||||
#include "BreakpointManager.h"
|
||||
#include "CpuState.h"
|
||||
#include "DebuggerInterface.h"
|
||||
#include "FunctionDebugInfo.h"
|
||||
#include "FunctionInstance.h"
|
||||
#include "ImageDebugInfo.h"
|
||||
#include "InstructionInfo.h"
|
||||
#include "Jobs.h"
|
||||
@ -126,7 +126,7 @@ ThreadHandler::HandleBreakpointHit(BreakpointHitEvent* event)
|
||||
// spurious breakpoint -- might be a temporary breakpoint, that has
|
||||
// already been uninstalled
|
||||
continueThread = true;
|
||||
} else if (breakpoint->UserState() != USER_BREAKPOINT_ENABLED) {
|
||||
} else if (breakpoint->HasEnabledUserBreakpoint()) {
|
||||
// breakpoint of another thread or one that has been disabled in
|
||||
// the meantime
|
||||
continueThread = true;
|
||||
@ -382,20 +382,21 @@ ThreadHandler::_GetStatementAtInstructionPointer(StackFrame* frame)
|
||||
{
|
||||
AutoLocker<TeamDebugModel> locker(fDebugModel);
|
||||
|
||||
FunctionDebugInfo* function = frame->Function();
|
||||
if (function == NULL)
|
||||
FunctionInstance* functionInstance = frame->Function();
|
||||
if (functionInstance == NULL)
|
||||
return NULL;
|
||||
FunctionDebugInfo* function = functionInstance->GetFunctionDebugInfo();
|
||||
|
||||
// If there's source code attached to the function, we can just get the
|
||||
// statement.
|
||||
SourceCode* sourceCode = function->GetSourceCode();
|
||||
if (sourceCode != NULL) {
|
||||
Statement* statement = sourceCode->StatementAtAddress(
|
||||
frame->InstructionPointer());
|
||||
if (statement != NULL)
|
||||
statement->AddReference();
|
||||
return statement;
|
||||
}
|
||||
// SourceCode* sourceCode = function->GetSourceCode();
|
||||
// if (sourceCode != NULL) {
|
||||
// Statement* statement = sourceCode->StatementAtAddress(
|
||||
// frame->InstructionPointer());
|
||||
// if (statement != NULL)
|
||||
// statement->AddReference();
|
||||
// return statement;
|
||||
// }
|
||||
|
||||
locker.Unlock();
|
||||
|
||||
|
@ -11,7 +11,7 @@
|
||||
#include <AutoLocker.h>
|
||||
|
||||
#include "CpuState.h"
|
||||
#include "FunctionDebugInfo.h"
|
||||
#include "FunctionInstance.h"
|
||||
#include "Image.h"
|
||||
#include "ImageDebugInfo.h"
|
||||
#include "ImageDebugInfoProvider.h"
|
||||
@ -75,31 +75,38 @@ Architecture::CreateStackTrace(Team* team,
|
||||
|
||||
// get the function
|
||||
teamLocker.Lock();
|
||||
FunctionDebugInfo* function = NULL;
|
||||
if (imageDebugInfo != NULL)
|
||||
FunctionInstance* function = NULL;
|
||||
FunctionDebugInfo* functionDebugInfo = NULL;
|
||||
if (imageDebugInfo != NULL) {
|
||||
function = imageDebugInfo->FunctionAtAddress(instructionPointer);
|
||||
Reference<FunctionDebugInfo> functionReference(function);
|
||||
if (function != NULL)
|
||||
functionDebugInfo = function->GetFunctionDebugInfo();
|
||||
}
|
||||
Reference<FunctionInstance> functionReference(function);
|
||||
teamLocker.Unlock();
|
||||
|
||||
// If the last frame had been created by the architecture, we update the
|
||||
// CPU state.
|
||||
if (architectureFrame)
|
||||
UpdateStackFrameCpuState(frame, image, function, cpuState);
|
||||
if (architectureFrame) {
|
||||
UpdateStackFrameCpuState(frame, image,
|
||||
functionDebugInfo, cpuState);
|
||||
}
|
||||
|
||||
// create the frame using the debug info
|
||||
StackFrame* previousFrame = NULL;
|
||||
CpuState* previousCpuState = NULL;
|
||||
if (function != NULL) {
|
||||
status_t error = function->GetSpecificImageDebugInfo()->CreateFrame(
|
||||
image, function, cpuState, previousFrame, previousCpuState);
|
||||
status_t error = functionDebugInfo->GetSpecificImageDebugInfo()
|
||||
->CreateFrame(image, functionDebugInfo, cpuState, previousFrame,
|
||||
previousCpuState);
|
||||
if (error != B_OK && error != B_UNSUPPORTED)
|
||||
break;
|
||||
}
|
||||
|
||||
// If we have no frame yet, let the architecture create it.
|
||||
if (previousFrame == NULL) {
|
||||
status_t error = CreateStackFrame(image, function, cpuState,
|
||||
frame == NULL, previousFrame, previousCpuState);
|
||||
status_t error = CreateStackFrame(image, functionDebugInfo,
|
||||
cpuState, frame == NULL, previousFrame, previousCpuState);
|
||||
if (error != B_OK)
|
||||
break;
|
||||
architectureFrame = true;
|
||||
|
@ -296,8 +296,9 @@ ArchitectureX86::DisassembleCode(FunctionDebugInfo* function,
|
||||
bool breakpointAllowed;
|
||||
while (disassembler.GetNextInstruction(line, instructionAddress,
|
||||
instructionSize, breakpointAllowed) == B_OK) {
|
||||
// TODO: Respect breakpointAllowed!
|
||||
if (!source->AddInstructionLine(line, instructionAddress,
|
||||
instructionSize, breakpointAllowed)) {
|
||||
instructionSize)) {
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
}
|
||||
@ -320,9 +321,7 @@ ArchitectureX86::GetStatement(FunctionDebugInfo* function,
|
||||
|
||||
// create a statement
|
||||
ContiguousStatement* statement = new(std::nothrow) ContiguousStatement(
|
||||
SourceLocation(0), SourceLocation(1),
|
||||
TargetAddressRange(info.Address(), info.Size()),
|
||||
info.IsBreakpointAllowed());
|
||||
SourceLocation(0), TargetAddressRange(info.Address(), info.Size()));
|
||||
if (statement == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
|
@ -49,17 +49,17 @@ BasicFunctionDebugInfo::Size() const
|
||||
}
|
||||
|
||||
|
||||
const char*
|
||||
const BString&
|
||||
BasicFunctionDebugInfo::Name() const
|
||||
{
|
||||
return fName.String();
|
||||
return fName;
|
||||
}
|
||||
|
||||
|
||||
const char*
|
||||
const BString&
|
||||
BasicFunctionDebugInfo::PrettyName() const
|
||||
{
|
||||
return fPrettyName.String();
|
||||
return fPrettyName;
|
||||
}
|
||||
|
||||
|
||||
|
@ -23,8 +23,8 @@ public:
|
||||
virtual SpecificImageDebugInfo* GetSpecificImageDebugInfo() const;
|
||||
virtual target_addr_t Address() const;
|
||||
virtual target_size_t Size() const;
|
||||
virtual const char* Name() const;
|
||||
virtual const char* PrettyName() const;
|
||||
virtual const BString& Name() const;
|
||||
virtual const BString& PrettyName() const;
|
||||
|
||||
virtual LocatableFile* SourceFile() 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
|
||||
DebuggerImageDebugInfo::_CompareSymbols(const SymbolInfo* a,
|
||||
const SymbolInfo* b)
|
||||
|
@ -36,6 +36,10 @@ public:
|
||||
virtual status_t GetStatement(FunctionDebugInfo* function,
|
||||
target_addr_t address,
|
||||
Statement*& _statement);
|
||||
virtual status_t GetStatementForSourceLocation(
|
||||
FunctionDebugInfo* function,
|
||||
const SourceLocation& sourceLocation,
|
||||
Statement*& _statement);
|
||||
|
||||
private:
|
||||
static int _CompareSymbols(const SymbolInfo* a,
|
||||
|
@ -63,17 +63,17 @@ DwarfFunctionDebugInfo::Size() const
|
||||
}
|
||||
|
||||
|
||||
const char*
|
||||
const BString&
|
||||
DwarfFunctionDebugInfo::Name() const
|
||||
{
|
||||
return fName.String();
|
||||
return fName;
|
||||
}
|
||||
|
||||
|
||||
const char*
|
||||
const BString&
|
||||
DwarfFunctionDebugInfo::PrettyName() const
|
||||
{
|
||||
return fName.String();
|
||||
return fName;
|
||||
}
|
||||
|
||||
|
||||
|
@ -32,8 +32,8 @@ public:
|
||||
virtual SpecificImageDebugInfo* GetSpecificImageDebugInfo() const;
|
||||
virtual target_addr_t Address() const;
|
||||
virtual target_size_t Size() const;
|
||||
virtual const char* Name() const;
|
||||
virtual const char* PrettyName() const;
|
||||
virtual const BString& Name() const;
|
||||
virtual const BString& PrettyName() const;
|
||||
|
||||
virtual LocatableFile* SourceFile() const;
|
||||
virtual SourceLocation SourceStartLocation() const;
|
||||
|
@ -320,11 +320,179 @@ DwarfImageDebugInfo::LoadSourceCode(FunctionDebugInfo* function,
|
||||
|
||||
|
||||
status_t
|
||||
DwarfImageDebugInfo::GetStatement(FunctionDebugInfo* function,
|
||||
DwarfImageDebugInfo::GetStatement(FunctionDebugInfo* _function,
|
||||
target_addr_t address, Statement*& _statement)
|
||||
{
|
||||
// TODO:...
|
||||
return fArchitecture->GetStatement(function, address, _statement);
|
||||
DwarfFunctionDebugInfo* function
|
||||
= 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
|
||||
// comparison below
|
||||
const char* directory;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
int32 fileIndex = _GetSourceFileIndex(unit, function->SourceFile());
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
// not loaded yet -- get the source file
|
||||
SourceFile* 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
|
||||
ContiguousStatement* statement = new(std::nothrow)
|
||||
ContiguousStatement(
|
||||
SourceLocation(statementLine, statementColumn),
|
||||
SourceLocation(statementLine, statementColumn),
|
||||
TargetAddressRange(fRelocationDelta + statementAddress,
|
||||
endAddress - statementAddress), true);
|
||||
endAddress - statementAddress));
|
||||
if (statement == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
@ -463,3 +617,25 @@ DwarfImageDebugInfo::_LookupSourceCode(CompilationUnit* unit,
|
||||
SourceCodeEntry* entry = fSourceCodes->Lookup(SourceCodeKey(unit, file));
|
||||
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,
|
||||
target_addr_t address,
|
||||
Statement*& _statement);
|
||||
virtual status_t GetStatementForSourceLocation(
|
||||
FunctionDebugInfo* function,
|
||||
const SourceLocation& sourceLocation,
|
||||
Statement*& _statement);
|
||||
|
||||
private:
|
||||
struct SourceCodeKey;
|
||||
@ -60,6 +64,8 @@ private:
|
||||
SourceCode*& _sourceCode);
|
||||
FileSourceCode* _LookupSourceCode(CompilationUnit* unit,
|
||||
LocatableFile* file);
|
||||
int32 _GetSourceFileIndex(CompilationUnit* unit,
|
||||
LocatableFile* sourceFile) const;
|
||||
|
||||
private:
|
||||
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 "SourceCode.h"
|
||||
|
||||
|
||||
FunctionDebugInfo::FunctionDebugInfo()
|
||||
:
|
||||
fSourceCode(NULL),
|
||||
fSourceCodeState(FUNCTION_SOURCE_NOT_LOADED)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
|
||||
#include <Referenceable.h>
|
||||
#include <util/DoublyLinkedList.h>
|
||||
|
||||
#include "SourceLocation.h"
|
||||
#include "Types.h"
|
||||
|
||||
|
||||
enum function_source_state {
|
||||
FUNCTION_SOURCE_NOT_LOADED,
|
||||
FUNCTION_SOURCE_LOADING,
|
||||
FUNCTION_SOURCE_LOADED,
|
||||
FUNCTION_SOURCE_UNAVAILABLE
|
||||
};
|
||||
|
||||
|
||||
class BString;
|
||||
class LocatableFile;
|
||||
class SourceCode;
|
||||
class SpecificImageDebugInfo;
|
||||
|
||||
|
||||
class FunctionDebugInfo : public Referenceable {
|
||||
public:
|
||||
class Listener;
|
||||
|
||||
public:
|
||||
FunctionDebugInfo();
|
||||
virtual ~FunctionDebugInfo();
|
||||
@ -36,41 +24,12 @@ public:
|
||||
virtual SpecificImageDebugInfo* GetSpecificImageDebugInfo() const = 0;
|
||||
virtual target_addr_t Address() const = 0;
|
||||
virtual target_size_t Size() const = 0;
|
||||
virtual const char* Name() const = 0;
|
||||
virtual const char* PrettyName() const = 0;
|
||||
virtual const BString& Name() const = 0;
|
||||
virtual const BString& PrettyName() const = 0;
|
||||
|
||||
virtual LocatableFile* SourceFile() const = 0;
|
||||
virtual SourceLocation SourceStartLocation() 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 "FunctionDebugInfo.h"
|
||||
#include "FunctionInstance.h"
|
||||
#include "SpecificImageDebugInfo.h"
|
||||
|
||||
|
||||
@ -20,8 +21,8 @@ ImageDebugInfo::ImageDebugInfo(const ImageInfo& imageInfo)
|
||||
|
||||
ImageDebugInfo::~ImageDebugInfo()
|
||||
{
|
||||
for (int32 i = 0; FunctionDebugInfo* function = fFunctions.ItemAt(i); i++)
|
||||
function->RemoveReference();
|
||||
for (int32 i = 0; FunctionInstance* function = fFunctions.ItemAt(i); i++)
|
||||
function->ReleaseReference();
|
||||
}
|
||||
|
||||
|
||||
@ -39,23 +40,35 @@ ImageDebugInfo::FinishInit()
|
||||
// missing functions from less expressive debug infos
|
||||
for (int32 i = 0; SpecificImageDebugInfo* specificInfo
|
||||
= fSpecificInfos.ItemAt(i); i++) {
|
||||
FunctionList functions;
|
||||
BObjectList<FunctionDebugInfo> functions;
|
||||
status_t error = specificInfo->GetFunctions(functions);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
for (int32 k = 0; FunctionDebugInfo* function = functions.ItemAt(k);
|
||||
k++) {
|
||||
if (FunctionAtAddress(function->Address()) == NULL) {
|
||||
if (!fFunctions.BinaryInsert(function, &_CompareFunctions)) {
|
||||
for (; (function = functions.ItemAt(k)); k++) {
|
||||
function->RemoveReference();
|
||||
return B_NO_MEMORY;
|
||||
if (FunctionAtAddress(function->Address()) != NULL)
|
||||
continue;
|
||||
|
||||
FunctionInstance* instance = new(std::nothrow) FunctionInstance(
|
||||
this, function);
|
||||
if (instance == NULL
|
||||
|| !fFunctions.BinaryInsert(instance, &_CompareFunctions)) {
|
||||
delete instance;
|
||||
error = B_NO_MEMORY;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else
|
||||
|
||||
// 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;
|
||||
@ -69,14 +82,14 @@ ImageDebugInfo::CountFunctions() const
|
||||
}
|
||||
|
||||
|
||||
FunctionDebugInfo*
|
||||
FunctionInstance*
|
||||
ImageDebugInfo::FunctionAt(int32 index) const
|
||||
{
|
||||
return fFunctions.ItemAt(index);
|
||||
}
|
||||
|
||||
|
||||
FunctionDebugInfo*
|
||||
FunctionInstance*
|
||||
ImageDebugInfo::FunctionAtAddress(target_addr_t address) const
|
||||
{
|
||||
return fFunctions.BinarySearchByKey(address, &_CompareAddressFunction);
|
||||
@ -84,8 +97,8 @@ ImageDebugInfo::FunctionAtAddress(target_addr_t address) const
|
||||
|
||||
|
||||
/*static*/ int
|
||||
ImageDebugInfo::_CompareFunctions(const FunctionDebugInfo* a,
|
||||
const FunctionDebugInfo* b)
|
||||
ImageDebugInfo::_CompareFunctions(const FunctionInstance* a,
|
||||
const FunctionInstance* b)
|
||||
{
|
||||
return a->Address() < b->Address()
|
||||
? -1 : (a->Address() == b->Address() ? 0 : 1);
|
||||
@ -94,7 +107,7 @@ ImageDebugInfo::_CompareFunctions(const FunctionDebugInfo* a,
|
||||
|
||||
/*static*/ int
|
||||
ImageDebugInfo::_CompareAddressFunction(const target_addr_t* address,
|
||||
const FunctionDebugInfo* function)
|
||||
const FunctionInstance* function)
|
||||
{
|
||||
if (*address < function->Address())
|
||||
return -1;
|
||||
|
@ -17,6 +17,7 @@
|
||||
class Architecture;
|
||||
class DebuggerInterface;
|
||||
class FunctionDebugInfo;
|
||||
class FunctionInstance;
|
||||
class SpecificImageDebugInfo;
|
||||
|
||||
|
||||
@ -29,19 +30,19 @@ public:
|
||||
status_t FinishInit();
|
||||
|
||||
int32 CountFunctions() const;
|
||||
FunctionDebugInfo* FunctionAt(int32 index) const;
|
||||
FunctionDebugInfo* FunctionAtAddress(target_addr_t address) const;
|
||||
FunctionInstance* FunctionAt(int32 index) const;
|
||||
FunctionInstance* FunctionAtAddress(target_addr_t address) const;
|
||||
|
||||
private:
|
||||
typedef BObjectList<SpecificImageDebugInfo> SpecificInfoList;
|
||||
typedef BObjectList<FunctionDebugInfo> FunctionList;
|
||||
typedef BObjectList<FunctionInstance> FunctionList;
|
||||
|
||||
private:
|
||||
static int _CompareFunctions(const FunctionDebugInfo* a,
|
||||
const FunctionDebugInfo* b);
|
||||
static int _CompareFunctions(const FunctionInstance* a,
|
||||
const FunctionInstance* b);
|
||||
static int _CompareAddressFunction(
|
||||
const target_addr_t* address,
|
||||
const FunctionDebugInfo* function);
|
||||
const FunctionInstance* function);
|
||||
|
||||
private:
|
||||
ImageInfo fImageInfo;
|
||||
|
@ -17,6 +17,7 @@ class DebuggerInterface;
|
||||
class FunctionDebugInfo;
|
||||
class Image;
|
||||
class SourceCode;
|
||||
class SourceLocation;
|
||||
class StackFrame;
|
||||
class Statement;
|
||||
|
||||
@ -45,6 +46,11 @@ public:
|
||||
target_addr_t address,
|
||||
Statement*& _statement) = 0;
|
||||
// returns reference
|
||||
virtual status_t GetStatementForSourceLocation(
|
||||
FunctionDebugInfo* function,
|
||||
const SourceLocation& sourceLocation,
|
||||
Statement*& _statement) = 0;
|
||||
// returns reference
|
||||
};
|
||||
|
||||
|
||||
|
@ -11,8 +11,62 @@
|
||||
|
||||
#include "DebuggerTeamDebugInfo.h"
|
||||
#include "DwarfTeamDebugInfo.h"
|
||||
#include "Function.h"
|
||||
#include "ImageDebugInfo.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,
|
||||
@ -21,19 +75,39 @@ TeamDebugInfo::TeamDebugInfo(DebuggerInterface* debuggerInterface,
|
||||
fDebuggerInterface(debuggerInterface),
|
||||
fArchitecture(architecture),
|
||||
fFileManager(fileManager),
|
||||
fSpecificInfos(10, true)
|
||||
fSpecificInfos(10, true),
|
||||
fFunctions(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
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
|
||||
// descending order of expressiveness.
|
||||
|
||||
@ -45,7 +119,7 @@ TeamDebugInfo::Init()
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
|
||||
status_t error = dwarfInfo->Init();
|
||||
error = dwarfInfo->Init();
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
@ -98,3 +172,65 @@ TeamDebugInfo::LoadImageDebugInfo(const ImageInfo& imageInfo,
|
||||
_imageDebugInfo = imageDebugInfoDeleter.Detach();
|
||||
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 <Referenceable.h>
|
||||
#include <util/OpenHashTable.h>
|
||||
|
||||
#include "ImageInfo.h"
|
||||
|
||||
@ -14,6 +15,8 @@
|
||||
class Architecture;
|
||||
class DebuggerInterface;
|
||||
class FileManager;
|
||||
class Function;
|
||||
class FunctionInstance;
|
||||
class ImageDebugInfo;
|
||||
class ImageInfo;
|
||||
class LocatableFile;
|
||||
@ -34,14 +37,24 @@ public:
|
||||
LocatableFile* imageFile,
|
||||
ImageDebugInfo*& _imageDebugInfo);
|
||||
|
||||
// team is locked
|
||||
status_t AddImageDebugInfo(
|
||||
ImageDebugInfo* imageDebugInfo);
|
||||
void RemoveImageDebugInfo(
|
||||
ImageDebugInfo* imageDebugInfo);
|
||||
|
||||
private:
|
||||
struct FunctionHashDefinition;
|
||||
|
||||
typedef BObjectList<SpecificTeamDebugInfo> SpecificInfoList;
|
||||
typedef OpenHashTable<FunctionHashDefinition> FunctionTable;
|
||||
|
||||
private:
|
||||
DebuggerInterface* fDebuggerInterface;
|
||||
Architecture* fArchitecture;
|
||||
FileManager* fFileManager;
|
||||
SpecificInfoList fSpecificInfos;
|
||||
FunctionTable* fFunctions;
|
||||
};
|
||||
|
||||
|
||||
|
@ -14,7 +14,7 @@
|
||||
|
||||
#include "table/TableColumns.h"
|
||||
|
||||
#include "FunctionDebugInfo.h"
|
||||
#include "FunctionInstance.h"
|
||||
#include "Image.h"
|
||||
#include "ImageDebugInfo.h"
|
||||
#include "LocatableFile.h"
|
||||
@ -63,11 +63,11 @@ public:
|
||||
|
||||
// create an array with the functions
|
||||
int32 functionCount = fImageDebugInfo->CountFunctions();
|
||||
FunctionDebugInfo** functions
|
||||
= new(std::nothrow) FunctionDebugInfo*[functionCount];
|
||||
FunctionInstance** functions
|
||||
= new(std::nothrow) FunctionInstance*[functionCount];
|
||||
if (functions == NULL)
|
||||
return;
|
||||
ArrayDeleter<FunctionDebugInfo*> functionsDeleter(functions);
|
||||
ArrayDeleter<FunctionInstance*> functionsDeleter(functions);
|
||||
|
||||
for (int32 i = 0; i < functionCount; i++)
|
||||
functions[i] = fImageDebugInfo->FunctionAt(i);
|
||||
@ -170,12 +170,12 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
FunctionDebugInfo* function = (FunctionDebugInfo*)object;
|
||||
FunctionInstance* function = (FunctionInstance*)object;
|
||||
value.SetTo(function->PrettyName(), B_VARIANT_DONT_COPY_DATA);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GetFunctionPath(FunctionDebugInfo* function, TreeTablePath& _path)
|
||||
bool GetFunctionPath(FunctionInstance* function, TreeTablePath& _path)
|
||||
{
|
||||
int32 index = -1;
|
||||
for (int32 i = 0; i < fFunctionCount; i++) {
|
||||
@ -198,7 +198,7 @@ public:
|
||||
}
|
||||
|
||||
bool GetObjectForPath(const TreeTablePath& path,
|
||||
LocatableFile*& _sourceFile, FunctionDebugInfo*& _function)
|
||||
LocatableFile*& _sourceFile, FunctionInstance*& _function)
|
||||
{
|
||||
int32 componentCount = path.CountComponents();
|
||||
if (componentCount == 0 || componentCount > 2)
|
||||
@ -256,8 +256,8 @@ private:
|
||||
return pathA.Compare(pathB);
|
||||
}
|
||||
|
||||
static bool _FunctionLess(const FunctionDebugInfo* a,
|
||||
const FunctionDebugInfo* b)
|
||||
static bool _FunctionLess(const FunctionInstance* a,
|
||||
const FunctionInstance* b)
|
||||
{
|
||||
// compare source file name first
|
||||
int compared = _CompareSourceFileNames(a->SourceFile(),
|
||||
@ -271,7 +271,7 @@ private:
|
||||
|
||||
private:
|
||||
ImageDebugInfo* fImageDebugInfo;
|
||||
FunctionDebugInfo** fFunctions;
|
||||
FunctionInstance** fFunctions;
|
||||
int32 fFunctionCount;
|
||||
int32* fSourceFileIndices;
|
||||
int32 fSourceFileCount;
|
||||
@ -357,7 +357,7 @@ printf("ImageFunctionsView::SetImageDebugInfo(%p) done\n", imageDebugInfo);
|
||||
|
||||
|
||||
void
|
||||
ImageFunctionsView::SetFunction(FunctionDebugInfo* function)
|
||||
ImageFunctionsView::SetFunction(FunctionInstance* function)
|
||||
{
|
||||
printf("ImageFunctionsView::SetFunction(%p)\n", function);
|
||||
TreeTablePath path;
|
||||
@ -377,7 +377,7 @@ ImageFunctionsView::TreeTableSelectionChanged(TreeTable* table)
|
||||
return;
|
||||
|
||||
LocatableFile* sourceFile = NULL;
|
||||
FunctionDebugInfo* function = NULL;
|
||||
FunctionInstance* function = NULL;
|
||||
TreeTablePath path;
|
||||
if (table->SelectionModel()->GetPathAt(0, path))
|
||||
fFunctionsTableModel->GetObjectForPath(path, sourceFile, function);
|
||||
|
@ -11,7 +11,7 @@
|
||||
#include "Team.h"
|
||||
|
||||
|
||||
class FunctionDebugInfo;
|
||||
class FunctionInstance;
|
||||
|
||||
|
||||
class ImageFunctionsView : public BGroupView, private TreeTableListener {
|
||||
@ -29,7 +29,7 @@ public:
|
||||
|
||||
void SetImageDebugInfo(
|
||||
ImageDebugInfo* imageDebugInfo);
|
||||
void SetFunction(FunctionDebugInfo* function);
|
||||
void SetFunction(FunctionInstance* function);
|
||||
|
||||
private:
|
||||
class FunctionsTableModel;
|
||||
@ -53,7 +53,7 @@ public:
|
||||
virtual ~Listener();
|
||||
|
||||
virtual void FunctionSelectionChanged(
|
||||
FunctionDebugInfo* function) = 0;
|
||||
FunctionInstance* function) = 0;
|
||||
};
|
||||
|
||||
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include <ObjectList.h>
|
||||
|
||||
#include "Breakpoint.h"
|
||||
#include "Function.h"
|
||||
#include "SourceCode.h"
|
||||
#include "StackTrace.h"
|
||||
#include "Statement.h"
|
||||
@ -519,8 +520,7 @@ SourceView::MarkerView::Draw(BRect updateRect)
|
||||
|
||||
Statement* statement = fSourceCode->StatementAtLine(line);
|
||||
if (statement == NULL
|
||||
|| statement->StartSourceLocation().Line() != (uint32)line
|
||||
|| !statement->BreakpointAllowed()) {
|
||||
|| statement->StartSourceLocation().Line() != (uint32)line) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -543,8 +543,7 @@ SourceView::MarkerView::MouseDown(BPoint where)
|
||||
|
||||
Statement* statement = fSourceCode->StatementAtLine(line);
|
||||
if (statement == NULL
|
||||
|| statement->StartSourceLocation().Line() != (uint32)line
|
||||
|| !statement->BreakpointAllowed()) {
|
||||
|| statement->StartSourceLocation().Line() != (uint32)line) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -595,15 +594,24 @@ SourceView::MarkerView::_UpdateIPMarkers()
|
||||
fIPMarkers.MakeEmpty();
|
||||
|
||||
if (fSourceCode != NULL && fStackTrace != NULL) {
|
||||
AutoLocker<TeamDebugModel> locker(fDebugModel);
|
||||
|
||||
for (int32 i = 0; StackFrame* frame = fStackTrace->FrameAt(i);
|
||||
i++) {
|
||||
target_addr_t ip = frame->InstructionPointer();
|
||||
Statement* statement = fSourceCode->StatementAtAddress(ip);
|
||||
if (statement == NULL)
|
||||
FunctionInstance* functionInstance;
|
||||
Statement* statement;
|
||||
if (fDebugModel->GetTeam()->GetStatementAtAddress(ip,
|
||||
functionInstance, statement) != B_OK) {
|
||||
continue;
|
||||
}
|
||||
Reference<Statement> statementReference(statement, true);
|
||||
|
||||
uint32 line = statement->StartSourceLocation().Line();
|
||||
if (line >= (uint32)LineCount())
|
||||
if (functionInstance->GetFunction()->GetSourceCode() != fSourceCode
|
||||
|| line < 0 || line >= (uint32)LineCount()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool isTopFrame = i == 0
|
||||
&& frame->Type() != STACK_FRAME_TYPE_SYSCALL;
|
||||
@ -638,25 +646,30 @@ SourceView::MarkerView::_UpdateBreakpointMarkers()
|
||||
AutoLocker<TeamDebugModel> locker(fDebugModel);
|
||||
|
||||
// get the breakpoints in our source code range
|
||||
BObjectList<Breakpoint> breakpoints;
|
||||
fDebugModel->GetBreakpointsInAddressRange(
|
||||
fSourceCode->StatementAddressRange(), breakpoints);
|
||||
BObjectList<UserBreakpoint> breakpoints;
|
||||
fDebugModel->GetBreakpointsForSourceCode(fSourceCode, breakpoints);
|
||||
|
||||
for (int32 i = 0; Breakpoint* breakpoint = breakpoints.ItemAt(i); i++) {
|
||||
if (breakpoint->UserState() == USER_BREAKPOINT_NONE)
|
||||
for (int32 i = 0; UserBreakpoint* breakpoint = breakpoints.ItemAt(i);
|
||||
i++) {
|
||||
UserBreakpointInstance* breakpointInstance
|
||||
= breakpoint->InstanceAt(0);
|
||||
FunctionInstance* functionInstance;
|
||||
Statement* statement;
|
||||
if (fDebugModel->GetTeam()->GetStatementAtAddress(
|
||||
breakpointInstance->Address(), functionInstance,
|
||||
statement) != B_OK) {
|
||||
continue;
|
||||
}
|
||||
Reference<Statement> statementReference(statement, true);
|
||||
|
||||
Statement* statement = fSourceCode->StatementAtAddress(
|
||||
breakpoint->Address());
|
||||
if (statement == NULL)
|
||||
continue;
|
||||
uint32 line = statement->StartSourceLocation().Line();
|
||||
if (line >= (uint32)LineCount())
|
||||
if (functionInstance->GetFunction()->GetSourceCode() != fSourceCode
|
||||
|| line < 0 || line >= (uint32)LineCount()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BreakpointMarker* marker = new(std::nothrow) BreakpointMarker(
|
||||
line, breakpoint->Address(),
|
||||
breakpoint->UserState() == USER_BREAKPOINT_ENABLED);
|
||||
line, breakpointInstance->Address(), breakpoint->IsEnabled());
|
||||
if (marker == NULL || !fBreakpointMarkers.AddItem(marker)) {
|
||||
delete marker;
|
||||
break;
|
||||
@ -995,9 +1008,15 @@ SourceView::ScrollToAddress(target_addr_t address)
|
||||
if (fSourceCode == NULL)
|
||||
return false;
|
||||
|
||||
Statement* statement = fSourceCode->StatementAtAddress(address);
|
||||
if (statement == NULL)
|
||||
AutoLocker<TeamDebugModel> locker(fDebugModel);
|
||||
|
||||
FunctionInstance* functionInstance;
|
||||
Statement* statement;
|
||||
if (fDebugModel->GetTeam()->GetStatementAtAddress(address, functionInstance,
|
||||
statement) != B_OK) {
|
||||
return false;
|
||||
}
|
||||
Reference<Statement> statementReference(statement, true);
|
||||
|
||||
return ScrollToLine(statement->StartSourceLocation().Line());
|
||||
}
|
||||
@ -1013,11 +1032,16 @@ SourceView::ScrollToLine(uint32 line)
|
||||
float bottom = top + fFontInfo.lineHeight - 1;
|
||||
|
||||
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
|
||||
// least one more line is visible.
|
||||
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);
|
||||
}
|
||||
else if (top - fFontInfo.lineHeight < visible.top)
|
||||
ScrollBy(0, top - fFontInfo.lineHeight - visible.top);
|
||||
else if (bottom + fFontInfo.lineHeight > visible.bottom)
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
#include "table/TableColumns.h"
|
||||
|
||||
#include "FunctionDebugInfo.h"
|
||||
#include "FunctionInstance.h"
|
||||
#include "Image.h"
|
||||
#include "StackTrace.h"
|
||||
|
||||
@ -105,7 +105,7 @@ public:
|
||||
case 2:
|
||||
{
|
||||
Image* image = frame->GetImage();
|
||||
FunctionDebugInfo* function = frame->Function();
|
||||
FunctionInstance* function = frame->Function();
|
||||
if (image == NULL && function == NULL) {
|
||||
value.SetTo("?", B_VARIANT_DONT_COPY_DATA);
|
||||
return true;
|
||||
|
@ -215,7 +215,7 @@ TeamWindow::StackFrameSelectionChanged(StackFrame* frame)
|
||||
|
||||
|
||||
void
|
||||
TeamWindow::FunctionSelectionChanged(FunctionDebugInfo* function)
|
||||
TeamWindow::FunctionSelectionChanged(FunctionInstance* function)
|
||||
{
|
||||
_SetActiveFunction(function);
|
||||
}
|
||||
@ -281,7 +281,7 @@ TeamWindow::UserBreakpointChanged(const TeamDebugModel::BreakpointEvent& event)
|
||||
|
||||
|
||||
void
|
||||
TeamWindow::FunctionSourceCodeChanged(FunctionDebugInfo* function)
|
||||
TeamWindow::FunctionSourceCodeChanged(Function* function)
|
||||
{
|
||||
printf("TeamWindow::FunctionSourceCodeChanged(%p): source: %p, state: %d\n",
|
||||
function, function->GetSourceCode(), function->SourceCodeState());
|
||||
@ -469,15 +469,15 @@ TeamWindow::_SetActiveStackFrame(StackFrame* frame)
|
||||
|
||||
|
||||
void
|
||||
TeamWindow::_SetActiveFunction(FunctionDebugInfo* function)
|
||||
TeamWindow::_SetActiveFunction(FunctionInstance* functionInstance)
|
||||
{
|
||||
if (function == fActiveFunction)
|
||||
if (functionInstance == fActiveFunction)
|
||||
return;
|
||||
|
||||
AutoLocker<TeamDebugModel> locker(fDebugModel);
|
||||
|
||||
if (fActiveFunction != NULL) {
|
||||
fActiveFunction->RemoveListener(this);
|
||||
fActiveFunction->GetFunction()->RemoveListener(this);
|
||||
fActiveFunction->RemoveReference();
|
||||
}
|
||||
|
||||
@ -487,12 +487,12 @@ TeamWindow::_SetActiveFunction(FunctionDebugInfo* function)
|
||||
|
||||
fActiveFunction = NULL;
|
||||
|
||||
if (function != NULL) {
|
||||
if (functionInstance != NULL) {
|
||||
_SetActiveImage(fDebugModel->GetTeam()->ImageByAddress(
|
||||
function->Address()));
|
||||
functionInstance->Address()));
|
||||
}
|
||||
|
||||
fActiveFunction = function;
|
||||
fActiveFunction = functionInstance;
|
||||
|
||||
locker.Lock();
|
||||
|
||||
@ -501,13 +501,14 @@ TeamWindow::_SetActiveFunction(FunctionDebugInfo* function)
|
||||
|
||||
if (fActiveFunction != NULL) {
|
||||
fActiveFunction->AddReference();
|
||||
fActiveFunction->AddListener(this);
|
||||
fActiveFunction->GetFunction()->AddListener(this);
|
||||
|
||||
sourceCode = fActiveFunction->GetSourceCode();
|
||||
Function* function = fActiveFunction->GetFunction();
|
||||
sourceCode = function->GetSourceCode();
|
||||
sourceCodeReference.SetTo(sourceCode);
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
@ -522,8 +523,10 @@ TeamWindow::_SetActiveFunction(FunctionDebugInfo* function)
|
||||
void
|
||||
TeamWindow::_SetActiveSourceCode(SourceCode* sourceCode)
|
||||
{
|
||||
if (sourceCode == fActiveSourceCode)
|
||||
if (sourceCode == fActiveSourceCode) {
|
||||
_ScrollToActiveFunction();
|
||||
return;
|
||||
}
|
||||
|
||||
if (fActiveSourceCode != NULL)
|
||||
fActiveSourceCode->RemoveReference();
|
||||
@ -535,16 +538,9 @@ TeamWindow::_SetActiveSourceCode(SourceCode* sourceCode)
|
||||
|
||||
fSourceView->SetSourceCode(fActiveSourceCode);
|
||||
|
||||
// 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());
|
||||
}
|
||||
_ScrollToActiveFunction();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
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
|
||||
TeamWindow::_HandleThreadStateChanged(thread_id threadID)
|
||||
{
|
||||
@ -693,7 +702,7 @@ TeamWindow::_HandleSourceCodeChanged()
|
||||
// get a reference to the source code
|
||||
AutoLocker<TeamDebugModel> locker(fDebugModel);
|
||||
|
||||
SourceCode* sourceCode = fActiveFunction->GetSourceCode();
|
||||
SourceCode* sourceCode = fActiveFunction->GetFunction()->GetSourceCode();
|
||||
Reference<SourceCode> sourceCodeReference(sourceCode);
|
||||
|
||||
locker.Unlock();
|
||||
|
@ -9,7 +9,7 @@
|
||||
#include <Window.h>
|
||||
|
||||
#include "SourceView.h"
|
||||
#include "FunctionDebugInfo.h"
|
||||
#include "Function.h"
|
||||
#include "ImageFunctionsView.h"
|
||||
#include "ImageListView.h"
|
||||
#include "StackTraceView.h"
|
||||
@ -20,7 +20,6 @@
|
||||
|
||||
class BButton;
|
||||
class BTabView;
|
||||
class FunctionDebugInfo;
|
||||
class Image;
|
||||
class RegisterView;
|
||||
class SourceCode;
|
||||
@ -30,7 +29,7 @@ class StackFrame;
|
||||
class TeamWindow : public BWindow, ThreadListView::Listener,
|
||||
ImageListView::Listener, StackTraceView::Listener,
|
||||
ImageFunctionsView::Listener, SourceView::Listener, Team::Listener,
|
||||
TeamDebugModel::Listener, FunctionDebugInfo::Listener {
|
||||
TeamDebugModel::Listener, Function::Listener {
|
||||
public:
|
||||
class Listener;
|
||||
|
||||
@ -58,7 +57,7 @@ private:
|
||||
|
||||
// ImageFunctionsView::Listener
|
||||
virtual void FunctionSelectionChanged(
|
||||
FunctionDebugInfo* function);
|
||||
FunctionInstance* function);
|
||||
|
||||
// SourceView::Listener
|
||||
virtual void SetBreakpointRequested(target_addr_t address,
|
||||
@ -80,9 +79,8 @@ private:
|
||||
const TeamDebugModel::BreakpointEvent&
|
||||
event);
|
||||
|
||||
// FunctionDebugInfo::Listener
|
||||
virtual void FunctionSourceCodeChanged(
|
||||
FunctionDebugInfo* function);
|
||||
// Function::Listener
|
||||
virtual void FunctionSourceCodeChanged(Function* function);
|
||||
|
||||
void _Init();
|
||||
|
||||
@ -90,10 +88,11 @@ private:
|
||||
void _SetActiveImage(Image* image);
|
||||
void _SetActiveStackTrace(StackTrace* stackTrace);
|
||||
void _SetActiveStackFrame(StackFrame* frame);
|
||||
void _SetActiveFunction(FunctionDebugInfo* function);
|
||||
void _SetActiveFunction(FunctionInstance* function);
|
||||
void _SetActiveSourceCode(SourceCode* sourceCode);
|
||||
void _UpdateCpuState();
|
||||
void _UpdateRunButtons();
|
||||
void _ScrollToActiveFunction();
|
||||
|
||||
void _HandleThreadStateChanged(thread_id threadID);
|
||||
void _HandleCpuStateChanged(thread_id threadID);
|
||||
@ -109,7 +108,7 @@ private:
|
||||
Image* fActiveImage;
|
||||
StackTrace* fActiveStackTrace;
|
||||
StackFrame* fActiveStackFrame;
|
||||
FunctionDebugInfo* fActiveFunction;
|
||||
FunctionInstance* fActiveFunction;
|
||||
SourceCode* fActiveSourceCode;
|
||||
Listener* fListener;
|
||||
BTabView* fTabView;
|
||||
@ -132,7 +131,7 @@ public:
|
||||
virtual ~Listener();
|
||||
|
||||
virtual void FunctionSourceCodeRequested(TeamWindow* window,
|
||||
FunctionDebugInfo* function) = 0;
|
||||
FunctionInstance* function) = 0;
|
||||
virtual void ImageDebugInfoRequested(TeamWindow* window,
|
||||
Image* image) = 0;
|
||||
virtual void ThreadActionRequested(TeamWindow* window,
|
||||
|
@ -21,7 +21,6 @@ Breakpoint::Breakpoint(Image* image, target_addr_t address)
|
||||
:
|
||||
fAddress(address),
|
||||
fImage(image),
|
||||
fUserState(USER_BREAKPOINT_NONE),
|
||||
fInstalled(false)
|
||||
{
|
||||
}
|
||||
@ -32,13 +31,6 @@ Breakpoint::~Breakpoint()
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Breakpoint::SetUserState(user_breakpoint_state state)
|
||||
{
|
||||
fUserState = state;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Breakpoint::SetInstalled(bool installed)
|
||||
{
|
||||
@ -49,14 +41,45 @@ Breakpoint::SetInstalled(bool installed)
|
||||
bool
|
||||
Breakpoint::ShouldBeInstalled() const
|
||||
{
|
||||
return fUserState == USER_BREAKPOINT_ENABLED || !fClients.IsEmpty();
|
||||
if (!fClients.IsEmpty())
|
||||
return true;
|
||||
|
||||
return !fClients.IsEmpty() || HasEnabledUserBreakpoint();
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
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
|
||||
#define BREAKPOINT_H
|
||||
|
||||
#include <ObjectList.h>
|
||||
#include <Referenceable.h>
|
||||
|
||||
#include "Types.h"
|
||||
|
||||
|
||||
enum user_breakpoint_state {
|
||||
USER_BREAKPOINT_NONE,
|
||||
USER_BREAKPOINT_ENABLED,
|
||||
USER_BREAKPOINT_DISABLED
|
||||
};
|
||||
#include "UserBreakpoint.h"
|
||||
|
||||
|
||||
class Image;
|
||||
@ -35,14 +25,22 @@ public:
|
||||
Image* GetImage() const { return fImage; }
|
||||
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; }
|
||||
void SetInstalled(bool installed);
|
||||
|
||||
bool ShouldBeInstalled() 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);
|
||||
void RemoveClient(BreakpointClient* client);
|
||||
@ -59,8 +57,8 @@ private:
|
||||
private:
|
||||
target_addr_t fAddress;
|
||||
Image* fImage;
|
||||
UserBreakpointInstanceList fUserBreakpoints;
|
||||
ClientList fClients;
|
||||
user_breakpoint_state fUserState;
|
||||
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*
|
||||
DisassembledCode::StatementAtLine(int32 index) const
|
||||
{
|
||||
@ -79,25 +65,25 @@ DisassembledCode::StatementAtLine(int32 index) const
|
||||
}
|
||||
|
||||
|
||||
Statement*
|
||||
DisassembledCode::StatementAtAddress(target_addr_t address) const
|
||||
{
|
||||
return fStatements.BinarySearchByKey(address, &_CompareAddressStatement);
|
||||
}
|
||||
//Statement*
|
||||
//DisassembledCode::StatementAtAddress(target_addr_t address) const
|
||||
//{
|
||||
// return fStatements.BinarySearchByKey(address, &_CompareAddressStatement);
|
||||
//}
|
||||
|
||||
|
||||
TargetAddressRange
|
||||
DisassembledCode::StatementAddressRange() const
|
||||
{
|
||||
if (fStatements.IsEmpty())
|
||||
return TargetAddressRange();
|
||||
|
||||
ContiguousStatement* first = fStatements.ItemAt(0);
|
||||
ContiguousStatement* last
|
||||
= fStatements.ItemAt(fStatements.CountItems() - 1);
|
||||
return TargetAddressRange(first->AddressRange().Start(),
|
||||
last->AddressRange().End());
|
||||
}
|
||||
//TargetAddressRange
|
||||
//DisassembledCode::StatementAddressRange() const
|
||||
//{
|
||||
// if (fStatements.IsEmpty())
|
||||
// return TargetAddressRange();
|
||||
//
|
||||
// ContiguousStatement* first = fStatements.ItemAt(0);
|
||||
// ContiguousStatement* last
|
||||
// = fStatements.ItemAt(fStatements.CountItems() - 1);
|
||||
// return TargetAddressRange(first->AddressRange().Start(),
|
||||
// last->AddressRange().End());
|
||||
//}
|
||||
|
||||
|
||||
bool
|
||||
@ -109,13 +95,12 @@ DisassembledCode::AddCommentLine(const BString& line)
|
||||
|
||||
bool
|
||||
DisassembledCode::AddInstructionLine(const BString& line, target_addr_t address,
|
||||
target_size_t size, bool breakpointAllowed)
|
||||
target_size_t size)
|
||||
{
|
||||
int32 lineIndex = fLines.CountItems();
|
||||
|
||||
ContiguousStatement* statement = new(std::nothrow) ContiguousStatement(
|
||||
SourceLocation(lineIndex), SourceLocation(lineIndex + 1),
|
||||
TargetAddressRange(address, size), breakpointAllowed);
|
||||
SourceLocation(lineIndex), TargetAddressRange(address, size));
|
||||
if (statement == NULL)
|
||||
return false;
|
||||
|
||||
|
@ -22,18 +22,15 @@ public:
|
||||
virtual int32 CountLines() 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* StatementAtAddress(target_addr_t address) const;
|
||||
// Statement* StatementAtAddress(target_addr_t address) const;
|
||||
|
||||
virtual TargetAddressRange StatementAddressRange() const;
|
||||
// TargetAddressRange StatementAddressRange() const;
|
||||
|
||||
public:
|
||||
bool AddCommentLine(const BString& line);
|
||||
bool AddInstructionLine(const BString& line,
|
||||
target_addr_t address, target_size_t size,
|
||||
bool breakpointAllowed);
|
||||
target_addr_t address, target_size_t size);
|
||||
// instructions must be added in
|
||||
// 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*
|
||||
FileSourceCode::StatementAtLine(int32 index) const
|
||||
{
|
||||
@ -99,25 +85,25 @@ FileSourceCode::StatementAtLine(int32 index) const
|
||||
}
|
||||
|
||||
|
||||
Statement*
|
||||
FileSourceCode::StatementAtAddress(target_addr_t address) const
|
||||
{
|
||||
return fStatements.BinarySearchByKey(address, &_CompareAddressStatement);
|
||||
}
|
||||
//Statement*
|
||||
//FileSourceCode::StatementAtAddress(target_addr_t address) const
|
||||
//{
|
||||
// return fStatements.BinarySearchByKey(address, &_CompareAddressStatement);
|
||||
//}
|
||||
|
||||
|
||||
TargetAddressRange
|
||||
FileSourceCode::StatementAddressRange() const
|
||||
{
|
||||
if (fStatements.IsEmpty())
|
||||
return TargetAddressRange();
|
||||
|
||||
ContiguousStatement* first = fStatements.ItemAt(0);
|
||||
ContiguousStatement* last
|
||||
= fStatements.ItemAt(fStatements.CountItems() - 1);
|
||||
return TargetAddressRange(first->AddressRange().Start(),
|
||||
last->AddressRange().End());
|
||||
}
|
||||
//TargetAddressRange
|
||||
//FileSourceCode::StatementAddressRange() const
|
||||
//{
|
||||
// if (fStatements.IsEmpty())
|
||||
// return TargetAddressRange();
|
||||
//
|
||||
// ContiguousStatement* first = fStatements.ItemAt(0);
|
||||
// ContiguousStatement* last
|
||||
// = fStatements.ItemAt(fStatements.CountItems() - 1);
|
||||
// return TargetAddressRange(first->AddressRange().Start(),
|
||||
// last->AddressRange().End());
|
||||
//}
|
||||
|
||||
|
||||
/*static*/ int
|
||||
|
@ -25,12 +25,10 @@ public:
|
||||
virtual int32 CountLines() 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* StatementAtAddress(target_addr_t address) const;
|
||||
// Statement* StatementAtAddress(target_addr_t address) const;
|
||||
|
||||
virtual TargetAddressRange StatementAddressRange() const;
|
||||
// virtual TargetAddressRange StatementAddressRange() const;
|
||||
|
||||
private:
|
||||
typedef BObjectList<ContiguousStatement> StatementList;
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "ImageDebugInfo.h"
|
||||
#include "LocatableFile.h"
|
||||
#include "Team.h"
|
||||
#include "TeamDebugInfo.h"
|
||||
|
||||
|
||||
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_debug_info_state state)
|
||||
{
|
||||
if (debugInfo == fDebugInfo && state == fDebugInfoState)
|
||||
return;
|
||||
return B_OK;
|
||||
|
||||
if (fDebugInfo != NULL)
|
||||
if (fDebugInfo != NULL) {
|
||||
fTeam->DebugInfo()->RemoveImageDebugInfo(fDebugInfo);
|
||||
fDebugInfo->RemoveReference();
|
||||
}
|
||||
|
||||
fDebugInfo = debugInfo;
|
||||
fDebugInfoState = state;
|
||||
|
||||
if (fDebugInfo != NULL)
|
||||
status_t error = B_OK;
|
||||
if (fDebugInfo != NULL) {
|
||||
error = fTeam->DebugInfo()->AddImageDebugInfo(fDebugInfo);
|
||||
if (error == B_OK) {
|
||||
fDebugInfo->AddReference();
|
||||
} else {
|
||||
fDebugInfo = NULL;
|
||||
fDebugInfoState = IMAGE_DEBUG_INFO_UNAVAILABLE;
|
||||
}
|
||||
}
|
||||
|
||||
// notify listeners
|
||||
fTeam->NotifyImageDebugInfoChanged(this);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
@ -34,7 +34,6 @@ public:
|
||||
|
||||
status_t Init();
|
||||
|
||||
|
||||
Team* GetTeam() const { return fTeam; }
|
||||
image_id ID() const { return fInfo.ImageID(); }
|
||||
const char* Name() const { return fInfo.Name(); }
|
||||
@ -48,7 +47,7 @@ public:
|
||||
ImageDebugInfo* GetImageDebugInfo() const { return fDebugInfo; }
|
||||
image_debug_info_state ImageDebugInfoState() const
|
||||
{ return fDebugInfoState; }
|
||||
void SetImageDebugInfo(ImageDebugInfo* debugInfo,
|
||||
status_t SetImageDebugInfo(ImageDebugInfo* debugInfo,
|
||||
image_debug_info_state state);
|
||||
|
||||
private:
|
||||
|
@ -20,13 +20,7 @@ public:
|
||||
virtual int32 CountLines() 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* StatementAtAddress(target_addr_t address)
|
||||
const = 0;
|
||||
|
||||
virtual TargetAddressRange StatementAddressRange() const = 0;
|
||||
};
|
||||
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
#include "StackFrame.h"
|
||||
|
||||
#include "CpuState.h"
|
||||
#include "FunctionDebugInfo.h"
|
||||
#include "FunctionInstance.h"
|
||||
#include "Image.h"
|
||||
|
||||
|
||||
@ -57,7 +57,7 @@ StackFrame::SetImage(Image* image)
|
||||
|
||||
|
||||
void
|
||||
StackFrame::SetFunction(FunctionDebugInfo* function)
|
||||
StackFrame::SetFunction(FunctionInstance* function)
|
||||
{
|
||||
if (fFunction != NULL)
|
||||
fFunction->RemoveReference();
|
||||
|
@ -22,7 +22,7 @@ enum stack_frame_type {
|
||||
|
||||
class CpuState;
|
||||
class Image;
|
||||
class FunctionDebugInfo;
|
||||
class FunctionInstance;
|
||||
|
||||
|
||||
class StackFrame : public Referenceable {
|
||||
@ -46,8 +46,8 @@ public:
|
||||
Image* GetImage() const { return fImage; }
|
||||
void SetImage(Image* image);
|
||||
|
||||
FunctionDebugInfo* Function() const { return fFunction; }
|
||||
void SetFunction(FunctionDebugInfo* function);
|
||||
FunctionInstance* Function() const { return fFunction; }
|
||||
void SetFunction(FunctionInstance* function);
|
||||
|
||||
private:
|
||||
stack_frame_type fType;
|
||||
@ -56,7 +56,7 @@ private:
|
||||
target_addr_t fInstructionPointer;
|
||||
target_addr_t fReturnAddress;
|
||||
Image* fImage;
|
||||
FunctionDebugInfo* fFunction;
|
||||
FunctionInstance* fFunction;
|
||||
};
|
||||
|
||||
|
||||
|
@ -17,12 +17,9 @@ Statement::~Statement()
|
||||
// #pragma mark - AbstractStatement
|
||||
|
||||
|
||||
AbstractStatement::AbstractStatement(const SourceLocation& start,
|
||||
const SourceLocation& end, bool breakpointAllowed)
|
||||
AbstractStatement::AbstractStatement(const SourceLocation& start)
|
||||
:
|
||||
fStart(start),
|
||||
fEnd(end),
|
||||
fBreakpointAllowed(breakpointAllowed)
|
||||
fStart(start)
|
||||
{
|
||||
}
|
||||
|
||||
@ -34,28 +31,13 @@ AbstractStatement::StartSourceLocation() const
|
||||
}
|
||||
|
||||
|
||||
SourceLocation
|
||||
AbstractStatement::EndSourceLocation() const
|
||||
{
|
||||
return fEnd;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
AbstractStatement::BreakpointAllowed() const
|
||||
{
|
||||
return fBreakpointAllowed;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - ContiguousStatement
|
||||
|
||||
|
||||
ContiguousStatement::ContiguousStatement(const SourceLocation& start,
|
||||
const SourceLocation& end, const TargetAddressRange& range,
|
||||
bool breakpointAllowed)
|
||||
const TargetAddressRange& range)
|
||||
:
|
||||
AbstractStatement(start, end, breakpointAllowed),
|
||||
AbstractStatement(start),
|
||||
fRange(range)
|
||||
{
|
||||
}
|
||||
|
@ -17,7 +17,6 @@ public:
|
||||
virtual ~Statement();
|
||||
|
||||
virtual SourceLocation StartSourceLocation() const = 0;
|
||||
virtual SourceLocation EndSourceLocation() const = 0;
|
||||
|
||||
virtual TargetAddressRange CoveringAddressRange() const = 0;
|
||||
|
||||
@ -26,35 +25,24 @@ public:
|
||||
|
||||
virtual bool ContainsAddress(target_addr_t address)
|
||||
const = 0;
|
||||
|
||||
virtual bool BreakpointAllowed() const = 0;
|
||||
};
|
||||
|
||||
|
||||
class AbstractStatement : public Statement {
|
||||
public:
|
||||
AbstractStatement(const SourceLocation& start,
|
||||
const SourceLocation& end,
|
||||
bool breakpointAllowed);
|
||||
AbstractStatement(const SourceLocation& start);
|
||||
|
||||
virtual SourceLocation StartSourceLocation() const;
|
||||
virtual SourceLocation EndSourceLocation() const;
|
||||
|
||||
virtual bool BreakpointAllowed() const;
|
||||
|
||||
protected:
|
||||
SourceLocation fStart;
|
||||
SourceLocation fEnd;
|
||||
bool fBreakpointAllowed;
|
||||
};
|
||||
|
||||
|
||||
class ContiguousStatement : public AbstractStatement {
|
||||
public:
|
||||
ContiguousStatement(const SourceLocation& start,
|
||||
const SourceLocation& end,
|
||||
const TargetAddressRange& range,
|
||||
bool breakpointAllowed);
|
||||
const TargetAddressRange& range);
|
||||
|
||||
const TargetAddressRange& AddressRange() const
|
||||
{ return fRange; }
|
||||
|
@ -9,6 +9,9 @@
|
||||
|
||||
#include <AutoLocker.h>
|
||||
|
||||
#include "FunctionInstance.h"
|
||||
#include "ImageDebugInfo.h"
|
||||
#include "SpecificImageDebugInfo.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
|
||||
Team::AddListener(Listener* listener)
|
||||
{
|
||||
|
@ -28,7 +28,9 @@ enum {
|
||||
};
|
||||
|
||||
|
||||
class FunctionInstance;
|
||||
class LocatableFile;
|
||||
class Statement;
|
||||
class TeamDebugInfo;
|
||||
|
||||
|
||||
@ -68,6 +70,13 @@ public:
|
||||
Image* ImageByAddress(target_addr_t address) 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 RemoveListener(Listener* listener);
|
||||
|
||||
|
@ -10,6 +10,8 @@
|
||||
#include <AutoLocker.h>
|
||||
|
||||
#include "Breakpoint.h"
|
||||
#include "Function.h"
|
||||
#include "UserBreakpoint.h"
|
||||
|
||||
|
||||
// #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
|
||||
TeamDebugModel::GetBreakpointsInAddressRange(TargetAddressRange range,
|
||||
BObjectList<Breakpoint>& breakpoints) const
|
||||
TeamDebugModel::GetBreakpointsForSourceCode(SourceCode* sourceCode,
|
||||
BObjectList<UserBreakpoint>& 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);
|
||||
// TODO: This can probably be optimized. Maybe by registering the user
|
||||
// breakpoints with the team debug model and sorting them by source code.
|
||||
for (int32 i = 0; Breakpoint* breakpoint = fBreakpoints.ItemAt(i); i++) {
|
||||
UserBreakpointInstance* userBreakpointInstance
|
||||
= breakpoint->FirstUserBreakpoint();
|
||||
if (userBreakpointInstance == NULL)
|
||||
continue;
|
||||
|
||||
UserBreakpoint* userBreakpoint
|
||||
= userBreakpointInstance->GetUserBreakpoint();
|
||||
if (userBreakpoint->GetFunction()->GetSourceCode() == sourceCode)
|
||||
breakpoints.AddItem(userBreakpoint);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -22,7 +22,9 @@ enum {
|
||||
|
||||
class Architecture;
|
||||
class Breakpoint;
|
||||
class SourceCode;
|
||||
class TeamMemory;
|
||||
class UserBreakpoint;
|
||||
|
||||
|
||||
class TeamDebugModel {
|
||||
@ -56,9 +58,13 @@ public:
|
||||
Breakpoint* BreakpointAt(int32 index) const;
|
||||
Breakpoint* BreakpointAtAddress(
|
||||
target_addr_t address) const;
|
||||
void GetBreakpointsInAddressRange(
|
||||
TargetAddressRange range,
|
||||
BObjectList<Breakpoint>& breakpoints) const;
|
||||
// void GetBreakpointsInAddressRange(
|
||||
// TargetAddressRange range,
|
||||
// BObjectList<Breakpoint>& breakpoints) const;
|
||||
void GetBreakpointsForSourceCode(
|
||||
SourceCode* sourceCode,
|
||||
BObjectList<UserBreakpoint>& breakpoints)
|
||||
const;
|
||||
|
||||
void AddListener(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