- 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
LocatableEntry.cpp
LocatableFile.cpp
SourceFile.cpp
# gui/team_window
ImageFunctionsView.cpp
@@ -88,6 +89,7 @@ Application Debugger :
# model
Breakpoint.cpp
DisassembledCode.cpp
FileSourceCode.cpp
Image.cpp
ImageInfo.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
TeamDebugInfo* teamDebugInfo = new(std::nothrow) TeamDebugInfo(
fDebuggerInterface, fDebuggerInterface->GetArchitecture());
fDebuggerInterface, fDebuggerInterface->GetArchitecture(),
fFileManager);
if (teamDebugInfo == NULL)
return B_NO_MEMORY;
Reference<TeamDebugInfo> teamDebugInfoReference(teamDebugInfo);
@@ -63,8 +63,8 @@ BasicFunctionDebugInfo::PrettyName() const
}
const char*
BasicFunctionDebugInfo::SourceFileName() const
LocatableFile*
BasicFunctionDebugInfo::SourceFile() const
{
return NULL;
}
@@ -26,7 +26,7 @@ public:
virtual const char* Name() const;
virtual const char* PrettyName() const;
virtual const char* SourceFileName() const;
virtual LocatableFile* SourceFile() const;
virtual SourceLocation SourceStartLocation() const;
virtual SourceLocation SourceEndLocation() const;
@@ -7,29 +7,38 @@
#include "DebugInfoEntries.h"
#include "DwarfImageDebugInfo.h"
#include "LocatableFile.h"
#include "TargetAddressRangeList.h"
DwarfFunctionDebugInfo::DwarfFunctionDebugInfo(
DwarfImageDebugInfo* imageDebugInfo, DIESubprogram* subprogramEntry,
TargetAddressRangeList* addressRanges, const BString& name,
const BString& sourceFile, const SourceLocation& sourceLocation)
DwarfImageDebugInfo* imageDebugInfo, CompilationUnit* compilationUnit,
DIESubprogram* subprogramEntry, TargetAddressRangeList* addressRanges,
const BString& name, LocatableFile* sourceFile,
const SourceLocation& sourceLocation)
:
fImageDebugInfo(imageDebugInfo),
fCompilationUnit(compilationUnit),
fAddressRanges(addressRanges),
fName(name),
fSourceFile(sourceFile),
fSourceLocation(sourceLocation)
{
fImageDebugInfo->AddReference();
fAddressRanges->AddReference();
fImageDebugInfo->AcquireReference();
fAddressRanges->AcquireReference();
if (fSourceFile != NULL)
fSourceFile->AcquireReference();
}
DwarfFunctionDebugInfo::~DwarfFunctionDebugInfo()
{
fAddressRanges->RemoveReference();
fImageDebugInfo->RemoveReference();
if (fSourceFile != NULL)
fSourceFile->ReleaseReference();
fAddressRanges->ReleaseReference();
fImageDebugInfo->ReleaseReference();
}
@@ -68,10 +77,10 @@ DwarfFunctionDebugInfo::PrettyName() const
}
const char*
DwarfFunctionDebugInfo::SourceFileName() const
LocatableFile*
DwarfFunctionDebugInfo::SourceFile() const
{
return fSourceFile.Length() > 0 ? fSourceFile.String() : NULL;
return fSourceFile;
}
@@ -11,6 +11,7 @@
#include "SourceLocation.h"
class CompilationUnit;
class DIESubprogram;
class DwarfImageDebugInfo;
class TargetAddressRangeList;
@@ -20,10 +21,11 @@ class DwarfFunctionDebugInfo : public FunctionDebugInfo {
public:
DwarfFunctionDebugInfo(
DwarfImageDebugInfo* imageDebugInfo,
CompilationUnit* compilationUnit,
DIESubprogram* subprogramEntry,
TargetAddressRangeList* addressRanges,
const BString& name,
const BString& sourceFile,
LocatableFile* sourceFile,
const SourceLocation& sourceLocation);
virtual ~DwarfFunctionDebugInfo();
@@ -33,15 +35,19 @@ public:
virtual const char* Name() const;
virtual const char* PrettyName() const;
virtual const char* SourceFileName() const;
virtual LocatableFile* SourceFile() const;
virtual SourceLocation SourceStartLocation() const;
virtual SourceLocation SourceEndLocation() const;
CompilationUnit* GetCompilationUnit() const
{ return fCompilationUnit; }
private:
DwarfImageDebugInfo* fImageDebugInfo;
CompilationUnit* fCompilationUnit;
TargetAddressRangeList* fAddressRanges;
BString fName;
BString fSourceFile;
LocatableFile* fSourceFile;
SourceLocation fSourceLocation;
};
@@ -11,6 +11,7 @@
#include <new>
#include <AutoDeleter.h>
#include <AutoLocker.h>
#include "Architecture.h"
#include "CompilationUnit.h"
@@ -20,28 +21,136 @@
#include "DwarfFunctionDebugInfo.h"
#include "DwarfUtils.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,
Architecture* architecture, DwarfFile* file)
Architecture* architecture, FileManager* fileManager, DwarfFile* file)
:
fLock("dwarf image debug info"),
fImageInfo(imageInfo),
fArchitecture(architecture),
fFileManager(fileManager),
fFile(file),
fTextSegment(NULL),
fRelocationDelta(0)
fRelocationDelta(0),
fSourceCodes(NULL)
{
}
DwarfImageDebugInfo::~DwarfImageDebugInfo()
{
SourceCodeEntry* entry = fSourceCodes->Clear(true);
while (entry != NULL) {
SourceCodeEntry* next = entry->fNext;
entry->sourceCode->ReleaseReference();
entry = next;
}
delete fSourceCodes;
}
status_t
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();
if (fTextSegment == NULL)
return B_ENTRY_NOT_FOUND;
@@ -118,27 +227,24 @@ printf(" %ld compilation units\n", fFile->CountCompilationUnits());
}
// get the source location
const char* directory = NULL;
const char* file = NULL;
uint32 line = 0;
uint32 column = 0;
const char* directoryPath = NULL;
const char* fileName = NULL;
uint32 line = -1;
uint32 column = -1;
DwarfUtils::GetDeclarationLocation(fFile, subprogramEntry,
directory, file, line, column);
BString fileName;
if (file != NULL) {
if (directory != NULL)
fileName << directory << '/' << file;
else
fileName << file;
directoryPath, fileName, line, column);
LocatableFile* file = NULL;
if (fileName != NULL) {
file = fFileManager->GetSourceFile(directoryPath,
fileName);
}
// TODO: Avoid unnessecary string allocation! The source file name
// is the same for all contained functions, so they could share the
// string.
Reference<LocatableFile> fileReference(file, true);
// create and add the functions
DwarfFunctionDebugInfo* function
= new(std::nothrow) DwarfFunctionDebugInfo(this,
subprogramEntry, rangeList, name, fileName,
= new(std::nothrow) DwarfFunctionDebugInfo(this, unit,
subprogramEntry, rangeList, name, file,
SourceLocation(line, column));
if (function == NULL || !functions.AddItem(function)) {
delete function;
@@ -185,7 +291,14 @@ status_t
DwarfImageDebugInfo::LoadSourceCode(FunctionDebugInfo* function,
SourceCode*& _sourceCode)
{
AutoLocker<BLocker> locker(fLock);
// 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;
target_size_t bufferSize = std::min(function->Size(), kMaxBufferSize);
@@ -214,3 +327,140 @@ DwarfImageDebugInfo::GetStatement(FunctionDebugInfo* function,
// TODO:...
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
#define DWARF_IMAGE_DEBUG_INFO_H
#include <Locker.h>
#include <util/OpenHashTable.h>
#include "ImageInfo.h"
#include "SpecificImageDebugInfo.h"
class Architecture;
class CompilationUnit;
class DwarfFile;
class ElfSegment;
class FileManager;
class FileSourceCode;
class LocatableFile;
class SourceCode;
class DwarfImageDebugInfo : public SpecificImageDebugInfo {
public:
DwarfImageDebugInfo(const ImageInfo& imageInfo,
Architecture* architecture,
DwarfFile* file);
FileManager* fileManager, DwarfFile* file);
virtual ~DwarfImageDebugInfo();
status_t Init();
@@ -40,11 +49,27 @@ public:
Statement*& _statement);
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;
Architecture* fArchitecture;
FileManager* fFileManager;
DwarfFile* fFile;
ElfSegment* fTextSegment;
target_addr_t fRelocationDelta;
SourceCodeTable* fSourceCodes;
};
@@ -14,9 +14,11 @@
#include "LocatableFile.h"
DwarfTeamDebugInfo::DwarfTeamDebugInfo(Architecture* architecture)
DwarfTeamDebugInfo::DwarfTeamDebugInfo(Architecture* architecture,
FileManager* fileManager)
:
fArchitecture(architecture),
fFileManager(fileManager),
fManager(NULL)
{
}
@@ -62,7 +64,7 @@ DwarfTeamDebugInfo::CreateImageDebugInfo(const ImageInfo& imageInfo,
// create the image debug info
DwarfImageDebugInfo* debuggerInfo = new(std::nothrow) DwarfImageDebugInfo(
imageInfo, fArchitecture, file);
imageInfo, fArchitecture, fFileManager, file);
if (debuggerInfo == NULL)
return B_NO_MEMORY;
@@ -10,12 +10,14 @@
class Architecture;
class DwarfManager;
class FileManager;
class ImageInfo;
class DwarfTeamDebugInfo : public SpecificTeamDebugInfo {
public:
DwarfTeamDebugInfo(Architecture* architecture);
DwarfTeamDebugInfo(Architecture* architecture,
FileManager* fileManager);
virtual ~DwarfTeamDebugInfo();
status_t Init();
@@ -26,6 +28,7 @@ public:
private:
Architecture* fArchitecture;
FileManager* fFileManager;
DwarfManager* fManager;
};
@@ -20,6 +20,7 @@ enum function_source_state {
};
class LocatableFile;
class SourceCode;
class SpecificImageDebugInfo;
@@ -38,7 +39,7 @@ public:
virtual const char* Name() 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 SourceEndLocation() const = 0;
@@ -16,10 +16,11 @@
TeamDebugInfo::TeamDebugInfo(DebuggerInterface* debuggerInterface,
Architecture* architecture)
Architecture* architecture, FileManager* fileManager)
:
fDebuggerInterface(debuggerInterface),
fArchitecture(architecture),
fFileManager(fileManager),
fSpecificInfos(10, true)
{
}
@@ -38,7 +39,7 @@ TeamDebugInfo::Init()
// DWARF
DwarfTeamDebugInfo* dwarfInfo = new(std::nothrow) DwarfTeamDebugInfo(
fArchitecture);
fArchitecture, fFileManager);
if (dwarfInfo == NULL || !fSpecificInfos.AddItem(dwarfInfo)) {
delete dwarfInfo;
return B_NO_MEMORY;
+4 -1
View File
@@ -13,6 +13,7 @@
class Architecture;
class DebuggerInterface;
class FileManager;
class ImageDebugInfo;
class ImageInfo;
class LocatableFile;
@@ -23,7 +24,8 @@ class TeamDebugInfo : public Referenceable {
public:
TeamDebugInfo(
DebuggerInterface* debuggerInterface,
Architecture* architecture);
Architecture* architecture,
FileManager* fileManager);
~TeamDebugInfo();
status_t Init();
@@ -38,6 +40,7 @@ private:
private:
DebuggerInterface* fDebuggerInterface;
Architecture* fArchitecture;
FileManager* fFileManager;
SpecificInfoList fSpecificInfos;
};
@@ -11,6 +11,7 @@
#include "Array.h"
#include "DwarfTypes.h"
#include "LineNumberProgram.h"
class AbbreviationTable;
@@ -45,6 +46,9 @@ public:
DIECompileUnitBase* UnitEntry() const { return fUnitEntry; }
void SetUnitEntry(DIECompileUnitBase* entry);
LineNumberProgram& GetLineNumberProgram()
{ return fLineNumberProgram; }
status_t AddDebugInfoEntry(DebugInfoEntry* entry,
dwarf_off_t offset);
int CountEntries() const;
@@ -77,6 +81,7 @@ private:
Array<dwarf_off_t> fEntryOffsets;
DirectoryList fDirectories;
FileList fFiles;
LineNumberProgram fLineNumberProgram;
};
+20 -1
View File
@@ -5,6 +5,7 @@
#include "DwarfFile.h"
#include <algorithm>
#include <new>
#include <AutoDeleter.h>
@@ -631,6 +632,9 @@ printf("DwarfFile::_ParseLineInfo(%p), offset: %lu\n", unit, offset);
// unit length
bool dwarf64;
uint64 unitLength = dataReader.ReadInitialLength(dwarf64);
if (unitLength > (uint64)dataReader.BytesRemaining())
return B_BAD_DATA;
off_t unitOffset = dataReader.Offset();
// version (uhalf)
uint16 version = dataReader.Read<uint16>(0);
@@ -638,6 +642,10 @@ printf("DwarfFile::_ParseLineInfo(%p), offset: %lu\n", unit, offset);
// header_length (4/8)
uint64 headerLength = dwarf64
? 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
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);
// standard_opcode_lengths (ubyte[])
const uint8* standardOpcodeLengths = (const uint8*)dataReader.Data();
dataReader.Skip(opcodeBase - 1);
if (dataReader.HasOverflow())
@@ -702,7 +711,17 @@ printf("DwarfFile::_ParseLineInfo(%p), offset: %lu\n", unit, offset);
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;
_file = fileName;
_line = line;
_column = column;
_line = line - 1;
_column = column - 1;
return true;
}
+1
View File
@@ -23,6 +23,7 @@ MergeObject Debugger_dwarf.o
DwarfFile.cpp
DwarfManager.cpp
DwarfUtils.cpp
LineNumberProgram.cpp
SourceLanguageInfo.cpp
TagNames.cpp
;
@@ -0,0 +1,208 @@
/*
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* 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, ingo_weinhold@gmx.de.
* 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 <AutoDeleter.h>
#include <AutoLocker.h>
#include "LocatableDirectory.h"
#include "LocatableFile.h"
#include "SourceFile.h"
#include "StringUtils.h"
@@ -111,12 +113,6 @@ public:
~Domain()
{
LocatableEntry* entry = fEntries.Clear(true);
while (entry != NULL) {
LocatableEntry* next = entry->fNext;
entry->RemoveReference();
entry = next;
}
}
status_t Init()
@@ -168,7 +164,7 @@ public:
BString name;
_SplitPath(path, directory, name);
LocatableEntry* entry = fEntries.Lookup(EntryPath(directory, name));
LocatableEntry* entry = _LookupEntry(EntryPath(directory, name));
if (entry == NULL)
return;
@@ -186,10 +182,12 @@ private:
fManager->Unlock();
}
virtual bool LocatableEntryUnused(LocatableEntry* entry)
virtual void LocatableEntryUnused(LocatableEntry* entry)
{
fEntries.Remove(entry);
return true;
fManager->Lock();
if (fEntries.Lookup(EntryPath(entry)) == entry)
fEntries.Remove(entry);
fManager->Unlock();
}
bool _LocateDirectory(LocatableDirectory* directory,
@@ -285,7 +283,7 @@ private:
LocatableFile* _GetFile(const BString& directoryPath, const BString& name)
{
// if already know return the file
LocatableEntry* entry = fEntries.Lookup(EntryPath(directoryPath, name));
LocatableEntry* entry = _LookupEntry(EntryPath(directoryPath, name));
if (entry != NULL) {
LocatableFile* file = dynamic_cast<LocatableFile*>(entry);
if (file == NULL)
@@ -321,7 +319,7 @@ private:
// if already know return the directory
LocatableEntry* entry
= fEntries.Lookup(EntryPath(directoryPath, fileName));
= _LookupEntry(EntryPath(directoryPath, fileName));
if (entry != NULL) {
LocatableDirectory* directory
= dynamic_cast<LocatableDirectory*>(entry);
@@ -354,13 +352,30 @@ private:
directory->SetLocatedPath(dirPath, false);
} else if (parentDirectory != NULL
&& parentDirectory->State() != LOCATABLE_ENTRY_UNLOCATED) {
// TODO:...
BString locatedDirectoryPath;
if (parentDirectory->GetLocatedPath(locatedDirectoryPath))
_LocateEntryInParentDir(directory, locatedDirectoryPath);
}
fEntries.Insert(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)
{
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
@@ -452,7 +527,8 @@ FileManager::FileManager()
:
fLock("file manager"),
fTargetDomain(NULL),
fSourceDomain(NULL)
fSourceDomain(NULL),
fSourceFiles(NULL)
{
}
@@ -461,6 +537,7 @@ FileManager::~FileManager()
{
delete fTargetDomain;
delete fSourceDomain;
delete fSourceFiles;
}
@@ -489,6 +566,15 @@ FileManager::Init(bool targetIsLocal)
if (error != B_OK)
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;
}
@@ -539,3 +625,75 @@ FileManager::SourceEntryLocated(const BString& path, const BString& locatedPath)
AutoLocker<FileManager> locker(this);
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 SourceFile;
class FileManager {
@@ -40,17 +41,32 @@ public:
void SourceEntryLocated(const BString& path,
const BString& locatedPath);
status_t LoadSourceFile(LocatableFile* file,
SourceFile*& _sourceFile);
// returns a reference
private:
struct EntryPath;
struct EntryHashDefinition;
class Domain;
struct SourceFileEntry;
struct SourceFileHashDefinition;
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:
BLocker fLock;
Domain* fTargetDomain;
Domain* fSourceDomain;
SourceFileTable* fSourceFiles;
};
+1 -3
View File
@@ -43,7 +43,5 @@ LocatableEntry::~LocatableEntry()
void
LocatableEntry::LastReferenceReleased()
{
AutoLocker<LocatableEntryOwner> locker(fOwner);
if (CountReferences() == 0 && fOwner->LocatableEntryUnused(this))
delete this;
fOwner->LocatableEntryUnused(this);
}
+1 -1
View File
@@ -30,7 +30,7 @@ public:
virtual bool Lock() = 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, ingo_weinhold@gmx.de.
* 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, ingo_weinhold@gmx.de.
* 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 "Image.h"
#include "ImageDebugInfo.h"
#include "LocatableFile.h"
// #pragma mark - FunctionsTableModel
@@ -77,8 +78,8 @@ public:
// count the different source files
int32 sourceFileCount = 1;
for (int32 i = 1; i < functionCount; i++) {
if (_CompareSourceFileNames(functions[i - 1]->SourceFileName(),
functions[i]->SourceFileName()) != 0) {
if (_CompareSourceFileNames(functions[i - 1]->SourceFile(),
functions[i]->SourceFile()) != 0) {
sourceFileCount++;
}
}
@@ -93,8 +94,8 @@ public:
int32 sourceFileIndex = 1;
for (int32 i = 1; i < functionCount; i++) {
if (_CompareSourceFileNames(functions[i - 1]->SourceFileName(),
functions[i]->SourceFileName()) != 0) {
if (_CompareSourceFileNames(functions[i - 1]->SourceFile(),
functions[i]->SourceFile()) != 0) {
fSourceFileIndices[sourceFileIndex++] = i;
}
}
@@ -158,9 +159,14 @@ public:
if (object >= fSourceFileIndices
&& object < fSourceFileIndices + fSourceFileCount) {
const char* name = fFunctions[*(int32*)object]->SourceFileName();
value.SetTo(name != NULL ? name : "<no source file>",
B_VARIANT_DONT_COPY_DATA);
int32 index = *(int32*)object;
if (LocatableFile* file = fFunctions[index]->SourceFile()) {
BString path;
file->GetPath(path);
value.SetTo(path);
} else
value.SetTo("<no source file>", B_VARIANT_DONT_COPY_DATA);
return true;
}
@@ -191,8 +197,8 @@ public:
&& _path.AddComponent(index - fSourceFileIndices[sourceIndex]);
}
bool GetObjectForPath(const TreeTablePath& path, const char*& _sourceFile,
FunctionDebugInfo*& _function)
bool GetObjectForPath(const TreeTablePath& path,
LocatableFile*& _sourceFile, FunctionDebugInfo*& _function)
{
int32 componentCount = path.CountComponents();
if (componentCount == 0 || componentCount > 2)
@@ -202,8 +208,7 @@ public:
if (sourceIndex < 0 || sourceIndex >= fSourceFileCount)
return false;
_sourceFile = fFunctions[fSourceFileIndices[sourceIndex]]
->SourceFileName();
_sourceFile = fFunctions[fSourceFileIndices[sourceIndex]]->SourceFile();
_function = NULL;
@@ -232,7 +237,7 @@ private:
return nextFunctionIndex - fSourceFileIndices[sourceIndex];
}
static int _CompareSourceFileNames(const char* a, const char* b)
static int _CompareSourceFileNames(LocatableFile* a, LocatableFile* b)
{
if (a == b)
return 0;
@@ -242,15 +247,21 @@ private:
if (b == NULL)
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,
const FunctionDebugInfo* b)
{
// compare source file name first
int compared = _CompareSourceFileNames(a->SourceFileName(),
b->SourceFileName());
int compared = _CompareSourceFileNames(a->SourceFile(),
b->SourceFile());
if (compared != 0)
return compared < 0;
@@ -338,6 +349,9 @@ printf("ImageFunctionsView::SetImageDebugInfo(%p)\n", imageDebugInfo);
fFunctionsTable->SetNodeExpanded(path, true, false);
}
if (fImageDebugInfo != NULL)
fFunctionsTable->ResizeAllColumnsToPreferred();
printf("ImageFunctionsView::SetImageDebugInfo(%p) done\n", imageDebugInfo);
}
@@ -362,7 +376,7 @@ ImageFunctionsView::TreeTableSelectionChanged(TreeTable* table)
if (fListener == NULL)
return;
const char* sourceFile = NULL;
LocatableFile* sourceFile = NULL;
FunctionDebugInfo* function = NULL;
TreeTablePath path;
if (table->SelectionModel()->GetPathAt(0, path))
+144
View File
@@ -0,0 +1,144 @@
/*
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* 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, ingo_weinhold@gmx.de.
* 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