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:
Ingo Weinhold 2009-07-07 20:47:39 +00:00
parent ccf28e4dd1
commit f66bd6256a
54 changed files with 1549 additions and 515 deletions

View File

@ -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;
}

View File

@ -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;

View File

@ -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

View File

@ -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();

View File

@ -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;
};

View File

@ -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);
}

View File

@ -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,

View File

@ -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();

View File

@ -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;

View File

@ -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;

View File

@ -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;
}

View File

@ -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;

View File

@ -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)

View File

@ -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,

View File

@ -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;
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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;

View 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)
{
}

View 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

View File

@ -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)
{
}

View File

@ -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
};

View 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();
}

View 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

View File

@ -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;

View File

@ -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;

View File

@ -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
};

View File

@ -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.
}
}
}

View File

@ -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;
};

View File

@ -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);

View File

@ -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;
};

View File

@ -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)

View File

@ -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;

View File

@ -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();

View File

@ -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,

View File

@ -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);
}

View File

@ -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;
};

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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;
}

View File

@ -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:

View File

@ -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;
};

View File

@ -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();

View File

@ -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;
};

View File

@ -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)
{
}

View File

@ -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; }

View File

@ -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)
{

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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);

View 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;
}

View 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