lnfogdb.pp 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2012 by Jonas Maebe
  4. Stabs Line Info Retriever
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. {
  12. This unit should not be compiled in objfpc mode, since this would make it
  13. dependent on objpas unit.
  14. }
  15. {$IFNDEF FPC_DOTTEDUNITS}
  16. unit lnfogdb;
  17. {$ENDIF FPC_DOTTEDUNITS}
  18. interface
  19. {$S-}
  20. {$Q-}
  21. function GetLineInfo(addr:ptruint;var func,source:string;var line:longint) : boolean;
  22. implementation
  23. {$IFDEF FPC_DOTTEDUNITS}
  24. uses
  25. System.CTypes,UnixApi.Base,UnixApi.Unix;
  26. {$ELSE FPC_DOTTEDUNITS}
  27. uses
  28. ctypes,baseunix,unix;
  29. {$ENDIF FPC_DOTTEDUNITS}
  30. function GetLineInfo(addr:ptruint;var func,source:string;var line:longint) : boolean;
  31. var
  32. mypid: pid_t;
  33. res,
  34. err: cint;
  35. command,
  36. pidstr: string;
  37. commfile,
  38. resfile: text;
  39. begin
  40. GetLineInfo:=false;
  41. {$i-}
  42. { reset inoutres in case it was set by a previous operation }
  43. ioresult;
  44. mypid:=fpgetpid;
  45. str(mypid,pidstr);
  46. { create temporary file containig gdb command }
  47. assign(commfile,'/tmp/fpcbt'+pidstr);
  48. rewrite(commfile);
  49. if ioresult<>0 then
  50. exit;
  51. str(addr,command);
  52. writeln(commfile,'attach '+pidstr);
  53. writeln(commfile,'info line *'+command);
  54. res:=ioresult;
  55. close(commfile);
  56. if (res<>0) or
  57. (ioresult<>0) then
  58. begin
  59. erase(commfile);
  60. exit;
  61. end;
  62. { execute gdb to get the linenr info (set language to English (=C) for
  63. parsing reasons) }
  64. res:=fpsystem('LANG=C gdb '+paramstr(0)+' -n -batch -x /tmp/fpcbt'+pidstr+' > /tmp/fpcbt'+pidstr+'.out');
  65. erase(commfile);
  66. {$ifdef DEBUG_LINEINFO}
  67. writeln('rescode from executing gdb: ',res);
  68. {$endif}
  69. if res<>0 then
  70. exit(false);
  71. assign(resfile,'/tmp/fpcbt'+pidstr+'.out');
  72. reset(resfile);
  73. if ioresult<>0 then
  74. begin
  75. erase(resfile);
  76. exit;
  77. end;
  78. { get last line }
  79. while not eof(resfile) do
  80. readln(resfile,command);
  81. res:=ioresult;
  82. close(resfile);
  83. { clear inoutres, don't really care about result of close }
  84. ioresult;
  85. erase(resfile);
  86. if (res<>0) or
  87. (ioresult<>0) then
  88. exit;
  89. { format:
  90. Line 16 of "hello.pp" starts at address 0x100003a4 <PASCALMAIN+24> and ends at 0x100003b0 <PASCALMAIN+36>.
  91. or
  92. No line number information available for address 0x3aca
  93. }
  94. {$ifdef DEBUG_LINEINFO}
  95. writeln('gdb result: ',command);
  96. {$endif}
  97. if copy(command,1,5)<>'Line ' then
  98. exit(false);
  99. { extract line number }
  100. delete(command,1,5);
  101. res:=pos(' ',command);
  102. if res=0 then
  103. exit(false);
  104. val(copy(command,1,res-1),line,err);
  105. if err<>0 then
  106. exit;
  107. { extra file name }
  108. delete(command,1,res+4);
  109. res:=pos('"',command);
  110. if res=0 then
  111. exit;
  112. source:=copy(command,1,res-1);
  113. { if we can't extract the function name: no big deal }
  114. func:='';
  115. GetLineInfo:=true;
  116. res:=pos('<',command);
  117. if res=0 then
  118. exit;
  119. delete(command,1,res);
  120. res:=pos('>',command);
  121. if res=0 then
  122. res:=length(command)
  123. else
  124. begin
  125. err:=pos('+',command);
  126. if err<res then
  127. res:=err;
  128. end;
  129. func:=copy(command,1,res-1)
  130. end;
  131. function GdbBackTraceStr(addr:Pointer):shortstring;
  132. var
  133. func,
  134. source : string;
  135. hs : string[32];
  136. line : longint;
  137. Store : TBackTraceStrFunc;
  138. Success : boolean;
  139. begin
  140. {$ifdef DEBUG_LINEINFO}
  141. writeln(stderr,'StabxBackTraceStr called');
  142. {$endif DEBUG_LINEINFO}
  143. { reset to prevent infinite recursion if problems inside the code PM }
  144. Success:=false;
  145. Store:=BackTraceStrFunc;
  146. BackTraceStrFunc:=@SysBackTraceStr;
  147. Success:=GetLineInfo(ptruint(addr),func,source,line);
  148. { create string }
  149. GdbBackTraceStr:=' $'+HexStr(ptruint(addr),sizeof(ptruint)*2);
  150. if func<>'' then
  151. GdbBackTraceStr:=GdbBackTraceStr+' '+func;
  152. if source<>'' then
  153. begin
  154. if func<>'' then
  155. GdbBackTraceStr:=GdbBackTraceStr+', ';
  156. if line<>0 then
  157. begin
  158. str(line,hs);
  159. GdbBackTraceStr:=GdbBackTraceStr+' line '+hs;
  160. end;
  161. GdbBackTraceStr:=GdbBackTraceStr+' of '+source;
  162. end;
  163. if Success then
  164. BackTraceStrFunc:=Store;
  165. end;
  166. initialization
  167. BackTraceStrFunc:=@GdbBackTraceStr;
  168. end.