|
@@ -21,11 +21,27 @@
|
|
dependent on objpas unit.
|
|
dependent on objpas unit.
|
|
}
|
|
}
|
|
unit lnfodwrf;
|
|
unit lnfodwrf;
|
|
|
|
+
|
|
interface
|
|
interface
|
|
|
|
|
|
{$S-}
|
|
{$S-}
|
|
|
|
|
|
|
|
+{$IF FPC_VERSION<3}
|
|
|
|
+type
|
|
|
|
+ CodePointer = Pointer;
|
|
|
|
+{$ENDIF}
|
|
|
|
+
|
|
function GetLineInfo(addr:ptruint;var func,source:string;var line:longint) : boolean;
|
|
function GetLineInfo(addr:ptruint;var func,source:string;var line:longint) : boolean;
|
|
|
|
+function DwarfBackTraceStr(addr: CodePointer): string;
|
|
|
|
+procedure CloseDwarf;
|
|
|
|
+
|
|
|
|
+var
|
|
|
|
+ // Allows more efficient operation by reusing previously loaded debug data
|
|
|
|
+ // when the target module filename is the same. However, if an invalid memory
|
|
|
|
+ // address is supplied then further calls may result in an undefined behaviour.
|
|
|
|
+ // In summary: enable for speed, disable for resilience.
|
|
|
|
+ AllowReuseOfLineInfoData: Boolean = True;
|
|
|
|
+
|
|
|
|
|
|
implementation
|
|
implementation
|
|
|
|
|
|
@@ -61,7 +77,6 @@ var
|
|
e : TExeFile;
|
|
e : TExeFile;
|
|
EBuf: Array [0..EBUF_SIZE-1] of Byte;
|
|
EBuf: Array [0..EBUF_SIZE-1] of Byte;
|
|
EBufCnt, EBufPos: Integer;
|
|
EBufCnt, EBufPos: Integer;
|
|
- DwarfErr : boolean;
|
|
|
|
{ the offset and size of the DWARF debug_line section in the file }
|
|
{ the offset and size of the DWARF debug_line section in the file }
|
|
DwarfOffset : longint;
|
|
DwarfOffset : longint;
|
|
DwarfSize : longint;
|
|
DwarfSize : longint;
|
|
@@ -137,18 +152,47 @@ var
|
|
baseaddr : pointer;
|
|
baseaddr : pointer;
|
|
filename,
|
|
filename,
|
|
dbgfn : string;
|
|
dbgfn : string;
|
|
|
|
+ lastfilename: string; { store last processed file }
|
|
|
|
+ lastopendwarf: Boolean; { store last result of processing a file }
|
|
|
|
|
|
-function Opendwarf(addr : pointer) : boolean;
|
|
|
|
|
|
+function OpenDwarf(addr : pointer) : boolean;
|
|
begin
|
|
begin
|
|
- Opendwarf:=false;
|
|
|
|
- if dwarferr then
|
|
|
|
- exit;
|
|
|
|
|
|
+ // False by default
|
|
|
|
+ OpenDwarf:=false;
|
|
|
|
+
|
|
|
|
+ // Empty so can test if GetModuleByAddr has worked
|
|
|
|
+ filename := '';
|
|
|
|
|
|
|
|
+ // Get filename by address using GetModuleByAddr
|
|
GetModuleByAddr(addr,baseaddr,filename);
|
|
GetModuleByAddr(addr,baseaddr,filename);
|
|
{$ifdef DEBUG_LINEINFO}
|
|
{$ifdef DEBUG_LINEINFO}
|
|
writeln(stderr,filename,' Baseaddr: ',hexstr(ptruint(baseaddr),sizeof(baseaddr)*2));
|
|
writeln(stderr,filename,' Baseaddr: ',hexstr(ptruint(baseaddr),sizeof(baseaddr)*2));
|
|
{$endif DEBUG_LINEINFO}
|
|
{$endif DEBUG_LINEINFO}
|
|
|
|
|
|
|
|
+ // Check if GetModuleByAddr has worked
|
|
|
|
+ if filename = '' then
|
|
|
|
+ exit;
|
|
|
|
+
|
|
|
|
+ // If target filename same as previous, then re-use previous result
|
|
|
|
+ if AllowReuseOfLineInfoData and (filename = lastfilename) then
|
|
|
|
+ begin
|
|
|
|
+ {$ifdef DEBUG_LINEINFO}
|
|
|
|
+ writeln(stderr,'Reusing debug data');
|
|
|
|
+ {$endif DEBUG_LINEINFO}
|
|
|
|
+ OpenDwarf:=lastopendwarf;
|
|
|
|
+ exit;
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+ // Close previously opened Dwarf
|
|
|
|
+ CloseDwarf;
|
|
|
|
+
|
|
|
|
+ // Reset last open dwarf result
|
|
|
|
+ lastopendwarf := false;
|
|
|
|
+
|
|
|
|
+ // Save newly processed filename
|
|
|
|
+ lastfilename := filename;
|
|
|
|
+
|
|
|
|
+ // Open exe file or debug link
|
|
if not OpenExeFile(e,filename) then
|
|
if not OpenExeFile(e,filename) then
|
|
exit;
|
|
exit;
|
|
if ReadDebugLink(e,dbgfn) then
|
|
if ReadDebugLink(e,dbgfn) then
|
|
@@ -158,21 +202,25 @@ begin
|
|
exit;
|
|
exit;
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
+ // Find debug data section
|
|
e.processaddress:=ptruint(baseaddr)-e.processaddress;
|
|
e.processaddress:=ptruint(baseaddr)-e.processaddress;
|
|
-
|
|
|
|
if FindExeSection(e,'.debug_line',dwarfoffset,dwarfsize) then
|
|
if FindExeSection(e,'.debug_line',dwarfoffset,dwarfsize) then
|
|
- Opendwarf:=true
|
|
|
|
|
|
+ begin
|
|
|
|
+ lastopendwarf:=true;
|
|
|
|
+ OpenDwarf:=true;
|
|
|
|
+ end
|
|
else
|
|
else
|
|
- begin
|
|
|
|
- dwarferr:=true;
|
|
|
|
- exit;
|
|
|
|
- end;
|
|
|
|
|
|
+ CloseExeFile(e);
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
|
|
-procedure Closedwarf;
|
|
|
|
|
|
+procedure CloseDwarf;
|
|
begin
|
|
begin
|
|
- CloseExeFile(e);
|
|
|
|
|
|
+ if e.isopen then
|
|
|
|
+ CloseExeFile(e);
|
|
|
|
+
|
|
|
|
+ // Reset last processed filename
|
|
|
|
+ lastfilename := '';
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
|
|
@@ -731,13 +779,9 @@ begin
|
|
source := '';
|
|
source := '';
|
|
found := false;
|
|
found := false;
|
|
GetLineInfo:=false;
|
|
GetLineInfo:=false;
|
|
- if DwarfErr then
|
|
|
|
|
|
+
|
|
|
|
+ if not OpenDwarf(pointer(addr)) then
|
|
exit;
|
|
exit;
|
|
- if not e.isopen then
|
|
|
|
- begin
|
|
|
|
- if not OpenDwarf(pointer(addr)) then
|
|
|
|
- exit;
|
|
|
|
- end;
|
|
|
|
|
|
|
|
addr := addr - e.processaddress;
|
|
addr := addr - e.processaddress;
|
|
|
|
|
|
@@ -749,21 +793,26 @@ begin
|
|
current_offset := ParseCompilationUnit(addr, current_offset,
|
|
current_offset := ParseCompilationUnit(addr, current_offset,
|
|
source, line, found);
|
|
source, line, found);
|
|
end;
|
|
end;
|
|
- if e.isopen then
|
|
|
|
|
|
+
|
|
|
|
+ if not AllowReuseOfLineInfoData then
|
|
CloseDwarf;
|
|
CloseDwarf;
|
|
|
|
+
|
|
GetLineInfo:=true;
|
|
GetLineInfo:=true;
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
|
|
-function DwarfBackTraceStr(addr : Pointer) : shortstring;
|
|
|
|
|
|
+function DwarfBackTraceStr(addr: CodePointer): string;
|
|
var
|
|
var
|
|
func,
|
|
func,
|
|
source : string;
|
|
source : string;
|
|
- hs : string[32];
|
|
|
|
|
|
+ hs : string;
|
|
line : longint;
|
|
line : longint;
|
|
Store : TBackTraceStrFunc;
|
|
Store : TBackTraceStrFunc;
|
|
Success : boolean;
|
|
Success : boolean;
|
|
begin
|
|
begin
|
|
|
|
+ {$ifdef DEBUG_LINEINFO}
|
|
|
|
+ writeln(stderr,'DwarfBackTraceStr called');
|
|
|
|
+ {$endif DEBUG_LINEINFO}
|
|
{ reset to prevent infinite recursion if problems inside the code }
|
|
{ reset to prevent infinite recursion if problems inside the code }
|
|
Success:=false;
|
|
Success:=false;
|
|
Store := BackTraceStrFunc;
|
|
Store := BackTraceStrFunc;
|
|
@@ -771,27 +820,32 @@ begin
|
|
Success:=GetLineInfo(ptruint(addr), func, source, line);
|
|
Success:=GetLineInfo(ptruint(addr), func, source, line);
|
|
{ create string }
|
|
{ create string }
|
|
DwarfBackTraceStr :=' $' + HexStr(ptruint(addr), sizeof(ptruint) * 2);
|
|
DwarfBackTraceStr :=' $' + HexStr(ptruint(addr), sizeof(ptruint) * 2);
|
|
- if func<>'' then
|
|
|
|
- DwarfBackTraceStr := DwarfBackTraceStr + ' ' + func;
|
|
|
|
-
|
|
|
|
- if source<>'' then begin
|
|
|
|
|
|
+ if Success then
|
|
|
|
+ begin
|
|
if func<>'' then
|
|
if func<>'' then
|
|
- DwarfBackTraceStr := DwarfBackTraceStr + ', ';
|
|
|
|
- if line<>0 then begin
|
|
|
|
- str(line, hs);
|
|
|
|
- DwarfBackTraceStr := DwarfBackTraceStr + ' line ' + hs;
|
|
|
|
|
|
+ DwarfBackTraceStr := DwarfBackTraceStr + ' ' + func;
|
|
|
|
+ if source<>'' then
|
|
|
|
+ begin
|
|
|
|
+ if func<>'' then
|
|
|
|
+ DwarfBackTraceStr := DwarfBackTraceStr + ', ';
|
|
|
|
+ if line<>0 then
|
|
|
|
+ begin
|
|
|
|
+ str(line, hs);
|
|
|
|
+ DwarfBackTraceStr := DwarfBackTraceStr + ' line ' + hs;
|
|
|
|
+ end;
|
|
|
|
+ DwarfBackTraceStr := DwarfBackTraceStr + ' of ' + source;
|
|
end;
|
|
end;
|
|
- DwarfBackTraceStr := DwarfBackTraceStr + ' of ' + source;
|
|
|
|
end;
|
|
end;
|
|
- if Success then
|
|
|
|
- BackTraceStrFunc := Store;
|
|
|
|
|
|
+ BackTraceStrFunc := Store;
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
|
|
initialization
|
|
initialization
|
|
|
|
+ lastfilename := '';
|
|
|
|
+ lastopendwarf := false;
|
|
BackTraceStrFunc := @DwarfBacktraceStr;
|
|
BackTraceStrFunc := @DwarfBacktraceStr;
|
|
|
|
|
|
finalization
|
|
finalization
|
|
- if e.isopen then
|
|
|
|
- CloseDwarf();
|
|
|
|
|
|
+ CloseDwarf;
|
|
|
|
+
|
|
end.
|
|
end.
|