View Issue Details

IDProjectCategoryView StatusLast Update
0013518FPCRTLpublic2019-12-05 16:03
ReporterBoguslaw Brandys Assigned ToMichael Van Canneyt  
PrioritynormalSeverityminorReproducibilityalways
Status resolvedResolutionfixed 
PlatformwindowsOSwindows xp home 
Target Version3.2.0Fixed in Version3.0.0 
Summary0013518: Only first backtrace in big program has attached source nad line information
DescriptionIn big program like GUI created by Lazarus, only first backtrace can contain source and line informations. This is due to StabBackTraceStr function from lineinfo unit changing BackTraceStrFunc pointer to SysBackTraceStr during generation of backtrace. In case of long backtrace with incorrect pointers,that pointer is not returned back to lineinfo function which causes described problem with any subsequent generated backtrace.
TagsBackTraceStrFunc, debug, Exception, lineinfo, patch
Fixed in Revision31026
FPCOldBugId
FPCTarget-
Attached Files

Relationships

has duplicate 0021370 resolvedJonas Maebe The debug doesn't generate the info of the error. 
has duplicate 0028245 resolvedJonas Maebe Exceptions in TApplication.OnException have no line info 

Activities

Boguslaw Brandys

2009-04-15 21:57

reporter   ~0026775

Last edited: 2009-04-15 22:07

There is also a problem when GetModuleByAddr returns system libraries like user32.dll for some pointers, stabs cannot be found there and staberr:= true is set, and it's set permanently. IMHO GetModuleByAddr should return only modules with debug info inside ,in other case maybe ParamStr(0).

2009-04-16 16:58

 

lineinfo.patch (4,139 bytes)   
Index: rtl/inc/exeinfo.pp
===================================================================
--- rtl/inc/exeinfo.pp	(revision 13014)
+++ rtl/inc/exeinfo.pp	(working copy)
@@ -46,7 +46,7 @@
 function CloseExeFile(var e:TExeFile):boolean;
 function ReadDebugLink(var e:TExeFile;var dbgfn:string):boolean;
 
-procedure GetModuleByAddr(addr: pointer; var baseaddr: pointer; var filename: string);
+function GetModuleByAddr(addr: pointer; var baseaddr: pointer; var filename: string):boolean;
 
 implementation
 
@@ -55,14 +55,16 @@
 
 {$ifdef unix}
 
-  procedure GetModuleByAddr(addr: pointer; var baseaddr: pointer; var filename: string);
+  function GetModuleByAddr(addr: pointer; var baseaddr: pointer; var filename: string):boolean;
     begin
+      GetModuleByAddr := false;
       if assigned(UnixGetModuleByAddrHook) then
         UnixGetModuleByAddrHook(addr,baseaddr,filename)
       else
         begin
           baseaddr:=nil;
           filename:=ParamStr(0);
+          GetModuleByAddr := true;
         end;
     end;
 
@@ -76,11 +78,15 @@
 {$else wince}
     TST: array[0..Max_Path] of Char;
 {$endif wince}
-  procedure GetModuleByAddr(addr: pointer; var baseaddr: pointer; var filename: string);
+  function GetModuleByAddr(addr: pointer; var baseaddr: pointer; var filename: string):boolean;
     begin
+      GetModuleByAddr := false;
       baseaddr:= nil;
       if VirtualQuery(addr, @Tmm, SizeOf(Tmm))<>sizeof(Tmm) then
-        filename:=ParamStr(0)
+      begin
+        filename:=ParamStr(0);
+        GetModuleByAddr := true;
+      end
       else
         begin
           TST[0]:= #0;
@@ -95,8 +101,9 @@
 
 {$else windows}
 
-  procedure GetModuleByAddr(addr: pointer; var baseaddr: pointer; var filename: string);
+  function GetModuleByAddr(addr: pointer; var baseaddr: pointer; var filename: string):boolean;
     begin
+      GetModuleByAddr := true;
       baseaddr:= nil;
       filename:=ParamStr(0);
     end;
