View Issue Details

IDProjectCategoryView StatusLast Update
0028283FPCRTLpublic2019-05-02 14:23
ReporterDenis Kozlov Assigned ToMichael Van Canneyt  
PrioritynormalSeverityminorReproducibilityalways
Status resolvedResolutionfixed 
PlatformWindows 
Target Version3.0.2Fixed in Version3.1.1 
Summary0028283: DWARF debug line info (lnfodwrf.pp) is broken
DescriptionThis is a follow up from a recently fixed STABS bug (lineinfo.pp):
http://bugs.freepascal.org/view.php?id=13518

DWARF debug line info (lnfodwrf.pp) seems to be broken in several ways.

1) The static "dwarferr" variable disables the whole unit on the first failure to read debug exe section, e.g. when address results in an external library which doesn't have debug info. Same type of issue as in the recently closed STABS bug.

2) The back trace only produces line info for the first address (without function name), and nothing for the rest of lines. This is even if the above problem is fixed.

Attached below in Additional Information section is a comparison of back traces between DWARF (lnfodwrf.pp) and fixed STABS (lineinfo.pp). Project was tested with several debug info types, i.e.: Dwarf with sets, Dwarf2, Dwarf3, Stabs. Using a slightly modified version of the example project from above mentioned STABS bug.
Additional InformationBack trace using DWARF:
===========================================================
  $00423E0A line 78 of unit1.pas
  $00504D4E
  $0051C1FF
  $0051C8FF
  $0051C11A
  $0040AE26
  $004F8DFE
  $00542275
  $004D1E2A
  $00547B25
  $75B76238
  $75B768EA
  $75B7CD1A
  $75B7CD81
  $70E44601
  $70E44663
  $70E444ED
===========================================================

Back trace using STABS:
===========================================================
  $00423E0A TFORM1__BUTTON2CLICK, line 78 of unit1.pas
  $00504D4E TCONTROL__CLICK, line 2711 of ./include/control.inc
  $0051C1FF TBUTTONCONTROL__CLICK, line 54 of ./include/buttoncontrol.inc
  $0051C8FF TCUSTOMBUTTON__CLICK, line 169 of ./include/buttons.inc
  $0051C11A TBUTTONCONTROL__WMDEFAULTCLICKED, line 20 of ./include/buttoncontrol.inc
  $0040AE26
  $004F8DFE TWINCONTROL__WNDPROC, line 5326 of ./include/wincontrol.inc
  $00542275 DELIVERMESSAGE, line 112 of lclmessageglue.pas
  $004D1E2A WINDOWPROC, line 2480 of ./win32/win32callback.inc
  $00547B25 CUSTOMFORMWNDPROC, line 395 of ./win32/win32wsforms.pp
  $75B76238
  $75B768EA
  $75B7CD1A
  $75B7CD81
  $70E44601
  $70E44663
  $70E444ED
===========================================================
TagsBackTraceStrFunc, DwarfBackTraceStr, Exception, lnfodwrf, patch
Fixed in Revision32919
FPCOldBugId
FPCTarget
Attached Files

Relationships

related to 0017547 closedFlorian backtrace/line information is missing function names under 64-bit FPC 

Activities

Denis Kozlov

2015-06-12 13:50

reporter  

Denis Kozlov

2015-06-12 13:52

reporter   ~0084398

Attached a sample project.

Currently debug info type is set to Dwarf2, but can be changed in Project Options if needed.

Jonas Maebe

2015-06-12 16:18

manager   ~0084407

Please don't submit lazarus projects when reporting FPC bugs.

Michael Van Canneyt

2015-06-12 18:12

administrator   ~0084413

http://eli.thegreenplace.net/2011/02/07/how-debuggers-work-part-3-debugging-information

states that debug_info must be read for the function names; but only debug_lines is read in lnfodwrf.

Michael Van Canneyt

2015-06-12 18:13

administrator  

Michael Van Canneyt

2015-06-12 18:13

administrator   ~0084414

Uploaded a simple program that shows the missing function names.
(does not show the error in case of missing debug info)

Jonas Maebe

2015-06-12 18:18

manager   ~0084415

That the function names are missing is known, it's simply not implemented. See e.g. 0017547

I'm not aware of any bug reports about the DWARF lineinfo unit only showing something for the first entry in the backtrace though.

Michael Van Canneyt

2015-06-12 20:16

administrator   ~0084420

I am not sure about that either, but it is correct that it stops as soon as there is a module (lib) without debug info, the design was the same as for the old lineinfo unit. That part can probably easily be copied.

