From a4b0c19209887ee3619cf3f8b2935f51d23afca3 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Fri, 10 Jul 2009 00:08:45 +0000 Subject: [PATCH] * Finished the transformation of the SourceCode interface: - Replaced StatementAtLine() by GetStatementLocationRange(), which doesn't return a statement (i.e. also target addresses), but just a range in the source code. This can also be implemented by FileSourceCode, which can therefore be used for more than one instance of a function. - Added GetStatementAtLocation() which kind of is also a replacement for StatementAtLine(), but is optional and only provided by DisassembledSourceCode. - Added GetSourceFile(), which has to be provided when GetStatementAtLocation() is not implemented. - Kicked the statement stuff out of FileSourceCode. It only knows source ranges, now. * Team: Added GetStatementAtSourceLocation(), which is the real replacement for SourceCode::StatementAtLine() in cases where a statement is actually needed. It uses SourceCode::GetStatementAtLocation(), if available and otherwise finds a function at the source location, and gets a statement for one of its instances. * TeamDebugInfo: Does now manage a source file -> functions map allowing to look up functions at source file locations. * DwarfImageDebugInfo: - Switched the path in the source code hash table key for a LocatableFile, which is cheaper to hash and to compare. - Fixed bugs where the relocation delta was ignored. - Replace a -1 in the SourceLocation column component by 0 to avoid mismatches. * SourceLocation: Changed component types from uint32 to int32. Otherwise -1 is not representable. Things mostly work as before starting the refactoring to support function instances. All is not well yet, though. E.g. we don't merge the source code information for common source files (like headers) provided by different compilation units (or even images) yet. We need to do that, since the debug info for a compilation unit only contains line number information for inline functions (in headers) that are actually used. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@31495 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/apps/debugger/TeamDebugger.cpp | 11 +- .../debug_info/DebuggerImageDebugInfo.cpp | 2 +- .../debug_info/DebuggerImageDebugInfo.h | 2 +- .../debug_info/DwarfImageDebugInfo.cpp | 117 ++++----- .../debugger/debug_info/DwarfImageDebugInfo.h | 2 +- .../debug_info/SpecificImageDebugInfo.h | 2 +- .../debugger/debug_info/TeamDebugInfo.cpp | 225 +++++++++++++++++- src/apps/debugger/debug_info/TeamDebugInfo.h | 13 + .../debugger/gui/team_window/SourceView.cpp | 20 +- src/apps/debugger/model/DisassembledCode.cpp | 50 ++-- src/apps/debugger/model/DisassembledCode.h | 13 +- src/apps/debugger/model/FileSourceCode.cpp | 133 +++++------ src/apps/debugger/model/FileSourceCode.h | 40 ++-- src/apps/debugger/model/SourceCode.cpp | 1 + src/apps/debugger/model/SourceCode.h | 17 +- src/apps/debugger/model/Team.cpp | 54 ++++- src/apps/debugger/model/Team.h | 9 + src/apps/debugger/types/SourceLocation.h | 22 +- 18 files changed, 524 insertions(+), 209 deletions(-) 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; };