- 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:
Ingo Weinhold
2009-07-03 00:56:39 +00:00
parent 92194962f6
commit 593fa6776a
28 changed files with 1249 additions and 80 deletions
+2
View File
@@ -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
+2 -1
View File
@@ -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;
+4 -1
View File
@@ -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;
}; };
+20 -1
View File
@@ -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);
} }
+2 -2
View File
@@ -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;
} }
+1
View File
@@ -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
+172 -14
View File
@@ -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);
}
+16
View File
@@ -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;
}; };
+1 -3
View File
@@ -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;
} }
+1 -1
View File
@@ -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;
}; };
+139
View File
@@ -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;
}
+46
View File
@@ -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))
+144
View File
@@ -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;
}
+53
View File
@@ -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