Denis Kozlov

2016-01-09 12:30

reporter  

20160109-lnfodwrf.pp.patch (5,436 bytes)   
Index: rtl/inc/lnfodwrf.pp
===================================================================
--- rtl/inc/lnfodwrf.pp	(revision 32893)
+++ rtl/inc/lnfodwrf.pp	(working copy)
@@ -21,12 +21,28 @@
   dependent on objpas unit.
 }
 unit lnfodwrf;
+
 interface
 
 {$S-}
 
+{$IF FPC_VERSION<3}
+type
+  CodePointer = Pointer;
+{$ENDIF}
+
 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
 
 uses
@@ -61,7 +77,6 @@
   e : TExeFile;
   EBuf: Array [0..EBUF_SIZE-1] of Byte;
   EBufCnt, EBufPos: Integer;
-  DwarfErr : boolean;
   { the offset and size of the DWARF debug_line section in the file }
   DwarfOffset : longint;
   DwarfSize : longint;
@@ -137,18 +152,47 @@
   baseaddr : pointer;
   filename,
   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
-  Opendwarf:=false;
-  if dwarferr then
-    exit;
+  // False by default
+  Result:=false;
 
+  // Empty so can test if GetModuleByAddr has worked
+  filename := '';
+
+  // Get filename by address using GetModuleByAddr
   GetModuleByAddr(addr,baseaddr,filename);
 {$ifdef DEBUG_LINEINFO}
   writeln(stderr,filename,' Baseaddr: ',hexstr(ptruint(baseaddr),sizeof(baseaddr)*2));
 {$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}
+    Result:=lastopendwarf;
+    exit;
+  end;
+
+  // Close previously opened stabs
+  CloseDwarf;
+
+  // Reset last open stabs result
+  lastopendwarf := false;
+
+  // Save newly processed filename
+  lastfilename := filename;
+
+  // Open exe file or debug link
   if not OpenExeFile(e,filename) then
     exit;
   if ReadDebugLink(e,dbgfn) then
@@ -158,21 +202,25 @@
         exit;
     end;
 
+  // Find debug data section
   e.processaddress:=ptruint(baseaddr)-e.processaddress;
-
   if FindExeSection(e,'.debug_line',dwarfoffset,dwarfsize) then
-    Opendwarf:=true
+  begin
+    lastopendwarf:=true;
+    Result:=true;
+  end
   else
-    begin
-      dwarferr:=true;
-      exit;
-    end;
+    CloseExeFile(e);
 end;
 
 
-procedure Closedwarf;
+procedure CloseDwarf;
 begin
-  CloseExeFile(e);
+  if e.isopen then
+    CloseExeFile(e);
+
+  // Reset last processed filename
+  lastfilename := '';
 end;
 
 
@@ -730,14 +778,10 @@
   func := '';
   source := '';
   found := false;
-  GetLineInfo:=false;
-  if DwarfErr then
+  Result:=false;
+
+  if not OpenDwarf(pointer(addr)) then
     exit;
-  if not e.isopen then
-   begin
-     if not OpenDwarf(pointer(addr)) then
-      exit;
-   end;
 
   addr := addr - e.processaddress;
 
@@ -749,21 +793,26 @@
     current_offset := ParseCompilationUnit(addr, current_offset,
       source, line, found);
   end;
-  if e.isopen then
+
+  if not AllowReuseOfLineInfoData then
     CloseDwarf;
-  GetLineInfo:=true;
+
+  Result:=true;
 end;
 
 
-function DwarfBackTraceStr(addr : CodePointer) : shortstring;
+function DwarfBackTraceStr(addr: CodePointer): string;
 var
   func,
   source : string;
-  hs     : string[32];
+  hs     : string;
   line   : longint;
   Store  : TBackTraceStrFunc;
   Success : boolean;
 begin
+  {$ifdef DEBUG_LINEINFO}
+  writeln(stderr,'DwarfBackTraceStr called');
+  {$endif DEBUG_LINEINFO}
   { reset to prevent infinite recursion if problems inside the code }
   Success:=false;
   Store := BackTraceStrFunc;
@@ -770,28 +819,33 @@
   BackTraceStrFunc := @SysBackTraceStr;
   Success:=GetLineInfo(ptruint(addr), func, source, line);
   { create string }
