* DWARF:
- DwarfUtils::GetDeclarationLocation(): Line/column numbers are one-based. - Added line number program interpretation (LineNumberProgram). * FunctionDebugInfo: Return the source file (LocatableFile) instead of the file name. * FileManager/LocatableEntry: Fixed handling when a LocatableEntry is unreferenced. There was a race condition before, since an unreferenced entry could be referenced and unreferenced again before removing it from the hash table, which could lead to double deletion. Now we never reuse an unreferenced entry and just remove it from the hash table when encountering one. * FileManager/SourceFile: Added class SourceFile which loads a source file from disk and slices it into lines. Managed by FileManager. * Added class FileSourceCode, a SourceCode implementation using a SourceFile as line provider. The statement management works pretty much exactly as in DissassembledCode. * DwarfImageDebugInfo: Implemented LoadSourceCode for real. It creates a FileSourceCode and uses the DWARF line number information for the statement information. This basically gets the source level view going, though there are still several problems -- stepping doesn't work perfectly yet, the source isn't found for all functions, there's no handling of duplicate functions (no idea why gcc generates them in the first place), etc. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@31382 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -75,6 +75,7 @@ Application Debugger :
|
|||||||
LocatableDirectory.cpp
|
LocatableDirectory.cpp
|
||||||
LocatableEntry.cpp
|
LocatableEntry.cpp
|
||||||
LocatableFile.cpp
|
LocatableFile.cpp
|
||||||
|
SourceFile.cpp
|
||||||
|
|
||||||
# gui/team_window
|
# gui/team_window
|
||||||
ImageFunctionsView.cpp
|
ImageFunctionsView.cpp
|
||||||
@@ -88,6 +89,7 @@ Application Debugger :
|
|||||||
# model
|
# model
|
||||||
Breakpoint.cpp
|
Breakpoint.cpp
|
||||||
DisassembledCode.cpp
|
DisassembledCode.cpp
|
||||||
|
FileSourceCode.cpp
|
||||||
Image.cpp
|
Image.cpp
|
||||||
ImageInfo.cpp
|
ImageInfo.cpp
|
||||||
SourceCode.cpp
|
SourceCode.cpp
|
||||||
|
|||||||
@@ -208,7 +208,8 @@ TeamDebugger::Init(team_id teamID, thread_id threadID, bool stopInMain)
|
|||||||
|
|
||||||
// create team debug info
|
// create team debug info
|
||||||
TeamDebugInfo* teamDebugInfo = new(std::nothrow) TeamDebugInfo(
|
TeamDebugInfo* teamDebugInfo = new(std::nothrow) TeamDebugInfo(
|
||||||
fDebuggerInterface, fDebuggerInterface->GetArchitecture());
|
fDebuggerInterface, fDebuggerInterface->GetArchitecture(),
|
||||||
|
fFileManager);
|
||||||
if (teamDebugInfo == NULL)
|
if (teamDebugInfo == NULL)
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
Reference<TeamDebugInfo> teamDebugInfoReference(teamDebugInfo);
|
Reference<TeamDebugInfo> teamDebugInfoReference(teamDebugInfo);
|
||||||
|
|||||||
@@ -63,8 +63,8 @@ BasicFunctionDebugInfo::PrettyName() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const char*
|
LocatableFile*
|
||||||
BasicFunctionDebugInfo::SourceFileName() const
|
BasicFunctionDebugInfo::SourceFile() const
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ public:
|
|||||||
virtual const char* Name() const;
|
virtual const char* Name() const;
|
||||||
virtual const char* PrettyName() const;
|
virtual const char* PrettyName() const;
|
||||||
|
|
||||||
virtual const char* SourceFileName() const;
|
virtual LocatableFile* SourceFile() const;
|
||||||
virtual SourceLocation SourceStartLocation() const;
|
virtual SourceLocation SourceStartLocation() const;
|
||||||
virtual SourceLocation SourceEndLocation() const;
|
virtual SourceLocation SourceEndLocation() const;
|
||||||
|
|
||||||
|
|||||||
@@ -7,29 +7,38 @@
|
|||||||
|
|
||||||
#include "DebugInfoEntries.h"
|
#include "DebugInfoEntries.h"
|
||||||
#include "DwarfImageDebugInfo.h"
|
#include "DwarfImageDebugInfo.h"
|
||||||
|
#include "LocatableFile.h"
|
||||||
#include "TargetAddressRangeList.h"
|
#include "TargetAddressRangeList.h"
|
||||||
|
|
||||||
|
|
||||||
DwarfFunctionDebugInfo::DwarfFunctionDebugInfo(
|
DwarfFunctionDebugInfo::DwarfFunctionDebugInfo(
|
||||||
DwarfImageDebugInfo* imageDebugInfo, DIESubprogram* subprogramEntry,
|
DwarfImageDebugInfo* imageDebugInfo, CompilationUnit* compilationUnit,
|
||||||
TargetAddressRangeList* addressRanges, const BString& name,
|
DIESubprogram* subprogramEntry, TargetAddressRangeList* addressRanges,
|
||||||
const BString& sourceFile, const SourceLocation& sourceLocation)
|
const BString& name, LocatableFile* sourceFile,
|
||||||
|
const SourceLocation& sourceLocation)
|
||||||
:
|
:
|
||||||
fImageDebugInfo(imageDebugInfo),
|
fImageDebugInfo(imageDebugInfo),
|
||||||
|
fCompilationUnit(compilationUnit),
|
||||||
fAddressRanges(addressRanges),
|
fAddressRanges(addressRanges),
|
||||||
fName(name),
|
fName(name),
|
||||||
fSourceFile(sourceFile),
|
fSourceFile(sourceFile),
|
||||||
fSourceLocation(sourceLocation)
|
fSourceLocation(sourceLocation)
|
||||||
{
|
{
|
||||||
fImageDebugInfo->AddReference();
|
fImageDebugInfo->AcquireReference();
|
||||||
fAddressRanges->AddReference();
|
fAddressRanges->AcquireReference();
|
||||||
|
|
||||||
|
if (fSourceFile != NULL)
|
||||||
|
fSourceFile->AcquireReference();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
DwarfFunctionDebugInfo::~DwarfFunctionDebugInfo()
|
DwarfFunctionDebugInfo::~DwarfFunctionDebugInfo()
|
||||||
{
|
{
|
||||||
fAddressRanges->RemoveReference();
|
if (fSourceFile != NULL)
|
||||||
fImageDebugInfo->RemoveReference();
|
fSourceFile->ReleaseReference();
|
||||||
|
|
||||||
|
fAddressRanges->ReleaseReference();
|
||||||
|
fImageDebugInfo->ReleaseReference();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -68,10 +77,10 @@ DwarfFunctionDebugInfo::PrettyName() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const char*
|
LocatableFile*
|
||||||
DwarfFunctionDebugInfo::SourceFileName() const
|
DwarfFunctionDebugInfo::SourceFile() const
|
||||||
{
|
{
|
||||||
return fSourceFile.Length() > 0 ? fSourceFile.String() : NULL;
|
return fSourceFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
#include "SourceLocation.h"
|
#include "SourceLocation.h"
|
||||||
|
|
||||||
|
|
||||||
|
class CompilationUnit;
|
||||||
class DIESubprogram;
|
class DIESubprogram;
|
||||||
class DwarfImageDebugInfo;
|
class DwarfImageDebugInfo;
|
||||||
class TargetAddressRangeList;
|
class TargetAddressRangeList;
|
||||||
@@ -20,10 +21,11 @@ class DwarfFunctionDebugInfo : public FunctionDebugInfo {
|
|||||||
public:
|
public:
|
||||||
DwarfFunctionDebugInfo(
|
DwarfFunctionDebugInfo(
|
||||||
DwarfImageDebugInfo* imageDebugInfo,
|
DwarfImageDebugInfo* imageDebugInfo,
|
||||||
|
CompilationUnit* compilationUnit,
|
||||||
DIESubprogram* subprogramEntry,
|
DIESubprogram* subprogramEntry,
|
||||||
TargetAddressRangeList* addressRanges,
|
TargetAddressRangeList* addressRanges,
|
||||||
const BString& name,
|
const BString& name,
|
||||||
const BString& sourceFile,
|
LocatableFile* sourceFile,
|
||||||
const SourceLocation& sourceLocation);
|
const SourceLocation& sourceLocation);
|
||||||
virtual ~DwarfFunctionDebugInfo();
|
virtual ~DwarfFunctionDebugInfo();
|
||||||
|
|
||||||
@@ -33,15 +35,19 @@ public:
|
|||||||
virtual const char* Name() const;
|
virtual const char* Name() const;
|
||||||
virtual const char* PrettyName() const;
|
virtual const char* PrettyName() const;
|
||||||
|
|
||||||
virtual const char* SourceFileName() const;
|
virtual LocatableFile* SourceFile() const;
|
||||||
virtual SourceLocation SourceStartLocation() const;
|
virtual SourceLocation SourceStartLocation() const;
|
||||||
virtual SourceLocation SourceEndLocation() const;
|
virtual SourceLocation SourceEndLocation() const;
|
||||||
|
|
||||||
|
CompilationUnit* GetCompilationUnit() const
|
||||||
|
{ return fCompilationUnit; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DwarfImageDebugInfo* fImageDebugInfo;
|
DwarfImageDebugInfo* fImageDebugInfo;
|
||||||
|
CompilationUnit* fCompilationUnit;
|
||||||
TargetAddressRangeList* fAddressRanges;
|
TargetAddressRangeList* fAddressRanges;
|
||||||
BString fName;
|
BString fName;
|
||||||
BString fSourceFile;
|
LocatableFile* fSourceFile;
|
||||||
SourceLocation fSourceLocation;
|
SourceLocation fSourceLocation;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
#include <new>
|
#include <new>
|
||||||
|
|
||||||
#include <AutoDeleter.h>
|
#include <AutoDeleter.h>
|
||||||
|
#include <AutoLocker.h>
|
||||||
|
|
||||||
#include "Architecture.h"
|
#include "Architecture.h"
|
||||||
#include "CompilationUnit.h"
|
#include "CompilationUnit.h"
|
||||||
@@ -20,28 +21,136 @@
|
|||||||
#include "DwarfFunctionDebugInfo.h"
|
#include "DwarfFunctionDebugInfo.h"
|
||||||
#include "DwarfUtils.h"
|
#include "DwarfUtils.h"
|
||||||
#include "ElfFile.h"
|
#include "ElfFile.h"
|
||||||
|
#include "FileManager.h"
|
||||||
|
#include "FileSourceCode.h"
|
||||||
|
#include "LocatableFile.h"
|
||||||
|
#include "SourceFile.h"
|
||||||
|
#include "Statement.h"
|
||||||
|
#include "StringUtils.h"
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - SourceCodeEntry
|
||||||
|
|
||||||
|
|
||||||
|
struct DwarfImageDebugInfo::SourceCodeKey {
|
||||||
|
CompilationUnit* unit;
|
||||||
|
BString filePath;
|
||||||
|
|
||||||
|
SourceCodeKey(CompilationUnit* unit, const BString& filePath)
|
||||||
|
:
|
||||||
|
unit(unit),
|
||||||
|
filePath(filePath)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
SourceCodeKey(CompilationUnit* unit, LocatableFile* file)
|
||||||
|
:
|
||||||
|
unit(unit)
|
||||||
|
{
|
||||||
|
file->GetLocatedPath(filePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 HashValue() const
|
||||||
|
{
|
||||||
|
return (uint32)(addr_t)unit ^ StringUtils::HashValue(filePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const SourceCodeKey& other) const
|
||||||
|
{
|
||||||
|
return unit == other.unit && filePath == other.filePath;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct DwarfImageDebugInfo::SourceCodeEntry : SourceCodeKey,
|
||||||
|
HashTableLink<SourceCodeEntry> {
|
||||||
|
FileSourceCode* sourceCode;
|
||||||
|
|
||||||
|
SourceCodeEntry(CompilationUnit* unit, LocatableFile* file,
|
||||||
|
FileSourceCode* sourceCode)
|
||||||
|
:
|
||||||
|
SourceCodeKey(unit, file),
|
||||||
|
sourceCode(sourceCode)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - SourceCodeHashDefinition
|
||||||
|
|
||||||
|
|
||||||
|
struct DwarfImageDebugInfo::SourceCodeHashDefinition {
|
||||||
|
typedef SourceCodeKey KeyType;
|
||||||
|
typedef SourceCodeEntry ValueType;
|
||||||
|
|
||||||
|
size_t HashKey(const SourceCodeKey& key) const
|
||||||
|
{
|
||||||
|
return key.HashValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Hash(const SourceCodeEntry* value) const
|
||||||
|
{
|
||||||
|
return value->HashValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Compare(const SourceCodeKey& key, const SourceCodeEntry* value) const
|
||||||
|
{
|
||||||
|
return key == *value;
|
||||||
|
}
|
||||||
|
|
||||||
|
HashTableLink<SourceCodeEntry>* GetLink(SourceCodeEntry* value) const
|
||||||
|
{
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - DwarfImageDebugInfo
|
||||||
|
|
||||||
|
|
||||||
DwarfImageDebugInfo::DwarfImageDebugInfo(const ImageInfo& imageInfo,
|
DwarfImageDebugInfo::DwarfImageDebugInfo(const ImageInfo& imageInfo,
|
||||||
Architecture* architecture, DwarfFile* file)
|
Architecture* architecture, FileManager* fileManager, DwarfFile* file)
|
||||||
:
|
:
|
||||||
|
fLock("dwarf image debug info"),
|
||||||
fImageInfo(imageInfo),
|
fImageInfo(imageInfo),
|
||||||
fArchitecture(architecture),
|
fArchitecture(architecture),
|
||||||
|
fFileManager(fileManager),
|
||||||
fFile(file),
|
fFile(file),
|
||||||
fTextSegment(NULL),
|
fTextSegment(NULL),
|
||||||
fRelocationDelta(0)
|
fRelocationDelta(0),
|
||||||
|
fSourceCodes(NULL)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
DwarfImageDebugInfo::~DwarfImageDebugInfo()
|
DwarfImageDebugInfo::~DwarfImageDebugInfo()
|
||||||
{
|
{
|
||||||
|
SourceCodeEntry* entry = fSourceCodes->Clear(true);
|
||||||
|
while (entry != NULL) {
|
||||||
|
SourceCodeEntry* next = entry->fNext;
|
||||||
|
entry->sourceCode->ReleaseReference();
|
||||||
|
entry = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete fSourceCodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
DwarfImageDebugInfo::Init()
|
DwarfImageDebugInfo::Init()
|
||||||
{
|
{
|
||||||
|
status_t error = fLock.InitCheck();
|
||||||
|
if (error != B_OK)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
fSourceCodes = new (std::nothrow) SourceCodeTable;
|
||||||
|
if (fSourceCodes == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
error = fSourceCodes->Init();
|
||||||
|
if (error != B_OK)
|
||||||
|
return error;
|
||||||
|
|
||||||
fTextSegment = fFile->GetElfFile()->TextSegment();
|
fTextSegment = fFile->GetElfFile()->TextSegment();
|
||||||
if (fTextSegment == NULL)
|
if (fTextSegment == NULL)
|
||||||
return B_ENTRY_NOT_FOUND;
|
return B_ENTRY_NOT_FOUND;
|
||||||
@@ -118,27 +227,24 @@ printf(" %ld compilation units\n", fFile->CountCompilationUnits());
|
|||||||
}
|
}
|
||||||
|
|
||||||
// get the source location
|
// get the source location
|
||||||
const char* directory = NULL;
|
const char* directoryPath = NULL;
|
||||||
const char* file = NULL;
|
const char* fileName = NULL;
|
||||||
uint32 line = 0;
|
uint32 line = -1;
|
||||||
uint32 column = 0;
|
uint32 column = -1;
|
||||||
DwarfUtils::GetDeclarationLocation(fFile, subprogramEntry,
|
DwarfUtils::GetDeclarationLocation(fFile, subprogramEntry,
|
||||||
directory, file, line, column);
|
directoryPath, fileName, line, column);
|
||||||
BString fileName;
|
|
||||||
if (file != NULL) {
|
LocatableFile* file = NULL;
|
||||||
if (directory != NULL)
|
if (fileName != NULL) {
|
||||||
fileName << directory << '/' << file;
|
file = fFileManager->GetSourceFile(directoryPath,
|
||||||
else
|
fileName);
|
||||||
fileName << file;
|
|
||||||
}
|
}
|
||||||
// TODO: Avoid unnessecary string allocation! The source file name
|
Reference<LocatableFile> fileReference(file, true);
|
||||||
// is the same for all contained functions, so they could share the
|
|
||||||
// string.
|
|
||||||
|
|
||||||
// create and add the functions
|
// create and add the functions
|
||||||
DwarfFunctionDebugInfo* function
|
DwarfFunctionDebugInfo* function
|
||||||
= new(std::nothrow) DwarfFunctionDebugInfo(this,
|
= new(std::nothrow) DwarfFunctionDebugInfo(this, unit,
|
||||||
subprogramEntry, rangeList, name, fileName,
|
subprogramEntry, rangeList, name, file,
|
||||||
SourceLocation(line, column));
|
SourceLocation(line, column));
|
||||||
if (function == NULL || !functions.AddItem(function)) {
|
if (function == NULL || !functions.AddItem(function)) {
|
||||||
delete function;
|
delete function;
|
||||||
@@ -185,7 +291,14 @@ status_t
|
|||||||
DwarfImageDebugInfo::LoadSourceCode(FunctionDebugInfo* function,
|
DwarfImageDebugInfo::LoadSourceCode(FunctionDebugInfo* function,
|
||||||
SourceCode*& _sourceCode)
|
SourceCode*& _sourceCode)
|
||||||
{
|
{
|
||||||
|
AutoLocker<BLocker> locker(fLock);
|
||||||
|
|
||||||
// TODO: Load the actual source code!
|
// TODO: Load the actual source code!
|
||||||
|
status_t error = _LoadSourceCode(function, _sourceCode);
|
||||||
|
if (error == B_OK)
|
||||||
|
return B_OK;
|
||||||
|
|
||||||
|
// fall back to disassembling
|
||||||
|
|
||||||
static const target_size_t kMaxBufferSize = 64 * 1024;
|
static const target_size_t kMaxBufferSize = 64 * 1024;
|
||||||
target_size_t bufferSize = std::min(function->Size(), kMaxBufferSize);
|
target_size_t bufferSize = std::min(function->Size(), kMaxBufferSize);
|
||||||
@@ -214,3 +327,140 @@ DwarfImageDebugInfo::GetStatement(FunctionDebugInfo* function,
|
|||||||
// TODO:...
|
// TODO:...
|
||||||
return fArchitecture->GetStatement(function, address, _statement);
|
return fArchitecture->GetStatement(function, address, _statement);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
DwarfImageDebugInfo::_LoadSourceCode(FunctionDebugInfo* _function,
|
||||||
|
SourceCode*& _sourceCode)
|
||||||
|
{
|
||||||
|
DwarfFunctionDebugInfo* function
|
||||||
|
= dynamic_cast<DwarfFunctionDebugInfo*>(_function);
|
||||||
|
if (function == NULL)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
// get the source file
|
||||||
|
LocatableFile* file = function->SourceFile();
|
||||||
|
if (file == NULL)
|
||||||
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
|
||||||
|
// maybe it's already loaded
|
||||||
|
CompilationUnit* unit = function->GetCompilationUnit();
|
||||||
|
FileSourceCode* sourceCode = _LookupSourceCode(unit, file);
|
||||||
|
if (sourceCode) {
|
||||||
|
sourceCode->AcquireReference();
|
||||||
|
_sourceCode = sourceCode;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the index of the source file in the compilation unit for cheaper
|
||||||
|
// comparison below
|
||||||
|
const char* directory;
|
||||||
|
int32 fileIndex = -1;
|
||||||
|
for (int32 i = 0; const char* fileName = unit->FileAt(i, &directory); i++) {
|
||||||
|
LocatableFile* file = fFileManager->GetSourceFile(directory, fileName);
|
||||||
|
if (file != NULL) {
|
||||||
|
file->ReleaseReference();
|
||||||
|
if (file == function->SourceFile()) {
|
||||||
|
fileIndex = i + 1;
|
||||||
|
// indices are one-based
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("DwarfImageDebugInfo::_LoadSourceCode(), file: %ld, function at: %#llx\n", fileIndex, function->Address());
|
||||||
|
|
||||||
|
for (int32 i = 0; const char* fileName = unit->FileAt(i, &directory); i++) {
|
||||||
|
printf(" file %ld: %s\n", i, fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// not loaded yet -- get the source file
|
||||||
|
SourceFile* sourceFile;
|
||||||
|
status_t error = fFileManager->LoadSourceFile(file, sourceFile);
|
||||||
|
if (error != B_OK)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
// create the source code
|
||||||
|
sourceCode = new(std::nothrow) FileSourceCode(sourceFile);
|
||||||
|
sourceFile->ReleaseReference();
|
||||||
|
if (sourceCode == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
error = sourceCode->Init();
|
||||||
|
if (error != B_OK)
|
||||||
|
return error;
|
||||||
|
ObjectDeleter<FileSourceCode> sourceCodeDeleter(sourceCode);
|
||||||
|
|
||||||
|
// Get the statements by executing the line number program for the
|
||||||
|
// compilation unit and filtering the rows for our source file.
|
||||||
|
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)) {
|
||||||
|
printf(" %#lx (%ld, %ld, %ld) %d\n", state.address, state.file, state.line, state.column, state.isStatement);
|
||||||
|
bool isOurFile = state.file == fileIndex;
|
||||||
|
|
||||||
|
if (statementAddress != 0
|
||||||
|
&& (!isOurFile || state.isStatement || state.isSequenceEnd)) {
|
||||||
|
target_addr_t endAddress = state.address;
|
||||||
|
if (endAddress > statementAddress) {
|
||||||
|
// add the statement
|
||||||
|
ContiguousStatement* statement = new(std::nothrow)
|
||||||
|
ContiguousStatement(
|
||||||
|
SourceLocation(statementLine, statementColumn),
|
||||||
|
SourceLocation(statementLine, statementColumn),
|
||||||
|
TargetAddressRange(fRelocationDelta + statementAddress,
|
||||||
|
endAddress - statementAddress), true);
|
||||||
|
if (statement == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
error = sourceCode->AddStatement(statement);
|
||||||
|
if (error != B_OK) {
|
||||||
|
delete statement;
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
printf(" -> statement: %#llx - %#llx, line: %ld\n", statement->AddressRange().Start(),
|
||||||
|
statement->AddressRange().End(), statementLine);
|
||||||
|
}
|
||||||
|
|
||||||
|
statementAddress = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// skip statements of other files
|
||||||
|
if (!isOurFile)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (state.isStatement) {
|
||||||
|
statementAddress = state.address;
|
||||||
|
statementLine = state.line - 1;
|
||||||
|
statementColumn = state.column - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SourceCodeEntry* entry = new(std::nothrow) SourceCodeEntry(unit, file,
|
||||||
|
sourceCode);
|
||||||
|
if (entry == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
fSourceCodes->Insert(entry);
|
||||||
|
|
||||||
|
_sourceCode = sourceCodeDeleter.Detach();
|
||||||
|
_sourceCode->AcquireReference();
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FileSourceCode*
|
||||||
|
DwarfImageDebugInfo::_LookupSourceCode(CompilationUnit* unit,
|
||||||
|
LocatableFile* file)
|
||||||
|
{
|
||||||
|
SourceCodeEntry* entry = fSourceCodes->Lookup(SourceCodeKey(unit, file));
|
||||||
|
return entry != NULL ? entry->sourceCode : NULL;
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,20 +5,29 @@
|
|||||||
#ifndef DWARF_IMAGE_DEBUG_INFO_H
|
#ifndef DWARF_IMAGE_DEBUG_INFO_H
|
||||||
#define DWARF_IMAGE_DEBUG_INFO_H
|
#define DWARF_IMAGE_DEBUG_INFO_H
|
||||||
|
|
||||||
|
#include <Locker.h>
|
||||||
|
|
||||||
|
#include <util/OpenHashTable.h>
|
||||||
|
|
||||||
#include "ImageInfo.h"
|
#include "ImageInfo.h"
|
||||||
#include "SpecificImageDebugInfo.h"
|
#include "SpecificImageDebugInfo.h"
|
||||||
|
|
||||||
|
|
||||||
class Architecture;
|
class Architecture;
|
||||||
|
class CompilationUnit;
|
||||||
class DwarfFile;
|
class DwarfFile;
|
||||||
class ElfSegment;
|
class ElfSegment;
|
||||||
|
class FileManager;
|
||||||
|
class FileSourceCode;
|
||||||
|
class LocatableFile;
|
||||||
|
class SourceCode;
|
||||||
|
|
||||||
|
|
||||||
class DwarfImageDebugInfo : public SpecificImageDebugInfo {
|
class DwarfImageDebugInfo : public SpecificImageDebugInfo {
|
||||||
public:
|
public:
|
||||||
DwarfImageDebugInfo(const ImageInfo& imageInfo,
|
DwarfImageDebugInfo(const ImageInfo& imageInfo,
|
||||||
Architecture* architecture,
|
Architecture* architecture,
|
||||||
DwarfFile* file);
|
FileManager* fileManager, DwarfFile* file);
|
||||||
virtual ~DwarfImageDebugInfo();
|
virtual ~DwarfImageDebugInfo();
|
||||||
|
|
||||||
status_t Init();
|
status_t Init();
|
||||||
@@ -40,11 +49,27 @@ public:
|
|||||||
Statement*& _statement);
|
Statement*& _statement);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
struct SourceCodeKey;
|
||||||
|
struct SourceCodeEntry;
|
||||||
|
struct SourceCodeHashDefinition;
|
||||||
|
|
||||||
|
typedef OpenHashTable<SourceCodeHashDefinition> SourceCodeTable;
|
||||||
|
|
||||||
|
private:
|
||||||
|
status_t _LoadSourceCode(FunctionDebugInfo* function,
|
||||||
|
SourceCode*& _sourceCode);
|
||||||
|
FileSourceCode* _LookupSourceCode(CompilationUnit* unit,
|
||||||
|
LocatableFile* file);
|
||||||
|
|
||||||
|
private:
|
||||||
|
BLocker fLock;
|
||||||
ImageInfo fImageInfo;
|
ImageInfo fImageInfo;
|
||||||
Architecture* fArchitecture;
|
Architecture* fArchitecture;
|
||||||
|
FileManager* fFileManager;
|
||||||
DwarfFile* fFile;
|
DwarfFile* fFile;
|
||||||
ElfSegment* fTextSegment;
|
ElfSegment* fTextSegment;
|
||||||
target_addr_t fRelocationDelta;
|
target_addr_t fRelocationDelta;
|
||||||
|
SourceCodeTable* fSourceCodes;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -14,9 +14,11 @@
|
|||||||
#include "LocatableFile.h"
|
#include "LocatableFile.h"
|
||||||
|
|
||||||
|
|
||||||
DwarfTeamDebugInfo::DwarfTeamDebugInfo(Architecture* architecture)
|
DwarfTeamDebugInfo::DwarfTeamDebugInfo(Architecture* architecture,
|
||||||
|
FileManager* fileManager)
|
||||||
:
|
:
|
||||||
fArchitecture(architecture),
|
fArchitecture(architecture),
|
||||||
|
fFileManager(fileManager),
|
||||||
fManager(NULL)
|
fManager(NULL)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -62,7 +64,7 @@ DwarfTeamDebugInfo::CreateImageDebugInfo(const ImageInfo& imageInfo,
|
|||||||
|
|
||||||
// create the image debug info
|
// create the image debug info
|
||||||
DwarfImageDebugInfo* debuggerInfo = new(std::nothrow) DwarfImageDebugInfo(
|
DwarfImageDebugInfo* debuggerInfo = new(std::nothrow) DwarfImageDebugInfo(
|
||||||
imageInfo, fArchitecture, file);
|
imageInfo, fArchitecture, fFileManager, file);
|
||||||
if (debuggerInfo == NULL)
|
if (debuggerInfo == NULL)
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
|||||||
@@ -10,12 +10,14 @@
|
|||||||
|
|
||||||
class Architecture;
|
class Architecture;
|
||||||
class DwarfManager;
|
class DwarfManager;
|
||||||
|
class FileManager;
|
||||||
class ImageInfo;
|
class ImageInfo;
|
||||||
|
|
||||||
|
|
||||||
class DwarfTeamDebugInfo : public SpecificTeamDebugInfo {
|
class DwarfTeamDebugInfo : public SpecificTeamDebugInfo {
|
||||||
public:
|
public:
|
||||||
DwarfTeamDebugInfo(Architecture* architecture);
|
DwarfTeamDebugInfo(Architecture* architecture,
|
||||||
|
FileManager* fileManager);
|
||||||
virtual ~DwarfTeamDebugInfo();
|
virtual ~DwarfTeamDebugInfo();
|
||||||
|
|
||||||
status_t Init();
|
status_t Init();
|
||||||
@@ -26,6 +28,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
Architecture* fArchitecture;
|
Architecture* fArchitecture;
|
||||||
|
FileManager* fFileManager;
|
||||||
DwarfManager* fManager;
|
DwarfManager* fManager;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ enum function_source_state {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class LocatableFile;
|
||||||
class SourceCode;
|
class SourceCode;
|
||||||
class SpecificImageDebugInfo;
|
class SpecificImageDebugInfo;
|
||||||
|
|
||||||
@@ -38,7 +39,7 @@ public:
|
|||||||
virtual const char* Name() const = 0;
|
virtual const char* Name() const = 0;
|
||||||
virtual const char* PrettyName() const = 0;
|
virtual const char* PrettyName() const = 0;
|
||||||
|
|
||||||
virtual const char* SourceFileName() 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;
|
||||||
|
|
||||||
|
|||||||
@@ -16,10 +16,11 @@
|
|||||||
|
|
||||||
|
|
||||||
TeamDebugInfo::TeamDebugInfo(DebuggerInterface* debuggerInterface,
|
TeamDebugInfo::TeamDebugInfo(DebuggerInterface* debuggerInterface,
|
||||||
Architecture* architecture)
|
Architecture* architecture, FileManager* fileManager)
|
||||||
:
|
:
|
||||||
fDebuggerInterface(debuggerInterface),
|
fDebuggerInterface(debuggerInterface),
|
||||||
fArchitecture(architecture),
|
fArchitecture(architecture),
|
||||||
|
fFileManager(fileManager),
|
||||||
fSpecificInfos(10, true)
|
fSpecificInfos(10, true)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -38,7 +39,7 @@ TeamDebugInfo::Init()
|
|||||||
|
|
||||||
// DWARF
|
// DWARF
|
||||||
DwarfTeamDebugInfo* dwarfInfo = new(std::nothrow) DwarfTeamDebugInfo(
|
DwarfTeamDebugInfo* dwarfInfo = new(std::nothrow) DwarfTeamDebugInfo(
|
||||||
fArchitecture);
|
fArchitecture, fFileManager);
|
||||||
if (dwarfInfo == NULL || !fSpecificInfos.AddItem(dwarfInfo)) {
|
if (dwarfInfo == NULL || !fSpecificInfos.AddItem(dwarfInfo)) {
|
||||||
delete dwarfInfo;
|
delete dwarfInfo;
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
|
|
||||||
class Architecture;
|
class Architecture;
|
||||||
class DebuggerInterface;
|
class DebuggerInterface;
|
||||||
|
class FileManager;
|
||||||
class ImageDebugInfo;
|
class ImageDebugInfo;
|
||||||
class ImageInfo;
|
class ImageInfo;
|
||||||
class LocatableFile;
|
class LocatableFile;
|
||||||
@@ -23,7 +24,8 @@ class TeamDebugInfo : public Referenceable {
|
|||||||
public:
|
public:
|
||||||
TeamDebugInfo(
|
TeamDebugInfo(
|
||||||
DebuggerInterface* debuggerInterface,
|
DebuggerInterface* debuggerInterface,
|
||||||
Architecture* architecture);
|
Architecture* architecture,
|
||||||
|
FileManager* fileManager);
|
||||||
~TeamDebugInfo();
|
~TeamDebugInfo();
|
||||||
|
|
||||||
status_t Init();
|
status_t Init();
|
||||||
@@ -38,6 +40,7 @@ private:
|
|||||||
private:
|
private:
|
||||||
DebuggerInterface* fDebuggerInterface;
|
DebuggerInterface* fDebuggerInterface;
|
||||||
Architecture* fArchitecture;
|
Architecture* fArchitecture;
|
||||||
|
FileManager* fFileManager;
|
||||||
SpecificInfoList fSpecificInfos;
|
SpecificInfoList fSpecificInfos;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
#include "Array.h"
|
#include "Array.h"
|
||||||
#include "DwarfTypes.h"
|
#include "DwarfTypes.h"
|
||||||
|
#include "LineNumberProgram.h"
|
||||||
|
|
||||||
|
|
||||||
class AbbreviationTable;
|
class AbbreviationTable;
|
||||||
@@ -45,6 +46,9 @@ public:
|
|||||||
DIECompileUnitBase* UnitEntry() const { return fUnitEntry; }
|
DIECompileUnitBase* UnitEntry() const { return fUnitEntry; }
|
||||||
void SetUnitEntry(DIECompileUnitBase* entry);
|
void SetUnitEntry(DIECompileUnitBase* entry);
|
||||||
|
|
||||||
|
LineNumberProgram& GetLineNumberProgram()
|
||||||
|
{ return fLineNumberProgram; }
|
||||||
|
|
||||||
status_t AddDebugInfoEntry(DebugInfoEntry* entry,
|
status_t AddDebugInfoEntry(DebugInfoEntry* entry,
|
||||||
dwarf_off_t offset);
|
dwarf_off_t offset);
|
||||||
int CountEntries() const;
|
int CountEntries() const;
|
||||||
@@ -77,6 +81,7 @@ private:
|
|||||||
Array<dwarf_off_t> fEntryOffsets;
|
Array<dwarf_off_t> fEntryOffsets;
|
||||||
DirectoryList fDirectories;
|
DirectoryList fDirectories;
|
||||||
FileList fFiles;
|
FileList fFiles;
|
||||||
|
LineNumberProgram fLineNumberProgram;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
#include "DwarfFile.h"
|
#include "DwarfFile.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <new>
|
#include <new>
|
||||||
|
|
||||||
#include <AutoDeleter.h>
|
#include <AutoDeleter.h>
|
||||||
@@ -631,6 +632,9 @@ printf("DwarfFile::_ParseLineInfo(%p), offset: %lu\n", unit, offset);
|
|||||||
// unit length
|
// unit length
|
||||||
bool dwarf64;
|
bool dwarf64;
|
||||||
uint64 unitLength = dataReader.ReadInitialLength(dwarf64);
|
uint64 unitLength = dataReader.ReadInitialLength(dwarf64);
|
||||||
|
if (unitLength > (uint64)dataReader.BytesRemaining())
|
||||||
|
return B_BAD_DATA;
|
||||||
|
off_t unitOffset = dataReader.Offset();
|
||||||
|
|
||||||
// version (uhalf)
|
// version (uhalf)
|
||||||
uint16 version = dataReader.Read<uint16>(0);
|
uint16 version = dataReader.Read<uint16>(0);
|
||||||
@@ -638,6 +642,10 @@ printf("DwarfFile::_ParseLineInfo(%p), offset: %lu\n", unit, offset);
|
|||||||
// header_length (4/8)
|
// header_length (4/8)
|
||||||
uint64 headerLength = dwarf64
|
uint64 headerLength = dwarf64
|
||||||
? dataReader.Read<uint64>(0) : (uint64)dataReader.Read<uint32>(0);
|
? dataReader.Read<uint64>(0) : (uint64)dataReader.Read<uint32>(0);
|
||||||
|
off_t headerOffset = dataReader.Offset();
|
||||||
|
|
||||||
|
if ((uint64)dataReader.BytesRemaining() < headerLength)
|
||||||
|
return B_BAD_DATA;
|
||||||
|
|
||||||
// minimum instruction length
|
// minimum instruction length
|
||||||
uint8 minInstructionLength = dataReader.Read<uint8>(0);
|
uint8 minInstructionLength = dataReader.Read<uint8>(0);
|
||||||
@@ -655,6 +663,7 @@ printf("DwarfFile::_ParseLineInfo(%p), offset: %lu\n", unit, offset);
|
|||||||
uint8 opcodeBase = dataReader.Read<uint8>(0);
|
uint8 opcodeBase = dataReader.Read<uint8>(0);
|
||||||
|
|
||||||
// standard_opcode_lengths (ubyte[])
|
// standard_opcode_lengths (ubyte[])
|
||||||
|
const uint8* standardOpcodeLengths = (const uint8*)dataReader.Data();
|
||||||
dataReader.Skip(opcodeBase - 1);
|
dataReader.Skip(opcodeBase - 1);
|
||||||
|
|
||||||
if (dataReader.HasOverflow())
|
if (dataReader.HasOverflow())
|
||||||
@@ -702,7 +711,17 @@ printf("DwarfFile::_ParseLineInfo(%p), offset: %lu\n", unit, offset);
|
|||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
return B_OK;
|
off_t readerOffset = dataReader.Offset();
|
||||||
|
if ((uint64)readerOffset > readerOffset + headerLength)
|
||||||
|
return B_BAD_DATA;
|
||||||
|
off_t offsetToProgram = headerOffset + headerLength - readerOffset;
|
||||||
|
|
||||||
|
const uint8* program = (uint8*)dataReader.Data() + offsetToProgram;
|
||||||
|
size_t programSize = unitLength - (readerOffset - unitOffset);
|
||||||
|
|
||||||
|
return unit->GetLineNumberProgram().Init(program, programSize,
|
||||||
|
minInstructionLength, defaultIsStatement, lineBase, lineRange,
|
||||||
|
opcodeBase, standardOpcodeLengths);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ DwarfUtils::GetDeclarationLocation(DwarfFile* dwarfFile,
|
|||||||
|
|
||||||
_directory = directoryName;
|
_directory = directoryName;
|
||||||
_file = fileName;
|
_file = fileName;
|
||||||
_line = line;
|
_line = line - 1;
|
||||||
_column = column;
|
_column = column - 1;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ MergeObject Debugger_dwarf.o
|
|||||||
DwarfFile.cpp
|
DwarfFile.cpp
|
||||||
DwarfManager.cpp
|
DwarfManager.cpp
|
||||||
DwarfUtils.cpp
|
DwarfUtils.cpp
|
||||||
|
LineNumberProgram.cpp
|
||||||
SourceLanguageInfo.cpp
|
SourceLanguageInfo.cpp
|
||||||
TagNames.cpp
|
TagNames.cpp
|
||||||
;
|
;
|
||||||
|
|||||||
@@ -0,0 +1,208 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009, Ingo Weinhold, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "LineNumberProgram.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "Dwarf.h"
|
||||||
|
|
||||||
|
|
||||||
|
static const uint8 kLineNumberStandardOpcodeOperands[]
|
||||||
|
= { 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 };
|
||||||
|
static const uint32 kLineNumberStandardOpcodeCount = 12;
|
||||||
|
|
||||||
|
|
||||||
|
LineNumberProgram::LineNumberProgram()
|
||||||
|
:
|
||||||
|
fProgram(NULL),
|
||||||
|
fProgramSize(0),
|
||||||
|
fMinInstructionLength(0),
|
||||||
|
fDefaultIsStatement(0),
|
||||||
|
fLineBase(0),
|
||||||
|
fLineRange(0),
|
||||||
|
fOpcodeBase(0),
|
||||||
|
fStandardOpcodeLengths(NULL)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LineNumberProgram::~LineNumberProgram()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
LineNumberProgram::Init(const void* program, size_t programSize,
|
||||||
|
uint8 minInstructionLength, bool defaultIsStatement, int8 lineBase,
|
||||||
|
uint8 lineRange, uint8 opcodeBase, const uint8* standardOpcodeLengths)
|
||||||
|
{
|
||||||
|
// first check the operand counts for the standard opcodes
|
||||||
|
uint8 standardOpcodeCount = std::min((uint32)opcodeBase - 1,
|
||||||
|
kLineNumberStandardOpcodeCount);
|
||||||
|
for (uint8 i = 0; i < standardOpcodeCount; i++) {
|
||||||
|
if (standardOpcodeLengths[i] != kLineNumberStandardOpcodeOperands[i]) {
|
||||||
|
printf("operand count for standard opcode %u does not what we expect\n", i + 1);
|
||||||
|
return B_BAD_DATA;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fProgram = program;
|
||||||
|
fProgramSize = programSize;
|
||||||
|
fMinInstructionLength = minInstructionLength;
|
||||||
|
fDefaultIsStatement = defaultIsStatement;
|
||||||
|
fLineBase = lineBase;
|
||||||
|
fLineRange = lineRange;
|
||||||
|
fOpcodeBase = opcodeBase;
|
||||||
|
fStandardOpcodeLengths = standardOpcodeLengths;
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
LineNumberProgram::GetInitialState(State& state) const
|
||||||
|
{
|
||||||
|
if (!IsValid())
|
||||||
|
return;
|
||||||
|
|
||||||
|
_SetToInitial(state);
|
||||||
|
state.dataReader.SetTo(fProgram, fProgramSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
LineNumberProgram::GetNextRow(State& state) const
|
||||||
|
{
|
||||||
|
if (state.isSequenceEnd)
|
||||||
|
_SetToInitial(state);
|
||||||
|
|
||||||
|
DataReader& dataReader = state.dataReader;
|
||||||
|
|
||||||
|
while (dataReader.BytesRemaining() > 0) {
|
||||||
|
bool appendRow = false;
|
||||||
|
uint8 opcode = dataReader.Read<uint8>(0);
|
||||||
|
if (opcode >= fOpcodeBase) {
|
||||||
|
// special opcode
|
||||||
|
uint adjustedOpcode = opcode - fOpcodeBase;
|
||||||
|
state.address += (adjustedOpcode / fLineRange)
|
||||||
|
* fMinInstructionLength;
|
||||||
|
state.line += adjustedOpcode % fLineRange + fLineBase;
|
||||||
|
state.isBasicBlock = false;
|
||||||
|
state.isPrologueEnd = false;
|
||||||
|
state.isEpilogueBegin = false;
|
||||||
|
appendRow = true;
|
||||||
|
} else if (opcode > 0) {
|
||||||
|
// standard opcode
|
||||||
|
switch (opcode) {
|
||||||
|
case DW_LNS_copy:
|
||||||
|
state.isBasicBlock = false;
|
||||||
|
state.isPrologueEnd = false;
|
||||||
|
state.isEpilogueBegin = false;
|
||||||
|
appendRow = true;
|
||||||
|
break;
|
||||||
|
case DW_LNS_advance_pc:
|
||||||
|
state.address += dataReader.ReadUnsignedLEB128(0)
|
||||||
|
* fMinInstructionLength;
|
||||||
|
break;
|
||||||
|
case DW_LNS_advance_line:
|
||||||
|
state.line += dataReader.ReadSignedLEB128(0);
|
||||||
|
break;
|
||||||
|
case DW_LNS_set_file:
|
||||||
|
state.file = dataReader.ReadUnsignedLEB128(0);
|
||||||
|
break;
|
||||||
|
case DW_LNS_set_column:
|
||||||
|
state.column = dataReader.ReadUnsignedLEB128(0);
|
||||||
|
break;
|
||||||
|
case DW_LNS_negate_stmt:
|
||||||
|
state.isStatement = !state.isStatement;
|
||||||
|
break;
|
||||||
|
case DW_LNS_set_basic_block:
|
||||||
|
state.isBasicBlock = true;
|
||||||
|
break;
|
||||||
|
case DW_LNS_const_add_pc:
|
||||||
|
state.address += ((255 - fOpcodeBase) / fLineRange)
|
||||||
|
* fMinInstructionLength;
|
||||||
|
break;
|
||||||
|
case DW_LNS_fixed_advance_pc:
|
||||||
|
state.address += dataReader.Read<uint16>(0);
|
||||||
|
break;
|
||||||
|
case DW_LNS_set_prologue_end:
|
||||||
|
state.isPrologueEnd = true;
|
||||||
|
break;
|
||||||
|
case DW_LNS_set_epilogue_begin:
|
||||||
|
state.isEpilogueBegin = true;
|
||||||
|
break;
|
||||||
|
case DW_LNS_set_isa:
|
||||||
|
state.instructionSet = dataReader.ReadUnsignedLEB128(0);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf("unsupported standard opcode %u\n", opcode);
|
||||||
|
for (int32 i = 0; i < fStandardOpcodeLengths[opcode - 1];
|
||||||
|
i++) {
|
||||||
|
dataReader.ReadUnsignedLEB128(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// extended opcode
|
||||||
|
uint32 instructionLength = dataReader.ReadUnsignedLEB128(0);
|
||||||
|
off_t instructionOffset = dataReader.Offset();
|
||||||
|
uint8 extendedOpcode = dataReader.Read<uint8>(0);
|
||||||
|
|
||||||
|
switch (extendedOpcode) {
|
||||||
|
case DW_LNE_end_sequence:
|
||||||
|
state.isSequenceEnd = true;
|
||||||
|
appendRow = true;
|
||||||
|
break;
|
||||||
|
case DW_LNE_set_address:
|
||||||
|
state.address = dataReader.Read<dwarf_addr_t>(0);
|
||||||
|
break;
|
||||||
|
case DW_LNE_define_file:
|
||||||
|
{
|
||||||
|
state.explicitFile = dataReader.ReadString();
|
||||||
|
state.explicitFileDirIndex
|
||||||
|
= dataReader.ReadUnsignedLEB128(0);
|
||||||
|
dataReader.ReadUnsignedLEB128(0); // modification time
|
||||||
|
dataReader.ReadUnsignedLEB128(0); // file length
|
||||||
|
state.file = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
printf("unsupported extended opcode: %u\n", extendedOpcode);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
dataReader.Skip(instructionLength
|
||||||
|
- (dataReader.Offset() - instructionOffset));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dataReader.HasOverflow())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (appendRow)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
LineNumberProgram::_SetToInitial(State& state) const
|
||||||
|
{
|
||||||
|
state.address = 0;
|
||||||
|
state.file = 1;
|
||||||
|
state.line = 1;
|
||||||
|
state.column = 0;
|
||||||
|
state.isStatement = fDefaultIsStatement;
|
||||||
|
state.isBasicBlock = false;
|
||||||
|
state.isSequenceEnd = false;
|
||||||
|
state.isPrologueEnd = false;
|
||||||
|
state.isEpilogueBegin = false;
|
||||||
|
state.instructionSet = 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009, Ingo Weinhold, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef LINE_NUMBER_PROGRAM_H
|
||||||
|
#define LINE_NUMBER_PROGRAM_H
|
||||||
|
|
||||||
|
#include "DataReader.h"
|
||||||
|
#include "DwarfTypes.h"
|
||||||
|
|
||||||
|
|
||||||
|
class LineNumberProgram {
|
||||||
|
public:
|
||||||
|
struct State;
|
||||||
|
|
||||||
|
public:
|
||||||
|
LineNumberProgram();
|
||||||
|
~LineNumberProgram();
|
||||||
|
|
||||||
|
status_t Init(const void* program, size_t programSize,
|
||||||
|
uint8 minInstructionLength,
|
||||||
|
bool defaultIsStatement, int8 lineBase,
|
||||||
|
uint8 lineRange, uint8 opcodeBase,
|
||||||
|
const uint8* standardOpcodeLengths);
|
||||||
|
|
||||||
|
bool IsValid() const { return fProgram != NULL; }
|
||||||
|
void GetInitialState(State& state) const;
|
||||||
|
bool GetNextRow(State& state) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void _SetToInitial(State& state) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
const void* fProgram;
|
||||||
|
size_t fProgramSize;
|
||||||
|
uint8 fMinInstructionLength;
|
||||||
|
bool fDefaultIsStatement;
|
||||||
|
int8 fLineBase;
|
||||||
|
uint8 fLineRange;
|
||||||
|
uint8 fOpcodeBase;
|
||||||
|
const uint8* fStandardOpcodeLengths;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct LineNumberProgram::State {
|
||||||
|
dwarf_addr_t address;
|
||||||
|
int32 file;
|
||||||
|
int32 line;
|
||||||
|
int32 column;
|
||||||
|
bool isStatement;
|
||||||
|
bool isBasicBlock;
|
||||||
|
bool isSequenceEnd;
|
||||||
|
bool isPrologueEnd;
|
||||||
|
bool isEpilogueBegin;
|
||||||
|
uint32 instructionSet;
|
||||||
|
|
||||||
|
// when file is set to -1
|
||||||
|
const char* explicitFile;
|
||||||
|
uint32 explicitFileDirIndex;
|
||||||
|
|
||||||
|
DataReader dataReader;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // LINE_NUMBER_PROGRAM_H
|
||||||
@@ -7,10 +7,12 @@
|
|||||||
|
|
||||||
#include <new>
|
#include <new>
|
||||||
|
|
||||||
|
#include <AutoDeleter.h>
|
||||||
#include <AutoLocker.h>
|
#include <AutoLocker.h>
|
||||||
|
|
||||||
#include "LocatableDirectory.h"
|
#include "LocatableDirectory.h"
|
||||||
#include "LocatableFile.h"
|
#include "LocatableFile.h"
|
||||||
|
#include "SourceFile.h"
|
||||||
#include "StringUtils.h"
|
#include "StringUtils.h"
|
||||||
|
|
||||||
|
|
||||||
@@ -111,12 +113,6 @@ public:
|
|||||||
|
|
||||||
~Domain()
|
~Domain()
|
||||||
{
|
{
|
||||||
LocatableEntry* entry = fEntries.Clear(true);
|
|
||||||
while (entry != NULL) {
|
|
||||||
LocatableEntry* next = entry->fNext;
|
|
||||||
entry->RemoveReference();
|
|
||||||
entry = next;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
status_t Init()
|
status_t Init()
|
||||||
@@ -168,7 +164,7 @@ public:
|
|||||||
BString name;
|
BString name;
|
||||||
_SplitPath(path, directory, name);
|
_SplitPath(path, directory, name);
|
||||||
|
|
||||||
LocatableEntry* entry = fEntries.Lookup(EntryPath(directory, name));
|
LocatableEntry* entry = _LookupEntry(EntryPath(directory, name));
|
||||||
if (entry == NULL)
|
if (entry == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -186,10 +182,12 @@ private:
|
|||||||
fManager->Unlock();
|
fManager->Unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool LocatableEntryUnused(LocatableEntry* entry)
|
virtual void LocatableEntryUnused(LocatableEntry* entry)
|
||||||
{
|
{
|
||||||
fEntries.Remove(entry);
|
fManager->Lock();
|
||||||
return true;
|
if (fEntries.Lookup(EntryPath(entry)) == entry)
|
||||||
|
fEntries.Remove(entry);
|
||||||
|
fManager->Unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _LocateDirectory(LocatableDirectory* directory,
|
bool _LocateDirectory(LocatableDirectory* directory,
|
||||||
@@ -285,7 +283,7 @@ private:
|
|||||||
LocatableFile* _GetFile(const BString& directoryPath, const BString& name)
|
LocatableFile* _GetFile(const BString& directoryPath, const BString& name)
|
||||||
{
|
{
|
||||||
// if already know return the file
|
// if already know return the file
|
||||||
LocatableEntry* entry = fEntries.Lookup(EntryPath(directoryPath, name));
|
LocatableEntry* entry = _LookupEntry(EntryPath(directoryPath, name));
|
||||||
if (entry != NULL) {
|
if (entry != NULL) {
|
||||||
LocatableFile* file = dynamic_cast<LocatableFile*>(entry);
|
LocatableFile* file = dynamic_cast<LocatableFile*>(entry);
|
||||||
if (file == NULL)
|
if (file == NULL)
|
||||||
@@ -321,7 +319,7 @@ private:
|
|||||||
|
|
||||||
// if already know return the directory
|
// if already know return the directory
|
||||||
LocatableEntry* entry
|
LocatableEntry* entry
|
||||||
= fEntries.Lookup(EntryPath(directoryPath, fileName));
|
= _LookupEntry(EntryPath(directoryPath, fileName));
|
||||||
if (entry != NULL) {
|
if (entry != NULL) {
|
||||||
LocatableDirectory* directory
|
LocatableDirectory* directory
|
||||||
= dynamic_cast<LocatableDirectory*>(entry);
|
= dynamic_cast<LocatableDirectory*>(entry);
|
||||||
@@ -354,13 +352,30 @@ private:
|
|||||||
directory->SetLocatedPath(dirPath, false);
|
directory->SetLocatedPath(dirPath, false);
|
||||||
} else if (parentDirectory != NULL
|
} else if (parentDirectory != NULL
|
||||||
&& parentDirectory->State() != LOCATABLE_ENTRY_UNLOCATED) {
|
&& parentDirectory->State() != LOCATABLE_ENTRY_UNLOCATED) {
|
||||||
// TODO:...
|
BString locatedDirectoryPath;
|
||||||
|
if (parentDirectory->GetLocatedPath(locatedDirectoryPath))
|
||||||
|
_LocateEntryInParentDir(directory, locatedDirectoryPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
fEntries.Insert(directory);
|
fEntries.Insert(directory);
|
||||||
return directory;
|
return directory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LocatableEntry* _LookupEntry(const EntryPath& entryPath)
|
||||||
|
{
|
||||||
|
LocatableEntry* entry = fEntries.Lookup(entryPath);
|
||||||
|
if (entry == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
// if already unreferenced, remove it
|
||||||
|
if (entry->CountReferences() == 0) {
|
||||||
|
fEntries.Remove(entry);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
void _NormalizePath(const BString& path, BString& _normalizedPath)
|
void _NormalizePath(const BString& path, BString& _normalizedPath)
|
||||||
{
|
{
|
||||||
BString normalizedPath;
|
BString normalizedPath;
|
||||||
@@ -445,6 +460,66 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - SourceFileEntry
|
||||||
|
|
||||||
|
|
||||||
|
struct FileManager::SourceFileEntry : public SourceFileOwner,
|
||||||
|
public HashTableLink<SourceFileEntry> {
|
||||||
|
|
||||||
|
FileManager* manager;
|
||||||
|
BString path;
|
||||||
|
SourceFile* file;
|
||||||
|
|
||||||
|
SourceFileEntry(FileManager* manager, const BString& path)
|
||||||
|
:
|
||||||
|
manager(manager),
|
||||||
|
path(path),
|
||||||
|
file(NULL)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void SourceFileUnused(SourceFile* sourceFile)
|
||||||
|
{
|
||||||
|
manager->_SourceFileUnused(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void SourceFileDeleted(SourceFile* sourceFile)
|
||||||
|
{
|
||||||
|
// We have already been removed from the table, so commit suicide.
|
||||||
|
delete this;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - SourceFileHashDefinition
|
||||||
|
|
||||||
|
|
||||||
|
struct FileManager::SourceFileHashDefinition {
|
||||||
|
typedef BString KeyType;
|
||||||
|
typedef SourceFileEntry ValueType;
|
||||||
|
|
||||||
|
size_t HashKey(const BString& key) const
|
||||||
|
{
|
||||||
|
return StringUtils::HashValue(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Hash(const SourceFileEntry* value) const
|
||||||
|
{
|
||||||
|
return HashKey(value->path);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Compare(const BString& key, const SourceFileEntry* value) const
|
||||||
|
{
|
||||||
|
return value->path == key;
|
||||||
|
}
|
||||||
|
|
||||||
|
HashTableLink<SourceFileEntry>* GetLink(SourceFileEntry* value) const
|
||||||
|
{
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark - FileManager
|
// #pragma mark - FileManager
|
||||||
|
|
||||||
|
|
||||||
@@ -452,7 +527,8 @@ FileManager::FileManager()
|
|||||||
:
|
:
|
||||||
fLock("file manager"),
|
fLock("file manager"),
|
||||||
fTargetDomain(NULL),
|
fTargetDomain(NULL),
|
||||||
fSourceDomain(NULL)
|
fSourceDomain(NULL),
|
||||||
|
fSourceFiles(NULL)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -461,6 +537,7 @@ FileManager::~FileManager()
|
|||||||
{
|
{
|
||||||
delete fTargetDomain;
|
delete fTargetDomain;
|
||||||
delete fSourceDomain;
|
delete fSourceDomain;
|
||||||
|
delete fSourceFiles;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -489,6 +566,15 @@ FileManager::Init(bool targetIsLocal)
|
|||||||
if (error != B_OK)
|
if (error != B_OK)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
|
// create source file table
|
||||||
|
fSourceFiles = new(std::nothrow) SourceFileTable;
|
||||||
|
if (fSourceFiles == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
error = fSourceFiles->Init();
|
||||||
|
if (error != B_OK)
|
||||||
|
return error;
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -539,3 +625,75 @@ FileManager::SourceEntryLocated(const BString& path, const BString& locatedPath)
|
|||||||
AutoLocker<FileManager> locker(this);
|
AutoLocker<FileManager> locker(this);
|
||||||
fSourceDomain->EntryLocated(path, locatedPath);
|
fSourceDomain->EntryLocated(path, locatedPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
FileManager::LoadSourceFile(LocatableFile* file, SourceFile*& _sourceFile)
|
||||||
|
{
|
||||||
|
AutoLocker<FileManager> locker(this);
|
||||||
|
|
||||||
|
// get the path
|
||||||
|
BString path;
|
||||||
|
if (!file->GetLocatedPath(path))
|
||||||
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
|
||||||
|
// we might already know the source file
|
||||||
|
SourceFileEntry* entry = _LookupSourceFile(path);
|
||||||
|
if (entry != NULL) {
|
||||||
|
entry->file->AcquireReference();
|
||||||
|
_sourceFile = entry->file;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// create the hash table entry
|
||||||
|
entry = new(std::nothrow) SourceFileEntry(this, path);
|
||||||
|
if (entry == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
// load the file
|
||||||
|
SourceFile* sourceFile = new(std::nothrow) SourceFile(entry);
|
||||||
|
if (sourceFile == NULL) {
|
||||||
|
delete entry;
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
}
|
||||||
|
ObjectDeleter<SourceFile> sourceFileDeleter(sourceFile);
|
||||||
|
|
||||||
|
entry->file = sourceFile;
|
||||||
|
|
||||||
|
status_t error = sourceFile->Init(path);
|
||||||
|
if (error != B_OK)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
fSourceFiles->Insert(entry);
|
||||||
|
|
||||||
|
_sourceFile = sourceFileDeleter.Detach();
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FileManager::SourceFileEntry*
|
||||||
|
FileManager::_LookupSourceFile(const BString& path)
|
||||||
|
{
|
||||||
|
SourceFileEntry* entry = fSourceFiles->Lookup(path);
|
||||||
|
if (entry == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
// the entry might be unused already -- in that case remove it
|
||||||
|
if (entry->file->CountReferences() == 0) {
|
||||||
|
fSourceFiles->Remove(entry);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
FileManager::_SourceFileUnused(SourceFileEntry* entry)
|
||||||
|
{
|
||||||
|
AutoLocker<FileManager> locker(this);
|
||||||
|
|
||||||
|
SourceFileEntry* otherEntry = fSourceFiles->Lookup(entry->path);
|
||||||
|
if (otherEntry == entry)
|
||||||
|
fSourceFiles->Remove(entry);
|
||||||
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
|
|
||||||
class LocatableFile;
|
class LocatableFile;
|
||||||
|
class SourceFile;
|
||||||
|
|
||||||
|
|
||||||
class FileManager {
|
class FileManager {
|
||||||
@@ -40,17 +41,32 @@ public:
|
|||||||
void SourceEntryLocated(const BString& path,
|
void SourceEntryLocated(const BString& path,
|
||||||
const BString& locatedPath);
|
const BString& locatedPath);
|
||||||
|
|
||||||
|
status_t LoadSourceFile(LocatableFile* file,
|
||||||
|
SourceFile*& _sourceFile);
|
||||||
|
// returns a reference
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct EntryPath;
|
struct EntryPath;
|
||||||
struct EntryHashDefinition;
|
struct EntryHashDefinition;
|
||||||
class Domain;
|
class Domain;
|
||||||
|
struct SourceFileEntry;
|
||||||
|
struct SourceFileHashDefinition;
|
||||||
|
|
||||||
typedef OpenHashTable<EntryHashDefinition> LocatableEntryTable;
|
typedef OpenHashTable<EntryHashDefinition> LocatableEntryTable;
|
||||||
|
typedef OpenHashTable<SourceFileHashDefinition> SourceFileTable;
|
||||||
|
|
||||||
|
friend struct SourceFileEntry;
|
||||||
|
// for gcc 2
|
||||||
|
|
||||||
|
private:
|
||||||
|
SourceFileEntry* _LookupSourceFile(const BString& path);
|
||||||
|
void _SourceFileUnused(SourceFileEntry* entry);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
BLocker fLock;
|
BLocker fLock;
|
||||||
Domain* fTargetDomain;
|
Domain* fTargetDomain;
|
||||||
Domain* fSourceDomain;
|
Domain* fSourceDomain;
|
||||||
|
SourceFileTable* fSourceFiles;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -43,7 +43,5 @@ LocatableEntry::~LocatableEntry()
|
|||||||
void
|
void
|
||||||
LocatableEntry::LastReferenceReleased()
|
LocatableEntry::LastReferenceReleased()
|
||||||
{
|
{
|
||||||
AutoLocker<LocatableEntryOwner> locker(fOwner);
|
fOwner->LocatableEntryUnused(this);
|
||||||
if (CountReferences() == 0 && fOwner->LocatableEntryUnused(this))
|
|
||||||
delete this;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ public:
|
|||||||
virtual bool Lock() = 0;
|
virtual bool Lock() = 0;
|
||||||
virtual void Unlock() = 0;
|
virtual void Unlock() = 0;
|
||||||
|
|
||||||
virtual bool LocatableEntryUnused(LocatableEntry* entry) = 0;
|
virtual void LocatableEntryUnused(LocatableEntry* entry) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,139 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009, Ingo Weinhold, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "SourceFile.h"
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <new>
|
||||||
|
|
||||||
|
|
||||||
|
static const int32 kMaxSourceFileSize = 10 * 1024 * 1024;
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - SourceFileOwner
|
||||||
|
|
||||||
|
|
||||||
|
SourceFileOwner::~SourceFileOwner()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - SourceFile
|
||||||
|
|
||||||
|
|
||||||
|
SourceFile::SourceFile(SourceFileOwner* owner)
|
||||||
|
:
|
||||||
|
fOwner(owner),
|
||||||
|
fFileContent(NULL),
|
||||||
|
fLineOffsets(NULL),
|
||||||
|
fLineCount(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SourceFile::~SourceFile()
|
||||||
|
{
|
||||||
|
free(fFileContent);
|
||||||
|
delete[] fLineOffsets;
|
||||||
|
fOwner->SourceFileDeleted(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
SourceFile::Init(const char* path)
|
||||||
|
{
|
||||||
|
// open the file
|
||||||
|
int fd = open(path, O_RDONLY);
|
||||||
|
if (fd < 0)
|
||||||
|
return errno;
|
||||||
|
|
||||||
|
// stat the file to get its size
|
||||||
|
struct stat st;
|
||||||
|
if (fstat(fd, &st) < 0) {
|
||||||
|
close(fd);
|
||||||
|
return errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (st.st_size > kMaxSourceFileSize)
|
||||||
|
return B_FILE_TOO_LARGE;
|
||||||
|
size_t fileSize = st.st_size;
|
||||||
|
|
||||||
|
if (fileSize == 0)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
// allocate the content buffer
|
||||||
|
fFileContent = (char*)malloc(fileSize + 1);
|
||||||
|
// one more byte for a terminating null
|
||||||
|
if (fFileContent == NULL) {
|
||||||
|
close(fd);
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
// read the file
|
||||||
|
ssize_t bytesRead = read(fd, fFileContent, fileSize);
|
||||||
|
close(fd);
|
||||||
|
if (bytesRead < 0 || (size_t)bytesRead != fileSize)
|
||||||
|
return bytesRead < 0 ? errno : B_FILE_ERROR;
|
||||||
|
|
||||||
|
// null-terminate
|
||||||
|
fFileContent[fileSize] = '\0';
|
||||||
|
|
||||||
|
// count lines
|
||||||
|
fLineCount = 0;
|
||||||
|
for (size_t i = 0; i < fileSize; i++) {
|
||||||
|
if (fFileContent[i] == '\n')
|
||||||
|
fLineCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fFileContent[fileSize - 1] != '\n')
|
||||||
|
fLineCount++;
|
||||||
|
|
||||||
|
// allocate line offset array
|
||||||
|
fLineOffsets = new(std::nothrow) int32[fLineCount];
|
||||||
|
if (fLineOffsets == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
// get the line offsets and null-terminate the lines
|
||||||
|
int32 lineIndex = 0;
|
||||||
|
fLineOffsets[lineIndex++] = 0;
|
||||||
|
for (size_t i = 0; i < fileSize; i++) {
|
||||||
|
if (fFileContent[i] == '\n') {
|
||||||
|
fFileContent[i] = '\0';
|
||||||
|
fLineOffsets[lineIndex++] = i + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int32
|
||||||
|
SourceFile::CountLines() const
|
||||||
|
{
|
||||||
|
return fLineCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const char*
|
||||||
|
SourceFile::LineAt(int32 index) const
|
||||||
|
{
|
||||||
|
return index >= 0 && index < fLineCount
|
||||||
|
? fFileContent + fLineOffsets[index] : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SourceFile::LastReferenceReleased()
|
||||||
|
{
|
||||||
|
fOwner->SourceFileUnused(this);
|
||||||
|
delete this;
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009, Ingo Weinhold, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef SOURCE_FILE_H
|
||||||
|
#define SOURCE_FILE_H
|
||||||
|
|
||||||
|
#include <Referenceable.h>
|
||||||
|
|
||||||
|
|
||||||
|
class SourceFile;
|
||||||
|
|
||||||
|
|
||||||
|
class SourceFileOwner {
|
||||||
|
public:
|
||||||
|
virtual ~SourceFileOwner();
|
||||||
|
|
||||||
|
virtual void SourceFileUnused(SourceFile* sourceFile) = 0;
|
||||||
|
virtual void SourceFileDeleted(SourceFile* sourceFile) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class SourceFile : public Referenceable {
|
||||||
|
public:
|
||||||
|
SourceFile(SourceFileOwner* owner);
|
||||||
|
~SourceFile();
|
||||||
|
|
||||||
|
status_t Init(const char* path);
|
||||||
|
|
||||||
|
int32 CountLines() const;
|
||||||
|
const char* LineAt(int32 index) const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void LastReferenceReleased();
|
||||||
|
|
||||||
|
private:
|
||||||
|
SourceFileOwner* fOwner;
|
||||||
|
char* fFileContent;
|
||||||
|
int32* fLineOffsets;
|
||||||
|
int32 fLineCount;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif // SOURCE_FILE_H
|
||||||
@@ -17,6 +17,7 @@
|
|||||||
#include "FunctionDebugInfo.h"
|
#include "FunctionDebugInfo.h"
|
||||||
#include "Image.h"
|
#include "Image.h"
|
||||||
#include "ImageDebugInfo.h"
|
#include "ImageDebugInfo.h"
|
||||||
|
#include "LocatableFile.h"
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark - FunctionsTableModel
|
// #pragma mark - FunctionsTableModel
|
||||||
@@ -77,8 +78,8 @@ public:
|
|||||||
// count the different source files
|
// count the different source files
|
||||||
int32 sourceFileCount = 1;
|
int32 sourceFileCount = 1;
|
||||||
for (int32 i = 1; i < functionCount; i++) {
|
for (int32 i = 1; i < functionCount; i++) {
|
||||||
if (_CompareSourceFileNames(functions[i - 1]->SourceFileName(),
|
if (_CompareSourceFileNames(functions[i - 1]->SourceFile(),
|
||||||
functions[i]->SourceFileName()) != 0) {
|
functions[i]->SourceFile()) != 0) {
|
||||||
sourceFileCount++;
|
sourceFileCount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -93,8 +94,8 @@ public:
|
|||||||
|
|
||||||
int32 sourceFileIndex = 1;
|
int32 sourceFileIndex = 1;
|
||||||
for (int32 i = 1; i < functionCount; i++) {
|
for (int32 i = 1; i < functionCount; i++) {
|
||||||
if (_CompareSourceFileNames(functions[i - 1]->SourceFileName(),
|
if (_CompareSourceFileNames(functions[i - 1]->SourceFile(),
|
||||||
functions[i]->SourceFileName()) != 0) {
|
functions[i]->SourceFile()) != 0) {
|
||||||
fSourceFileIndices[sourceFileIndex++] = i;
|
fSourceFileIndices[sourceFileIndex++] = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -158,9 +159,14 @@ public:
|
|||||||
|
|
||||||
if (object >= fSourceFileIndices
|
if (object >= fSourceFileIndices
|
||||||
&& object < fSourceFileIndices + fSourceFileCount) {
|
&& object < fSourceFileIndices + fSourceFileCount) {
|
||||||
const char* name = fFunctions[*(int32*)object]->SourceFileName();
|
int32 index = *(int32*)object;
|
||||||
value.SetTo(name != NULL ? name : "<no source file>",
|
if (LocatableFile* file = fFunctions[index]->SourceFile()) {
|
||||||
B_VARIANT_DONT_COPY_DATA);
|
BString path;
|
||||||
|
file->GetPath(path);
|
||||||
|
value.SetTo(path);
|
||||||
|
} else
|
||||||
|
value.SetTo("<no source file>", B_VARIANT_DONT_COPY_DATA);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,8 +197,8 @@ public:
|
|||||||
&& _path.AddComponent(index - fSourceFileIndices[sourceIndex]);
|
&& _path.AddComponent(index - fSourceFileIndices[sourceIndex]);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GetObjectForPath(const TreeTablePath& path, const char*& _sourceFile,
|
bool GetObjectForPath(const TreeTablePath& path,
|
||||||
FunctionDebugInfo*& _function)
|
LocatableFile*& _sourceFile, FunctionDebugInfo*& _function)
|
||||||
{
|
{
|
||||||
int32 componentCount = path.CountComponents();
|
int32 componentCount = path.CountComponents();
|
||||||
if (componentCount == 0 || componentCount > 2)
|
if (componentCount == 0 || componentCount > 2)
|
||||||
@@ -202,8 +208,7 @@ public:
|
|||||||
if (sourceIndex < 0 || sourceIndex >= fSourceFileCount)
|
if (sourceIndex < 0 || sourceIndex >= fSourceFileCount)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
_sourceFile = fFunctions[fSourceFileIndices[sourceIndex]]
|
_sourceFile = fFunctions[fSourceFileIndices[sourceIndex]]->SourceFile();
|
||||||
->SourceFileName();
|
|
||||||
|
|
||||||
_function = NULL;
|
_function = NULL;
|
||||||
|
|
||||||
@@ -232,7 +237,7 @@ private:
|
|||||||
return nextFunctionIndex - fSourceFileIndices[sourceIndex];
|
return nextFunctionIndex - fSourceFileIndices[sourceIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _CompareSourceFileNames(const char* a, const char* b)
|
static int _CompareSourceFileNames(LocatableFile* a, LocatableFile* b)
|
||||||
{
|
{
|
||||||
if (a == b)
|
if (a == b)
|
||||||
return 0;
|
return 0;
|
||||||
@@ -242,15 +247,21 @@ private:
|
|||||||
if (b == NULL)
|
if (b == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
return strcmp(a, b);
|
BString pathA;
|
||||||
|
a->GetPath(pathA);
|
||||||
|
|
||||||
|
BString pathB;
|
||||||
|
b->GetPath(pathB);
|
||||||
|
|
||||||
|
return pathA.Compare(pathB);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool _FunctionLess(const FunctionDebugInfo* a,
|
static bool _FunctionLess(const FunctionDebugInfo* a,
|
||||||
const FunctionDebugInfo* b)
|
const FunctionDebugInfo* b)
|
||||||
{
|
{
|
||||||
// compare source file name first
|
// compare source file name first
|
||||||
int compared = _CompareSourceFileNames(a->SourceFileName(),
|
int compared = _CompareSourceFileNames(a->SourceFile(),
|
||||||
b->SourceFileName());
|
b->SourceFile());
|
||||||
if (compared != 0)
|
if (compared != 0)
|
||||||
return compared < 0;
|
return compared < 0;
|
||||||
|
|
||||||
@@ -338,6 +349,9 @@ printf("ImageFunctionsView::SetImageDebugInfo(%p)\n", imageDebugInfo);
|
|||||||
fFunctionsTable->SetNodeExpanded(path, true, false);
|
fFunctionsTable->SetNodeExpanded(path, true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (fImageDebugInfo != NULL)
|
||||||
|
fFunctionsTable->ResizeAllColumnsToPreferred();
|
||||||
|
|
||||||
printf("ImageFunctionsView::SetImageDebugInfo(%p) done\n", imageDebugInfo);
|
printf("ImageFunctionsView::SetImageDebugInfo(%p) done\n", imageDebugInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -362,7 +376,7 @@ ImageFunctionsView::TreeTableSelectionChanged(TreeTable* table)
|
|||||||
if (fListener == NULL)
|
if (fListener == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const char* sourceFile = NULL;
|
LocatableFile* sourceFile = NULL;
|
||||||
FunctionDebugInfo* function = NULL;
|
FunctionDebugInfo* function = NULL;
|
||||||
TreeTablePath path;
|
TreeTablePath path;
|
||||||
if (table->SelectionModel()->GetPathAt(0, path))
|
if (table->SelectionModel()->GetPathAt(0, path))
|
||||||
|
|||||||
@@ -0,0 +1,144 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009, Ingo Weinhold, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "FileSourceCode.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "SourceFile.h"
|
||||||
|
#include "Statement.h"
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: Lot's of code duplication from DissassembledCode!
|
||||||
|
|
||||||
|
|
||||||
|
FileSourceCode::FileSourceCode(SourceFile* file)
|
||||||
|
:
|
||||||
|
fFile(file),
|
||||||
|
fLineStatements(NULL)
|
||||||
|
{
|
||||||
|
fFile->AcquireReference();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FileSourceCode::~FileSourceCode()
|
||||||
|
{
|
||||||
|
for (int32 i = 0; Statement* statement = fStatements.ItemAt(i); i++)
|
||||||
|
statement->RemoveReference();
|
||||||
|
|
||||||
|
delete[] fLineStatements;
|
||||||
|
|
||||||
|
fFile->ReleaseReference();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
FileSourceCode::Init()
|
||||||
|
{
|
||||||
|
fLineStatements = new(std::nothrow) Statement*[fFile->CountLines()];
|
||||||
|
if (fLineStatements == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
memset(fLineStatements, 0, fFile->CountLines() * sizeof(Statement*));
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
FileSourceCode::AddStatement(ContiguousStatement* statement)
|
||||||
|
{
|
||||||
|
if (!fStatements.BinaryInsert(statement, &_CompareStatements))
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
int32 line = statement->StartSourceLocation().Line();
|
||||||
|
if (line >= 0 && line < fFile->CountLines()
|
||||||
|
&& fLineStatements[line] == NULL) {
|
||||||
|
fLineStatements[line] = statement;
|
||||||
|
}
|
||||||
|
|
||||||
|
statement->AcquireReference();
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int32
|
||||||
|
FileSourceCode::CountLines() const
|
||||||
|
{
|
||||||
|
return fFile->CountLines();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const char*
|
||||||
|
FileSourceCode::LineAt(int32 index) const
|
||||||
|
{
|
||||||
|
return fFile->LineAt(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int32
|
||||||
|
FileSourceCode::CountStatements() const
|
||||||
|
{
|
||||||
|
return fStatements.CountItems();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Statement*
|
||||||
|
FileSourceCode::StatementAt(int32 index) const
|
||||||
|
{
|
||||||
|
return fStatements.ItemAt(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Statement*
|
||||||
|
FileSourceCode::StatementAtLine(int32 index) const
|
||||||
|
{
|
||||||
|
return index >= 0 && index < CountLines() ? fLineStatements[index] : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Statement*
|
||||||
|
FileSourceCode::StatementAtAddress(target_addr_t address) const
|
||||||
|
{
|
||||||
|
return fStatements.BinarySearchByKey(address, &_CompareAddressStatement);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TargetAddressRange
|
||||||
|
FileSourceCode::StatementAddressRange() const
|
||||||
|
{
|
||||||
|
if (fStatements.IsEmpty())
|
||||||
|
return TargetAddressRange();
|
||||||
|
|
||||||
|
ContiguousStatement* first = fStatements.ItemAt(0);
|
||||||
|
ContiguousStatement* last
|
||||||
|
= fStatements.ItemAt(fStatements.CountItems() - 1);
|
||||||
|
return TargetAddressRange(first->AddressRange().Start(),
|
||||||
|
last->AddressRange().End());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*static*/ int
|
||||||
|
FileSourceCode::_CompareStatements(const ContiguousStatement* a,
|
||||||
|
const ContiguousStatement* b)
|
||||||
|
{
|
||||||
|
target_addr_t addressA = a->AddressRange().Start();
|
||||||
|
target_addr_t addressB = b->AddressRange().Start();
|
||||||
|
if (addressA < addressB)
|
||||||
|
return -1;
|
||||||
|
return addressA == addressB ? 0 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*static*/ int
|
||||||
|
FileSourceCode::_CompareAddressStatement(const target_addr_t* address,
|
||||||
|
const ContiguousStatement* statement)
|
||||||
|
{
|
||||||
|
const TargetAddressRange& range = statement->AddressRange();
|
||||||
|
|
||||||
|
if (*address < range.Start())
|
||||||
|
return -1;
|
||||||
|
return *address < range.End() ? 0 : 1;
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009, Ingo Weinhold, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef FILE_SOURCE_CODE_H
|
||||||
|
#define FILE_SOURCE_CODE_H
|
||||||
|
|
||||||
|
#include <ObjectList.h>
|
||||||
|
|
||||||
|
#include "SourceCode.h"
|
||||||
|
|
||||||
|
|
||||||
|
class ContiguousStatement;
|
||||||
|
class SourceFile;
|
||||||
|
|
||||||
|
|
||||||
|
class FileSourceCode : public SourceCode {
|
||||||
|
public:
|
||||||
|
FileSourceCode(SourceFile* file);
|
||||||
|
virtual ~FileSourceCode();
|
||||||
|
|
||||||
|
status_t Init();
|
||||||
|
status_t AddStatement(ContiguousStatement* statement);
|
||||||
|
|
||||||
|
virtual int32 CountLines() const;
|
||||||
|
virtual const char* LineAt(int32 index) const;
|
||||||
|
|
||||||
|
virtual int32 CountStatements() const;
|
||||||
|
virtual Statement* StatementAt(int32 index) const;
|
||||||
|
virtual Statement* StatementAtLine(int32 index) const;
|
||||||
|
virtual Statement* StatementAtAddress(target_addr_t address) const;
|
||||||
|
|
||||||
|
virtual TargetAddressRange StatementAddressRange() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
typedef BObjectList<ContiguousStatement> StatementList;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static int _CompareStatements(
|
||||||
|
const ContiguousStatement* a,
|
||||||
|
const ContiguousStatement* b);
|
||||||
|
static int _CompareAddressStatement(
|
||||||
|
const target_addr_t* address,
|
||||||
|
const ContiguousStatement* statement);
|
||||||
|
|
||||||
|
private:
|
||||||
|
SourceFile* fFile;
|
||||||
|
Statement** fLineStatements;
|
||||||
|
StatementList fStatements;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // FILE_BASED_SOURCE_CODE_H
|
||||||
Reference in New Issue
Block a user