lineinfo.pp 7.3 KB

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