-  DwarfBackTraceStr :='  $' + HexStr(ptruint(addr), sizeof(ptruint) * 2);
-  if func<>'' then
-   DwarfBackTraceStr := DwarfBackTraceStr + '  ' + func;
-
-  if source<>'' then begin
+  Result :='  $' + HexStr(ptruint(addr), sizeof(ptruint) * 2);
+  if Success then
+  begin
     if func<>'' then
-      DwarfBackTraceStr := DwarfBackTraceStr + ', ';
-    if line<>0 then begin
-      str(line, hs);
-      DwarfBackTraceStr := DwarfBackTraceStr + ' line ' + hs;
+      Result := Result + '  ' + func;
+    if source<>'' then
+    begin
+      if func<>'' then
+        Result := Result + ', ';
+      if line<>0 then
+      begin
+        str(line, hs);
+        Result := Result + ' line ' + hs;
+      end;
+      Result := Result + ' of ' + source;
     end;
-    DwarfBackTraceStr := DwarfBackTraceStr + ' of ' + source;
   end;
-  if Success then
-    BackTraceStrFunc := Store;
+  BackTraceStrFunc := Store;
 end;
 
 
 initialization
+  lastfilename := '';
+  lastopendwarf := false;
   BackTraceStrFunc := @DwarfBacktraceStr;
 
 finalization
-  if e.isopen then
-    CloseDwarf();
+  CloseDwarf;
+
 end.
20160109-lnfodwrf.pp.patch (5,436 bytes)   

Denis Kozlov

2016-01-09 12:30

reporter   ~0088738

Last edited: 2016-01-09 14:59

View 2 revisions

Attached patch fixes issues as discussed on the mailing list:
http://lists.freepascal.org/pipermail/fpc-devel/2016-January/036462.html

20160109-2-lnfodwrf.pp.patch [^] (5,377 bytes) 2016-01-09 13:58

Summary of changes:
1) Apply fixes from STABS to DWARF - fix permanently disabled line info when a module without line info is encountered.
2) Optional reuse of line info data via global AllowReuseOfLineInfoData variable.
3) Minor code clean up.

Denis Kozlov

2016-01-09 14:58

reporter  

20160109-2-lnfodwrf.pp.patch (5,377 bytes)   
Index: rtl/inc/lnfodwrf.pp
===================================================================
--- rtl/inc/lnfodwrf.pp	(revision 32893)
+++ rtl/inc/lnfodwrf.pp	(working copy)
@@ -21,12 +21,28 @@
   dependent on objpas unit.
 }
 unit lnfodwrf;
+
 interface
 
 {$S-}
 
+{$IF FPC_VERSION<3}
+type
+  CodePointer = Pointer;
+{$ENDIF}
+
 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
 
 uses
@@ -61,7 +77,6 @@
   e : TExeFile;
   EBuf: Array [0..EBUF_SIZE-1] of Byte;
   EBufCnt, EBufPos: Integer;
-  DwarfErr : boolean;
   { the offset and size of the DWARF debug_line section in the file }
   DwarfOffset : longint;
   DwarfSize : longint;
@@ -137,18 +152,47 @@
   baseaddr : pointer;
   filename,
   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
