lineinfo.pp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2000 by Peter Vreman
  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. unit lineinfo;
  12. interface
  13. {$mode objfpc}
  14. {$S-}
  15. {$Q-}
  16. procedure GetLineInfo(addr:ptruint;var func,source:string;var line:longint);
  17. implementation
  18. uses
  19. exeinfo,strings;
  20. const
  21. N_Function = $24;
  22. N_TextLine = $44;
  23. N_DataLine = $46;
  24. N_BssLine = $48;
  25. N_SourceFile = $64;
  26. N_IncludeFile = $84;
  27. maxstabs = 40; { size of the stabs buffer }
  28. var
  29. { GDB after 4.18 uses offset to function begin
  30. in text section but OS/2 version still uses 4.16 PM }
  31. StabsFunctionRelative: boolean;
  32. type
  33. pstab=^tstab;
  34. tstab=packed record
  35. strpos : longint;
  36. ntype : byte;
  37. nother : byte;
  38. ndesc : word;
  39. nvalue : dword;
  40. end;
  41. { We use static variable so almost no stack is required, and is thus
  42. more safe when an error has occured in the program }
  43. var
  44. e : TExeFile;
  45. staberr : boolean;
  46. stabcnt, { amount of stabs }
  47. stablen,
  48. stabofs, { absolute stab section offset in executable }
  49. stabstrlen,
  50. stabstrofs : longint; { absolute stabstr section offset in executable }
  51. dirlength : longint; { length of the dirctory part of the source file }
  52. stabs : array[0..maxstabs-1] of tstab; { buffer }
  53. funcstab, { stab with current function info }
  54. linestab, { stab with current line info }
  55. dirstab, { stab with current directory info }
  56. filestab : tstab; { stab with current file info }
  57. function OpenStabs:boolean;
  58. var
  59. dbgfn : string;
  60. begin
  61. result:=false;
  62. if staberr then
  63. exit;
  64. if not OpenExeFile(e,paramstr(0)) then
  65. exit;
  66. if ReadDebugLink(e,dbgfn) then
  67. begin
  68. CloseExeFile(e);
  69. if not OpenExeFile(e,dbgfn) then
  70. exit;
  71. end;
  72. StabsFunctionRelative := E.FunctionRelative;
  73. if FindExeSection(e,'.stab',stabofs,stablen) and
  74. FindExeSection(e,'.stabstr',stabstrofs,stabstrlen) then
  75. begin
  76. stabcnt:=stablen div sizeof(tstab);
  77. result:=true;
  78. end
  79. else
  80. begin
  81. staberr:=true;
  82. exit;
  83. end;
  84. end;
  85. procedure CloseStabs;
  86. begin
  87. CloseExeFile(e);
  88. end;
  89. procedure GetLineInfo(addr:ptruint;var func,source:string;var line:longint);
  90. var
  91. res,
  92. stabsleft,
  93. stabscnt,i : longint;
  94. found : boolean;
  95. lastfunc : tstab;
  96. begin
  97. fillchar(func,high(func)+1,0);
  98. fillchar(source,high(source)+1,0);
  99. line:=0;
  100. if staberr then
  101. exit;
  102. if not e.isopen then
  103. begin
  104. if not OpenStabs then
  105. exit;
  106. end;
  107. { correct the value to the correct address in the file }
  108. { processaddress is set in OpenStabs }
  109. addr := addr - e.processaddress;
  110. fillchar(funcstab,sizeof(tstab),0);
  111. fillchar(filestab,sizeof(tstab),0);
  112. fillchar(dirstab,sizeof(tstab),0);
  113. fillchar(linestab,sizeof(tstab),0);
  114. fillchar(lastfunc,sizeof(tstab),0);
  115. found:=false;
  116. seek(e.f,stabofs);
  117. stabsleft:=stabcnt;
  118. repeat
  119. if stabsleft>maxstabs then
  120. stabscnt:=maxstabs
  121. else
  122. stabscnt:=stabsleft;
  123. blockread(e.f,stabs,stabscnt*sizeof(tstab),res);
  124. stabscnt:=res div sizeof(tstab);
  125. for i:=0 to stabscnt-1 do
  126. begin
  127. case stabs[i].ntype of
  128. N_BssLine,
  129. N_DataLine,
  130. N_TextLine :
  131. begin
  132. if (stabs[i].ntype=N_TextLine) and StabsFunctionRelative then
  133. inc(stabs[i].nvalue,lastfunc.nvalue);
  134. if (stabs[i].nvalue<=addr) and
  135. (stabs[i].nvalue>linestab.nvalue) then
  136. begin
  137. { if it's equal we can stop and take the last info }
  138. if stabs[i].nvalue=addr then
  139. found:=true
  140. else
  141. linestab:=stabs[i];
  142. end;
  143. end;
  144. N_Function :
  145. begin
  146. lastfunc:=stabs[i];
  147. if (stabs[i].nvalue<=addr) and
  148. (stabs[i].nvalue>funcstab.nvalue) then
  149. begin
  150. funcstab:=stabs[i];
  151. fillchar(linestab,sizeof(tstab),0);
  152. end;
  153. end;
  154. N_SourceFile,
  155. N_IncludeFile :
  156. begin
  157. if (stabs[i].nvalue<=addr) and
  158. (stabs[i].nvalue>=filestab.nvalue) then
  159. begin
  160. { if same value and type then the first one
  161. contained the directory PM }
  162. if (stabs[i].nvalue=filestab.nvalue) and
  163. (stabs[i].ntype=filestab.ntype) then
  164. dirstab:=filestab
  165. else
  166. fillchar(dirstab,sizeof(tstab),0);
  167. filestab:=stabs[i];
  168. fillchar(linestab,sizeof(tstab),0);
  169. { if new file then func is not valid anymore PM }
  170. if stabs[i].ntype=N_SourceFile then
  171. begin
  172. fillchar(funcstab,sizeof(tstab),0);
  173. fillchar(lastfunc,sizeof(tstab),0);
  174. end;
  175. end;
  176. end;
  177. end;
  178. end;
  179. dec(stabsleft,stabscnt);
  180. until found or (stabsleft=0);
  181. { get the line,source,function info }
  182. line:=linestab.ndesc;
  183. if dirstab.ntype<>0 then
  184. begin
  185. seek(e.f,stabstrofs+dirstab.strpos);
  186. blockread(e.f,source[1],high(source)-1,res);
  187. dirlength:=strlen(@source[1]);
  188. source[0]:=chr(dirlength);
  189. end
  190. else
  191. dirlength:=0;
  192. if filestab.ntype<>0 then
  193. begin
  194. seek(e.f,stabstrofs+filestab.strpos);
  195. blockread(e.f,source[dirlength+1],high(source)-(dirlength+1),res);
  196. source[0]:=chr(strlen(@source[1]));
  197. end;
  198. if funcstab.ntype<>0 then
  199. begin
  200. seek(e.f,stabstrofs+funcstab.strpos);
  201. blockread(e.f,func[1],high(func)-1,res);
  202. func[0]:=chr(strlen(@func[1]));
  203. i:=pos(':',func);
  204. if i>0 then
  205. Delete(func,i,255);
  206. end;
  207. end;
  208. function StabBackTraceStr(addr:Pointer):shortstring;
  209. var
  210. func,
  211. source : string;
  212. hs : string[32];
  213. line : longint;
  214. Store : TBackTraceStrFunc;
  215. begin
  216. { reset to prevent infinite recursion if problems inside the code PM }
  217. Store:=BackTraceStrFunc;
  218. BackTraceStrFunc:=@SysBackTraceStr;
  219. GetLineInfo(ptruint(addr),func,source,line);
  220. { create string }
  221. {$ifdef netware}
  222. { we need addr relative to code start on netware }
  223. dec(addr,ptruint(system.NWGetCodeStart));
  224. StabBackTraceStr:=' CodeStart + $'+HexStr(ptruint(addr),sizeof(ptruint)*2);
  225. {$else}
  226. StabBackTraceStr:=' $'+HexStr(ptruint(addr),sizeof(ptruint)*2);
  227. {$endif}
  228. if func<>'' then
  229. StabBackTraceStr:=StabBackTraceStr+' '+func;
  230. if source<>'' then
  231. begin
  232. if func<>'' then
  233. StabBackTraceStr:=StabBackTraceStr+', ';
  234. if line<>0 then
  235. begin
  236. str(line,hs);
  237. StabBackTraceStr:=StabBackTraceStr+' line '+hs;
  238. end;
  239. StabBackTraceStr:=StabBackTraceStr+' of '+source;
  240. end;
  241. if e.IsOpen then
  242. BackTraceStrFunc:=Store;
  243. end;
  244. initialization
  245. BackTraceStrFunc:=@StabBackTraceStr;
  246. finalization
  247. if e.isopen then
  248. CloseStabs;
  249. end.