Index: rtl/inc/lineinfo.pp
===================================================================
--- rtl/inc/lineinfo.pp	(revision 13014)
+++ rtl/inc/lineinfo.pp	(working copy)
@@ -77,12 +77,30 @@
 function OpenStabs(addr : pointer) : boolean;
   var
     baseaddr : pointer;
+    dbgfile,exemodule : Boolean;
 begin
   OpenStabs:=false;
+  dbgfile := false;
   if staberr then
     exit;
 
-  GetModuleByAddr(addr,baseaddr,filename);
+  {the best method would be a cache of files (names) whith debug sections}
+  {under windows common problem of code below is parsing system dll's like user32.dll }
+
+
+  exemodule := GetModuleByAddr(addr,baseaddr,filename);
+
+
+  if (e.filename<>filename) then
+   CloseExeFile(e)
+  else
+  begin
+   OpenStabs := true;
+   exit;
+  end;
+
+
+
 {$ifdef DEBUG_LINEINFO}
   writeln(stderr,filename,' Baseaddr: ',hexstr(ptruint(baseaddr),sizeof(baseaddr)*2));
 {$endif DEBUG_LINEINFO}
@@ -94,6 +112,7 @@
       CloseExeFile(e);
       if not OpenExeFile(e,dbgfn) then
         exit;
+      dbgfile := true;
     end;
   e.processaddress:=e.processaddress+dword(baseaddr);
   StabsFunctionRelative := E.FunctionRelative;
@@ -105,7 +124,9 @@
     end
   else
     begin
-      staberr:=true;
+      e.filename := '';//reset filename to avoid recursion
+      CloseExeFile(e);
+      if exemodule or dbgfile then  staberr:=true;
       exit;
     end;
 end;
@@ -134,12 +155,10 @@
   line:=0;
   if staberr then
     exit;
-  if not e.isopen then
-   begin
-     if not OpenStabs(pointer(addr)) then
-      exit;
-   end;
 
+  if not OpenStabs(pointer(addr)) then  exit;
+
+
   { correct the value to the correct address in the file }
   { processaddress is set in OpenStabs                   }
   addr := addr - e.processaddress;
@@ -246,8 +265,6 @@
      if i>0 then
       Delete(func,i,255);
    end;
-  if e.isopen then
-    CloseStabs;
   GetLineInfo:=true;
 end;
 
@@ -290,13 +307,13 @@
       end;
      StabBackTraceStr:=StabBackTraceStr+' of '+source;
    end;
-  if Success then
     BackTraceStrFunc:=Store;
 end;
 
 
 initialization
   BackTraceStrFunc:=@StabBackTraceStr;
+  e.filename := '';
 
 finalization
   if e.isopen then
lineinfo.patch (4,139 bytes)   

Boguslaw Brandys

2009-04-16 17:02

reporter   ~0026797

Patch attached which solves problem I hope.Tested under win32 on single executable and with dll with stabs debug.
Please test against any recursion test cases. Untested under unix/linux, win64, wince. Please test under those systems if you can.
Patch allows unlimited backtraces per program execution.

Jonas Maebe

2009-05-10 11:36

manager   ~0027478

I think the main reason for only symbolicating the first backtrace, is to avoid getting in an endless loop if the second exception is due to an invalid memory access inside the lineinfo unit itself.

Boguslaw Brandys

2009-05-12 09:10

reporter   ~0027545

Well,I understand it, and I think that why temporarily during lineinfo work it point backtrace into bare method SysBackTraceStr to avoid infinite loop. That part was not changed.The change was mostly removing unnecessairly opening/closing the same file for each output line and the usage of "guard variable" - staberr to follow that.Now staberr is set only in case of real problem which is for example missing stab sections in binary.

But I agree that the definitive way is to check new code in case of memory corruption during building of backtrace output.I'll do it as soon as I find spare time.

I think similar issue could be true for lnfodwrf.pp

Boguslaw Brandys

2009-06-27 17:46

reporter   ~0028802

I tested patch against possible recursion and found no problem.
For example I simulated memory access problem inside lineinfo internal GetLineInfo function and result is :

E:\test>test
Runtime error 200 at $0040145B
Runtime error 216 at $00408A01
  $00408A01
  $00408DD8
  $004043F7
  $00407BD0

I recreated patch against current SVN fpc version trunk [2009/06/27]

Boguslaw Brandys

2009-06-27 17:47

reporter   ~0028803

New patch is named lineinfo2.patch

2009-06-27 17:50

 

lineinfo2.patch (4,251 bytes)   
Index: rtl/inc/exeinfo.pp
===================================================================
--- rtl/inc/exeinfo.pp	(revision 13340)
+++ rtl/inc/exeinfo.pp	(working copy)
@@ -46,7 +46,7 @@
 function CloseExeFile(var e:TExeFile):boolean;
 function ReadDebugLink(var e:TExeFile;var dbgfn:string):boolean;
 
-procedure GetModuleByAddr(addr: pointer; var baseaddr: pointer; var filename: string);
+function GetModuleByAddr(addr: pointer; var baseaddr: pointer; var filename: string):boolean;
 
 implementation
 
@@ -55,14 +55,16 @@
 
 {$ifdef unix}
 
-  procedure GetModuleByAddr(addr: pointer; var baseaddr: pointer; var filename: string);
+  function GetModuleByAddr(addr: pointer; var baseaddr: pointer; var filename: string):boolean;
     begin
+      GetModuleByAddr := false;
       if assigned(UnixGetModuleByAddrHook) then
         UnixGetModuleByAddrHook(addr,baseaddr,filename)
       else
         begin
           baseaddr:=nil;
           filename:=ParamStr(0);
+          GetModuleByAddr := true;
         end;
     end;
 
@@ -76,11 +78,15 @@
 {$else wince}
     TST: array[0..Max_Path] of Char;
 {$endif wince}
-  procedure GetModuleByAddr(addr: pointer; var baseaddr: pointer; var filename: string);
+  function GetModuleByAddr(addr: pointer; var baseaddr: pointer; var filename: string):boolean;
     begin
-      baseaddr:=nil;
-      if VirtualQuery(addr, @Tmm, SizeOf(Tmm))<>sizeof(Tmm) then
-        filename:=ParamStr(0)
+      GetModuleByAddr := false;
+      baseaddr:= nil;
+    if VirtualQuery(addr, @Tmm, SizeOf(Tmm))<>sizeof(Tmm) then
+      begin
+        filename:=ParamStr(0);
+        GetModuleByAddr := true;
+      end
       else
         begin
           baseaddr:=Tmm.AllocationBase;
@@ -96,8 +102,9 @@
 
 {$else windows}
 
-  procedure GetModuleByAddr(addr: pointer; var baseaddr: pointer; var filename: string);
+  function GetModuleByAddr(addr: pointer; var baseaddr: pointer; var filename: string):boolean;
     begin
+      GetModuleByAddr := true;
       baseaddr:= nil;
       filename:=ParamStr(0);
     end;
Index: rtl/inc/lineinfo.pp
===================================================================
--- rtl/inc/lineinfo.pp	(revision 13340)
+++ rtl/inc/lineinfo.pp	(working copy)
@@ -77,12 +77,30 @@
 function OpenStabs(addr : pointer) : boolean;
   var
     baseaddr : pointer;
+    dbgfile,exemodule : Boolean;
 begin
   OpenStabs:=false;
+  dbgfile := false;
   if staberr then
     exit;
 
-  GetModuleByAddr(addr,baseaddr,filename);
+  {the best method would be a cache of files (names) whith debug sections}
+  {under windows common problem of code below is parsing system dll's like user32.dll }
+
+
+  exemodule := GetModuleByAddr(addr,baseaddr,filename);
+
+
+  if (e.filename<>filename) then
+   CloseExeFile(e)
+  else
+  begin
+   OpenStabs := true;
+   exit;
+  end;
+
+
+
 {$ifdef DEBUG_LINEINFO}
   writeln(stderr,filename,' Baseaddr: ',hexstr(ptruint(baseaddr),sizeof(baseaddr)*2));
 {$endif DEBUG_LINEINFO}
@@ -94,6 +112,7 @@
       CloseExeFile(e);
       if not OpenExeFile(e,dbgfn) then
         exit;
+      dbgfile := true;
     end;
   e.processaddress:=ptruint(baseaddr)-e.processaddress;
   StabsFunctionRelative := E.FunctionRelative;
@@ -105,7 +124,9 @@
     end
   else
     begin
-      staberr:=true;
+      e.filename := '';//reset filename to avoid recursion
+      CloseExeFile(e);
+      if exemodule or dbgfile then  staberr:=true;
       exit;
     end;
 end;
@@ -134,12 +155,10 @@
   line:=0;
   if staberr then
     exit;
-  if not e.isopen then
-   begin
-     if not OpenStabs(pointer(addr)) then
-      exit;
-   end;
 
+  if not OpenStabs(pointer(addr)) then  exit;
+
+
   { correct the value to the correct address in the file }
   { processaddress is set in OpenStabs                   }
   addr := dword(addr - e.processaddress);
@@ -246,8 +265,6 @@
      if i>0 then
       Delete(func,i,255);
    end;
-  if e.isopen then
-    CloseStabs;
   GetLineInfo:=true;
 end;
 
@@ -290,13 +307,13 @@
       end;
      StabBackTraceStr:=StabBackTraceStr+' of '+source;
    end;
-  if Success then
     BackTraceStrFunc:=Store;
 end;
 
 
 initialization
   BackTraceStrFunc:=@StabBackTraceStr;
+  e.filename := '';
 
 finalization
   if e.isopen then
lineinfo2.patch (4,251 bytes)   

cobines

2009-11-15 05:57

reporter   ~0032142

Failing to read debug line info should not be considered an error. Once a module is encountered without debug info (like the system libraries) the line info completely stops working.

The possible infinite loop is an unrelated issue, but there is already a guard for that. The guard however is supposed to work in case of a second exception, but it also applies when no debug info was found in a module.

Why the staberr, DwarfErr and Success variables cannot simply be removed?

2012-02-29 13:36

 

unCustomLineInfo.pas (8,192 bytes)

2012-02-29 13:37

 

unStackTrace.pas (2,573 bytes)

Everton Vieira

2012-02-29 13:37

reporter   ~0057163

I use this two units i just uploaded to do this.

Everton Vieira

2012-03-05 13:52

reporter   ~0057281

With this two units:

 unCustomLineInfo.pas [^] (8,192 bytes) 2012-02-29 13:36
 unStackTrace.pas [^] (2,573 bytes) 2012-02-29 13:37

I was able to do the exception back trace of the application.
Without simply doesn't work.

Everton Vieira

2012-03-08 17:34

reporter   ~0057411

I'm using on the Application.onException

Denis Kozlov

2015-06-05 15:39

reporter   ~0084267

Over 6 years old... I'm startled.

How can we build reliable software if we can't reliably get debug info from exceptions?

Jonas Maebe

2015-06-06 11:26

manager   ~0084280

> How can we build reliable software if we can't reliably get debug info from exceptions?

The same as on platforms where lineinfo is not supported at all: by using the debugger to determine the corresponding line numbers.

In gdb: info line *0xaddress
In lldb: image lookup -v --address 0xaddress

Boguslaw Brandys

2015-06-07 10:18

reporter   ~0084285

Welcome to the time machine Denis :-) I remember I spent lot of time to solve this problem yet no reaction from developers who can solve it in no time I think.Maybe add a voting system to appreciate what is really important for fpc users to fix first ?

Denis Kozlov

2015-06-08 17:30

reporter  

lineinfo.pp (9,646 bytes)

Denis Kozlov

2015-06-08 17:31

reporter   ~0084309

I didn't like previously submitted patches (several reasons). So, I have made an attempt at fixing basic issues with "lineinfo.pp".

I've tried to keep changes to a minimum and maintain currently used conventions to make validation easier. Instead of separate patches for 2.6, 3.0 and trunk branches I will attach a full "lineinfo.pp" unit which accommodates all branches.

Summary of changes:
1) Removed use of "staberr" variable which permanently disabled line info functionality on first failed attempt to read stabs.
2) Reuse last opened file in OpenStabs, using new "lastfilename" and "lastopenstabs" variables.
3) GetLineInfo no longer closes stabs, as this will not allow for reuse.
4) Restore original BackTraceStrFunc even if GetLineInfo has failed.
5) Conditional parameter type in StabBackTraceStr to handle both FPC v2 and v3 (due to CodePointer type).
6) Added StabBackTraceStr and CloseStabs to the interface section.