-  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);
 {$ifdef DEBUG_LINEINFO}
   writeln(stderr,filename,' Baseaddr: ',hexstr(ptruint(baseaddr),sizeof(baseaddr)*2));
 {$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 stabs
+  CloseDwarf;
+
+  // Reset last open stabs result
+  lastopendwarf := false;
+
+  // Save newly processed filename
+  lastfilename := filename;
+
+  // Open exe file or debug link
   if not OpenExeFile(e,filename) then
     exit;
   if ReadDebugLink(e,dbgfn) then
@@ -158,21 +202,25 @@
         exit;
     end;
 
+  // Find debug data section
   e.processaddress:=ptruint(baseaddr)-e.processaddress;
-
   if FindExeSection(e,'.debug_line',dwarfoffset,dwarfsize) then
-    Opendwarf:=true
+  begin
+    lastopendwarf:=true;
+    OpenDwarf:=true;
+  end
   else
-    begin
-      dwarferr:=true;
-      exit;
-    end;
+    CloseExeFile(e);
 end;
 
 
-procedure Closedwarf;
+procedure CloseDwarf;
 begin
-  CloseExeFile(e);
+  if e.isopen then
+    CloseExeFile(e);
+
+  // Reset last processed filename
+  lastfilename := '';
 end;
 
 
@@ -731,13 +779,9 @@
   source := '';
   found := false;
   GetLineInfo:=false;
-  if DwarfErr then
+
+  if not OpenDwarf(pointer(addr)) then
     exit;
-  if not e.isopen then
-   begin
-     if not OpenDwarf(pointer(addr)) then
-      exit;
-   end;
 
   addr := addr - e.processaddress;
 
@@ -749,21 +793,26 @@
     current_offset := ParseCompilationUnit(addr, current_offset,
       source, line, found);
   end;
-  if e.isopen then
+
+  if not AllowReuseOfLineInfoData then
     CloseDwarf;
+
   GetLineInfo:=true;
 end;
 
 
-function DwarfBackTraceStr(addr : CodePointer) : shortstring;
+function DwarfBackTraceStr(addr: CodePointer): string;
 var
   func,
   source : string;
-  hs     : string[32];
+  hs     : string;
   line   : longint;
   Store  : TBackTraceStrFunc;
   Success : boolean;
 begin
+  {$ifdef DEBUG_LINEINFO}
+  writeln(stderr,'DwarfBackTraceStr called');
+  {$endif DEBUG_LINEINFO}
   { reset to prevent infinite recursion if problems inside the code }
   Success:=false;
   Store := BackTraceStrFunc;
@@ -771,27 +820,32 @@
   Success:=GetLineInfo(ptruint(addr), func, source, line);
   { create string }
   DwarfBackTraceStr :='  $' + HexStr(ptruint(addr), sizeof(ptruint) * 2);
-  if func<>'' then
-   DwarfBackTraceStr := DwarfBackTraceStr + '  ' + func;
-
-  if source<>'' then begin
+  if Success then
+  begin
     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;
-    DwarfBackTraceStr := DwarfBackTraceStr + ' of ' + source;
   end;
-  if Success then
-    BackTraceStrFunc := Store;
+  BackTraceStrFunc := Store;
 end;
 
 
 initialization
+  lastfilename := '';
+  lastopendwarf := false;
   BackTraceStrFunc := @DwarfBacktraceStr;
 
 finalization
-  if e.isopen then
-    CloseDwarf();
+  CloseDwarf;
+
 end.
20160109-2-lnfodwrf.pp.patch (5,377 bytes)   

Michael Van Canneyt

2016-01-10 21:15

administrator   ~0088764

Applied the patch. Thank you!

Issue History

Date Modified Username Field Change
2015-06-12 13:43 Denis Kozlov New Issue
2015-06-12 13:44 Denis Kozlov Tag Attached: BackTraceStrFunc
2015-06-12 13:44 Denis Kozlov Tag Attached: Exception
2015-06-12 13:44 Denis Kozlov Tag Attached: DwarfBackTraceStr
2015-06-12 13:44 Denis Kozlov Tag Attached: lnfodwrf
2015-06-12 13:50 Denis Kozlov File Added: example-application-on-exception-line-info-dwarf.zip
2015-06-12 13:52 Denis Kozlov Note Added: 0084398
2015-06-12 16:18 Jonas Maebe Note Added: 0084407
2015-06-12 18:12 Michael Van Canneyt Note Added: 0084413
2015-06-12 18:13 Michael Van Canneyt File Added: simple_no_functionnames.zip
2015-06-12 18:13 Michael Van Canneyt Note Added: 0084414
2015-06-12 18:18 Jonas Maebe Note Added: 0084415
2015-06-12 20:14 Michael Van Canneyt Relationship added related to 0017547
2015-06-12 20:16 Michael Van Canneyt Note Added: 0084420
2016-01-09 12:30 Denis Kozlov File Added: 20160109-lnfodwrf.pp.patch
2016-01-09 12:30 Denis Kozlov Note Added: 0088738
2016-01-09 12:36 Denis Kozlov Tag Attached: patch
2016-01-09 14:58 Denis Kozlov File Added: 20160109-2-lnfodwrf.pp.patch
2016-01-09 14:59 Denis Kozlov Note Edited: 0088738 View Revisions
2016-01-10 21:15 Michael Van Canneyt Fixed in Revision => 32919
2016-01-10 21:15 Michael Van Canneyt Note Added: 0088764
2016-01-10 21:15 Michael Van Canneyt Status new => resolved
2016-01-10 21:15 Michael Van Canneyt Fixed in Version => 3.1.1
2016-01-10 21:15 Michael Van Canneyt Resolution open => fixed
2016-01-10 21:15 Michael Van Canneyt Assigned To => Michael Van Canneyt
2016-01-10 21:15 Michael Van Canneyt Target Version => 3.0.2