lnfogdb.pp 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  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. unit lnfogdb;
  16. interface
  17. {$S-}
  18. {$Q-}
  19. function GetLineInfo(addr:ptruint;var func,source:string;var line:longint) : boolean;
  20. implementation
  21. uses
  22. ctypes,baseunix,unix;
  23. function GetLineInfo(addr:ptruint;var func,source:string;var line:longint) : boolean;
  24. var
  25. mypid: pid_t;
  26. res,
  27. err: cint;
  28. command,
  29. pidstr: string;
  30. commfile,
  31. resfile: text;
  32. begin
  33. GetLineInfo:=false;
  34. {$i-}
  35. { reset inoutres in case it was set by a previous operation }
  36. ioresult;
  37. mypid:=fpgetpid;
  38. str(mypid,pidstr);
  39. { create temporary file containig gdb command }
  40. assign(commfile,'/tmp/fpcbt'+pidstr);
  41. rewrite(commfile);
  42. if ioresult<>0 then
  43. exit;
  44. str(addr,command);
  45. writeln(commfile,'attach '+pidstr);
  46. writeln(commfile,'info line *'+command);
  47. res:=ioresult;
  48. close(commfile);
  49. if (res<>0) or
  50. (ioresult<>0) then
  51. begin
  52. erase(commfile);
  53. exit;
  54. end;
  55. { execute gdb to get the linenr info (set language to English (=C) for
  56. parsing reasons) }
  57. res:=fpsystem('LANG=C gdb '+paramstr(0)+' -n -batch -x /tmp/fpcbt'+pidstr+' > /tmp/fpcbt'+pidstr+'.out');
  58. erase(commfile);
  59. {$ifdef DEBUG_LINEINFO}
  60. writeln('rescode from executing gdb: ',res);
  61. {$endif}
  62. if res<>0 then
  63. exit(false);
  64. assign(resfile,'/tmp/fpcbt'+pidstr+'.out');
  65. reset(resfile);
  66. if ioresult<>0 then
  67. begin
  68. erase(resfile);
  69. exit;
  70. end;
  71. { get last line }
  72. while not eof(resfile) do
  73. readln(resfile,command);
  74. res:=ioresult;
  75. close(resfile);
  76. { clear inoutres, don't really care about result of close }
  77. ioresult;
  78. erase(resfile);
  79. if (res<>0) or
  80. (ioresult<>0) then
  81. exit;
  82. { format:
  83. Line 16 of "hello.pp" starts at address 0x100003a4 <PASCALMAIN+24> and ends at 0x100003b0 <PASCALMAIN+36>.
  84. or
  85. No line number information available for address 0x3aca
  86. }
  87. {$ifdef DEBUG_LINEINFO}
  88. writeln('gdb result: ',command);
  89. {$endif}
  90. if copy(command,1,5)<>'Line ' then
  91. exit(false);
  92. { extract line number }
  93. delete(command,1,5);
  94. res:=pos(' ',command);
  95. if res=0 then
  96. exit(false);
  97. val(copy(command,1,res-1),line,err);
  98. if err<>0 then
  99. exit;
  100. { extra file name }
  101. delete(command,1,res+4);
  102. res:=pos('"',command);
  103. if res=0 then
  104. exit;
  105. source:=copy(command,1,res-1);
  106. { if we can't extract the function name: no big deal }
  107. func:='';
  108. GetLineInfo:=true;
  109. res:=pos('<',command);
  110. if res=0 then
  111. exit;
  112. delete(command,1,res);
  113. res:=pos('>',command);
  114. if res=0 then
  115. res:=length(command)
  116. else
  117. begin
  118. err:=pos('+',command);
  119. if err<res then
  120. res:=err;
  121. end;
  122. func:=copy(command,1,res-1)
  123. end;
  124. function GdbBackTraceStr(addr:Pointer):shortstring;
  125. var
  126. func,
  127. source : string;
  128. hs : string[32];
  129. line : longint;
  130. Store : TBackTraceStrFunc;
  131. Success : boolean;
  132. begin
  133. {$ifdef DEBUG_LINEINFO}
  134. writeln(stderr,'StabxBackTraceStr called');
  135. {$endif DEBUG_LINEINFO}
  136. { reset to prevent infinite recursion if problems inside the code PM }
  137. Success:=false;
  138. Store:=BackTraceStrFunc;
  139. BackTraceStrFunc:=@SysBackTraceStr;
  140. Success:=GetLineInfo(ptruint(addr),func,source,line);
  141. { create string }
  142. GdbBackTraceStr:=' $'+HexStr(ptruint(addr),sizeof(ptruint)*2);
  143. if func<>'' then
  144. GdbBackTraceStr:=GdbBackTraceStr+' '+func;
  145. if source<>'' then
  146. begin
  147. if func<>'' then
  148. GdbBackTraceStr:=GdbBackTraceStr+', ';
  149. if line<>0 then
  150. begin
  151. str(line,hs);
  152. GdbBackTraceStr:=GdbBackTraceStr+' line '+hs;
  153. end;
  154. GdbBackTraceStr:=GdbBackTraceStr+' of '+source;
  155. end;
  156. if Success then
  157. BackTraceStrFunc:=Store;
  158. end;
  159. initialization
  160. BackTraceStrFunc:=@GdbBackTraceStr;
  161. end.