Tested on Windows 7 with GUI and Console apps.

lineinfo.pp [^] (9,646 bytes) 2015-06-08 16:30

Michael Van Canneyt

2015-06-12 09:18

administrator   ~0084381

Applied the patch with a minor change for improved readability.
Thank you very much.

(@note to self: we should check the DWARF unit for the same error?)

Issue History

Date Modified Username Field Change
2009-04-15 09:08 Boguslaw Brandys New Issue
2009-04-15 21:57 Boguslaw Brandys Note Added: 0026775
2009-04-15 22:07 Boguslaw Brandys Note Edited: 0026775
2009-04-16 16:58 Boguslaw Brandys File Added: lineinfo.patch
2009-04-16 17:02 Boguslaw Brandys Note Added: 0026797
2009-05-10 11:36 Jonas Maebe Note Added: 0027478
2009-05-12 09:10 Boguslaw Brandys Note Added: 0027545
2009-06-27 17:46 Boguslaw Brandys Note Added: 0028802
2009-06-27 17:47 Boguslaw Brandys Note Added: 0028803
2009-06-27 17:50 Boguslaw Brandys File Added: lineinfo2.patch
2009-11-15 05:57 cobines Note Added: 0032142
2012-02-26 01:00 Jonas Maebe Relationship added has duplicate 0021370
2012-02-29 13:36 Everton Vieira File Added: unCustomLineInfo.pas
2012-02-29 13:37 Everton Vieira File Added: unStackTrace.pas
2012-02-29 13:37 Everton Vieira Note Added: 0057163
2012-03-05 13:52 Everton Vieira Note Added: 0057281
2012-03-08 17:34 Everton Vieira Note Added: 0057411
2015-06-05 15:10 Jonas Maebe Relationship added has duplicate 0028245
2015-06-05 15:39 Denis Kozlov Note Added: 0084267
2015-06-06 11:26 Jonas Maebe Note Added: 0084280
2015-06-07 10:18 Boguslaw Brandys Note Added: 0084285
2015-06-08 17:30 Denis Kozlov File Added: lineinfo.pp
2015-06-08 17:31 Denis Kozlov Note Added: 0084309
2015-06-08 17:34 Denis Kozlov Tag Attached: BackTraceStrFunc
2015-06-08 17:34 Denis Kozlov Tag Attached: Exception
2015-06-08 17:34 Denis Kozlov Tag Attached: patch
2015-06-08 17:34 Denis Kozlov Tag Attached: debug
2015-06-08 17:34 Denis Kozlov Tag Attached: lineinfo
2015-06-12 09:18 Michael Van Canneyt Fixed in Revision => 31026
2015-06-12 09:18 Michael Van Canneyt Note Added: 0084381
2015-06-12 09:18 Michael Van Canneyt Status new => resolved
2015-06-12 09:18 Michael Van Canneyt Fixed in Version => 3.1.1
2015-06-12 09:18 Michael Van Canneyt Resolution open => fixed
2015-06-12 09:18 Michael Van Canneyt Assigned To => Michael Van Canneyt
2015-06-12 09:18 Michael Van Canneyt Target Version => 4.0.0
2015-08-30 22:38 Joost van der Sluis Fixed in Version 3.1.1 => 3.0.1
2019-12-05 16:03 Michael Van Canneyt Target Version 4.0.0 => 3.2.0
2019-12-05 16:03 Michael Van Canneyt FPCTarget => -