diff --git a/src/apps/debugger/TeamDebugger.cpp b/src/apps/debugger/TeamDebugger.cpp index a1d4ffcd93..5c253397cc 100644 --- a/src/apps/debugger/TeamDebugger.cpp +++ b/src/apps/debugger/TeamDebugger.cpp @@ -879,14 +879,7 @@ printf(" function: %p\n", function); = functionInstance->GetFunctionDebugInfo(); SourceLocation sourceLocation; Statement* breakpointStatement = NULL; -// if (SourceCode* sourceCode = functionDebugInfo->GetSourceCode()) { -// breakpointStatement = sourceCode->StatementAtAddress(address); -// if (breakpointStatement != NULL) -// sourceLocation = breakpointStatement->StartSourceLocation(); -// } - - if (breakpointStatement == NULL - && functionDebugInfo->GetSpecificImageDebugInfo()->GetStatement( + if (functionDebugInfo->GetSpecificImageDebugInfo()->GetStatement( functionDebugInfo, address, breakpointStatement) != B_OK) { return; } @@ -920,7 +913,7 @@ printf(" function instance %p: range: %#llx - %#llx\n", instance, instance->Add Statement* statement = NULL; functionDebugInfo = instance->GetFunctionDebugInfo(); functionDebugInfo->GetSpecificImageDebugInfo() - ->GetStatementForSourceLocation(functionDebugInfo, + ->GetStatementAtSourceLocation(functionDebugInfo, sourceLocation, statement); if (statement != NULL) { instanceAddress = statement->CoveringAddressRange().Start(); diff --git a/src/apps/debugger/debug_info/DebuggerImageDebugInfo.cpp b/src/apps/debugger/debug_info/DebuggerImageDebugInfo.cpp index 7842e49342..a4d54a6bbd 100644 --- a/src/apps/debugger/debug_info/DebuggerImageDebugInfo.cpp +++ b/src/apps/debugger/debug_info/DebuggerImageDebugInfo.cpp @@ -119,7 +119,7 @@ DebuggerImageDebugInfo::GetStatement(FunctionDebugInfo* function, status_t -DebuggerImageDebugInfo::GetStatementForSourceLocation( +DebuggerImageDebugInfo::GetStatementAtSourceLocation( FunctionDebugInfo* function, const SourceLocation& sourceLocation, Statement*& _statement) { diff --git a/src/apps/debugger/debug_info/DebuggerImageDebugInfo.h b/src/apps/debugger/debug_info/DebuggerImageDebugInfo.h index 918d062753..e41eb79005 100644 --- a/src/apps/debugger/debug_info/DebuggerImageDebugInfo.h +++ b/src/apps/debugger/debug_info/DebuggerImageDebugInfo.h @@ -36,7 +36,7 @@ public: virtual status_t GetStatement(FunctionDebugInfo* function, target_addr_t address, Statement*& _statement); - virtual status_t GetStatementForSourceLocation( + virtual status_t GetStatementAtSourceLocation( FunctionDebugInfo* function, const SourceLocation& sourceLocation, Statement*& _statement); diff --git a/src/apps/debugger/debug_info/DwarfImageDebugInfo.cpp b/src/apps/debugger/debug_info/DwarfImageDebugInfo.cpp index 0ae085d774..124b8eba5f 100644 --- a/src/apps/debugger/debug_info/DwarfImageDebugInfo.cpp +++ b/src/apps/debugger/debug_info/DwarfImageDebugInfo.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -34,30 +35,29 @@ struct DwarfImageDebugInfo::SourceCodeKey { CompilationUnit* unit; - BString filePath; - - SourceCodeKey(CompilationUnit* unit, const BString& filePath) - : - unit(unit), - filePath(filePath) - { - } + LocatableFile* file; SourceCodeKey(CompilationUnit* unit, LocatableFile* file) : - unit(unit) + unit(unit), + file(file) { - file->GetLocatedPath(filePath); + file->AcquireReference(); + } + + ~SourceCodeKey() + { + file->ReleaseReference(); } uint32 HashValue() const { - return (uint32)(addr_t)unit ^ StringUtils::HashValue(filePath); + return (uint32)((addr_t)unit ^ (addr_t)file); } bool operator==(const SourceCodeKey& other) const { - return unit == other.unit && filePath == other.filePath; + return unit == other.unit && file == other.file; } }; @@ -244,7 +244,7 @@ printf(" %ld compilation units\n", fFile->CountCompilationUnits()); DwarfFunctionDebugInfo* function = new(std::nothrow) DwarfFunctionDebugInfo(this, unit, subprogramEntry, rangeList, name, file, - SourceLocation(line, column)); + SourceLocation(line, std::max(column, 0L))); if (function == NULL || !functions.AddItem(function)) { delete function; return B_NO_MEMORY; @@ -292,7 +292,6 @@ DwarfImageDebugInfo::LoadSourceCode(FunctionDebugInfo* function, { AutoLocker locker(fLock); - // TODO: Load the actual source code! status_t error = _LoadSourceCode(function, _sourceCode); if (error == B_OK) return B_OK; @@ -323,30 +322,26 @@ status_t DwarfImageDebugInfo::GetStatement(FunctionDebugInfo* _function, target_addr_t address, Statement*& _statement) { +printf("DwarfImageDebugInfo::GetStatement(function: %p, address: %#llx)\n", +_function, address); DwarfFunctionDebugInfo* function = dynamic_cast(_function); if (function == NULL) +{ +printf(" -> no dwarf function\n"); return B_BAD_VALUE; +} AutoLocker locker(fLock); - // get the source file - LocatableFile* file = function->SourceFile(); - if (file == NULL) - return B_ENTRY_NOT_FOUND; - - // maybe the source code is already loaded -- this will simplify things + // check whether we have the source code CompilationUnit* unit = function->GetCompilationUnit(); -// FileSourceCode* sourceCode = _LookupSourceCode(unit, file); -// if (sourceCode) { -// Statement* statement = sourceCode->StatementAtAddress(address); -// if (statement == NULL) -// return B_ENTRY_NOT_FOUND; -// -// statement->AcquireReference(); -// _statement = statement; -// return B_OK; -// } + LocatableFile* file = function->SourceFile(); + if (file == NULL) { +printf(" -> no source file\n"); + // no source code -- rather return the assembly statement + return fArchitecture->GetStatement(function, address, _statement); + } // get the index of the source file in the compilation unit for cheaper // comparison below @@ -356,7 +351,13 @@ DwarfImageDebugInfo::GetStatement(FunctionDebugInfo* _function, // compilation unit. LineNumberProgram& program = unit->GetLineNumberProgram(); if (!program.IsValid()) +{ +printf(" -> no line number program\n"); return B_BAD_DATA; +} + + // adjust address + address -= fRelocationDelta; LineNumberProgram::State state; program.GetInitialState(state); @@ -393,26 +394,27 @@ DwarfImageDebugInfo::GetStatement(FunctionDebugInfo* _function, if (state.isStatement) { statementAddress = state.address; statementLine = state.line - 1; - statementColumn = state.column - 1; + statementColumn = std::max(state.column - 1, 0L); } } +printf(" -> no line number program match\n"); return B_ENTRY_NOT_FOUND; } status_t -DwarfImageDebugInfo::GetStatementForSourceLocation(FunctionDebugInfo* _function, +DwarfImageDebugInfo::GetStatementAtSourceLocation(FunctionDebugInfo* _function, const SourceLocation& sourceLocation, Statement*& _statement) { DwarfFunctionDebugInfo* function = dynamic_cast(_function); if (function == NULL) return B_BAD_VALUE; -target_addr_t functionStartAddress = function->Address(); +target_addr_t functionStartAddress = function->Address() - fRelocationDelta; target_addr_t functionEndAddress = functionStartAddress + function->Size(); -printf("DwarfImageDebugInfo::GetStatementForSourceLocation(%p): function range: %#llx - %#llx\n", -function, functionStartAddress, functionEndAddress); +printf("DwarfImageDebugInfo::GetStatementAtSourceLocation(%p, (%ld, %ld)): function range: %#llx - %#llx\n", +function, sourceLocation.Line(), sourceLocation.Column(), functionStartAddress, functionEndAddress); AutoLocker locker(fLock); @@ -421,26 +423,13 @@ function, functionStartAddress, functionEndAddress); if (file == NULL) return B_ENTRY_NOT_FOUND; - // maybe the source code is already loaded -- this will simplify things CompilationUnit* unit = function->GetCompilationUnit(); - FileSourceCode* sourceCode = _LookupSourceCode(unit, file); - if (sourceCode) { -// TODO: This is not precise enough -- columns are ignored! - Statement* statement = sourceCode->StatementAtLine( - sourceLocation.Line()); - if (statement == NULL) - return B_ENTRY_NOT_FOUND; - - statement->AcquireReference(); - _statement = statement; - return B_OK; - } // get the index of the source file in the compilation unit for cheaper // comparison below int32 fileIndex = _GetSourceFileIndex(unit, file); -// target_addr_t functionStartAddress = function->Address(); +// target_addr_t functionStartAddress = function->Address() - fRelocationDelta; // target_addr_t functionEndAddress = functionStartAddress + function->Size(); // Get the statement by executing the line number program for the @@ -461,11 +450,15 @@ function, functionStartAddress, functionEndAddress); if (statementAddress != 0 && (!isOurFile || state.isStatement || state.isSequenceEnd)) { target_addr_t endAddress = state.address; +if (statementAddress < endAddress) { +printf(" statement: %#llx - %#llx, location: (%ld, %ld)\n", statementAddress, endAddress, statementLine, statementColumn); +} if (statementAddress < endAddress && statementAddress >= functionStartAddress && statementAddress < functionEndAddress && statementLine == (int32)sourceLocation.Line() && statementColumn == (int32)sourceLocation.Column()) { +printf(" -> found statement!\n"); ContiguousStatement* statement = new(std::nothrow) ContiguousStatement( SourceLocation(statementLine, statementColumn), @@ -488,7 +481,7 @@ function, functionStartAddress, functionEndAddress); if (state.isStatement) { statementAddress = state.address; statementLine = state.line - 1; - statementColumn = state.column - 1; + statementColumn = std::max(state.column - 1, 0L); } } @@ -535,7 +528,7 @@ printf(" file %ld: %s\n", i, fileName); return error; // create the source code - sourceCode = new(std::nothrow) FileSourceCode(sourceFile); + sourceCode = new(std::nothrow) FileSourceCode(file, sourceFile); sourceFile->ReleaseReference(); if (sourceCode == NULL) return B_NO_MEMORY; @@ -564,23 +557,13 @@ printf(" %#lx (%ld, %ld, %ld) %d\n", state.address, state.file, state.line, s if (statementAddress != 0 && (!isOurFile || state.isStatement || state.isSequenceEnd)) { target_addr_t endAddress = state.address; - if (endAddress > statementAddress) { + if (endAddress > statementAddress) { // add the statement - ContiguousStatement* statement = new(std::nothrow) - ContiguousStatement( - SourceLocation(statementLine, statementColumn), - TargetAddressRange(fRelocationDelta + statementAddress, - endAddress - statementAddress)); - if (statement == NULL) - return B_NO_MEMORY; - - error = sourceCode->AddStatement(statement); - if (error != B_OK) { - delete statement; + error = sourceCode->AddSourceLocation( + SourceLocation(statementLine, statementColumn)); + if (error != B_OK) return error; - } -printf(" -> statement: %#llx - %#llx, line: %ld\n", statement->AddressRange().Start(), -statement->AddressRange().End(), statementLine); +printf(" -> statement: %#llx - %#llx, source location: (%ld, %ld)\n", statementAddress, endAddress, statementLine, statementColumn); } statementAddress = 0; @@ -593,7 +576,7 @@ statement->AddressRange().End(), statementLine); if (state.isStatement) { statementAddress = state.address; statementLine = state.line - 1; - statementColumn = state.column - 1; + statementColumn = std::max(state.column - 1, 0L); } } diff --git a/src/apps/debugger/debug_info/DwarfImageDebugInfo.h b/src/apps/debugger/debug_info/DwarfImageDebugInfo.h index a822d83cc1..ae6e5f1673 100644 --- a/src/apps/debugger/debug_info/DwarfImageDebugInfo.h +++ b/src/apps/debugger/debug_info/DwarfImageDebugInfo.h @@ -47,7 +47,7 @@ public: virtual status_t GetStatement(FunctionDebugInfo* function, target_addr_t address, Statement*& _statement); - virtual status_t GetStatementForSourceLocation( + virtual status_t GetStatementAtSourceLocation( FunctionDebugInfo* function, const SourceLocation& sourceLocation, Statement*& _statement); diff --git a/src/apps/debugger/debug_info/SpecificImageDebugInfo.h b/src/apps/debugger/debug_info/SpecificImageDebugInfo.h index 2192377c83..b9c0442dfd 100644 --- a/src/apps/debugger/debug_info/SpecificImageDebugInfo.h +++ b/src/apps/debugger/debug_info/SpecificImageDebugInfo.h @@ -46,7 +46,7 @@ public: target_addr_t address, Statement*& _statement) = 0; // returns reference - virtual status_t GetStatementForSourceLocation( + virtual status_t GetStatementAtSourceLocation( FunctionDebugInfo* function, const SourceLocation& sourceLocation, Statement*& _statement) = 0; diff --git a/src/apps/debugger/debug_info/TeamDebugInfo.cpp b/src/apps/debugger/debug_info/TeamDebugInfo.cpp index eafd4e9045..625106e481 100644 --- a/src/apps/debugger/debug_info/TeamDebugInfo.cpp +++ b/src/apps/debugger/debug_info/TeamDebugInfo.cpp @@ -3,8 +3,11 @@ * Distributed under the terms of the MIT License. */ + #include "TeamDebugInfo.h" +#include + #include #include @@ -13,6 +16,7 @@ #include "DwarfTeamDebugInfo.h" #include "Function.h" #include "ImageDebugInfo.h" +#include "LocatableFile.h" #include "SpecificImageDebugInfo.h" #include "StringUtils.h" @@ -66,6 +70,131 @@ struct TeamDebugInfo::FunctionHashDefinition { }; +// #pragma mark - SourceFileEntry + + +struct TeamDebugInfo::SourceFileEntry : public HashTableLink { + SourceFileEntry(LocatableFile* sourceFile) + : + fSourceFile(sourceFile) + { + fSourceFile->AcquireReference(); + } + + ~SourceFileEntry() + { + fSourceFile->ReleaseReference(); + } + + status_t Init() + { + return B_OK; + } + + LocatableFile* SourceFile() const + { + return fSourceFile; + } + + bool IsUnused() const + { + return fFunctions.IsEmpty(); + } + + status_t AddFunction(Function* function) + { + if (!fFunctions.BinaryInsert(function, &_CompareFunctions)) + return B_NO_MEMORY; + + return B_OK; + } + + void RemoveFunction(Function* function) + { + int32 index = fFunctions.BinarySearchIndex(*function, + &_CompareFunctions); + if (index >= 0) + fFunctions.RemoveItemAt(index); + } + + Function* FunctionAtLocation(const SourceLocation& location) const + { + int32 index = fFunctions.BinarySearchIndexByKey(location, + &_CompareLocationFunction); + if (index >= 0) + return fFunctions.ItemAt(index); + + // No exact match, so we return the previous function which might still + // contain the location. + index = -index - 1; + + if (index == 0) + return NULL; + + return fFunctions.ItemAt(index - 1); + } + +private: + typedef BObjectList FunctionList; + +private: + static int _CompareFunctions(const Function* a, const Function* b) + { + SourceLocation locationA = a->GetSourceLocation(); + SourceLocation locationB = b->GetSourceLocation(); + + if (locationA < locationB) + return -1; + + return locationA == locationB ? 0 : 1; + } + + static int _CompareLocationFunction(const SourceLocation* location, + const Function* function) + { + SourceLocation functionLocation = function->GetSourceLocation(); + + if (*location < functionLocation) + return -1; + + return *location == functionLocation ? 0 : 1; + } + +private: + LocatableFile* fSourceFile; + FunctionList fFunctions; +}; + + +// #pragma mark - SourceFileHashDefinition + + +struct TeamDebugInfo::SourceFileHashDefinition { + typedef const LocatableFile* KeyType; + typedef SourceFileEntry ValueType; + + size_t HashKey(const LocatableFile* key) const + { + return (size_t)(addr_t)key; + } + + size_t Hash(const SourceFileEntry* value) const + { + return HashKey(value->SourceFile()); + } + + bool Compare(const LocatableFile* key, const SourceFileEntry* value) const + { + return key == value->SourceFile(); + } + + HashTableLink* GetLink(SourceFileEntry* value) const + { + return value; + } +}; + + // #pragma mark - TeamDebugInfo @@ -76,13 +205,25 @@ TeamDebugInfo::TeamDebugInfo(DebuggerInterface* debuggerInterface, fArchitecture(architecture), fFileManager(fileManager), fSpecificInfos(10, true), - fFunctions(NULL) + fFunctions(NULL), + fSourceFiles(NULL) { } TeamDebugInfo::~TeamDebugInfo() { + if (fSourceFiles != NULL) { + SourceFileEntry* entry = fSourceFiles->Clear(true); + while (entry != NULL) { + SourceFileEntry* next = entry->fNext; + delete entry; + entry = next; + } + + delete fSourceFiles; + } + if (fFunctions != NULL) { Function* function = fFunctions->Clear(true); while (function != NULL) { @@ -108,6 +249,15 @@ TeamDebugInfo::Init() if (error != B_OK) return error; + // create source file hash table + fSourceFiles = new(std::nothrow) SourceFileTable; + if (fSourceFiles == NULL) + return B_NO_MEMORY; + + error = fSourceFiles->Init(); + if (error != B_OK) + return error; + // Create specific infos for all types of debug info we support, in // descending order of expressiveness. @@ -198,9 +348,16 @@ printf(" adding instance %p to existing function %p\n", instance, function); printf(" adding instance %p to new function %p\n", instance, function); function->AddInstance(instance); instance->SetFunction(function); - fFunctions->Insert(function); + + status_t error = _AddFunction(function); // Insert after adding the instance. Otherwise the function // wouldn't be hashable/comparable. + if (error != B_OK) { + function->RemoveInstance(instance); + instance->SetFunction(NULL); + RemoveImageDebugInfo(imageDebugInfo); + return error; + } } } @@ -222,7 +379,7 @@ TeamDebugInfo::RemoveImageDebugInfo(ImageDebugInfo* imageDebugInfo) // Note, that we have to remove it from the hash before removing // the instance, since otherwise the function cannot be compared // anymore. - fFunctions->Remove(function); + _RemoveFunction(function); function->ReleaseReference(); // The instance still has a reference. } @@ -234,3 +391,65 @@ TeamDebugInfo::RemoveImageDebugInfo(ImageDebugInfo* imageDebugInfo) } } } + + +Function* +TeamDebugInfo::FunctionAtSourceLocation(LocatableFile* file, + const SourceLocation& location) +{ + if (SourceFileEntry* entry = fSourceFiles->Lookup(file)) + return entry->FunctionAtLocation(location); + return NULL; +} + + +status_t +TeamDebugInfo::_AddFunction(Function* function) +{ + // If the function refers to a source file, add it to the respective entry. + if (LocatableFile* sourceFile = function->SourceFile()) { + SourceFileEntry* entry = fSourceFiles->Lookup(sourceFile); + if (entry == NULL) { + // no entry for the source file yet -- create on + entry = new(std::nothrow) SourceFileEntry(sourceFile); + if (entry == NULL) + return B_NO_MEMORY; + + status_t error = entry->Init(); + if (error != B_OK) { + delete entry; + return error; + } + + fSourceFiles->Insert(entry); + } + + // add the function + status_t error = entry->AddFunction(function); + if (error != B_OK) { + if (entry->IsUnused()) { + fSourceFiles->Remove(entry); + delete entry; + } + return error; + } + } + + fFunctions->Insert(function); + + return B_OK; +} + + +void +TeamDebugInfo::_RemoveFunction(Function* function) +{ + fFunctions->Remove(function); + + // If the function refers to a source file, remove it from the respective + // entry. + if (LocatableFile* sourceFile = function->SourceFile()) { + if (SourceFileEntry* entry = fSourceFiles->Lookup(sourceFile)) + entry->RemoveFunction(function); + } +} diff --git a/src/apps/debugger/debug_info/TeamDebugInfo.h b/src/apps/debugger/debug_info/TeamDebugInfo.h index 96fb5945ee..6c5ea69546 100644 --- a/src/apps/debugger/debug_info/TeamDebugInfo.h +++ b/src/apps/debugger/debug_info/TeamDebugInfo.h @@ -5,6 +5,7 @@ #ifndef TEAM_DEBUG_INFO_H #define TEAM_DEBUG_INFO_H + #include #include #include @@ -20,6 +21,7 @@ class FunctionInstance; class ImageDebugInfo; class ImageInfo; class LocatableFile; +class SourceLocation; class SpecificTeamDebugInfo; @@ -43,11 +45,21 @@ public: void RemoveImageDebugInfo( ImageDebugInfo* imageDebugInfo); + Function* FunctionAtSourceLocation(LocatableFile* file, + const SourceLocation& location); + private: struct FunctionHashDefinition; + struct SourceFileEntry; + struct SourceFileHashDefinition; typedef BObjectList SpecificInfoList; typedef OpenHashTable FunctionTable; + typedef OpenHashTable SourceFileTable; + +private: + status_t _AddFunction(Function* function); + void _RemoveFunction(Function* function); private: DebuggerInterface* fDebuggerInterface; @@ -55,6 +67,7 @@ private: FileManager* fFileManager; SpecificInfoList fSpecificInfos; FunctionTable* fFunctions; + SourceFileTable* fSourceFiles; }; diff --git a/src/apps/debugger/gui/team_window/SourceView.cpp b/src/apps/debugger/gui/team_window/SourceView.cpp index 12dfe354e4..a1a8b166d9 100644 --- a/src/apps/debugger/gui/team_window/SourceView.cpp +++ b/src/apps/debugger/gui/team_window/SourceView.cpp @@ -518,9 +518,11 @@ SourceView::MarkerView::Draw(BRect updateRect) if (!drawBreakpointOptionMarker) continue; - Statement* statement = fSourceCode->StatementAtLine(line); - if (statement == NULL - || statement->StartSourceLocation().Line() != (uint32)line) { + + SourceLocation statementStart, statementEnd; + if (!fSourceCode->GetStatementLocationRange(SourceLocation(line), + statementStart, statementEnd) + || statementStart.Line() != line) { continue; } @@ -541,11 +543,15 @@ SourceView::MarkerView::MouseDown(BPoint where) if (line < 0) return; - Statement* statement = fSourceCode->StatementAtLine(line); - if (statement == NULL - || statement->StartSourceLocation().Line() != (uint32)line) { + AutoLocker locker(fDebugModel); + Statement* statement; + if (fDebugModel->GetTeam()->GetStatementAtSourceLocation(fSourceCode, + SourceLocation(line), statement) != B_OK) { return; } + Reference statementReference(statement, true); + if (statement->StartSourceLocation().Line() != line) + return; int32 modifiers; if (Looper()->CurrentMessage()->FindInt32("modifiers", &modifiers) != B_OK) @@ -1005,6 +1011,7 @@ SourceView::UserBreakpointChanged(target_addr_t address) bool SourceView::ScrollToAddress(target_addr_t address) { +printf("SourceView::ScrollToAddress(%#llx)\n", address); if (fSourceCode == NULL) return false; @@ -1025,6 +1032,7 @@ SourceView::ScrollToAddress(target_addr_t address) bool SourceView::ScrollToLine(uint32 line) { +printf("SourceView::ScrollToLine(%lu)\n", line); if (fSourceCode == NULL || line >= (uint32)fSourceCode->CountLines()) return false; diff --git a/src/apps/debugger/model/DisassembledCode.cpp b/src/apps/debugger/model/DisassembledCode.cpp index 54e63642ee..c83b06a5fc 100644 --- a/src/apps/debugger/model/DisassembledCode.cpp +++ b/src/apps/debugger/model/DisassembledCode.cpp @@ -3,6 +3,7 @@ * Distributed under the terms of the MIT License. */ + #include "DisassembledCode.h" #include @@ -57,33 +58,40 @@ DisassembledCode::LineAt(int32 index) const } -Statement* -DisassembledCode::StatementAtLine(int32 index) const +bool +DisassembledCode::GetStatementLocationRange(const SourceLocation& location, + SourceLocation& _start, SourceLocation& _end) const { - Line* line = fLines.ItemAt(index); - return line != NULL ? line->statement : NULL; + Line* line = fLines.ItemAt(location.Line()); + if (line == NULL || line->statement == NULL) + return false; + + _start = line->statement->StartSourceLocation(); + _end = SourceLocation(_start.Line() + 1); + // TODO: Multi-line instructions! + return true; } -//Statement* -//DisassembledCode::StatementAtAddress(target_addr_t address) const -//{ -// return fStatements.BinarySearchByKey(address, &_CompareAddressStatement); -//} +LocatableFile* +DisassembledCode::GetSourceFile() const +{ + return NULL; +} -//TargetAddressRange -//DisassembledCode::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()); -//} +status_t +DisassembledCode::GetStatementAtLocation(const SourceLocation& location, + Statement*& _statement) +{ + Line* line = fLines.ItemAt(location.Line()); + if (line == NULL || line->statement == NULL) + return B_ENTRY_NOT_FOUND; + + _statement = line->statement; + _statement->AcquireReference(); + return B_OK; +} bool diff --git a/src/apps/debugger/model/DisassembledCode.h b/src/apps/debugger/model/DisassembledCode.h index 8d61f82a46..11f1a3a4d3 100644 --- a/src/apps/debugger/model/DisassembledCode.h +++ b/src/apps/debugger/model/DisassembledCode.h @@ -5,6 +5,7 @@ #ifndef DISASSEMBLED_CODE_H #define DISASSEMBLED_CODE_H + #include #include "SourceCode.h" @@ -22,10 +23,16 @@ public: virtual int32 CountLines() const; virtual const char* LineAt(int32 index) const; - virtual Statement* StatementAtLine(int32 index) const; -// Statement* StatementAtAddress(target_addr_t address) const; + virtual bool GetStatementLocationRange( + const SourceLocation& location, + SourceLocation& _start, + SourceLocation& _end) const; -// TargetAddressRange StatementAddressRange() const; + virtual LocatableFile* GetSourceFile() const; + + virtual status_t GetStatementAtLocation( + const SourceLocation& location, + Statement*& _statement); public: bool AddCommentLine(const BString& line); diff --git a/src/apps/debugger/model/FileSourceCode.cpp b/src/apps/debugger/model/FileSourceCode.cpp index 4f222e4bbd..5800998124 100644 --- a/src/apps/debugger/model/FileSourceCode.cpp +++ b/src/apps/debugger/model/FileSourceCode.cpp @@ -3,33 +3,29 @@ * Distributed under the terms of the MIT License. */ + #include "FileSourceCode.h" #include +#include "LocatableFile.h" #include "SourceFile.h" -#include "Statement.h" +#include "SourceLocation.h" -// TODO: Lot's of code duplication from DissassembledCode! - - -FileSourceCode::FileSourceCode(SourceFile* file) +FileSourceCode::FileSourceCode(LocatableFile* file, SourceFile* sourceFile) : fFile(file), - fLineStatements(NULL) + fSourceFile(sourceFile) { fFile->AcquireReference(); + fSourceFile->AcquireReference(); } FileSourceCode::~FileSourceCode() { - for (int32 i = 0; Statement* statement = fStatements.ItemAt(i); i++) - statement->RemoveReference(); - - delete[] fLineStatements; - + fSourceFile->ReleaseReference(); fFile->ReleaseReference(); } @@ -37,94 +33,91 @@ FileSourceCode::~FileSourceCode() 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) +FileSourceCode::AddSourceLocation(const SourceLocation& location) { - if (!fStatements.BinaryInsert(statement, &_CompareStatements)) - return B_NO_MEMORY; + // Find the insertion index; don't insert twice. + bool foundMatch; + int32 index = _FindSourceLocationIndex(location, foundMatch); + if (foundMatch) + return B_OK; - int32 line = statement->StartSourceLocation().Line(); - if (line >= 0 && line < fFile->CountLines() - && fLineStatements[line] == NULL) { - fLineStatements[line] = statement; - } - - statement->AcquireReference(); - return B_OK; + return fSourceLocations.Insert(location, index) ? B_OK : B_NO_MEMORY; } int32 FileSourceCode::CountLines() const { - return fFile->CountLines(); + return fSourceFile->CountLines(); } const char* FileSourceCode::LineAt(int32 index) const { - return fFile->LineAt(index); + return fSourceFile->LineAt(index); } -Statement* -FileSourceCode::StatementAtLine(int32 index) const +bool +FileSourceCode::GetStatementLocationRange(const SourceLocation& location, + SourceLocation& _start, SourceLocation& _end) const { - return index >= 0 && index < CountLines() ? fLineStatements[index] : NULL; + int32 lineCount = CountLines(); + if (location.Line() >= lineCount) + return false; + + bool foundMatch; + int32 index = _FindSourceLocationIndex(location, foundMatch); + + if (!foundMatch) { + if (index == 0) + return false; + index--; + } + + _start = fSourceLocations[index]; + _end = index + 1 < lineCount + ? fSourceLocations[index + 1] : SourceLocation(lineCount); + return true; } -//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) +LocatableFile* +FileSourceCode::GetSourceFile() const { - target_addr_t addressA = a->AddressRange().Start(); - target_addr_t addressB = b->AddressRange().Start(); - if (addressA < addressB) - return -1; - return addressA == addressB ? 0 : 1; + return fFile; } -/*static*/ int -FileSourceCode::_CompareAddressStatement(const target_addr_t* address, - const ContiguousStatement* statement) +status_t +FileSourceCode::GetStatementAtLocation(const SourceLocation& location, + Statement*& _statement) { - const TargetAddressRange& range = statement->AddressRange(); - - if (*address < range.Start()) - return -1; - return *address < range.End() ? 0 : 1; + return B_UNSUPPORTED; +} + + +int32 +FileSourceCode::_FindSourceLocationIndex(const SourceLocation& location, + bool& _foundMatch) const +{ + int32 lower = 0; + int32 upper = fSourceLocations.Size(); + while (lower < upper) { + int32 mid = (lower + upper) / 2; + if (location <= fSourceLocations[mid]) + upper = mid; + else + lower = mid + 1; + } + + _foundMatch = lower < fSourceLocations.Size() + && location == fSourceLocations[lower]; + return lower; } diff --git a/src/apps/debugger/model/FileSourceCode.h b/src/apps/debugger/model/FileSourceCode.h index 52fb92cb51..81a5b0bc1e 100644 --- a/src/apps/debugger/model/FileSourceCode.h +++ b/src/apps/debugger/model/FileSourceCode.h @@ -5,46 +5,48 @@ #ifndef FILE_SOURCE_CODE_H #define FILE_SOURCE_CODE_H -#include +#include "Array.h" #include "SourceCode.h" -class ContiguousStatement; +class LocatableFile; class SourceFile; class FileSourceCode : public SourceCode { public: - FileSourceCode(SourceFile* file); + FileSourceCode(LocatableFile* file, + SourceFile* sourceFile); virtual ~FileSourceCode(); status_t Init(); - status_t AddStatement(ContiguousStatement* statement); + status_t AddSourceLocation( + const SourceLocation& location); virtual int32 CountLines() const; virtual const char* LineAt(int32 index) const; - virtual Statement* StatementAtLine(int32 index) const; -// Statement* StatementAtAddress(target_addr_t address) const; + virtual bool GetStatementLocationRange( + const SourceLocation& location, + SourceLocation& _start, + SourceLocation& _end) const; -// virtual TargetAddressRange StatementAddressRange() const; + virtual LocatableFile* GetSourceFile() const; + + virtual status_t GetStatementAtLocation( + const SourceLocation& location, + Statement*& _statement); private: - typedef BObjectList StatementList; + int32 _FindSourceLocationIndex( + const SourceLocation& location, + bool& _foundMatch) const; 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; + LocatableFile* fFile; + SourceFile* fSourceFile; + Array fSourceLocations; }; diff --git a/src/apps/debugger/model/SourceCode.cpp b/src/apps/debugger/model/SourceCode.cpp index a06d6c1925..2019a53584 100644 --- a/src/apps/debugger/model/SourceCode.cpp +++ b/src/apps/debugger/model/SourceCode.cpp @@ -3,6 +3,7 @@ * Distributed under the terms of the MIT License. */ + #include "SourceCode.h" diff --git a/src/apps/debugger/model/SourceCode.h b/src/apps/debugger/model/SourceCode.h index a50efee4a1..0b8dff4644 100644 --- a/src/apps/debugger/model/SourceCode.h +++ b/src/apps/debugger/model/SourceCode.h @@ -5,11 +5,14 @@ #ifndef SOURCE_CODE_H #define SOURCE_CODE_H + #include #include "TargetAddressRange.h" +class LocatableFile; +class SourceLocation; class Statement; @@ -20,7 +23,19 @@ public: virtual int32 CountLines() const = 0; virtual const char* LineAt(int32 index) const = 0; - virtual Statement* StatementAtLine(int32 index) const = 0; + virtual bool GetStatementLocationRange( + const SourceLocation& location, + SourceLocation& _start, + SourceLocation& _end) const = 0; + + virtual LocatableFile* GetSourceFile() const = 0; + + virtual status_t GetStatementAtLocation( + const SourceLocation& location, + Statement*& _statement) = 0; + // returns a reference, + // may return B_UNSUPPORTED, when + // SourceFile() returns non-NULL }; diff --git a/src/apps/debugger/model/Team.cpp b/src/apps/debugger/model/Team.cpp index b2d739af7a..c093159f0c 100644 --- a/src/apps/debugger/model/Team.cpp +++ b/src/apps/debugger/model/Team.cpp @@ -5,12 +5,15 @@ #include "Team.h" +#include + #include #include -#include "FunctionInstance.h" +#include "Function.h" #include "ImageDebugInfo.h" +#include "SourceCode.h" #include "SpecificImageDebugInfo.h" #include "TeamDebugInfo.h" @@ -208,20 +211,30 @@ status_t Team::GetStatementAtAddress(target_addr_t address, FunctionInstance*& _function, Statement*& _statement) { +printf("Team::GetStatementAtAddress(%#llx)\n", address); // get the image at the address Image* image = ImageByAddress(address); if (image == NULL) +{ +printf(" -> no image\n"); return B_ENTRY_NOT_FOUND; +} ImageDebugInfo* imageDebugInfo = image->GetImageDebugInfo(); if (imageDebugInfo == NULL) +{ +printf(" -> no image debug info\n"); return B_ENTRY_NOT_FOUND; +} // get the function FunctionInstance* functionInstance = imageDebugInfo->FunctionAtAddress(address); if (functionInstance == NULL) +{ +printf(" -> no function instance\n"); return B_ENTRY_NOT_FOUND; +} // get the statement from the image debug info FunctionDebugInfo* functionDebugInfo @@ -230,13 +243,52 @@ Team::GetStatementAtAddress(target_addr_t address, FunctionInstance*& _function, ->GetStatement(functionDebugInfo, address, _statement); // TODO: Provide the corresponding SourceCode, if available! if (error != B_OK) +{ +printf(" -> no statement from the specific image debug info\n"); return error; +} _function = functionInstance; return B_OK; } +status_t +Team::GetStatementAtSourceLocation(SourceCode* sourceCode, + const SourceLocation& location, Statement*& _statement) +{ +printf("Team::GetStatementAtSourceLocation(%p, (%ld, %ld))\n", sourceCode, location.Line(), location.Column()); + // If we're lucky the source code can provide us with a statement. + status_t error = sourceCode->GetStatementAtLocation(location, _statement); + if (error == B_OK) + return error; + + // Go the long and stony way over the source file and the team debug info. + // get the source file for the source code + LocatableFile* sourceFile = sourceCode->GetSourceFile(); + if (sourceFile == NULL) + return B_ENTRY_NOT_FOUND; + + // get the function at the source location + Function* function = fDebugInfo->FunctionAtSourceLocation(sourceFile, + location); + if (function == NULL) + return B_ENTRY_NOT_FOUND; + + // Get some function instance and ask its image debug info to provide us + // with a statement. + FunctionInstance* functionInstance = function->FirstInstance(); + if (functionInstance == NULL) + return B_ENTRY_NOT_FOUND; + + FunctionDebugInfo* functionDebugInfo + = functionInstance->GetFunctionDebugInfo(); + return functionDebugInfo->GetSpecificImageDebugInfo() + ->GetStatementAtSourceLocation(functionDebugInfo, location, _statement); + +} + + void Team::AddListener(Listener* listener) { diff --git a/src/apps/debugger/model/Team.h b/src/apps/debugger/model/Team.h index 2416789123..80819e5276 100644 --- a/src/apps/debugger/model/Team.h +++ b/src/apps/debugger/model/Team.h @@ -30,6 +30,8 @@ enum { class FunctionInstance; class LocatableFile; +class SourceCode; +class SourceLocation; class Statement; class TeamDebugInfo; @@ -76,6 +78,13 @@ public: // returns a reference to the statement, // not to the functions instance, though, // caller must lock + status_t GetStatementAtSourceLocation( + SourceCode* sourceCode, + const SourceLocation& location, + Statement*& _statement); + // returns a reference to the statement + // (any matching statement!), + // caller must lock, void AddListener(Listener* listener); void RemoveListener(Listener* listener); diff --git a/src/apps/debugger/types/SourceLocation.h b/src/apps/debugger/types/SourceLocation.h index acb1745039..d224463b1e 100644 --- a/src/apps/debugger/types/SourceLocation.h +++ b/src/apps/debugger/types/SourceLocation.h @@ -10,7 +10,7 @@ class SourceLocation { public: - SourceLocation(uint32 line = 0, uint32 column = 0) + SourceLocation(int32 line = 0, int32 column = 0) : fLine(line), fColumn(column) @@ -41,19 +41,31 @@ public: return !(*this == other); } - uint32 Line() const + bool operator<(const SourceLocation& other) const + { + return fLine < other.fLine + || (fLine == other.fLine && fColumn < other.fColumn); + } + + bool operator<=(const SourceLocation& other) const + { + return fLine < other.fLine + || (fLine == other.fLine && fColumn <= other.fColumn); + } + + int32 Line() const { return fLine; } - uint32 Column() const + int32 Column() const { return fColumn; } private: - uint32 fLine; - uint32 fColumn; + int32 fLine; + int32 fColumn; };