diff --git a/src/apps/debugger/Jamfile b/src/apps/debugger/Jamfile index 4994da8cda..b56fdba480 100644 --- a/src/apps/debugger/Jamfile +++ b/src/apps/debugger/Jamfile @@ -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 diff --git a/src/apps/debugger/TeamDebugger.cpp b/src/apps/debugger/TeamDebugger.cpp index 4ce7e9df51..ebc223de19 100644 --- a/src/apps/debugger/TeamDebugger.cpp +++ b/src/apps/debugger/TeamDebugger.cpp @@ -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 teamDebugInfoReference(teamDebugInfo); diff --git a/src/apps/debugger/debug_info/BasicFunctionDebugInfo.cpp b/src/apps/debugger/debug_info/BasicFunctionDebugInfo.cpp index 0818347c81..f08e6b5f7d 100644 --- a/src/apps/debugger/debug_info/BasicFunctionDebugInfo.cpp +++ b/src/apps/debugger/debug_info/BasicFunctionDebugInfo.cpp @@ -63,8 +63,8 @@ BasicFunctionDebugInfo::PrettyName() const } -const char* -BasicFunctionDebugInfo::SourceFileName() const +LocatableFile* +BasicFunctionDebugInfo::SourceFile() const { return NULL; } diff --git a/src/apps/debugger/debug_info/BasicFunctionDebugInfo.h b/src/apps/debugger/debug_info/BasicFunctionDebugInfo.h index 3c574b1757..969213b3f7 100644 --- a/src/apps/debugger/debug_info/BasicFunctionDebugInfo.h +++ b/src/apps/debugger/debug_info/BasicFunctionDebugInfo.h @@ -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; diff --git a/src/apps/debugger/debug_info/DwarfFunctionDebugInfo.cpp b/src/apps/debugger/debug_info/DwarfFunctionDebugInfo.cpp index 6ab6651b91..e64295a883 100644 --- a/src/apps/debugger/debug_info/DwarfFunctionDebugInfo.cpp +++ b/src/apps/debugger/debug_info/DwarfFunctionDebugInfo.cpp @@ -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; } diff --git a/src/apps/debugger/debug_info/DwarfFunctionDebugInfo.h b/src/apps/debugger/debug_info/DwarfFunctionDebugInfo.h index 32e660a458..7190f9074d 100644 --- a/src/apps/debugger/debug_info/DwarfFunctionDebugInfo.h +++ b/src/apps/debugger/debug_info/DwarfFunctionDebugInfo.h @@ -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; }; diff --git a/src/apps/debugger/debug_info/DwarfImageDebugInfo.cpp b/src/apps/debugger/debug_info/DwarfImageDebugInfo.cpp index 594b258613..5f2abe8806 100644 --- a/src/apps/debugger/debug_info/DwarfImageDebugInfo.cpp +++ b/src/apps/debugger/debug_info/DwarfImageDebugInfo.cpp @@ -11,6 +11,7 @@ #include #include +#include #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 { + 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* 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 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 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(_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 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; +} diff --git a/src/apps/debugger/debug_info/DwarfImageDebugInfo.h b/src/apps/debugger/debug_info/DwarfImageDebugInfo.h index f5cad8a14d..0bdacbcccb 100644 --- a/src/apps/debugger/debug_info/DwarfImageDebugInfo.h +++ b/src/apps/debugger/debug_info/DwarfImageDebugInfo.h @@ -5,20 +5,29 @@ #ifndef DWARF_IMAGE_DEBUG_INFO_H #define DWARF_IMAGE_DEBUG_INFO_H +#include + +#include + #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 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; }; diff --git a/src/apps/debugger/debug_info/DwarfTeamDebugInfo.cpp b/src/apps/debugger/debug_info/DwarfTeamDebugInfo.cpp index 9bfb3a6937..99c1f81380 100644 --- a/src/apps/debugger/debug_info/DwarfTeamDebugInfo.cpp +++ b/src/apps/debugger/debug_info/DwarfTeamDebugInfo.cpp @@ -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; diff --git a/src/apps/debugger/debug_info/DwarfTeamDebugInfo.h b/src/apps/debugger/debug_info/DwarfTeamDebugInfo.h index 9e21119f1c..555dab45f6 100644 --- a/src/apps/debugger/debug_info/DwarfTeamDebugInfo.h +++ b/src/apps/debugger/debug_info/DwarfTeamDebugInfo.h @@ -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; }; diff --git a/src/apps/debugger/debug_info/FunctionDebugInfo.h b/src/apps/debugger/debug_info/FunctionDebugInfo.h index 63181814a1..242b45f1aa 100644 --- a/src/apps/debugger/debug_info/FunctionDebugInfo.h +++ b/src/apps/debugger/debug_info/FunctionDebugInfo.h @@ -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; diff --git a/src/apps/debugger/debug_info/TeamDebugInfo.cpp b/src/apps/debugger/debug_info/TeamDebugInfo.cpp index 3c04965004..6f1036f6bb 100644 --- a/src/apps/debugger/debug_info/TeamDebugInfo.cpp +++ b/src/apps/debugger/debug_info/TeamDebugInfo.cpp @@ -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; diff --git a/src/apps/debugger/debug_info/TeamDebugInfo.h b/src/apps/debugger/debug_info/TeamDebugInfo.h index 72e089e4e1..6f713aa355 100644 --- a/src/apps/debugger/debug_info/TeamDebugInfo.h +++ b/src/apps/debugger/debug_info/TeamDebugInfo.h @@ -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; }; diff --git a/src/apps/debugger/dwarf/CompilationUnit.h b/src/apps/debugger/dwarf/CompilationUnit.h index 8864358a51..5f2e7b490a 100644 --- a/src/apps/debugger/dwarf/CompilationUnit.h +++ b/src/apps/debugger/dwarf/CompilationUnit.h @@ -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 fEntryOffsets; DirectoryList fDirectories; FileList fFiles; + LineNumberProgram fLineNumberProgram; }; diff --git a/src/apps/debugger/dwarf/DwarfFile.cpp b/src/apps/debugger/dwarf/DwarfFile.cpp index f6249d895c..a60f888a30 100644 --- a/src/apps/debugger/dwarf/DwarfFile.cpp +++ b/src/apps/debugger/dwarf/DwarfFile.cpp @@ -5,6 +5,7 @@ #include "DwarfFile.h" +#include #include #include @@ -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(0); @@ -638,6 +642,10 @@ printf("DwarfFile::_ParseLineInfo(%p), offset: %lu\n", unit, offset); // header_length (4/8) uint64 headerLength = dwarf64 ? dataReader.Read(0) : (uint64)dataReader.Read(0); + off_t headerOffset = dataReader.Offset(); + + if ((uint64)dataReader.BytesRemaining() < headerLength) + return B_BAD_DATA; // minimum instruction length uint8 minInstructionLength = dataReader.Read(0); @@ -655,6 +663,7 @@ printf("DwarfFile::_ParseLineInfo(%p), offset: %lu\n", unit, offset); uint8 opcodeBase = dataReader.Read(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); } diff --git a/src/apps/debugger/dwarf/DwarfUtils.cpp b/src/apps/debugger/dwarf/DwarfUtils.cpp index 459d93186b..bd7c39d46f 100644 --- a/src/apps/debugger/dwarf/DwarfUtils.cpp +++ b/src/apps/debugger/dwarf/DwarfUtils.cpp @@ -128,7 +128,7 @@ DwarfUtils::GetDeclarationLocation(DwarfFile* dwarfFile, _directory = directoryName; _file = fileName; - _line = line; - _column = column; + _line = line - 1; + _column = column - 1; return true; } diff --git a/src/apps/debugger/dwarf/Jamfile b/src/apps/debugger/dwarf/Jamfile index 7cc3444a76..74504a80b8 100644 --- a/src/apps/debugger/dwarf/Jamfile +++ b/src/apps/debugger/dwarf/Jamfile @@ -23,6 +23,7 @@ MergeObject Debugger_dwarf.o DwarfFile.cpp DwarfManager.cpp DwarfUtils.cpp + LineNumberProgram.cpp SourceLanguageInfo.cpp TagNames.cpp ; diff --git a/src/apps/debugger/dwarf/LineNumberProgram.cpp b/src/apps/debugger/dwarf/LineNumberProgram.cpp new file mode 100644 index 0000000000..1ac3361adb --- /dev/null +++ b/src/apps/debugger/dwarf/LineNumberProgram.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 + +#include +#include + +#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(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(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(0); + + switch (extendedOpcode) { + case DW_LNE_end_sequence: + state.isSequenceEnd = true; + appendRow = true; + break; + case DW_LNE_set_address: + state.address = dataReader.Read(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; +} diff --git a/src/apps/debugger/dwarf/LineNumberProgram.h b/src/apps/debugger/dwarf/LineNumberProgram.h new file mode 100644 index 0000000000..24426f86a8 --- /dev/null +++ b/src/apps/debugger/dwarf/LineNumberProgram.h @@ -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 diff --git a/src/apps/debugger/files/FileManager.cpp b/src/apps/debugger/files/FileManager.cpp index 07caa80760..3cf0eb4cc4 100644 --- a/src/apps/debugger/files/FileManager.cpp +++ b/src/apps/debugger/files/FileManager.cpp @@ -7,10 +7,12 @@ #include +#include #include #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(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(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 { + + 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* 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 locker(this); fSourceDomain->EntryLocated(path, locatedPath); } + + +status_t +FileManager::LoadSourceFile(LocatableFile* file, SourceFile*& _sourceFile) +{ + AutoLocker 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 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 locker(this); + + SourceFileEntry* otherEntry = fSourceFiles->Lookup(entry->path); + if (otherEntry == entry) + fSourceFiles->Remove(entry); +} diff --git a/src/apps/debugger/files/FileManager.h b/src/apps/debugger/files/FileManager.h index 5c329b2392..89d2ff26e1 100644 --- a/src/apps/debugger/files/FileManager.h +++ b/src/apps/debugger/files/FileManager.h @@ -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 LocatableEntryTable; + typedef OpenHashTable 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; }; diff --git a/src/apps/debugger/files/LocatableEntry.cpp b/src/apps/debugger/files/LocatableEntry.cpp index d2f62e71fb..a4e2247961 100644 --- a/src/apps/debugger/files/LocatableEntry.cpp +++ b/src/apps/debugger/files/LocatableEntry.cpp @@ -43,7 +43,5 @@ LocatableEntry::~LocatableEntry() void LocatableEntry::LastReferenceReleased() { - AutoLocker locker(fOwner); - if (CountReferences() == 0 && fOwner->LocatableEntryUnused(this)) - delete this; + fOwner->LocatableEntryUnused(this); } diff --git a/src/apps/debugger/files/LocatableEntry.h b/src/apps/debugger/files/LocatableEntry.h index 2e8f4be4fc..a1f6f5fc71 100644 --- a/src/apps/debugger/files/LocatableEntry.h +++ b/src/apps/debugger/files/LocatableEntry.h @@ -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; }; diff --git a/src/apps/debugger/files/SourceFile.cpp b/src/apps/debugger/files/SourceFile.cpp new file mode 100644 index 0000000000..f940717a43 --- /dev/null +++ b/src/apps/debugger/files/SourceFile.cpp @@ -0,0 +1,139 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + +#include "SourceFile.h" + +#include +#include +#include +#include +#include +#include +#include + +#include + + +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; +} diff --git a/src/apps/debugger/files/SourceFile.h b/src/apps/debugger/files/SourceFile.h new file mode 100644 index 0000000000..8b757c9569 --- /dev/null +++ b/src/apps/debugger/files/SourceFile.h @@ -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 + + +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 diff --git a/src/apps/debugger/gui/team_window/ImageFunctionsView.cpp b/src/apps/debugger/gui/team_window/ImageFunctionsView.cpp index 97f79b21ad..6cb0d9111b 100644 --- a/src/apps/debugger/gui/team_window/ImageFunctionsView.cpp +++ b/src/apps/debugger/gui/team_window/ImageFunctionsView.cpp @@ -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 : "", - 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("", 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)) diff --git a/src/apps/debugger/model/FileSourceCode.cpp b/src/apps/debugger/model/FileSourceCode.cpp new file mode 100644 index 0000000000..d4677bb28c --- /dev/null +++ b/src/apps/debugger/model/FileSourceCode.cpp @@ -0,0 +1,144 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + +#include "FileSourceCode.h" + +#include + +#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; +} diff --git a/src/apps/debugger/model/FileSourceCode.h b/src/apps/debugger/model/FileSourceCode.h new file mode 100644 index 0000000000..04103f0291 --- /dev/null +++ b/src/apps/debugger/model/FileSourceCode.h @@ -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 + +#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 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