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 status_t
BreakpointManager::InstallUserBreakpoint(target_addr_t address, BreakpointManager::InstallUserBreakpoint(UserBreakpoint* userBreakpoint,
bool enabled) bool enabled)
{ {
user_breakpoint_state state = enabled printf("BreakpointManager::InstallUserBreakpoint(%p, %d)\n", userBreakpoint, enabled);
? USER_BREAKPOINT_ENABLED : USER_BREAKPOINT_DISABLED; AutoLocker<BLocker> installLocker(fLock);
AutoLocker<TeamDebugModel> modelLocker(fDebugModel); AutoLocker<TeamDebugModel> modelLocker(fDebugModel);
// If there already is a breakpoint, it might already have the requested bool oldEnabled = userBreakpoint->IsEnabled();
// state. if (userBreakpoint->IsValid() && enabled == oldEnabled)
Breakpoint* breakpoint = fDebugModel->BreakpointAtAddress(address); {
if (breakpoint != NULL && breakpoint->UserState() == state) printf(" user breakpoint already valid and with same enabled state\n");
return B_OK; return B_OK;
}
// create a breakpoint, if it doesn't exist yet // get/create the breakpoints for all instances
if (breakpoint == NULL) { printf(" creating breakpoints for breakpoint instances\n");
Image* image = fDebugModel->GetTeam()->ImageByAddress(address); status_t error = B_OK;
if (image == NULL) for (int32 i = 0;
return B_BAD_ADDRESS; UserBreakpointInstance* instance = userBreakpoint->InstanceAt(i); i++) {
printf(" breakpoint instance %p\n", instance);
if (instance->GetBreakpoint() != NULL)
{
printf(" -> already has breakpoint\n");
continue;
}
breakpoint = new(std::nothrow) Breakpoint(image, address); target_addr_t address = instance->Address();
if (breakpoint == NULL) Breakpoint* breakpoint = fDebugModel->BreakpointAtAddress(address);
return B_NO_MEMORY; if (breakpoint == NULL) {
printf(" -> no breakpoint at that address yet\n");
Image* image = fDebugModel->GetTeam()->ImageByAddress(address);
if (image == NULL) {
printf(" -> no image at that address\n");
error = B_BAD_ADDRESS;
break;
}
if (!fDebugModel->AddBreakpoint(breakpoint)) breakpoint = new(std::nothrow) Breakpoint(image, address);
return B_NO_MEMORY; if (breakpoint == NULL) {
error = B_NO_MEMORY;
break;
}
if (!fDebugModel->AddBreakpoint(breakpoint)) {
error = B_NO_MEMORY;
break;
}
}
printf(" -> adding instance to breakpoint %p\n", breakpoint);
breakpoint->AddUserBreakpoint(instance);
instance->SetBreakpoint(breakpoint);
} }
user_breakpoint_state oldState = breakpoint->UserState(); // If everything looks good so far mark the user breakpoint according to
// its new state.
if (error == B_OK)
userBreakpoint->SetEnabled(enabled);
// set the breakpoint state // notify user breakpoint listeners
breakpoint->SetUserState(state); if (error == B_OK) {
fDebugModel->NotifyUserBreakpointChanged(breakpoint); for (int32 i = 0;
UserBreakpointInstance* instance = userBreakpoint->InstanceAt(i);
i++) {
fDebugModel->NotifyUserBreakpointChanged(instance->GetBreakpoint());
}
}
AutoLocker<BLocker> installLocker(fLock);
// We need to make the installation decision with both locks held, and
// we keep this lock until we have the breakpoint installed/uninstalled.
bool install = breakpoint->ShouldBeInstalled();
if (breakpoint->IsInstalled() == install)
return B_OK;
// The breakpoint needs to be installed/uninstalled.
Reference<Breakpoint> breakpointReference(breakpoint);
modelLocker.Unlock(); modelLocker.Unlock();
status_t error = install // install/uninstall the breakpoints as needed
? fDebuggerInterface->InstallBreakpoint(address) printf(" updating breakpoints\n");
: fDebuggerInterface->UninstallBreakpoint(address);
// Mark the breakpoint installed/uninstalled, if everything went fine.
if (error == B_OK) { if (error == B_OK) {
breakpoint->SetInstalled(install); for (int32 i = 0;
return B_OK; UserBreakpointInstance* instance = userBreakpoint->InstanceAt(i);
i++) {
printf(" breakpoint instance %p\n", instance);
error = _UpdateBreakpointInstallation(instance->GetBreakpoint());
if (error != B_OK)
break;
}
} }
// revert on error if (error == B_OK) {
installLocker. Unlock(); printf(" success, marking user breakpoint valid\n");
modelLocker.Lock(); // everything went fine -- mark the user breakpoint valid
if (!userBreakpoint->IsValid()) {
modelLocker.Lock();
userBreakpoint->SetValid(true);
userBreakpoint->AcquireReference();
// TODO: Put the user breakpoint some place?
modelLocker.Unlock();
}
} else {
// something went wrong -- revert the situation
printf(" error, reverting\n");
modelLocker.Lock();
userBreakpoint->SetEnabled(oldEnabled);
modelLocker.Unlock();
breakpoint->SetUserState(oldState); if (!oldEnabled || !userBreakpoint->IsValid()) {
fDebugModel->NotifyUserBreakpointChanged(breakpoint); for (int32 i = 0; UserBreakpointInstance* instance
= userBreakpoint->InstanceAt(i);
i++) {
Breakpoint* breakpoint = instance->GetBreakpoint();
if (breakpoint == NULL)
continue;
if (breakpoint->IsUnused()) if (!userBreakpoint->IsValid()) {
fDebugModel->RemoveBreakpoint(breakpoint); instance->SetBreakpoint(NULL);
breakpoint->RemoveUserBreakpoint(instance);
}
_UpdateBreakpointInstallation(breakpoint);
modelLocker.Lock();
fDebugModel->NotifyUserBreakpointChanged(breakpoint);
if (breakpoint->IsUnused())
fDebugModel->RemoveBreakpoint(breakpoint);
modelLocker.Unlock();
}
}
}
installLocker.Unlock();
return error; return error;
} }
void void
BreakpointManager::UninstallUserBreakpoint(target_addr_t address) BreakpointManager::UninstallUserBreakpoint(UserBreakpoint* userBreakpoint)
{ {
AutoLocker<BLocker> installLocker(fLock);
AutoLocker<TeamDebugModel> modelLocker(fDebugModel); AutoLocker<TeamDebugModel> modelLocker(fDebugModel);
Breakpoint* breakpoint = fDebugModel->BreakpointAtAddress(address); if (!userBreakpoint->IsValid())
if (breakpoint == NULL || breakpoint->UserState() == USER_BREAKPOINT_NONE)
return; return;
// set the breakpoint state userBreakpoint->SetValid(false);
breakpoint->SetUserState(USER_BREAKPOINT_NONE); userBreakpoint->SetEnabled(false);
fDebugModel->NotifyUserBreakpointChanged(breakpoint);
AutoLocker<BLocker> installLocker(fLock);
// We need to make the uninstallation decision with both locks held, and
// we keep this lock until we have the breakpoint uninstalled.
// check whether the breakpoint needs to be uninstalled
bool uninstall = !breakpoint->ShouldBeInstalled()
&& breakpoint->IsInstalled();
// if unused remove it
Reference<Breakpoint> breakpointReference(breakpoint);
if (breakpoint->IsUnused())
fDebugModel->RemoveBreakpoint(breakpoint);
modelLocker.Unlock(); modelLocker.Unlock();
if (uninstall) { // uninstall the breakpoints as needed
fDebuggerInterface->UninstallBreakpoint(address); for (int32 i = 0;
breakpoint->SetInstalled(false); UserBreakpointInstance* instance = userBreakpoint->InstanceAt(i); i++) {
if (Breakpoint* breakpoint = instance->GetBreakpoint())
_UpdateBreakpointInstallation(breakpoint);
} }
modelLocker.Lock();
// detach the breakpoints from the user breakpoint instances
for (int32 i = 0;
UserBreakpointInstance* instance = userBreakpoint->InstanceAt(i); i++) {
if (Breakpoint* breakpoint = instance->GetBreakpoint()) {
instance->SetBreakpoint(NULL);
breakpoint->RemoveUserBreakpoint(instance);
fDebugModel->NotifyUserBreakpointChanged(breakpoint);
if (breakpoint->IsUnused())
fDebugModel->RemoveBreakpoint(breakpoint);
}
}
modelLocker.Unlock();
installLocker.Unlock();
// release the reference from InstallUserBreakpoint()
userBreakpoint->ReleaseReference();
} }
@ -147,6 +218,7 @@ status_t
BreakpointManager::InstallTemporaryBreakpoint(target_addr_t address, BreakpointManager::InstallTemporaryBreakpoint(target_addr_t address,
BreakpointClient* client) BreakpointClient* client)
{ {
AutoLocker<BLocker> installLocker(fLock);
AutoLocker<TeamDebugModel> modelLocker(fDebugModel); AutoLocker<TeamDebugModel> modelLocker(fDebugModel);
// create a breakpoint, if it doesn't exist yet // create a breakpoint, if it doesn't exist yet
@ -169,10 +241,6 @@ BreakpointManager::InstallTemporaryBreakpoint(target_addr_t address,
// add the client // add the client
status_t error; status_t error;
if (breakpoint->AddClient(client)) { if (breakpoint->AddClient(client)) {
AutoLocker<BLocker> installLocker(fLock);
// We need to make the installation decision with both locks held,
// and we keep this lock until we have the breakpoint installed.
if (breakpoint->IsInstalled()) if (breakpoint->IsInstalled())
return B_OK; return B_OK;
@ -185,7 +253,6 @@ BreakpointManager::InstallTemporaryBreakpoint(target_addr_t address,
return B_OK; return B_OK;
} }
installLocker.Unlock();
modelLocker.Lock(); modelLocker.Lock();
breakpoint->RemoveClient(client); breakpoint->RemoveClient(client);
@ -204,6 +271,7 @@ void
BreakpointManager::UninstallTemporaryBreakpoint(target_addr_t address, BreakpointManager::UninstallTemporaryBreakpoint(target_addr_t address,
BreakpointClient* client) BreakpointClient* client)
{ {
AutoLocker<BLocker> installLocker(fLock);
AutoLocker<TeamDebugModel> modelLocker(fDebugModel); AutoLocker<TeamDebugModel> modelLocker(fDebugModel);
Breakpoint* breakpoint = fDebugModel->BreakpointAtAddress(address); Breakpoint* breakpoint = fDebugModel->BreakpointAtAddress(address);
@ -213,10 +281,6 @@ BreakpointManager::UninstallTemporaryBreakpoint(target_addr_t address,
// remove the client // remove the client
breakpoint->RemoveClient(client); breakpoint->RemoveClient(client);
AutoLocker<BLocker> installLocker(fLock);
// We need to make the uninstallation decision with both locks held, and
// we keep this lock until we have the breakpoint uninstalled.
// check whether the breakpoint needs to be uninstalled // check whether the breakpoint needs to be uninstalled
bool uninstall = !breakpoint->ShouldBeInstalled() bool uninstall = !breakpoint->ShouldBeInstalled()
&& breakpoint->IsInstalled(); && breakpoint->IsInstalled();
@ -233,3 +297,30 @@ BreakpointManager::UninstallTemporaryBreakpoint(target_addr_t address,
breakpoint->SetInstalled(false); breakpoint->SetInstalled(false);
} }
} }
status_t
BreakpointManager::_UpdateBreakpointInstallation(Breakpoint* breakpoint)
{
bool shouldBeInstalled = breakpoint->ShouldBeInstalled();
printf("BreakpointManager::_UpdateBreakpointInstallation(%p): should be installed: %d, is installed: %d\n", breakpoint, shouldBeInstalled, breakpoint->IsInstalled());
if (shouldBeInstalled == breakpoint->IsInstalled())
return B_OK;
if (shouldBeInstalled) {
// install
status_t error = fDebuggerInterface->InstallBreakpoint(
breakpoint->Address());
if (error != B_OK)
return error;
printf("BREAKPOINT at %#llx installed: %s\n", breakpoint->Address(), strerror(error));
breakpoint->SetInstalled(true);
} else {
// uninstall
fDebuggerInterface->UninstallBreakpoint(breakpoint->Address());
printf("BREAKPOINT at %#llx uninstalled\n", breakpoint->Address());
breakpoint->SetInstalled(false);
}
return B_OK;
}

View File

@ -22,9 +22,15 @@ public:
status_t Init(); status_t Init();
status_t InstallUserBreakpoint(target_addr_t address, // status_t InstallUserBreakpoint(target_addr_t address,
// bool enabled);
// void UninstallUserBreakpoint(target_addr_t address);
status_t InstallUserBreakpoint(
UserBreakpoint* userBreakpoint,
bool enabled); bool enabled);
void UninstallUserBreakpoint(target_addr_t address); void UninstallUserBreakpoint(
UserBreakpoint* userBreakpoint);
status_t InstallTemporaryBreakpoint( status_t InstallTemporaryBreakpoint(
target_addr_t address, target_addr_t address,
@ -33,6 +39,11 @@ public:
target_addr_t address, target_addr_t address,
BreakpointClient* client); BreakpointClient* client);
private:
status_t _UpdateBreakpointInstallation(
Breakpoint* breakpoint);
// fLock must be held
private: private:
BLocker fLock; // used to synchronize un-/installing BLocker fLock; // used to synchronize un-/installing
TeamDebugModel* fDebugModel; TeamDebugModel* fDebugModel;

View File

@ -56,7 +56,9 @@ Application Debugger :
DwarfFunctionDebugInfo.cpp DwarfFunctionDebugInfo.cpp
DwarfImageDebugInfo.cpp DwarfImageDebugInfo.cpp
DwarfTeamDebugInfo.cpp DwarfTeamDebugInfo.cpp
Function.cpp
FunctionDebugInfo.cpp FunctionDebugInfo.cpp
FunctionInstance.cpp
ImageDebugInfo.cpp ImageDebugInfo.cpp
ImageDebugInfoProvider.cpp ImageDebugInfoProvider.cpp
SpecificImageDebugInfo.cpp SpecificImageDebugInfo.cpp
@ -97,6 +99,7 @@ Application Debugger :
StackTrace.cpp StackTrace.cpp
Statement.cpp Statement.cpp
SymbolInfo.cpp SymbolInfo.cpp
UserBreakpoint.cpp
Team.cpp Team.cpp
TeamDebugModel.cpp TeamDebugModel.cpp
TeamMemory.cpp TeamMemory.cpp

View File

@ -12,7 +12,7 @@
#include "Architecture.h" #include "Architecture.h"
#include "CpuState.h" #include "CpuState.h"
#include "DebuggerInterface.h" #include "DebuggerInterface.h"
#include "FunctionDebugInfo.h" #include "Function.h"
#include "Image.h" #include "Image.h"
#include "ImageDebugInfo.h" #include "ImageDebugInfo.h"
#include "SourceCode.h" #include "SourceCode.h"
@ -258,7 +258,7 @@ LoadImageDebugInfoJob::Do()
// set the result // set the result
locker.Lock(); locker.Lock();
if (error == B_OK) { if (error == B_OK) {
fImage->SetImageDebugInfo(debugInfo, IMAGE_DEBUG_INFO_LOADED); error = fImage->SetImageDebugInfo(debugInfo, IMAGE_DEBUG_INFO_LOADED);
debugInfo->RemoveReference(); debugInfo->RemoveReference();
} else { } else {
fImage->SetImageDebugInfo(NULL, IMAGE_DEBUG_INFO_UNAVAILABLE); fImage->SetImageDebugInfo(NULL, IMAGE_DEBUG_INFO_UNAVAILABLE);
@ -319,7 +319,7 @@ LoadImageDebugInfoJob::ScheduleIfNecessary(Worker* worker, Image* image,
LoadSourceCodeJob::LoadSourceCodeJob( LoadSourceCodeJob::LoadSourceCodeJob(
DebuggerInterface* debuggerInterface, Architecture* architecture, DebuggerInterface* debuggerInterface, Architecture* architecture,
Team* team, FunctionDebugInfo* function) Team* team, Function* function)
: :
fDebuggerInterface(debuggerInterface), fDebuggerInterface(debuggerInterface),
fArchitecture(architecture), fArchitecture(architecture),
@ -346,13 +346,29 @@ LoadSourceCodeJob::Key() const
status_t status_t
LoadSourceCodeJob::Do() LoadSourceCodeJob::Do()
{ {
// Get the function debug info for an instance which we can use to load the
// source code.
AutoLocker<Team> locker(fTeam);
status_t error = B_OK;
FunctionDebugInfo* functionDebugInfo = NULL;
if (FunctionInstance* instance = fFunction->FirstInstance()) {
functionDebugInfo = instance->GetFunctionDebugInfo();
} else
error = B_ENTRY_NOT_FOUND;
Reference<FunctionDebugInfo> functionDebugInfoReference(functionDebugInfo);
locker.Unlock();
// load the source code, if we can // load the source code, if we can
SourceCode* sourceCode = NULL; SourceCode* sourceCode = NULL;
status_t error = fFunction->GetSpecificImageDebugInfo()->LoadSourceCode( if (error == B_OK) {
fFunction, sourceCode); error = functionDebugInfo->GetSpecificImageDebugInfo()->LoadSourceCode(
functionDebugInfo, sourceCode);
}
// set the result // set the result
AutoLocker<Team> locker(fTeam); locker.Lock();
if (error == B_OK) { if (error == B_OK) {
fFunction->SetSourceCode(sourceCode, FUNCTION_SOURCE_LOADED); fFunction->SetSourceCode(sourceCode, FUNCTION_SOURCE_LOADED);
sourceCode->RemoveReference(); sourceCode->RemoveReference();

View File

@ -12,7 +12,7 @@
class Architecture; class Architecture;
class CpuState; class CpuState;
class DebuggerInterface; class DebuggerInterface;
class FunctionDebugInfo; class Function;
class Image; class Image;
class StackFrame; class StackFrame;
class Team; class Team;
@ -112,8 +112,8 @@ class LoadSourceCodeJob : public Job {
public: public:
LoadSourceCodeJob( LoadSourceCodeJob(
DebuggerInterface* debuggerInterface, DebuggerInterface* debuggerInterface,
Architecture* architecture, Architecture* architecture, Team* team,
Team* team, FunctionDebugInfo* function); Function* function);
virtual ~LoadSourceCodeJob(); virtual ~LoadSourceCodeJob();
virtual JobKey Key() const; virtual JobKey Key() const;
@ -123,7 +123,7 @@ private:
DebuggerInterface* fDebuggerInterface; DebuggerInterface* fDebuggerInterface;
Architecture* fArchitecture; Architecture* fArchitecture;
Team* fTeam; Team* fTeam;
FunctionDebugInfo* fFunction; Function* fFunction;
}; };

View File

@ -21,11 +21,15 @@
#include "CpuState.h" #include "CpuState.h"
#include "DebuggerInterface.h" #include "DebuggerInterface.h"
#include "FileManager.h" #include "FileManager.h"
#include "Function.h"
#include "ImageDebugInfo.h"
#include "Jobs.h" #include "Jobs.h"
#include "LocatableFile.h" #include "LocatableFile.h"
#include "MessageCodes.h" #include "MessageCodes.h"
#include "SymbolInfo.h" #include "SourceCode.h"
#include "SpecificImageDebugInfo.h"
#include "Statement.h" #include "Statement.h"
#include "SymbolInfo.h"
#include "TeamDebugInfo.h" #include "TeamDebugInfo.h"
#include "TeamDebugModel.h" #include "TeamDebugModel.h"
@ -479,8 +483,10 @@ TeamDebugger::MessageReceived(BMessage* message)
void void
TeamDebugger::FunctionSourceCodeRequested(TeamWindow* window, TeamDebugger::FunctionSourceCodeRequested(TeamWindow* window,
FunctionDebugInfo* function) FunctionInstance* functionInstance)
{ {
Function* function = functionInstance->GetFunction();
// mark loading // mark loading
AutoLocker< ::Team> locker(fTeam); AutoLocker< ::Team> locker(fTeam);
if (function->SourceCodeState() != FUNCTION_SOURCE_NOT_LOADED) if (function->SourceCodeState() != FUNCTION_SOURCE_NOT_LOADED)
@ -821,6 +827,8 @@ TeamDebugger::_HandleImageDeleted(ImageDeletedEvent* event)
imageHandler->ReleaseReference(); imageHandler->ReleaseReference();
} }
// TODO: Remove breakpoints in the image!
return false; return false;
} }
@ -837,7 +845,114 @@ void
TeamDebugger::_HandleSetUserBreakpoint(target_addr_t address, bool enabled) TeamDebugger::_HandleSetUserBreakpoint(target_addr_t address, bool enabled)
{ {
printf("TeamDebugger::_HandleSetUserBreakpoint(%#llx, %d)\n", address, enabled); printf("TeamDebugger::_HandleSetUserBreakpoint(%#llx, %d)\n", address, enabled);
status_t error = fBreakpointManager->InstallUserBreakpoint(address, // check whether there already is a breakpoint
AutoLocker< ::Team> locker(fTeam);
Breakpoint* breakpoint = fDebugModel->BreakpointAtAddress(address);
UserBreakpoint* userBreakpoint = NULL;
if (breakpoint != NULL && breakpoint->FirstUserBreakpoint() != NULL)
userBreakpoint = breakpoint->FirstUserBreakpoint()->GetUserBreakpoint();
Reference<UserBreakpoint> userBreakpointReference(userBreakpoint);
if (userBreakpoint == NULL) {
printf(" no breakpoint yet\n");
// get the function at the address
Image* image = fTeam->ImageByAddress(address);
printf(" image: %p\n", image);
if (image == NULL)
return;
ImageDebugInfo* imageDebugInfo = image->GetImageDebugInfo();
printf(" image debug info: %p\n", imageDebugInfo);
if (imageDebugInfo == NULL)
return;
// TODO: Handle this case by loading the debug info, if possible!
FunctionInstance* functionInstance
= imageDebugInfo->FunctionAtAddress(address);
printf(" function instance: %p\n", functionInstance);
if (functionInstance == NULL)
return;
Function* function = functionInstance->GetFunction();
printf(" function: %p\n", function);
// get the source location for the address
FunctionDebugInfo* functionDebugInfo
= functionInstance->GetFunctionDebugInfo();
SourceLocation sourceLocation;
Statement* breakpointStatement = NULL;
// if (SourceCode* sourceCode = functionDebugInfo->GetSourceCode()) {
// breakpointStatement = sourceCode->StatementAtAddress(address);
// if (breakpointStatement != NULL)
// sourceLocation = breakpointStatement->StartSourceLocation();
// }
if (breakpointStatement == NULL
&& functionDebugInfo->GetSpecificImageDebugInfo()->GetStatement(
functionDebugInfo, address, breakpointStatement) != B_OK) {
return;
}
sourceLocation = breakpointStatement->StartSourceLocation();
breakpointStatement->ReleaseReference();
target_addr_t relativeAddress = address - functionInstance->Address();
printf(" relative address: %#llx, source location: (%ld, %ld)\n", relativeAddress, sourceLocation.Line(), sourceLocation.Column());
// create the user breakpoint
userBreakpoint = new(std::nothrow) UserBreakpoint(function);
if (userBreakpoint == NULL)
return;
userBreakpointReference.SetTo(userBreakpoint, true);
printf(" created user breakpoint: %p\n", userBreakpoint);
// iterate through all function instances and create
// UserBreakpointInstances
for (FunctionInstanceList::ConstIterator it
= function->Instances().GetIterator();
FunctionInstance* instance = it.Next();) {
printf(" function instance %p: range: %#llx - %#llx\n", instance, instance->Address(), instance->Address() + instance->Size());
// get the breakpoint address for the instance
target_addr_t instanceAddress = 0;
if (instance == functionInstance) {
instanceAddress = address;
} else if (functionInstance->SourceFile() != NULL) {
// We have a source file, so get the address for the source
// location.
Statement* statement = NULL;
functionDebugInfo = instance->GetFunctionDebugInfo();
functionDebugInfo->GetSpecificImageDebugInfo()
->GetStatementForSourceLocation(functionDebugInfo,
sourceLocation, statement);
if (statement != NULL) {
instanceAddress = statement->CoveringAddressRange().Start();
// TODO: What about BreakpointAllowed()?
statement->ReleaseReference();
}
}
printf(" breakpoint address using source info: %llx\n", instanceAddress);
if (instanceAddress == 0) {
// No source file (or we failed getting the statement), so try
// to use the same relative address.
if (relativeAddress > instance->Size())
continue;
instanceAddress = instance->Address() + relativeAddress;
}
printf(" final breakpoint address: %llx\n", instanceAddress);
UserBreakpointInstance* breakpointInstance = new(std::nothrow)
UserBreakpointInstance(userBreakpoint, instanceAddress);
if (breakpointInstance == NULL
|| !userBreakpoint->AddInstance(breakpointInstance)) {
delete breakpointInstance;
return;
}
printf(" breakpoint instance: %p\n", breakpointInstance);
}
}
locker.Unlock();
status_t error = fBreakpointManager->InstallUserBreakpoint(userBreakpoint,
enabled); enabled);
if (error != B_OK) { if (error != B_OK) {
_NotifyUser("Install Breakpoint", "Failed to install breakpoint: %s", _NotifyUser("Install Breakpoint", "Failed to install breakpoint: %s",
@ -850,7 +965,19 @@ void
TeamDebugger::_HandleClearUserBreakpoint(target_addr_t address) TeamDebugger::_HandleClearUserBreakpoint(target_addr_t address)
{ {
printf("TeamDebugger::_HandleClearUserBreakpoint(%#llx)\n", address); printf("TeamDebugger::_HandleClearUserBreakpoint(%#llx)\n", address);
fBreakpointManager->UninstallUserBreakpoint(address);
AutoLocker< ::Team> locker(fTeam);
Breakpoint* breakpoint = fDebugModel->BreakpointAtAddress(address);
if (breakpoint == NULL || breakpoint->FirstUserBreakpoint() == NULL)
return;
UserBreakpoint* userBreakpoint
= breakpoint->FirstUserBreakpoint()->GetUserBreakpoint();
Reference<UserBreakpoint> userBreakpointReference(userBreakpoint);
locker.Unlock();
fBreakpointManager->UninstallUserBreakpoint(userBreakpoint);
} }

View File

@ -42,7 +42,7 @@ public:
private: private:
// TeamWindow::Listener // TeamWindow::Listener
virtual void FunctionSourceCodeRequested(TeamWindow* window, virtual void FunctionSourceCodeRequested(TeamWindow* window,
FunctionDebugInfo* function); FunctionInstance* function);
virtual void ImageDebugInfoRequested(TeamWindow* window, virtual void ImageDebugInfoRequested(TeamWindow* window,
Image* image); Image* image);
virtual void ThreadActionRequested(TeamWindow* window, virtual void ThreadActionRequested(TeamWindow* window,

View File

@ -15,7 +15,7 @@
#include "BreakpointManager.h" #include "BreakpointManager.h"
#include "CpuState.h" #include "CpuState.h"
#include "DebuggerInterface.h" #include "DebuggerInterface.h"
#include "FunctionDebugInfo.h" #include "FunctionInstance.h"
#include "ImageDebugInfo.h" #include "ImageDebugInfo.h"
#include "InstructionInfo.h" #include "InstructionInfo.h"
#include "Jobs.h" #include "Jobs.h"
@ -126,7 +126,7 @@ ThreadHandler::HandleBreakpointHit(BreakpointHitEvent* event)
// spurious breakpoint -- might be a temporary breakpoint, that has // spurious breakpoint -- might be a temporary breakpoint, that has
// already been uninstalled // already been uninstalled
continueThread = true; continueThread = true;
} else if (breakpoint->UserState() != USER_BREAKPOINT_ENABLED) { } else if (breakpoint->HasEnabledUserBreakpoint()) {
// breakpoint of another thread or one that has been disabled in // breakpoint of another thread or one that has been disabled in
// the meantime // the meantime
continueThread = true; continueThread = true;
@ -382,20 +382,21 @@ ThreadHandler::_GetStatementAtInstructionPointer(StackFrame* frame)
{ {
AutoLocker<TeamDebugModel> locker(fDebugModel); AutoLocker<TeamDebugModel> locker(fDebugModel);
FunctionDebugInfo* function = frame->Function(); FunctionInstance* functionInstance = frame->Function();
if (function == NULL) if (functionInstance == NULL)
return NULL; return NULL;
FunctionDebugInfo* function = functionInstance->GetFunctionDebugInfo();
// If there's source code attached to the function, we can just get the // If there's source code attached to the function, we can just get the
// statement. // statement.
SourceCode* sourceCode = function->GetSourceCode(); // SourceCode* sourceCode = function->GetSourceCode();
if (sourceCode != NULL) { // if (sourceCode != NULL) {
Statement* statement = sourceCode->StatementAtAddress( // Statement* statement = sourceCode->StatementAtAddress(
frame->InstructionPointer()); // frame->InstructionPointer());
if (statement != NULL) // if (statement != NULL)
statement->AddReference(); // statement->AddReference();
return statement; // return statement;
} // }
locker.Unlock(); locker.Unlock();

View File

@ -11,7 +11,7 @@
#include <AutoLocker.h> #include <AutoLocker.h>
#include "CpuState.h" #include "CpuState.h"
#include "FunctionDebugInfo.h" #include "FunctionInstance.h"
#include "Image.h" #include "Image.h"
#include "ImageDebugInfo.h" #include "ImageDebugInfo.h"
#include "ImageDebugInfoProvider.h" #include "ImageDebugInfoProvider.h"
@ -75,31 +75,38 @@ Architecture::CreateStackTrace(Team* team,
// get the function // get the function
teamLocker.Lock(); teamLocker.Lock();
FunctionDebugInfo* function = NULL; FunctionInstance* function = NULL;
if (imageDebugInfo != NULL) FunctionDebugInfo* functionDebugInfo = NULL;
if (imageDebugInfo != NULL) {
function = imageDebugInfo->FunctionAtAddress(instructionPointer); function = imageDebugInfo->FunctionAtAddress(instructionPointer);
Reference<FunctionDebugInfo> functionReference(function); if (function != NULL)
functionDebugInfo = function->GetFunctionDebugInfo();
}
Reference<FunctionInstance> functionReference(function);
teamLocker.Unlock(); teamLocker.Unlock();
// If the last frame had been created by the architecture, we update the // If the last frame had been created by the architecture, we update the
// CPU state. // CPU state.
if (architectureFrame) if (architectureFrame) {
UpdateStackFrameCpuState(frame, image, function, cpuState); UpdateStackFrameCpuState(frame, image,
functionDebugInfo, cpuState);
}
// create the frame using the debug info // create the frame using the debug info
StackFrame* previousFrame = NULL; StackFrame* previousFrame = NULL;
CpuState* previousCpuState = NULL; CpuState* previousCpuState = NULL;
if (function != NULL) { if (function != NULL) {
status_t error = function->GetSpecificImageDebugInfo()->CreateFrame( status_t error = functionDebugInfo->GetSpecificImageDebugInfo()
image, function, cpuState, previousFrame, previousCpuState); ->CreateFrame(image, functionDebugInfo, cpuState, previousFrame,
previousCpuState);
if (error != B_OK && error != B_UNSUPPORTED) if (error != B_OK && error != B_UNSUPPORTED)
break; break;
} }
// If we have no frame yet, let the architecture create it. // If we have no frame yet, let the architecture create it.
if (previousFrame == NULL) { if (previousFrame == NULL) {
status_t error = CreateStackFrame(image, function, cpuState, status_t error = CreateStackFrame(image, functionDebugInfo,
frame == NULL, previousFrame, previousCpuState); cpuState, frame == NULL, previousFrame, previousCpuState);
if (error != B_OK) if (error != B_OK)
break; break;
architectureFrame = true; architectureFrame = true;

View File

@ -296,8 +296,9 @@ ArchitectureX86::DisassembleCode(FunctionDebugInfo* function,
bool breakpointAllowed; bool breakpointAllowed;
while (disassembler.GetNextInstruction(line, instructionAddress, while (disassembler.GetNextInstruction(line, instructionAddress,
instructionSize, breakpointAllowed) == B_OK) { instructionSize, breakpointAllowed) == B_OK) {
// TODO: Respect breakpointAllowed!
if (!source->AddInstructionLine(line, instructionAddress, if (!source->AddInstructionLine(line, instructionAddress,
instructionSize, breakpointAllowed)) { instructionSize)) {
return B_NO_MEMORY; return B_NO_MEMORY;
} }
} }
@ -320,9 +321,7 @@ ArchitectureX86::GetStatement(FunctionDebugInfo* function,
// create a statement // create a statement
ContiguousStatement* statement = new(std::nothrow) ContiguousStatement( ContiguousStatement* statement = new(std::nothrow) ContiguousStatement(
SourceLocation(0), SourceLocation(1), SourceLocation(0), TargetAddressRange(info.Address(), info.Size()));
TargetAddressRange(info.Address(), info.Size()),
info.IsBreakpointAllowed());
if (statement == NULL) if (statement == NULL)
return B_NO_MEMORY; return B_NO_MEMORY;

View File

@ -49,17 +49,17 @@ BasicFunctionDebugInfo::Size() const
} }
const char* const BString&
BasicFunctionDebugInfo::Name() const BasicFunctionDebugInfo::Name() const
{ {
return fName.String(); return fName;
} }
const char* const BString&
BasicFunctionDebugInfo::PrettyName() const BasicFunctionDebugInfo::PrettyName() const
{ {
return fPrettyName.String(); return fPrettyName;
} }

View File

@ -23,8 +23,8 @@ public:
virtual SpecificImageDebugInfo* GetSpecificImageDebugInfo() const; virtual SpecificImageDebugInfo* GetSpecificImageDebugInfo() const;
virtual target_addr_t Address() const; virtual target_addr_t Address() const;
virtual target_size_t Size() const; virtual target_size_t Size() const;
virtual const char* Name() const; virtual const BString& Name() const;
virtual const char* PrettyName() const; virtual const BString& PrettyName() const;
virtual LocatableFile* SourceFile() const; virtual LocatableFile* SourceFile() const;
virtual SourceLocation SourceStartLocation() const; virtual SourceLocation SourceStartLocation() const;

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 /*static*/ int
DebuggerImageDebugInfo::_CompareSymbols(const SymbolInfo* a, DebuggerImageDebugInfo::_CompareSymbols(const SymbolInfo* a,
const SymbolInfo* b) const SymbolInfo* b)

View File

@ -36,6 +36,10 @@ public:
virtual status_t GetStatement(FunctionDebugInfo* function, virtual status_t GetStatement(FunctionDebugInfo* function,
target_addr_t address, target_addr_t address,
Statement*& _statement); Statement*& _statement);
virtual status_t GetStatementForSourceLocation(
FunctionDebugInfo* function,
const SourceLocation& sourceLocation,
Statement*& _statement);
private: private:
static int _CompareSymbols(const SymbolInfo* a, static int _CompareSymbols(const SymbolInfo* a,

View File

@ -63,17 +63,17 @@ DwarfFunctionDebugInfo::Size() const
} }
const char* const BString&
DwarfFunctionDebugInfo::Name() const DwarfFunctionDebugInfo::Name() const
{ {
return fName.String(); return fName;
} }
const char* const BString&
DwarfFunctionDebugInfo::PrettyName() const DwarfFunctionDebugInfo::PrettyName() const
{ {
return fName.String(); return fName;
} }

View File

@ -32,8 +32,8 @@ public:
virtual SpecificImageDebugInfo* GetSpecificImageDebugInfo() const; virtual SpecificImageDebugInfo* GetSpecificImageDebugInfo() const;
virtual target_addr_t Address() const; virtual target_addr_t Address() const;
virtual target_size_t Size() const; virtual target_size_t Size() const;
virtual const char* Name() const; virtual const BString& Name() const;
virtual const char* PrettyName() const; virtual const BString& PrettyName() const;
virtual LocatableFile* SourceFile() const; virtual LocatableFile* SourceFile() const;
virtual SourceLocation SourceStartLocation() const; virtual SourceLocation SourceStartLocation() const;

View File

@ -320,11 +320,179 @@ DwarfImageDebugInfo::LoadSourceCode(FunctionDebugInfo* function,
status_t status_t
DwarfImageDebugInfo::GetStatement(FunctionDebugInfo* function, DwarfImageDebugInfo::GetStatement(FunctionDebugInfo* _function,
target_addr_t address, Statement*& _statement) target_addr_t address, Statement*& _statement)
{ {
// TODO:... DwarfFunctionDebugInfo* function
return fArchitecture->GetStatement(function, address, _statement); = dynamic_cast<DwarfFunctionDebugInfo*>(_function);
if (function == NULL)
return B_BAD_VALUE;
AutoLocker<BLocker> locker(fLock);
// get the source file
LocatableFile* file = function->SourceFile();
if (file == NULL)
return B_ENTRY_NOT_FOUND;
// maybe the source code is already loaded -- this will simplify things
CompilationUnit* unit = function->GetCompilationUnit();
// FileSourceCode* sourceCode = _LookupSourceCode(unit, file);
// if (sourceCode) {
// Statement* statement = sourceCode->StatementAtAddress(address);
// if (statement == NULL)
// return B_ENTRY_NOT_FOUND;
//
// statement->AcquireReference();
// _statement = statement;
// return B_OK;
// }
// get the index of the source file in the compilation unit for cheaper
// comparison below
int32 fileIndex = _GetSourceFileIndex(unit, file);
// Get the statement by executing the line number program for the
// compilation unit.
LineNumberProgram& program = unit->GetLineNumberProgram();
if (!program.IsValid())
return B_BAD_DATA;
LineNumberProgram::State state;
program.GetInitialState(state);
target_addr_t statementAddress = 0;
int32 statementLine = -1;
int32 statementColumn = -1;
while (program.GetNextRow(state)) {
bool isOurFile = state.file == fileIndex;
if (statementAddress != 0
&& (!isOurFile || state.isStatement || state.isSequenceEnd)) {
target_addr_t endAddress = state.address;
if (address >= statementAddress && address < endAddress) {
ContiguousStatement* statement = new(std::nothrow)
ContiguousStatement(
SourceLocation(statementLine, statementColumn),
TargetAddressRange(fRelocationDelta + statementAddress,
endAddress - statementAddress));
if (statement == NULL)
return B_NO_MEMORY;
_statement = statement;
return B_OK;
}
statementAddress = 0;
}
// skip statements of other files
if (!isOurFile)
continue;
if (state.isStatement) {
statementAddress = state.address;
statementLine = state.line - 1;
statementColumn = state.column - 1;
}
}
return B_ENTRY_NOT_FOUND;
}
status_t
DwarfImageDebugInfo::GetStatementForSourceLocation(FunctionDebugInfo* _function,
const SourceLocation& sourceLocation, Statement*& _statement)
{
DwarfFunctionDebugInfo* function
= dynamic_cast<DwarfFunctionDebugInfo*>(_function);
if (function == NULL)
return B_BAD_VALUE;
target_addr_t functionStartAddress = function->Address();
target_addr_t functionEndAddress = functionStartAddress + function->Size();
printf("DwarfImageDebugInfo::GetStatementForSourceLocation(%p): function range: %#llx - %#llx\n",
function, functionStartAddress, functionEndAddress);
AutoLocker<BLocker> locker(fLock);
// get the source file
LocatableFile* file = function->SourceFile();
if (file == NULL)
return B_ENTRY_NOT_FOUND;
// maybe the source code is already loaded -- this will simplify things
CompilationUnit* unit = function->GetCompilationUnit();
FileSourceCode* sourceCode = _LookupSourceCode(unit, file);
if (sourceCode) {
// TODO: This is not precise enough -- columns are ignored!
Statement* statement = sourceCode->StatementAtLine(
sourceLocation.Line());
if (statement == NULL)
return B_ENTRY_NOT_FOUND;
statement->AcquireReference();
_statement = statement;
return B_OK;
}
// get the index of the source file in the compilation unit for cheaper
// comparison below
int32 fileIndex = _GetSourceFileIndex(unit, file);
// target_addr_t functionStartAddress = function->Address();
// target_addr_t functionEndAddress = functionStartAddress + function->Size();
// Get the statement by executing the line number program for the
// compilation unit.
LineNumberProgram& program = unit->GetLineNumberProgram();
if (!program.IsValid())
return B_BAD_DATA;
LineNumberProgram::State state;
program.GetInitialState(state);
target_addr_t statementAddress = 0;
int32 statementLine = -1;
int32 statementColumn = -1;
while (program.GetNextRow(state)) {
bool isOurFile = state.file == fileIndex;
if (statementAddress != 0
&& (!isOurFile || state.isStatement || state.isSequenceEnd)) {
target_addr_t endAddress = state.address;
if (statementAddress < endAddress
&& statementAddress >= functionStartAddress
&& statementAddress < functionEndAddress
&& statementLine == (int32)sourceLocation.Line()
&& statementColumn == (int32)sourceLocation.Column()) {
ContiguousStatement* statement = new(std::nothrow)
ContiguousStatement(
SourceLocation(statementLine, statementColumn),
TargetAddressRange(fRelocationDelta + statementAddress,
endAddress - statementAddress));
if (statement == NULL)
return B_NO_MEMORY;
_statement = statement;
return B_OK;
}
statementAddress = 0;
}
// skip statements of other files
if (!isOurFile)
continue;
if (state.isStatement) {
statementAddress = state.address;
statementLine = state.line - 1;
statementColumn = state.column - 1;
}
}
return B_ENTRY_NOT_FOUND;
} }
@ -353,26 +521,13 @@ DwarfImageDebugInfo::_LoadSourceCode(FunctionDebugInfo* _function,
// get the index of the source file in the compilation unit for cheaper // get the index of the source file in the compilation unit for cheaper
// comparison below // comparison below
const char* directory; int32 fileIndex = _GetSourceFileIndex(unit, function->SourceFile());
int32 fileIndex = -1;
for (int32 i = 0; const char* fileName = unit->FileAt(i, &directory); i++) {
LocatableFile* file = fFileManager->GetSourceFile(directory, fileName);
if (file != NULL) {
file->ReleaseReference();
if (file == function->SourceFile()) {
fileIndex = i + 1;
// indices are one-based
break;
}
}
}
printf("DwarfImageDebugInfo::_LoadSourceCode(), file: %ld, function at: %#llx\n", fileIndex, function->Address()); printf("DwarfImageDebugInfo::_LoadSourceCode(), file: %ld, function at: %#llx\n", fileIndex, function->Address());
for (int32 i = 0; const char* fileName = unit->FileAt(i, &directory); i++) { for (int32 i = 0; const char* fileName = unit->FileAt(i, NULL); i++) {
printf(" file %ld: %s\n", i, fileName); printf(" file %ld: %s\n", i, fileName);
} }
// not loaded yet -- get the source file // not loaded yet -- get the source file
SourceFile* sourceFile; SourceFile* sourceFile;
status_t error = fFileManager->LoadSourceFile(file, sourceFile); status_t error = fFileManager->LoadSourceFile(file, sourceFile);
@ -413,10 +568,9 @@ printf(" %#lx (%ld, %ld, %ld) %d\n", state.address, state.file, state.line, s
// add the statement // add the statement
ContiguousStatement* statement = new(std::nothrow) ContiguousStatement* statement = new(std::nothrow)
ContiguousStatement( ContiguousStatement(
SourceLocation(statementLine, statementColumn),
SourceLocation(statementLine, statementColumn), SourceLocation(statementLine, statementColumn),
TargetAddressRange(fRelocationDelta + statementAddress, TargetAddressRange(fRelocationDelta + statementAddress,
endAddress - statementAddress), true); endAddress - statementAddress));
if (statement == NULL) if (statement == NULL)
return B_NO_MEMORY; return B_NO_MEMORY;
@ -463,3 +617,25 @@ DwarfImageDebugInfo::_LookupSourceCode(CompilationUnit* unit,
SourceCodeEntry* entry = fSourceCodes->Lookup(SourceCodeKey(unit, file)); SourceCodeEntry* entry = fSourceCodes->Lookup(SourceCodeKey(unit, file));
return entry != NULL ? entry->sourceCode : NULL; return entry != NULL ? entry->sourceCode : NULL;
} }
int32
DwarfImageDebugInfo::_GetSourceFileIndex(CompilationUnit* unit,
LocatableFile* sourceFile) const
{
// get the index of the source file in the compilation unit for cheaper
// comparison below
const char* directory;
for (int32 i = 0; const char* fileName = unit->FileAt(i, &directory); i++) {
LocatableFile* file = fFileManager->GetSourceFile(directory, fileName);
if (file != NULL) {
file->ReleaseReference();
if (file == sourceFile) {
return i + 1;
// indices are one-based
}
}
}
return -1;
}

View File

@ -47,6 +47,10 @@ public:
virtual status_t GetStatement(FunctionDebugInfo* function, virtual status_t GetStatement(FunctionDebugInfo* function,
target_addr_t address, target_addr_t address,
Statement*& _statement); Statement*& _statement);
virtual status_t GetStatementForSourceLocation(
FunctionDebugInfo* function,
const SourceLocation& sourceLocation,
Statement*& _statement);
private: private:
struct SourceCodeKey; struct SourceCodeKey;
@ -60,6 +64,8 @@ private:
SourceCode*& _sourceCode); SourceCode*& _sourceCode);
FileSourceCode* _LookupSourceCode(CompilationUnit* unit, FileSourceCode* _LookupSourceCode(CompilationUnit* unit,
LocatableFile* file); LocatableFile* file);
int32 _GetSourceFileIndex(CompilationUnit* unit,
LocatableFile* sourceFile) const;
private: private:
BLocker fLock; BLocker fLock;

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 "FunctionDebugInfo.h"
#include "SourceCode.h"
FunctionDebugInfo::FunctionDebugInfo() FunctionDebugInfo::FunctionDebugInfo()
:
fSourceCode(NULL),
fSourceCodeState(FUNCTION_SOURCE_NOT_LOADED)
{ {
} }
FunctionDebugInfo::~FunctionDebugInfo() FunctionDebugInfo::~FunctionDebugInfo()
{
SetSourceCode(NULL, FUNCTION_SOURCE_NOT_LOADED);
}
void
FunctionDebugInfo::SetSourceCode(SourceCode* source,
function_source_state state)
{
if (source == fSourceCode && state == fSourceCodeState)
return;
if (fSourceCode != NULL)
fSourceCode->RemoveReference();
fSourceCode = source;
fSourceCodeState = state;
if (fSourceCode != NULL)
fSourceCode->AddReference();
// notify listeners
for (ListenerList::Iterator it = fListeners.GetIterator();
Listener* listener = it.Next();) {
listener->FunctionSourceCodeChanged(this);
}
}
void
FunctionDebugInfo::AddListener(Listener* listener)
{
fListeners.Add(listener);
}
void
FunctionDebugInfo::RemoveListener(Listener* listener)
{
fListeners.Remove(listener);
}
// #pragma mark - Listener
FunctionDebugInfo::Listener::~Listener()
{
}
void
FunctionDebugInfo::Listener::FunctionSourceCodeChanged(
FunctionDebugInfo* function)
{ {
} }

View File

@ -6,29 +6,17 @@
#define FUNCTION_DEBUG_INFO_H #define FUNCTION_DEBUG_INFO_H
#include <Referenceable.h> #include <Referenceable.h>
#include <util/DoublyLinkedList.h>
#include "SourceLocation.h" #include "SourceLocation.h"
#include "Types.h" #include "Types.h"
enum function_source_state { class BString;
FUNCTION_SOURCE_NOT_LOADED,
FUNCTION_SOURCE_LOADING,
FUNCTION_SOURCE_LOADED,
FUNCTION_SOURCE_UNAVAILABLE
};
class LocatableFile; class LocatableFile;
class SourceCode;
class SpecificImageDebugInfo; class SpecificImageDebugInfo;
class FunctionDebugInfo : public Referenceable { class FunctionDebugInfo : public Referenceable {
public:
class Listener;
public: public:
FunctionDebugInfo(); FunctionDebugInfo();
virtual ~FunctionDebugInfo(); virtual ~FunctionDebugInfo();
@ -36,41 +24,12 @@ public:
virtual SpecificImageDebugInfo* GetSpecificImageDebugInfo() const = 0; virtual SpecificImageDebugInfo* GetSpecificImageDebugInfo() const = 0;
virtual target_addr_t Address() const = 0; virtual target_addr_t Address() const = 0;
virtual target_size_t Size() const = 0; virtual target_size_t Size() const = 0;
virtual const char* Name() const = 0; virtual const BString& Name() const = 0;
virtual const char* PrettyName() const = 0; virtual const BString& PrettyName() const = 0;
virtual LocatableFile* SourceFile() const = 0; virtual LocatableFile* SourceFile() const = 0;
virtual SourceLocation SourceStartLocation() const = 0; virtual SourceLocation SourceStartLocation() const = 0;
virtual SourceLocation SourceEndLocation() const = 0; virtual SourceLocation SourceEndLocation() const = 0;
// mutable attributes follow (locking required)
SourceCode* GetSourceCode() const { return fSourceCode; }
function_source_state SourceCodeState() const
{ return fSourceCodeState; }
void SetSourceCode(SourceCode* source,
function_source_state state);
void AddListener(Listener* listener);
void RemoveListener(Listener* listener);
private:
typedef DoublyLinkedList<Listener> ListenerList;
private:
// mutable
SourceCode* fSourceCode;
function_source_state fSourceCodeState;
ListenerList fListeners;
};
class FunctionDebugInfo::Listener : public DoublyLinkedListLinkImpl<Listener> {
public:
virtual ~Listener();
virtual void FunctionSourceCodeChanged(
FunctionDebugInfo* function);
// called with lock held
}; };

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 <new>
#include "FunctionDebugInfo.h" #include "FunctionDebugInfo.h"
#include "FunctionInstance.h"
#include "SpecificImageDebugInfo.h" #include "SpecificImageDebugInfo.h"
@ -20,8 +21,8 @@ ImageDebugInfo::ImageDebugInfo(const ImageInfo& imageInfo)
ImageDebugInfo::~ImageDebugInfo() ImageDebugInfo::~ImageDebugInfo()
{ {
for (int32 i = 0; FunctionDebugInfo* function = fFunctions.ItemAt(i); i++) for (int32 i = 0; FunctionInstance* function = fFunctions.ItemAt(i); i++)
function->RemoveReference(); function->ReleaseReference();
} }
@ -39,23 +40,35 @@ ImageDebugInfo::FinishInit()
// missing functions from less expressive debug infos // missing functions from less expressive debug infos
for (int32 i = 0; SpecificImageDebugInfo* specificInfo for (int32 i = 0; SpecificImageDebugInfo* specificInfo
= fSpecificInfos.ItemAt(i); i++) { = fSpecificInfos.ItemAt(i); i++) {
FunctionList functions; BObjectList<FunctionDebugInfo> functions;
status_t error = specificInfo->GetFunctions(functions); status_t error = specificInfo->GetFunctions(functions);
if (error != B_OK) if (error != B_OK)
return error; return error;
for (int32 k = 0; FunctionDebugInfo* function = functions.ItemAt(k); for (int32 k = 0; FunctionDebugInfo* function = functions.ItemAt(k);
k++) { k++) {
if (FunctionAtAddress(function->Address()) == NULL) { if (FunctionAtAddress(function->Address()) != NULL)
if (!fFunctions.BinaryInsert(function, &_CompareFunctions)) { continue;
for (; (function = functions.ItemAt(k)); k++) {
function->RemoveReference(); FunctionInstance* instance = new(std::nothrow) FunctionInstance(
return B_NO_MEMORY; this, function);
} if (instance == NULL
} || !fFunctions.BinaryInsert(instance, &_CompareFunctions)) {
} else delete instance;
function->RemoveReference(); error = B_NO_MEMORY;
break;
}
} }
// Remove references returned by the specific debug info -- the
// FunctionInstance objects have references, now.
for (int32 k = 0; FunctionDebugInfo* function = functions.ItemAt(k);
k++) {
function->RemoveReference();
}
if (error != B_OK)
return error;
} }
return B_OK; return B_OK;
@ -69,14 +82,14 @@ ImageDebugInfo::CountFunctions() const
} }
FunctionDebugInfo* FunctionInstance*
ImageDebugInfo::FunctionAt(int32 index) const ImageDebugInfo::FunctionAt(int32 index) const
{ {
return fFunctions.ItemAt(index); return fFunctions.ItemAt(index);
} }
FunctionDebugInfo* FunctionInstance*
ImageDebugInfo::FunctionAtAddress(target_addr_t address) const ImageDebugInfo::FunctionAtAddress(target_addr_t address) const
{ {
return fFunctions.BinarySearchByKey(address, &_CompareAddressFunction); return fFunctions.BinarySearchByKey(address, &_CompareAddressFunction);
@ -84,8 +97,8 @@ ImageDebugInfo::FunctionAtAddress(target_addr_t address) const
/*static*/ int /*static*/ int
ImageDebugInfo::_CompareFunctions(const FunctionDebugInfo* a, ImageDebugInfo::_CompareFunctions(const FunctionInstance* a,
const FunctionDebugInfo* b) const FunctionInstance* b)
{ {
return a->Address() < b->Address() return a->Address() < b->Address()
? -1 : (a->Address() == b->Address() ? 0 : 1); ? -1 : (a->Address() == b->Address() ? 0 : 1);
@ -94,7 +107,7 @@ ImageDebugInfo::_CompareFunctions(const FunctionDebugInfo* a,
/*static*/ int /*static*/ int
ImageDebugInfo::_CompareAddressFunction(const target_addr_t* address, ImageDebugInfo::_CompareAddressFunction(const target_addr_t* address,
const FunctionDebugInfo* function) const FunctionInstance* function)
{ {
if (*address < function->Address()) if (*address < function->Address())
return -1; return -1;

View File

@ -17,6 +17,7 @@
class Architecture; class Architecture;
class DebuggerInterface; class DebuggerInterface;
class FunctionDebugInfo; class FunctionDebugInfo;
class FunctionInstance;
class SpecificImageDebugInfo; class SpecificImageDebugInfo;
@ -29,19 +30,19 @@ public:
status_t FinishInit(); status_t FinishInit();
int32 CountFunctions() const; int32 CountFunctions() const;
FunctionDebugInfo* FunctionAt(int32 index) const; FunctionInstance* FunctionAt(int32 index) const;
FunctionDebugInfo* FunctionAtAddress(target_addr_t address) const; FunctionInstance* FunctionAtAddress(target_addr_t address) const;
private: private:
typedef BObjectList<SpecificImageDebugInfo> SpecificInfoList; typedef BObjectList<SpecificImageDebugInfo> SpecificInfoList;
typedef BObjectList<FunctionDebugInfo> FunctionList; typedef BObjectList<FunctionInstance> FunctionList;
private: private:
static int _CompareFunctions(const FunctionDebugInfo* a, static int _CompareFunctions(const FunctionInstance* a,
const FunctionDebugInfo* b); const FunctionInstance* b);
static int _CompareAddressFunction( static int _CompareAddressFunction(
const target_addr_t* address, const target_addr_t* address,
const FunctionDebugInfo* function); const FunctionInstance* function);
private: private:
ImageInfo fImageInfo; ImageInfo fImageInfo;

View File

@ -17,6 +17,7 @@ class DebuggerInterface;
class FunctionDebugInfo; class FunctionDebugInfo;
class Image; class Image;
class SourceCode; class SourceCode;
class SourceLocation;
class StackFrame; class StackFrame;
class Statement; class Statement;
@ -45,6 +46,11 @@ public:
target_addr_t address, target_addr_t address,
Statement*& _statement) = 0; Statement*& _statement) = 0;
// returns reference // returns reference
virtual status_t GetStatementForSourceLocation(
FunctionDebugInfo* function,
const SourceLocation& sourceLocation,
Statement*& _statement) = 0;
// returns reference
}; };

View File

@ -11,8 +11,62 @@
#include "DebuggerTeamDebugInfo.h" #include "DebuggerTeamDebugInfo.h"
#include "DwarfTeamDebugInfo.h" #include "DwarfTeamDebugInfo.h"
#include "Function.h"
#include "ImageDebugInfo.h" #include "ImageDebugInfo.h"
#include "SpecificImageDebugInfo.h" #include "SpecificImageDebugInfo.h"
#include "StringUtils.h"
// #pragma mark - FunctionHashDefinition
struct TeamDebugInfo::FunctionHashDefinition {
typedef const FunctionInstance* KeyType;
typedef Function ValueType;
size_t HashKey(const FunctionInstance* key) const
{
// Instances without source file only equal themselves.
if (key->SourceFile() == NULL)
return (uint32)(addr_t)key;
uint32 hash = StringUtils::HashValue(key->Name());
hash = hash * 17 + (uint32)(addr_t)key->SourceFile();
SourceLocation location = key->GetSourceLocation();
hash = hash * 17 + location.Line();
hash = hash * 17 + location.Column();
return hash;
}
size_t Hash(const Function* value) const
{
return HashKey(value->FirstInstance());
}
bool Compare(const FunctionInstance* key, const Function* value) const
{
// source file must be the same
if (key->SourceFile() != value->SourceFile())
return false;
// Instances without source file only equal themselves.
if (key->SourceFile() == NULL)
return key == value->FirstInstance();
// Source location and function name must also match.
return key->GetSourceLocation() == value->GetSourceLocation()
&& key->Name() == value->Name();
}
HashTableLink<Function>* GetLink(Function* value) const
{
return value;
}
};
// #pragma mark - TeamDebugInfo
TeamDebugInfo::TeamDebugInfo(DebuggerInterface* debuggerInterface, TeamDebugInfo::TeamDebugInfo(DebuggerInterface* debuggerInterface,
@ -21,19 +75,39 @@ TeamDebugInfo::TeamDebugInfo(DebuggerInterface* debuggerInterface,
fDebuggerInterface(debuggerInterface), fDebuggerInterface(debuggerInterface),
fArchitecture(architecture), fArchitecture(architecture),
fFileManager(fileManager), fFileManager(fileManager),
fSpecificInfos(10, true) fSpecificInfos(10, true),
fFunctions(NULL)
{ {
} }
TeamDebugInfo::~TeamDebugInfo() TeamDebugInfo::~TeamDebugInfo()
{ {
if (fFunctions != NULL) {
Function* function = fFunctions->Clear(true);
while (function != NULL) {
Function* next = function->fNext;
function->ReleaseReference();
function = next;
}
delete fFunctions;
}
} }
status_t status_t
TeamDebugInfo::Init() TeamDebugInfo::Init()
{ {
// create function hash table
fFunctions = new(std::nothrow) FunctionTable;
if (fFunctions == NULL)
return B_NO_MEMORY;
status_t error = fFunctions->Init();
if (error != B_OK)
return error;
// Create specific infos for all types of debug info we support, in // Create specific infos for all types of debug info we support, in
// descending order of expressiveness. // descending order of expressiveness.
@ -45,7 +119,7 @@ TeamDebugInfo::Init()
return B_NO_MEMORY; return B_NO_MEMORY;
} }
status_t error = dwarfInfo->Init(); error = dwarfInfo->Init();
if (error != B_OK) if (error != B_OK)
return error; return error;
@ -98,3 +172,65 @@ TeamDebugInfo::LoadImageDebugInfo(const ImageInfo& imageInfo,
_imageDebugInfo = imageDebugInfoDeleter.Detach(); _imageDebugInfo = imageDebugInfoDeleter.Detach();
return B_OK; return B_OK;
} }
#include <stdio.h>
status_t
TeamDebugInfo::AddImageDebugInfo(ImageDebugInfo* imageDebugInfo)
{
printf("TeamDebugInfo::AddImageDebugInfo(%p)\n", imageDebugInfo);
// Match all of the image debug info's functions instances with functions.
for (int32 i = 0;
FunctionInstance* instance = imageDebugInfo->FunctionAt(i); i++) {
// lookup the function or create it, if it doesn't exist yet
Function* function = fFunctions->Lookup(instance);
if (function != NULL) {
// TODO: Also update possible user breakpoints in this function!
printf(" adding instance %p to existing function %p\n", instance, function);
function->AddInstance(instance);
instance->SetFunction(function);
} else {
function = new(std::nothrow) Function;
if (function == NULL) {
RemoveImageDebugInfo(imageDebugInfo);
return B_NO_MEMORY;
}
printf(" adding instance %p to new function %p\n", instance, function);
function->AddInstance(instance);
instance->SetFunction(function);
fFunctions->Insert(function);
// Insert after adding the instance. Otherwise the function
// wouldn't be hashable/comparable.
}
}
return B_OK;
}
void
TeamDebugInfo::RemoveImageDebugInfo(ImageDebugInfo* imageDebugInfo)
{
// Remove the functions from all of the image debug info's functions
// instances.
for (int32 i = 0;
FunctionInstance* instance = imageDebugInfo->FunctionAt(i); i++) {
if (Function* function = instance->GetFunction()) {
// TODO: Also update possible user breakpoints in this function!
if (function->FirstInstance() == function->LastInstance()) {
// function unused -- remove it
// Note, that we have to remove it from the hash before removing
// the instance, since otherwise the function cannot be compared
// anymore.
fFunctions->Remove(function);
function->ReleaseReference();
// The instance still has a reference.
}
function->RemoveInstance(instance);
instance->SetFunction(NULL);
// If this was the last instance, it will remove the last
// reference to the function.
}
}
}

View File

@ -7,6 +7,7 @@
#include <ObjectList.h> #include <ObjectList.h>
#include <Referenceable.h> #include <Referenceable.h>
#include <util/OpenHashTable.h>
#include "ImageInfo.h" #include "ImageInfo.h"
@ -14,6 +15,8 @@
class Architecture; class Architecture;
class DebuggerInterface; class DebuggerInterface;
class FileManager; class FileManager;
class Function;
class FunctionInstance;
class ImageDebugInfo; class ImageDebugInfo;
class ImageInfo; class ImageInfo;
class LocatableFile; class LocatableFile;
@ -34,14 +37,24 @@ public:
LocatableFile* imageFile, LocatableFile* imageFile,
ImageDebugInfo*& _imageDebugInfo); ImageDebugInfo*& _imageDebugInfo);
// team is locked
status_t AddImageDebugInfo(
ImageDebugInfo* imageDebugInfo);
void RemoveImageDebugInfo(
ImageDebugInfo* imageDebugInfo);
private: private:
struct FunctionHashDefinition;
typedef BObjectList<SpecificTeamDebugInfo> SpecificInfoList; typedef BObjectList<SpecificTeamDebugInfo> SpecificInfoList;
typedef OpenHashTable<FunctionHashDefinition> FunctionTable;
private: private:
DebuggerInterface* fDebuggerInterface; DebuggerInterface* fDebuggerInterface;
Architecture* fArchitecture; Architecture* fArchitecture;
FileManager* fFileManager; FileManager* fFileManager;
SpecificInfoList fSpecificInfos; SpecificInfoList fSpecificInfos;
FunctionTable* fFunctions;
}; };

View File

@ -14,7 +14,7 @@
#include "table/TableColumns.h" #include "table/TableColumns.h"
#include "FunctionDebugInfo.h" #include "FunctionInstance.h"
#include "Image.h" #include "Image.h"
#include "ImageDebugInfo.h" #include "ImageDebugInfo.h"
#include "LocatableFile.h" #include "LocatableFile.h"
@ -63,11 +63,11 @@ public:
// create an array with the functions // create an array with the functions
int32 functionCount = fImageDebugInfo->CountFunctions(); int32 functionCount = fImageDebugInfo->CountFunctions();
FunctionDebugInfo** functions FunctionInstance** functions
= new(std::nothrow) FunctionDebugInfo*[functionCount]; = new(std::nothrow) FunctionInstance*[functionCount];
if (functions == NULL) if (functions == NULL)
return; return;
ArrayDeleter<FunctionDebugInfo*> functionsDeleter(functions); ArrayDeleter<FunctionInstance*> functionsDeleter(functions);
for (int32 i = 0; i < functionCount; i++) for (int32 i = 0; i < functionCount; i++)
functions[i] = fImageDebugInfo->FunctionAt(i); functions[i] = fImageDebugInfo->FunctionAt(i);
@ -170,12 +170,12 @@ public:
return true; return true;
} }
FunctionDebugInfo* function = (FunctionDebugInfo*)object; FunctionInstance* function = (FunctionInstance*)object;
value.SetTo(function->PrettyName(), B_VARIANT_DONT_COPY_DATA); value.SetTo(function->PrettyName(), B_VARIANT_DONT_COPY_DATA);
return true; return true;
} }
bool GetFunctionPath(FunctionDebugInfo* function, TreeTablePath& _path) bool GetFunctionPath(FunctionInstance* function, TreeTablePath& _path)
{ {
int32 index = -1; int32 index = -1;
for (int32 i = 0; i < fFunctionCount; i++) { for (int32 i = 0; i < fFunctionCount; i++) {
@ -198,7 +198,7 @@ public:
} }
bool GetObjectForPath(const TreeTablePath& path, bool GetObjectForPath(const TreeTablePath& path,
LocatableFile*& _sourceFile, FunctionDebugInfo*& _function) LocatableFile*& _sourceFile, FunctionInstance*& _function)
{ {
int32 componentCount = path.CountComponents(); int32 componentCount = path.CountComponents();
if (componentCount == 0 || componentCount > 2) if (componentCount == 0 || componentCount > 2)
@ -256,8 +256,8 @@ private:
return pathA.Compare(pathB); return pathA.Compare(pathB);
} }
static bool _FunctionLess(const FunctionDebugInfo* a, static bool _FunctionLess(const FunctionInstance* a,
const FunctionDebugInfo* b) const FunctionInstance* b)
{ {
// compare source file name first // compare source file name first
int compared = _CompareSourceFileNames(a->SourceFile(), int compared = _CompareSourceFileNames(a->SourceFile(),
@ -271,7 +271,7 @@ private:
private: private:
ImageDebugInfo* fImageDebugInfo; ImageDebugInfo* fImageDebugInfo;
FunctionDebugInfo** fFunctions; FunctionInstance** fFunctions;
int32 fFunctionCount; int32 fFunctionCount;
int32* fSourceFileIndices; int32* fSourceFileIndices;
int32 fSourceFileCount; int32 fSourceFileCount;
@ -357,7 +357,7 @@ printf("ImageFunctionsView::SetImageDebugInfo(%p) done\n", imageDebugInfo);
void void
ImageFunctionsView::SetFunction(FunctionDebugInfo* function) ImageFunctionsView::SetFunction(FunctionInstance* function)
{ {
printf("ImageFunctionsView::SetFunction(%p)\n", function); printf("ImageFunctionsView::SetFunction(%p)\n", function);
TreeTablePath path; TreeTablePath path;
@ -377,7 +377,7 @@ ImageFunctionsView::TreeTableSelectionChanged(TreeTable* table)
return; return;
LocatableFile* sourceFile = NULL; LocatableFile* sourceFile = NULL;
FunctionDebugInfo* function = NULL; FunctionInstance* function = NULL;
TreeTablePath path; TreeTablePath path;
if (table->SelectionModel()->GetPathAt(0, path)) if (table->SelectionModel()->GetPathAt(0, path))
fFunctionsTableModel->GetObjectForPath(path, sourceFile, function); fFunctionsTableModel->GetObjectForPath(path, sourceFile, function);

View File

@ -11,7 +11,7 @@
#include "Team.h" #include "Team.h"
class FunctionDebugInfo; class FunctionInstance;
class ImageFunctionsView : public BGroupView, private TreeTableListener { class ImageFunctionsView : public BGroupView, private TreeTableListener {
@ -29,7 +29,7 @@ public:
void SetImageDebugInfo( void SetImageDebugInfo(
ImageDebugInfo* imageDebugInfo); ImageDebugInfo* imageDebugInfo);
void SetFunction(FunctionDebugInfo* function); void SetFunction(FunctionInstance* function);
private: private:
class FunctionsTableModel; class FunctionsTableModel;
@ -53,7 +53,7 @@ public:
virtual ~Listener(); virtual ~Listener();
virtual void FunctionSelectionChanged( virtual void FunctionSelectionChanged(
FunctionDebugInfo* function) = 0; FunctionInstance* function) = 0;
}; };

View File

@ -20,6 +20,7 @@
#include <ObjectList.h> #include <ObjectList.h>
#include "Breakpoint.h" #include "Breakpoint.h"
#include "Function.h"
#include "SourceCode.h" #include "SourceCode.h"
#include "StackTrace.h" #include "StackTrace.h"
#include "Statement.h" #include "Statement.h"
@ -519,8 +520,7 @@ SourceView::MarkerView::Draw(BRect updateRect)
Statement* statement = fSourceCode->StatementAtLine(line); Statement* statement = fSourceCode->StatementAtLine(line);
if (statement == NULL if (statement == NULL
|| statement->StartSourceLocation().Line() != (uint32)line || statement->StartSourceLocation().Line() != (uint32)line) {
|| !statement->BreakpointAllowed()) {
continue; continue;
} }
@ -543,8 +543,7 @@ SourceView::MarkerView::MouseDown(BPoint where)
Statement* statement = fSourceCode->StatementAtLine(line); Statement* statement = fSourceCode->StatementAtLine(line);
if (statement == NULL if (statement == NULL
|| statement->StartSourceLocation().Line() != (uint32)line || statement->StartSourceLocation().Line() != (uint32)line) {
|| !statement->BreakpointAllowed()) {
return; return;
} }
@ -595,15 +594,24 @@ SourceView::MarkerView::_UpdateIPMarkers()
fIPMarkers.MakeEmpty(); fIPMarkers.MakeEmpty();
if (fSourceCode != NULL && fStackTrace != NULL) { if (fSourceCode != NULL && fStackTrace != NULL) {
AutoLocker<TeamDebugModel> locker(fDebugModel);
for (int32 i = 0; StackFrame* frame = fStackTrace->FrameAt(i); for (int32 i = 0; StackFrame* frame = fStackTrace->FrameAt(i);
i++) { i++) {
target_addr_t ip = frame->InstructionPointer(); target_addr_t ip = frame->InstructionPointer();
Statement* statement = fSourceCode->StatementAtAddress(ip); FunctionInstance* functionInstance;
if (statement == NULL) Statement* statement;
if (fDebugModel->GetTeam()->GetStatementAtAddress(ip,
functionInstance, statement) != B_OK) {
continue; continue;
}
Reference<Statement> statementReference(statement, true);
uint32 line = statement->StartSourceLocation().Line(); uint32 line = statement->StartSourceLocation().Line();
if (line >= (uint32)LineCount()) if (functionInstance->GetFunction()->GetSourceCode() != fSourceCode
|| line < 0 || line >= (uint32)LineCount()) {
continue; continue;
}
bool isTopFrame = i == 0 bool isTopFrame = i == 0
&& frame->Type() != STACK_FRAME_TYPE_SYSCALL; && frame->Type() != STACK_FRAME_TYPE_SYSCALL;
@ -638,25 +646,30 @@ SourceView::MarkerView::_UpdateBreakpointMarkers()
AutoLocker<TeamDebugModel> locker(fDebugModel); AutoLocker<TeamDebugModel> locker(fDebugModel);
// get the breakpoints in our source code range // get the breakpoints in our source code range
BObjectList<Breakpoint> breakpoints; BObjectList<UserBreakpoint> breakpoints;
fDebugModel->GetBreakpointsInAddressRange( fDebugModel->GetBreakpointsForSourceCode(fSourceCode, breakpoints);
fSourceCode->StatementAddressRange(), breakpoints);
for (int32 i = 0; Breakpoint* breakpoint = breakpoints.ItemAt(i); i++) { for (int32 i = 0; UserBreakpoint* breakpoint = breakpoints.ItemAt(i);
if (breakpoint->UserState() == USER_BREAKPOINT_NONE) i++) {
UserBreakpointInstance* breakpointInstance
= breakpoint->InstanceAt(0);
FunctionInstance* functionInstance;
Statement* statement;
if (fDebugModel->GetTeam()->GetStatementAtAddress(
breakpointInstance->Address(), functionInstance,
statement) != B_OK) {
continue; continue;
}
Reference<Statement> statementReference(statement, true);
Statement* statement = fSourceCode->StatementAtAddress(
breakpoint->Address());
if (statement == NULL)
continue;
uint32 line = statement->StartSourceLocation().Line(); uint32 line = statement->StartSourceLocation().Line();
if (line >= (uint32)LineCount()) if (functionInstance->GetFunction()->GetSourceCode() != fSourceCode
|| line < 0 || line >= (uint32)LineCount()) {
continue; continue;
}
BreakpointMarker* marker = new(std::nothrow) BreakpointMarker( BreakpointMarker* marker = new(std::nothrow) BreakpointMarker(
line, breakpoint->Address(), line, breakpointInstance->Address(), breakpoint->IsEnabled());
breakpoint->UserState() == USER_BREAKPOINT_ENABLED);
if (marker == NULL || !fBreakpointMarkers.AddItem(marker)) { if (marker == NULL || !fBreakpointMarkers.AddItem(marker)) {
delete marker; delete marker;
break; break;
@ -995,9 +1008,15 @@ SourceView::ScrollToAddress(target_addr_t address)
if (fSourceCode == NULL) if (fSourceCode == NULL)
return false; return false;
Statement* statement = fSourceCode->StatementAtAddress(address); AutoLocker<TeamDebugModel> locker(fDebugModel);
if (statement == NULL)
FunctionInstance* functionInstance;
Statement* statement;
if (fDebugModel->GetTeam()->GetStatementAtAddress(address, functionInstance,
statement) != B_OK) {
return false; return false;
}
Reference<Statement> statementReference(statement, true);
return ScrollToLine(statement->StartSourceLocation().Line()); return ScrollToLine(statement->StartSourceLocation().Line());
} }
@ -1013,11 +1032,16 @@ SourceView::ScrollToLine(uint32 line)
float bottom = top + fFontInfo.lineHeight - 1; float bottom = top + fFontInfo.lineHeight - 1;
BRect visible = _VisibleRect(); BRect visible = _VisibleRect();
printf("SourceView::ScrollToLine(%ld)\n", line);
printf(" visible: (%f, %f) - (%f, %f), line: %f - %f\n", visible.left, visible.top, visible.right, visible.bottom, top, bottom);
// If not visible at all, scroll to the center, otherwise scroll so that at // If not visible at all, scroll to the center, otherwise scroll so that at
// least one more line is visible. // least one more line is visible.
if (top >= visible.bottom || bottom <= visible.top) if (top >= visible.bottom || bottom <= visible.top)
{
printf(" -> scrolling to (%f, %f)\n", visible.left, top - (visible.Height() + 1) / 2);
ScrollTo(visible.left, top - (visible.Height() + 1) / 2); ScrollTo(visible.left, top - (visible.Height() + 1) / 2);
}
else if (top - fFontInfo.lineHeight < visible.top) else if (top - fFontInfo.lineHeight < visible.top)
ScrollBy(0, top - fFontInfo.lineHeight - visible.top); ScrollBy(0, top - fFontInfo.lineHeight - visible.top);
else if (bottom + fFontInfo.lineHeight > visible.bottom) else if (bottom + fFontInfo.lineHeight > visible.bottom)

View File

@ -11,7 +11,7 @@
#include "table/TableColumns.h" #include "table/TableColumns.h"
#include "FunctionDebugInfo.h" #include "FunctionInstance.h"
#include "Image.h" #include "Image.h"
#include "StackTrace.h" #include "StackTrace.h"
@ -105,7 +105,7 @@ public:
case 2: case 2:
{ {
Image* image = frame->GetImage(); Image* image = frame->GetImage();
FunctionDebugInfo* function = frame->Function(); FunctionInstance* function = frame->Function();
if (image == NULL && function == NULL) { if (image == NULL && function == NULL) {
value.SetTo("?", B_VARIANT_DONT_COPY_DATA); value.SetTo("?", B_VARIANT_DONT_COPY_DATA);
return true; return true;

View File

@ -215,7 +215,7 @@ TeamWindow::StackFrameSelectionChanged(StackFrame* frame)
void void
TeamWindow::FunctionSelectionChanged(FunctionDebugInfo* function) TeamWindow::FunctionSelectionChanged(FunctionInstance* function)
{ {
_SetActiveFunction(function); _SetActiveFunction(function);
} }
@ -281,7 +281,7 @@ TeamWindow::UserBreakpointChanged(const TeamDebugModel::BreakpointEvent& event)
void void
TeamWindow::FunctionSourceCodeChanged(FunctionDebugInfo* function) TeamWindow::FunctionSourceCodeChanged(Function* function)
{ {
printf("TeamWindow::FunctionSourceCodeChanged(%p): source: %p, state: %d\n", printf("TeamWindow::FunctionSourceCodeChanged(%p): source: %p, state: %d\n",
function, function->GetSourceCode(), function->SourceCodeState()); function, function->GetSourceCode(), function->SourceCodeState());
@ -469,15 +469,15 @@ TeamWindow::_SetActiveStackFrame(StackFrame* frame)
void void
TeamWindow::_SetActiveFunction(FunctionDebugInfo* function) TeamWindow::_SetActiveFunction(FunctionInstance* functionInstance)
{ {
if (function == fActiveFunction) if (functionInstance == fActiveFunction)
return; return;
AutoLocker<TeamDebugModel> locker(fDebugModel); AutoLocker<TeamDebugModel> locker(fDebugModel);
if (fActiveFunction != NULL) { if (fActiveFunction != NULL) {
fActiveFunction->RemoveListener(this); fActiveFunction->GetFunction()->RemoveListener(this);
fActiveFunction->RemoveReference(); fActiveFunction->RemoveReference();
} }
@ -487,12 +487,12 @@ TeamWindow::_SetActiveFunction(FunctionDebugInfo* function)
fActiveFunction = NULL; fActiveFunction = NULL;
if (function != NULL) { if (functionInstance != NULL) {
_SetActiveImage(fDebugModel->GetTeam()->ImageByAddress( _SetActiveImage(fDebugModel->GetTeam()->ImageByAddress(
function->Address())); functionInstance->Address()));
} }
fActiveFunction = function; fActiveFunction = functionInstance;
locker.Lock(); locker.Lock();
@ -501,13 +501,14 @@ TeamWindow::_SetActiveFunction(FunctionDebugInfo* function)
if (fActiveFunction != NULL) { if (fActiveFunction != NULL) {
fActiveFunction->AddReference(); fActiveFunction->AddReference();
fActiveFunction->AddListener(this); fActiveFunction->GetFunction()->AddListener(this);
sourceCode = fActiveFunction->GetSourceCode(); Function* function = fActiveFunction->GetFunction();
sourceCode = function->GetSourceCode();
sourceCodeReference.SetTo(sourceCode); sourceCodeReference.SetTo(sourceCode);
// If the source code is not loaded yet, request it. // If the source code is not loaded yet, request it.
if (fActiveFunction->SourceCodeState() == FUNCTION_SOURCE_NOT_LOADED) if (function->SourceCodeState() == FUNCTION_SOURCE_NOT_LOADED)
fListener->FunctionSourceCodeRequested(this, fActiveFunction); fListener->FunctionSourceCodeRequested(this, fActiveFunction);
} }
@ -522,8 +523,10 @@ TeamWindow::_SetActiveFunction(FunctionDebugInfo* function)
void void
TeamWindow::_SetActiveSourceCode(SourceCode* sourceCode) TeamWindow::_SetActiveSourceCode(SourceCode* sourceCode)
{ {
if (sourceCode == fActiveSourceCode) if (sourceCode == fActiveSourceCode) {
_ScrollToActiveFunction();
return; return;
}
if (fActiveSourceCode != NULL) if (fActiveSourceCode != NULL)
fActiveSourceCode->RemoveReference(); fActiveSourceCode->RemoveReference();
@ -535,16 +538,9 @@ TeamWindow::_SetActiveSourceCode(SourceCode* sourceCode)
fSourceView->SetSourceCode(fActiveSourceCode); fSourceView->SetSourceCode(fActiveSourceCode);
// Scroll to the active function, if it doesn't match the stack frame (i.e. _ScrollToActiveFunction();
// has been selected manually).
if (fActiveFunction != NULL && fActiveSourceCode != NULL
&& (fActiveStackFrame == NULL
|| fActiveStackFrame->Function() != fActiveFunction)) {
fSourceView->ScrollToAddress(fActiveFunction->Address());
}
} }
void void
TeamWindow::_UpdateCpuState() TeamWindow::_UpdateCpuState()
{ {
@ -601,6 +597,19 @@ TeamWindow::_UpdateRunButtons()
} }
void
TeamWindow::_ScrollToActiveFunction()
{
// Scroll to the active function, if it doesn't match the stack frame (i.e.
// has been selected manually).
if (fActiveFunction != NULL && fActiveSourceCode != NULL
&& (fActiveStackFrame == NULL
|| fActiveStackFrame->Function() != fActiveFunction)) {
fSourceView->ScrollToAddress(fActiveFunction->Address());
}
}
void void
TeamWindow::_HandleThreadStateChanged(thread_id threadID) TeamWindow::_HandleThreadStateChanged(thread_id threadID)
{ {
@ -693,7 +702,7 @@ TeamWindow::_HandleSourceCodeChanged()
// get a reference to the source code // get a reference to the source code
AutoLocker<TeamDebugModel> locker(fDebugModel); AutoLocker<TeamDebugModel> locker(fDebugModel);
SourceCode* sourceCode = fActiveFunction->GetSourceCode(); SourceCode* sourceCode = fActiveFunction->GetFunction()->GetSourceCode();
Reference<SourceCode> sourceCodeReference(sourceCode); Reference<SourceCode> sourceCodeReference(sourceCode);
locker.Unlock(); locker.Unlock();

View File

@ -9,7 +9,7 @@
#include <Window.h> #include <Window.h>
#include "SourceView.h" #include "SourceView.h"
#include "FunctionDebugInfo.h" #include "Function.h"
#include "ImageFunctionsView.h" #include "ImageFunctionsView.h"
#include "ImageListView.h" #include "ImageListView.h"
#include "StackTraceView.h" #include "StackTraceView.h"
@ -20,7 +20,6 @@
class BButton; class BButton;
class BTabView; class BTabView;
class FunctionDebugInfo;
class Image; class Image;
class RegisterView; class RegisterView;
class SourceCode; class SourceCode;
@ -30,7 +29,7 @@ class StackFrame;
class TeamWindow : public BWindow, ThreadListView::Listener, class TeamWindow : public BWindow, ThreadListView::Listener,
ImageListView::Listener, StackTraceView::Listener, ImageListView::Listener, StackTraceView::Listener,
ImageFunctionsView::Listener, SourceView::Listener, Team::Listener, ImageFunctionsView::Listener, SourceView::Listener, Team::Listener,
TeamDebugModel::Listener, FunctionDebugInfo::Listener { TeamDebugModel::Listener, Function::Listener {
public: public:
class Listener; class Listener;
@ -58,7 +57,7 @@ private:
// ImageFunctionsView::Listener // ImageFunctionsView::Listener
virtual void FunctionSelectionChanged( virtual void FunctionSelectionChanged(
FunctionDebugInfo* function); FunctionInstance* function);
// SourceView::Listener // SourceView::Listener
virtual void SetBreakpointRequested(target_addr_t address, virtual void SetBreakpointRequested(target_addr_t address,
@ -80,9 +79,8 @@ private:
const TeamDebugModel::BreakpointEvent& const TeamDebugModel::BreakpointEvent&
event); event);
// FunctionDebugInfo::Listener // Function::Listener
virtual void FunctionSourceCodeChanged( virtual void FunctionSourceCodeChanged(Function* function);
FunctionDebugInfo* function);
void _Init(); void _Init();
@ -90,10 +88,11 @@ private:
void _SetActiveImage(Image* image); void _SetActiveImage(Image* image);
void _SetActiveStackTrace(StackTrace* stackTrace); void _SetActiveStackTrace(StackTrace* stackTrace);
void _SetActiveStackFrame(StackFrame* frame); void _SetActiveStackFrame(StackFrame* frame);
void _SetActiveFunction(FunctionDebugInfo* function); void _SetActiveFunction(FunctionInstance* function);
void _SetActiveSourceCode(SourceCode* sourceCode); void _SetActiveSourceCode(SourceCode* sourceCode);
void _UpdateCpuState(); void _UpdateCpuState();
void _UpdateRunButtons(); void _UpdateRunButtons();
void _ScrollToActiveFunction();
void _HandleThreadStateChanged(thread_id threadID); void _HandleThreadStateChanged(thread_id threadID);
void _HandleCpuStateChanged(thread_id threadID); void _HandleCpuStateChanged(thread_id threadID);
@ -109,7 +108,7 @@ private:
Image* fActiveImage; Image* fActiveImage;
StackTrace* fActiveStackTrace; StackTrace* fActiveStackTrace;
StackFrame* fActiveStackFrame; StackFrame* fActiveStackFrame;
FunctionDebugInfo* fActiveFunction; FunctionInstance* fActiveFunction;
SourceCode* fActiveSourceCode; SourceCode* fActiveSourceCode;
Listener* fListener; Listener* fListener;
BTabView* fTabView; BTabView* fTabView;
@ -132,7 +131,7 @@ public:
virtual ~Listener(); virtual ~Listener();
virtual void FunctionSourceCodeRequested(TeamWindow* window, virtual void FunctionSourceCodeRequested(TeamWindow* window,
FunctionDebugInfo* function) = 0; FunctionInstance* function) = 0;
virtual void ImageDebugInfoRequested(TeamWindow* window, virtual void ImageDebugInfoRequested(TeamWindow* window,
Image* image) = 0; Image* image) = 0;
virtual void ThreadActionRequested(TeamWindow* window, virtual void ThreadActionRequested(TeamWindow* window,

View File

@ -21,7 +21,6 @@ Breakpoint::Breakpoint(Image* image, target_addr_t address)
: :
fAddress(address), fAddress(address),
fImage(image), fImage(image),
fUserState(USER_BREAKPOINT_NONE),
fInstalled(false) fInstalled(false)
{ {
} }
@ -32,13 +31,6 @@ Breakpoint::~Breakpoint()
} }
void
Breakpoint::SetUserState(user_breakpoint_state state)
{
fUserState = state;
}
void void
Breakpoint::SetInstalled(bool installed) Breakpoint::SetInstalled(bool installed)
{ {
@ -49,14 +41,45 @@ Breakpoint::SetInstalled(bool installed)
bool bool
Breakpoint::ShouldBeInstalled() const Breakpoint::ShouldBeInstalled() const
{ {
return fUserState == USER_BREAKPOINT_ENABLED || !fClients.IsEmpty(); if (!fClients.IsEmpty())
return true;
return !fClients.IsEmpty() || HasEnabledUserBreakpoint();
} }
bool bool
Breakpoint::IsUnused() const Breakpoint::IsUnused() const
{ {
return fUserState == USER_BREAKPOINT_NONE && fClients.IsEmpty(); return fClients.IsEmpty() && fUserBreakpoints.IsEmpty();
}
bool
Breakpoint::HasEnabledUserBreakpoint() const
{
for (UserBreakpointInstanceList::ConstIterator it
= fUserBreakpoints.GetIterator();
UserBreakpointInstance* instance = it.Next();) {
if (instance->GetUserBreakpoint()->IsEnabled())
return true;
}
return false;
}
void
Breakpoint::AddUserBreakpoint(UserBreakpointInstance* instance)
{
fUserBreakpoints.Add(instance);
}
void
Breakpoint::RemoveUserBreakpoint(UserBreakpointInstance* instance)
{
fUserBreakpoints.Remove(instance);
} }

View File

@ -5,17 +5,7 @@
#ifndef BREAKPOINT_H #ifndef BREAKPOINT_H
#define BREAKPOINT_H #define BREAKPOINT_H
#include <ObjectList.h> #include "UserBreakpoint.h"
#include <Referenceable.h>
#include "Types.h"
enum user_breakpoint_state {
USER_BREAKPOINT_NONE,
USER_BREAKPOINT_ENABLED,
USER_BREAKPOINT_DISABLED
};
class Image; class Image;
@ -35,14 +25,22 @@ public:
Image* GetImage() const { return fImage; } Image* GetImage() const { return fImage; }
target_addr_t Address() const { return fAddress; } target_addr_t Address() const { return fAddress; }
user_breakpoint_state UserState() const { return fUserState; }
void SetUserState(user_breakpoint_state state);
bool IsInstalled() const { return fInstalled; } bool IsInstalled() const { return fInstalled; }
void SetInstalled(bool installed); void SetInstalled(bool installed);
bool ShouldBeInstalled() const; bool ShouldBeInstalled() const;
bool IsUnused() const; bool IsUnused() const;
bool HasEnabledUserBreakpoint() const;
UserBreakpointInstance* FirstUserBreakpoint() const
{ return fUserBreakpoints.Head(); }
UserBreakpointInstance* LastUserBreakpoint() const
{ return fUserBreakpoints.Tail(); }
void AddUserBreakpoint(
UserBreakpointInstance* instance);
void RemoveUserBreakpoint(
UserBreakpointInstance* instance);
bool AddClient(BreakpointClient* client); bool AddClient(BreakpointClient* client);
void RemoveClient(BreakpointClient* client); void RemoveClient(BreakpointClient* client);
@ -59,8 +57,8 @@ private:
private: private:
target_addr_t fAddress; target_addr_t fAddress;
Image* fImage; Image* fImage;
UserBreakpointInstanceList fUserBreakpoints;
ClientList fClients; ClientList fClients;
user_breakpoint_state fUserState;
bool fInstalled; bool fInstalled;
}; };

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* Statement*
DisassembledCode::StatementAtLine(int32 index) const DisassembledCode::StatementAtLine(int32 index) const
{ {
@ -79,25 +65,25 @@ DisassembledCode::StatementAtLine(int32 index) const
} }
Statement* //Statement*
DisassembledCode::StatementAtAddress(target_addr_t address) const //DisassembledCode::StatementAtAddress(target_addr_t address) const
{ //{
return fStatements.BinarySearchByKey(address, &_CompareAddressStatement); // return fStatements.BinarySearchByKey(address, &_CompareAddressStatement);
} //}
TargetAddressRange //TargetAddressRange
DisassembledCode::StatementAddressRange() const //DisassembledCode::StatementAddressRange() const
{ //{
if (fStatements.IsEmpty()) // if (fStatements.IsEmpty())
return TargetAddressRange(); // return TargetAddressRange();
//
ContiguousStatement* first = fStatements.ItemAt(0); // ContiguousStatement* first = fStatements.ItemAt(0);
ContiguousStatement* last // ContiguousStatement* last
= fStatements.ItemAt(fStatements.CountItems() - 1); // = fStatements.ItemAt(fStatements.CountItems() - 1);
return TargetAddressRange(first->AddressRange().Start(), // return TargetAddressRange(first->AddressRange().Start(),
last->AddressRange().End()); // last->AddressRange().End());
} //}
bool bool
@ -109,13 +95,12 @@ DisassembledCode::AddCommentLine(const BString& line)
bool bool
DisassembledCode::AddInstructionLine(const BString& line, target_addr_t address, DisassembledCode::AddInstructionLine(const BString& line, target_addr_t address,
target_size_t size, bool breakpointAllowed) target_size_t size)
{ {
int32 lineIndex = fLines.CountItems(); int32 lineIndex = fLines.CountItems();
ContiguousStatement* statement = new(std::nothrow) ContiguousStatement( ContiguousStatement* statement = new(std::nothrow) ContiguousStatement(
SourceLocation(lineIndex), SourceLocation(lineIndex + 1), SourceLocation(lineIndex), TargetAddressRange(address, size));
TargetAddressRange(address, size), breakpointAllowed);
if (statement == NULL) if (statement == NULL)
return false; return false;

View File

@ -22,18 +22,15 @@ public:
virtual int32 CountLines() const; virtual int32 CountLines() const;
virtual const char* LineAt(int32 index) const; virtual const char* LineAt(int32 index) const;
virtual int32 CountStatements() const;
virtual Statement* StatementAt(int32 index) const;
virtual Statement* StatementAtLine(int32 index) const; virtual Statement* StatementAtLine(int32 index) const;
virtual Statement* StatementAtAddress(target_addr_t address) const; // Statement* StatementAtAddress(target_addr_t address) const;
virtual TargetAddressRange StatementAddressRange() const; // TargetAddressRange StatementAddressRange() const;
public: public:
bool AddCommentLine(const BString& line); bool AddCommentLine(const BString& line);
bool AddInstructionLine(const BString& line, bool AddInstructionLine(const BString& line,
target_addr_t address, target_size_t size, target_addr_t address, target_size_t size);
bool breakpointAllowed);
// instructions must be added in // instructions must be added in
// ascending address order // ascending address order

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* Statement*
FileSourceCode::StatementAtLine(int32 index) const FileSourceCode::StatementAtLine(int32 index) const
{ {
@ -99,25 +85,25 @@ FileSourceCode::StatementAtLine(int32 index) const
} }
Statement* //Statement*
FileSourceCode::StatementAtAddress(target_addr_t address) const //FileSourceCode::StatementAtAddress(target_addr_t address) const
{ //{
return fStatements.BinarySearchByKey(address, &_CompareAddressStatement); // return fStatements.BinarySearchByKey(address, &_CompareAddressStatement);
} //}
TargetAddressRange //TargetAddressRange
FileSourceCode::StatementAddressRange() const //FileSourceCode::StatementAddressRange() const
{ //{
if (fStatements.IsEmpty()) // if (fStatements.IsEmpty())
return TargetAddressRange(); // return TargetAddressRange();
//
ContiguousStatement* first = fStatements.ItemAt(0); // ContiguousStatement* first = fStatements.ItemAt(0);
ContiguousStatement* last // ContiguousStatement* last
= fStatements.ItemAt(fStatements.CountItems() - 1); // = fStatements.ItemAt(fStatements.CountItems() - 1);
return TargetAddressRange(first->AddressRange().Start(), // return TargetAddressRange(first->AddressRange().Start(),
last->AddressRange().End()); // last->AddressRange().End());
} //}
/*static*/ int /*static*/ int

View File

@ -25,12 +25,10 @@ public:
virtual int32 CountLines() const; virtual int32 CountLines() const;
virtual const char* LineAt(int32 index) const; virtual const char* LineAt(int32 index) const;
virtual int32 CountStatements() const;
virtual Statement* StatementAt(int32 index) const;
virtual Statement* StatementAtLine(int32 index) const; virtual Statement* StatementAtLine(int32 index) const;
virtual Statement* StatementAtAddress(target_addr_t address) const; // Statement* StatementAtAddress(target_addr_t address) const;
virtual TargetAddressRange StatementAddressRange() const; // virtual TargetAddressRange StatementAddressRange() const;
private: private:
typedef BObjectList<ContiguousStatement> StatementList; typedef BObjectList<ContiguousStatement> StatementList;

View File

@ -8,6 +8,7 @@
#include "ImageDebugInfo.h" #include "ImageDebugInfo.h"
#include "LocatableFile.h" #include "LocatableFile.h"
#include "Team.h" #include "Team.h"
#include "TeamDebugInfo.h"
Image::Image(Team* team,const ImageInfo& imageInfo, LocatableFile* imageFile) Image::Image(Team* team,const ImageInfo& imageInfo, LocatableFile* imageFile)
@ -49,22 +50,34 @@ Image::ContainsAddress(target_addr_t address) const
} }
void status_t
Image::SetImageDebugInfo(ImageDebugInfo* debugInfo, Image::SetImageDebugInfo(ImageDebugInfo* debugInfo,
image_debug_info_state state) image_debug_info_state state)
{ {
if (debugInfo == fDebugInfo && state == fDebugInfoState) if (debugInfo == fDebugInfo && state == fDebugInfoState)
return; return B_OK;
if (fDebugInfo != NULL) if (fDebugInfo != NULL) {
fTeam->DebugInfo()->RemoveImageDebugInfo(fDebugInfo);
fDebugInfo->RemoveReference(); fDebugInfo->RemoveReference();
}
fDebugInfo = debugInfo; fDebugInfo = debugInfo;
fDebugInfoState = state; fDebugInfoState = state;
if (fDebugInfo != NULL) status_t error = B_OK;
fDebugInfo->AddReference(); if (fDebugInfo != NULL) {
error = fTeam->DebugInfo()->AddImageDebugInfo(fDebugInfo);
if (error == B_OK) {
fDebugInfo->AddReference();
} else {
fDebugInfo = NULL;
fDebugInfoState = IMAGE_DEBUG_INFO_UNAVAILABLE;
}
}
// notify listeners // notify listeners
fTeam->NotifyImageDebugInfoChanged(this); fTeam->NotifyImageDebugInfoChanged(this);
return error;
} }

View File

@ -34,7 +34,6 @@ public:
status_t Init(); status_t Init();
Team* GetTeam() const { return fTeam; } Team* GetTeam() const { return fTeam; }
image_id ID() const { return fInfo.ImageID(); } image_id ID() const { return fInfo.ImageID(); }
const char* Name() const { return fInfo.Name(); } const char* Name() const { return fInfo.Name(); }
@ -48,7 +47,7 @@ public:
ImageDebugInfo* GetImageDebugInfo() const { return fDebugInfo; } ImageDebugInfo* GetImageDebugInfo() const { return fDebugInfo; }
image_debug_info_state ImageDebugInfoState() const image_debug_info_state ImageDebugInfoState() const
{ return fDebugInfoState; } { return fDebugInfoState; }
void SetImageDebugInfo(ImageDebugInfo* debugInfo, status_t SetImageDebugInfo(ImageDebugInfo* debugInfo,
image_debug_info_state state); image_debug_info_state state);
private: private:

View File

@ -20,13 +20,7 @@ public:
virtual int32 CountLines() const = 0; virtual int32 CountLines() const = 0;
virtual const char* LineAt(int32 index) const = 0; virtual const char* LineAt(int32 index) const = 0;
virtual int32 CountStatements() const = 0;
virtual Statement* StatementAt(int32 index) const = 0;
virtual Statement* StatementAtLine(int32 index) const = 0; virtual Statement* StatementAtLine(int32 index) const = 0;
virtual Statement* StatementAtAddress(target_addr_t address)
const = 0;
virtual TargetAddressRange StatementAddressRange() const = 0;
}; };

View File

@ -6,7 +6,7 @@
#include "StackFrame.h" #include "StackFrame.h"
#include "CpuState.h" #include "CpuState.h"
#include "FunctionDebugInfo.h" #include "FunctionInstance.h"
#include "Image.h" #include "Image.h"
@ -57,7 +57,7 @@ StackFrame::SetImage(Image* image)
void void
StackFrame::SetFunction(FunctionDebugInfo* function) StackFrame::SetFunction(FunctionInstance* function)
{ {
if (fFunction != NULL) if (fFunction != NULL)
fFunction->RemoveReference(); fFunction->RemoveReference();

View File

@ -22,7 +22,7 @@ enum stack_frame_type {
class CpuState; class CpuState;
class Image; class Image;
class FunctionDebugInfo; class FunctionInstance;
class StackFrame : public Referenceable { class StackFrame : public Referenceable {
@ -46,8 +46,8 @@ public:
Image* GetImage() const { return fImage; } Image* GetImage() const { return fImage; }
void SetImage(Image* image); void SetImage(Image* image);
FunctionDebugInfo* Function() const { return fFunction; } FunctionInstance* Function() const { return fFunction; }
void SetFunction(FunctionDebugInfo* function); void SetFunction(FunctionInstance* function);
private: private:
stack_frame_type fType; stack_frame_type fType;
@ -56,7 +56,7 @@ private:
target_addr_t fInstructionPointer; target_addr_t fInstructionPointer;
target_addr_t fReturnAddress; target_addr_t fReturnAddress;
Image* fImage; Image* fImage;
FunctionDebugInfo* fFunction; FunctionInstance* fFunction;
}; };

View File

@ -17,12 +17,9 @@ Statement::~Statement()
// #pragma mark - AbstractStatement // #pragma mark - AbstractStatement
AbstractStatement::AbstractStatement(const SourceLocation& start, AbstractStatement::AbstractStatement(const SourceLocation& start)
const SourceLocation& end, bool breakpointAllowed)
: :
fStart(start), fStart(start)
fEnd(end),
fBreakpointAllowed(breakpointAllowed)
{ {
} }
@ -34,28 +31,13 @@ AbstractStatement::StartSourceLocation() const
} }
SourceLocation
AbstractStatement::EndSourceLocation() const
{
return fEnd;
}
bool
AbstractStatement::BreakpointAllowed() const
{
return fBreakpointAllowed;
}
// #pragma mark - ContiguousStatement // #pragma mark - ContiguousStatement
ContiguousStatement::ContiguousStatement(const SourceLocation& start, ContiguousStatement::ContiguousStatement(const SourceLocation& start,
const SourceLocation& end, const TargetAddressRange& range, const TargetAddressRange& range)
bool breakpointAllowed)
: :
AbstractStatement(start, end, breakpointAllowed), AbstractStatement(start),
fRange(range) fRange(range)
{ {
} }

View File

@ -17,7 +17,6 @@ public:
virtual ~Statement(); virtual ~Statement();
virtual SourceLocation StartSourceLocation() const = 0; virtual SourceLocation StartSourceLocation() const = 0;
virtual SourceLocation EndSourceLocation() const = 0;
virtual TargetAddressRange CoveringAddressRange() const = 0; virtual TargetAddressRange CoveringAddressRange() const = 0;
@ -26,35 +25,24 @@ public:
virtual bool ContainsAddress(target_addr_t address) virtual bool ContainsAddress(target_addr_t address)
const = 0; const = 0;
virtual bool BreakpointAllowed() const = 0;
}; };
class AbstractStatement : public Statement { class AbstractStatement : public Statement {
public: public:
AbstractStatement(const SourceLocation& start, AbstractStatement(const SourceLocation& start);
const SourceLocation& end,
bool breakpointAllowed);
virtual SourceLocation StartSourceLocation() const; virtual SourceLocation StartSourceLocation() const;
virtual SourceLocation EndSourceLocation() const;
virtual bool BreakpointAllowed() const;
protected: protected:
SourceLocation fStart; SourceLocation fStart;
SourceLocation fEnd;
bool fBreakpointAllowed;
}; };
class ContiguousStatement : public AbstractStatement { class ContiguousStatement : public AbstractStatement {
public: public:
ContiguousStatement(const SourceLocation& start, ContiguousStatement(const SourceLocation& start,
const SourceLocation& end, const TargetAddressRange& range);
const TargetAddressRange& range,
bool breakpointAllowed);
const TargetAddressRange& AddressRange() const const TargetAddressRange& AddressRange() const
{ return fRange; } { return fRange; }

View File

@ -9,6 +9,9 @@
#include <AutoLocker.h> #include <AutoLocker.h>
#include "FunctionInstance.h"
#include "ImageDebugInfo.h"
#include "SpecificImageDebugInfo.h"
#include "TeamDebugInfo.h" #include "TeamDebugInfo.h"
@ -201,6 +204,39 @@ Team::Images() const
} }
status_t
Team::GetStatementAtAddress(target_addr_t address, FunctionInstance*& _function,
Statement*& _statement)
{
// get the image at the address
Image* image = ImageByAddress(address);
if (image == NULL)
return B_ENTRY_NOT_FOUND;
ImageDebugInfo* imageDebugInfo = image->GetImageDebugInfo();
if (imageDebugInfo == NULL)
return B_ENTRY_NOT_FOUND;
// get the function
FunctionInstance* functionInstance
= imageDebugInfo->FunctionAtAddress(address);
if (functionInstance == NULL)
return B_ENTRY_NOT_FOUND;
// get the statement from the image debug info
FunctionDebugInfo* functionDebugInfo
= functionInstance->GetFunctionDebugInfo();
status_t error = functionDebugInfo->GetSpecificImageDebugInfo()
->GetStatement(functionDebugInfo, address, _statement);
// TODO: Provide the corresponding SourceCode, if available!
if (error != B_OK)
return error;
_function = functionInstance;
return B_OK;
}
void void
Team::AddListener(Listener* listener) Team::AddListener(Listener* listener)
{ {

View File

@ -28,7 +28,9 @@ enum {
}; };
class FunctionInstance;
class LocatableFile; class LocatableFile;
class Statement;
class TeamDebugInfo; class TeamDebugInfo;
@ -68,6 +70,13 @@ public:
Image* ImageByAddress(target_addr_t address) const; Image* ImageByAddress(target_addr_t address) const;
const ImageList& Images() const; const ImageList& Images() const;
status_t GetStatementAtAddress(target_addr_t address,
FunctionInstance*& _function,
Statement*& _statement);
// returns a reference to the statement,
// not to the functions instance, though,
// caller must lock
void AddListener(Listener* listener); void AddListener(Listener* listener);
void RemoveListener(Listener* listener); void RemoveListener(Listener* listener);

View File

@ -10,6 +10,8 @@
#include <AutoLocker.h> #include <AutoLocker.h>
#include "Breakpoint.h" #include "Breakpoint.h"
#include "Function.h"
#include "UserBreakpoint.h"
// #pragma mark - BreakpointByAddressPredicate // #pragma mark - BreakpointByAddressPredicate
@ -107,16 +109,36 @@ TeamDebugModel::BreakpointAtAddress(target_addr_t address) const
} }
//void
//TeamDebugModel::GetBreakpointsInAddressRange(TargetAddressRange range,
// BObjectList<Breakpoint>& breakpoints) const
//{
// int32 index = fBreakpoints.FindBinaryInsertionIndex(
// BreakpointByAddressPredicate(range.Start()));
// for (; Breakpoint* breakpoint = fBreakpoints.ItemAt(index); index++) {
// if (breakpoint->Address() > range.End())
// break;
// breakpoints.AddItem(breakpoint);
// }
//}
void void
TeamDebugModel::GetBreakpointsInAddressRange(TargetAddressRange range, TeamDebugModel::GetBreakpointsForSourceCode(SourceCode* sourceCode,
BObjectList<Breakpoint>& breakpoints) const BObjectList<UserBreakpoint>& breakpoints) const
{ {
int32 index = fBreakpoints.FindBinaryInsertionIndex( // TODO: This can probably be optimized. Maybe by registering the user
BreakpointByAddressPredicate(range.Start())); // breakpoints with the team debug model and sorting them by source code.
for (; Breakpoint* breakpoint = fBreakpoints.ItemAt(index); index++) { for (int32 i = 0; Breakpoint* breakpoint = fBreakpoints.ItemAt(i); i++) {
if (breakpoint->Address() > range.End()) UserBreakpointInstance* userBreakpointInstance
break; = breakpoint->FirstUserBreakpoint();
breakpoints.AddItem(breakpoint); if (userBreakpointInstance == NULL)
continue;
UserBreakpoint* userBreakpoint
= userBreakpointInstance->GetUserBreakpoint();
if (userBreakpoint->GetFunction()->GetSourceCode() == sourceCode)
breakpoints.AddItem(userBreakpoint);
} }
} }

View File

@ -22,7 +22,9 @@ enum {
class Architecture; class Architecture;
class Breakpoint; class Breakpoint;
class SourceCode;
class TeamMemory; class TeamMemory;
class UserBreakpoint;
class TeamDebugModel { class TeamDebugModel {
@ -56,9 +58,13 @@ public:
Breakpoint* BreakpointAt(int32 index) const; Breakpoint* BreakpointAt(int32 index) const;
Breakpoint* BreakpointAtAddress( Breakpoint* BreakpointAtAddress(
target_addr_t address) const; target_addr_t address) const;
void GetBreakpointsInAddressRange( // void GetBreakpointsInAddressRange(
TargetAddressRange range, // TargetAddressRange range,
BObjectList<Breakpoint>& breakpoints) const; // BObjectList<Breakpoint>& breakpoints) const;
void GetBreakpointsForSourceCode(
SourceCode* sourceCode,
BObjectList<UserBreakpoint>& breakpoints)
const;
void AddListener(Listener* listener); void AddListener(Listener* listener);
void RemoveListener(Listener* listener); void RemoveListener(Listener* listener);

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