lineinfo.pp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953
  1. {
  2. $Id$
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 2000 by Peter Vreman
  5. Stabs Line Info Retriever
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. unit lineinfo;
  13. interface
  14. {$IFDEF OS2}
  15. {$DEFINE EMX} (* EMX is the only possibility under OS/2 at the moment *)
  16. {$ENDIF OS2}
  17. {$S-}
  18. procedure GetLineInfo(addr:dword;var func,source:string;var line:longint);
  19. implementation
  20. uses
  21. strings;
  22. const
  23. N_Function = $24;
  24. N_TextLine = $44;
  25. N_DataLine = $46;
  26. N_BssLine = $48;
  27. N_SourceFile = $64;
  28. N_IncludeFile = $84;
  29. maxstabs = 40; { size of the stabs buffer }
  30. { GDB after 4.18 uses offset to function begin
  31. in text section but OS/2 version still uses 4.16 PM }
  32. StabsFunctionRelative : boolean = true;
  33. type
  34. pstab=^tstab;
  35. tstab=packed record
  36. strpos : longint;
  37. ntype : byte;
  38. nother : byte;
  39. ndesc : word;
  40. nvalue : dword;
  41. end;
  42. { We use static variable so almost no stack is required, and is thus
  43. more safe when an error has occured in the program }
  44. var
  45. opened : boolean; { set if the file is already open }
  46. f : file; { current file }
  47. stabcnt, { amount of stabs }
  48. stabofs, { absolute stab section offset in executable }
  49. stabstrofs : longint; { absolute stabstr section offset in executable }
  50. dirlength : longint; { length of the dirctory part of the source file }
  51. stabs : array[0..maxstabs-1] of tstab; { buffer }
  52. funcstab, { stab with current function info }
  53. linestab, { stab with current line info }
  54. dirstab, { stab with current directory info }
  55. filestab : tstab; { stab with current file info }
  56. { value to subtract to addr parameter to get correct address on file }
  57. { this should be equal to the process start address in memory }
  58. processaddress : cardinal;
  59. {****************************************************************************
  60. Executable Loaders
  61. ****************************************************************************}
  62. {$if netbsd or freebsd or linux or sunos}
  63. {$define ELF32}
  64. {$endif}
  65. {$ifdef go32v2}
  66. function LoadGo32Coff:boolean;
  67. type
  68. tcoffheader=packed record
  69. mach : word;
  70. nsects : word;
  71. time : longint;
  72. sympos : longint;
  73. syms : longint;
  74. opthdr : word;
  75. flag : word;
  76. other : array[0..27] of byte;
  77. end;
  78. tcoffsechdr=packed record
  79. name : array[0..7] of char;
  80. vsize : longint;
  81. rvaofs : longint;
  82. datalen : longint;
  83. datapos : longint;
  84. relocpos : longint;
  85. lineno1 : longint;
  86. nrelocs : word;
  87. lineno2 : word;
  88. flags : longint;
  89. end;
  90. var
  91. coffheader : tcoffheader;
  92. coffsec : tcoffsechdr;
  93. i : longint;
  94. begin
  95. processaddress := 0;
  96. LoadGo32Coff:=false;
  97. stabofs:=-1;
  98. stabstrofs:=-1;
  99. { read and check header }
  100. if filesize(f)<2048+sizeof(tcoffheader) then
  101. exit;
  102. seek(f,2048);
  103. blockread(f,coffheader,sizeof(tcoffheader));
  104. if coffheader.mach<>$14c then
  105. exit;
  106. { read section info }
  107. for i:=1to coffheader.nSects do
  108. begin
  109. blockread(f,coffsec,sizeof(tcoffsechdr));
  110. if (coffsec.name[4]='b') and
  111. (coffsec.name[1]='s') and
  112. (coffsec.name[2]='t') then
  113. begin
  114. if (coffsec.name[5]='s') and
  115. (coffsec.name[6]='t') then
  116. stabstrofs:=coffsec.datapos+2048
  117. else
  118. begin
  119. stabofs:=coffsec.datapos+2048;
  120. stabcnt:=coffsec.datalen div sizeof(tstab);
  121. end;
  122. end;
  123. end;
  124. LoadGo32Coff:=(stabofs<>-1) and (stabstrofs<>-1);
  125. end;
  126. {$endif Go32v2}
  127. {$ifdef win32}
  128. function LoadPeCoff:boolean;
  129. type
  130. tdosheader = packed record
  131. e_magic : word;
  132. e_cblp : word;
  133. e_cp : word;
  134. e_crlc : word;
  135. e_cparhdr : word;
  136. e_minalloc : word;
  137. e_maxalloc : word;
  138. e_ss : word;
  139. e_sp : word;
  140. e_csum : word;
  141. e_ip : word;
  142. e_cs : word;
  143. e_lfarlc : word;
  144. e_ovno : word;
  145. e_res : array[0..3] of word;
  146. e_oemid : word;
  147. e_oeminfo : word;
  148. e_res2 : array[0..9] of word;
  149. e_lfanew : longint;
  150. end;
  151. tpeheader = packed record
  152. PEMagic : longint;
  153. Machine : word;
  154. NumberOfSections : word;
  155. TimeDateStamp : longint;
  156. PointerToSymbolTable : longint;
  157. NumberOfSymbols : longint;
  158. SizeOfOptionalHeader : word;
  159. Characteristics : word;
  160. Magic : word;
  161. MajorLinkerVersion : byte;
  162. MinorLinkerVersion : byte;
  163. SizeOfCode : longint;
  164. SizeOfInitializedData : longint;
  165. SizeOfUninitializedData : longint;
  166. AddressOfEntryPoint : longint;
  167. BaseOfCode : longint;
  168. BaseOfData : longint;
  169. ImageBase : longint;
  170. SectionAlignment : longint;
  171. FileAlignment : longint;
  172. MajorOperatingSystemVersion : word;
  173. MinorOperatingSystemVersion : word;
  174. MajorImageVersion : word;
  175. MinorImageVersion : word;
  176. MajorSubsystemVersion : word;
  177. MinorSubsystemVersion : word;
  178. Reserved1 : longint;
  179. SizeOfImage : longint;
  180. SizeOfHeaders : longint;
  181. CheckSum : longint;
  182. Subsystem : word;
  183. DllCharacteristics : word;
  184. SizeOfStackReserve : longint;
  185. SizeOfStackCommit : longint;
  186. SizeOfHeapReserve : longint;
  187. SizeOfHeapCommit : longint;
  188. LoaderFlags : longint;
  189. NumberOfRvaAndSizes : longint;
  190. DataDirectory : array[1..$80] of byte;
  191. end;
  192. tcoffsechdr=packed record
  193. name : array[0..7] of char;
  194. vsize : longint;
  195. rvaofs : longint;
  196. datalen : longint;
  197. datapos : longint;
  198. relocpos : longint;
  199. lineno1 : longint;
  200. nrelocs : word;
  201. lineno2 : word;
  202. flags : longint;
  203. end;
  204. var
  205. dosheader : tdosheader;
  206. peheader : tpeheader;
  207. coffsec : tcoffsechdr;
  208. i : longint;
  209. begin
  210. processaddress := 0;
  211. LoadPeCoff:=false;
  212. stabofs:=-1;
  213. stabstrofs:=-1;
  214. { read and check header }
  215. if filesize(f)<sizeof(dosheader) then
  216. exit;
  217. blockread(f,dosheader,sizeof(tdosheader));
  218. seek(f,dosheader.e_lfanew);
  219. blockread(f,peheader,sizeof(tpeheader));
  220. if peheader.pemagic<>$4550 then
  221. exit;
  222. { read section info }
  223. for i:=1to peheader.NumberOfSections do
  224. begin
  225. blockread(f,coffsec,sizeof(tcoffsechdr));
  226. if (coffsec.name[4]='b') and
  227. (coffsec.name[1]='s') and
  228. (coffsec.name[2]='t') then
  229. begin
  230. if (coffsec.name[5]='s') and
  231. (coffsec.name[6]='t') then
  232. stabstrofs:=coffsec.datapos
  233. else
  234. begin
  235. stabofs:=coffsec.datapos;
  236. stabcnt:=coffsec.datalen div sizeof(tstab);
  237. end;
  238. end;
  239. end;
  240. LoadPeCoff:=(stabofs<>-1) and (stabstrofs<>-1);
  241. end;
  242. {$endif Win32}
  243. {$IFDEF EMX}
  244. function LoadEMXaout: boolean;
  245. type
  246. TDosHeader = packed record
  247. e_magic : word;
  248. e_cblp : word;
  249. e_cp : word;
  250. e_crlc : word;
  251. e_cparhdr : word;
  252. e_minalloc : word;
  253. e_maxalloc : word;
  254. e_ss : word;
  255. e_sp : word;
  256. e_csum : word;
  257. e_ip : word;
  258. e_cs : word;
  259. e_lfarlc : word;
  260. e_ovno : word;
  261. e_res : array[0..3] of word;
  262. e_oemid : word;
  263. e_oeminfo : word;
  264. e_res2 : array[0..9] of word;
  265. e_lfanew : longint;
  266. end;
  267. TEmxHeader = packed record
  268. Version: array [1..16] of char;
  269. Bound: word;
  270. AoutOfs: longint;
  271. Options: array [1..42] of char;
  272. end;
  273. TAoutHeader = packed record
  274. Magic: word;
  275. Machine: byte;
  276. Flags: byte;
  277. TextSize: longint;
  278. DataSize: longint;
  279. BssSize: longint;
  280. SymbSize: longint;
  281. EntryPoint: longint;
  282. TextRelocSize: longint;
  283. DataRelocSize: longint;
  284. end;
  285. const
  286. StartPageSize = $1000;
  287. var
  288. DosHeader: TDosHeader;
  289. EmxHeader: TEmxHeader;
  290. AoutHeader: TAoutHeader;
  291. S4: string [4];
  292. begin
  293. processaddress := 0;
  294. LoadEMXaout := false;
  295. StabOfs := -1;
  296. StabStrOfs := -1;
  297. { read and check header }
  298. if FileSize (F) > SizeOf (DosHeader) then
  299. begin
  300. BlockRead (F, DosHeader, SizeOf (TDosHeader));
  301. Seek (F, DosHeader.e_cparhdr shl 4);
  302. BlockRead (F, EmxHeader, SizeOf (TEmxHeader));
  303. S4 [0] := #4;
  304. Move (EmxHeader.Version, S4 [1], 4);
  305. if S4 = 'emx ' then
  306. begin
  307. Seek (F, EmxHeader.AoutOfs);
  308. BlockRead (F, AoutHeader, SizeOf (TAoutHeader));
  309. if AOutHeader.Magic=$10B then
  310. StabOfs := StartPageSize
  311. else
  312. StabOfs :=EmxHeader.AoutOfs + SizeOf (TAoutHeader);
  313. StabOfs := StabOfs
  314. + AoutHeader.TextSize
  315. + AoutHeader.DataSize
  316. + AoutHeader.TextRelocSize
  317. + AoutHeader.DataRelocSize;
  318. (* I don't really know, where this "+ 4" comes from, *)
  319. (* but it seems to be correct. :-) - TH *)
  320. (* Maybe not PM *)
  321. StabCnt := AoutHeader.SymbSize div SizeOf (TStab);
  322. StabStrOfs := StabOfs + AoutHeader.SymbSize;
  323. StabsFunctionRelative:=false;
  324. LoadEMXaout := (StabOfs <> -1) and (StabStrOfs <> -1);
  325. end;
  326. end;
  327. end;
  328. {$ENDIF EMX}
  329. {$ifdef ELF32}
  330. function LoadElf32:boolean;
  331. type
  332. telf32header=packed record
  333. magic0123 : longint;
  334. file_class : byte;
  335. data_encoding : byte;
  336. file_version : byte;
  337. padding : array[$07..$0f] of byte;
  338. e_type : word;
  339. e_machine : word;
  340. e_version : longword;
  341. e_entry : longword; // entrypoint
  342. e_phoff : longword; // program header offset
  343. e_shoff : longword; // sections header offset
  344. e_flags : longword;
  345. e_ehsize : word; // elf header size in bytes
  346. e_phentsize : word; // size of an entry in the program header array
  347. e_phnum : word; // 0..e_phnum-1 of entrys
  348. e_shentsize : word; // size of an entry in sections header array
  349. e_shnum : word; // 0..e_shnum-1 of entrys
  350. e_shstrndx : word; // index of string section header
  351. end;
  352. telf32sechdr=packed record
  353. sh_name : longword;
  354. sh_type : longword;
  355. sh_flags : longword;
  356. sh_addr : longword;
  357. sh_offset : longword;
  358. sh_size : longword;
  359. sh_link : longword;
  360. sh_info : longword;
  361. sh_addralign : longword;
  362. sh_entsize : longword;
  363. end;
  364. var
  365. elfheader : telf32header;
  366. elfsec : telf32sechdr;
  367. secnames : array[0..255] of char;
  368. pname : pchar;
  369. i : longint;
  370. begin
  371. processaddress := 0;
  372. LoadElf32:=false;
  373. stabofs:=-1;
  374. stabstrofs:=-1;
  375. { read and check header }
  376. if filesize(f)<sizeof(telf32header) then
  377. exit;
  378. blockread(f,elfheader,sizeof(telf32header));
  379. {$ifdef ENDIAN_LITTLE}
  380. if elfheader.magic0123<>$464c457f then
  381. exit;
  382. {$endif ENDIAN_LITTLE}
  383. {$ifdef ENDIAN_BIG}
  384. if elfheader.magic0123<>$7f454c46 then
  385. exit;
  386. { this seems to be at least the case for m68k cpu PM }
  387. {$ifdef m68k}
  388. {StabsFunctionRelative:=false;}
  389. {$endif m68k}
  390. {$endif ENDIAN_BIG}
  391. if elfheader.e_shentsize<>sizeof(telf32sechdr) then
  392. exit;
  393. { read section names }
  394. seek(f,elfheader.e_shoff+elfheader.e_shstrndx*cardinal(sizeof(telf32sechdr)));
  395. blockread(f,elfsec,sizeof(telf32sechdr));
  396. seek(f,elfsec.sh_offset);
  397. blockread(f,secnames,sizeof(secnames));
  398. { read section info }
  399. seek(f,elfheader.e_shoff);
  400. for i:=1to elfheader.e_shnum do
  401. begin
  402. blockread(f,elfsec,sizeof(telf32sechdr));
  403. pname:=@secnames[elfsec.sh_name];
  404. if (pname[4]='b') and
  405. (pname[1]='s') and
  406. (pname[2]='t') then
  407. begin
  408. if (pname[5]='s') and
  409. (pname[6]='t') then
  410. stabstrofs:=elfsec.sh_offset
  411. else
  412. begin
  413. stabofs:=elfsec.sh_offset;
  414. stabcnt:=elfsec.sh_size div sizeof(tstab);
  415. end;
  416. end;
  417. end;
  418. LoadElf32:=(stabofs<>-1) and (stabstrofs<>-1);
  419. end;
  420. {$endif ELF32}
  421. {$ifdef beos}
  422. {$i osposixh.inc}
  423. {$i syscall.inc}
  424. {$i beos.inc}
  425. function get_next_image_info(team: team_id; var cookie:longint; var info:image_info; size: size_t) : status_t;cdecl; external 'root' name '_get_next_image_info';
  426. function LoadElf32Beos:boolean;
  427. type
  428. telf32header=packed record
  429. magic0123 : longint;
  430. file_class : byte;
  431. data_encoding : byte;
  432. file_version : byte;
  433. padding : array[$07..$0f] of byte;
  434. e_type : word;
  435. e_machine : word;
  436. e_version : longword;
  437. e_entry : longword; // entrypoint
  438. e_phoff : longword; // program header offset
  439. e_shoff : longword; // sections header offset
  440. e_flags : longword;
  441. e_ehsize : word; // elf header size in bytes
  442. e_phentsize : word; // size of an entry in the program header array
  443. e_phnum : word; // 0..e_phnum-1 of entrys
  444. e_shentsize : word; // size of an entry in sections header array
  445. e_shnum : word; // 0..e_shnum-1 of entrys
  446. e_shstrndx : word; // index of string section header
  447. end;
  448. telf32sechdr=packed record
  449. sh_name : longword;
  450. sh_type : longword;
  451. sh_flags : longword;
  452. sh_addr : longword;
  453. sh_offset : longword;
  454. sh_size : longword;
  455. sh_link : longword;
  456. sh_info : longword;
  457. sh_addralign : longword;
  458. sh_entsize : longword;
  459. end;
  460. var
  461. elfheader : telf32header;
  462. elfsec : telf32sechdr;
  463. secnames : array[0..255] of char;
  464. pname : pchar;
  465. i : longint;
  466. cookie : longint;
  467. info : image_info;
  468. result : status_t;
  469. begin
  470. cookie := 0;
  471. fillchar(info, sizeof(image_info), 0);
  472. get_next_image_info(0,cookie,info,sizeof(info));
  473. if (info._type = B_APP_IMAGE) then
  474. processaddress := cardinal(info.text)
  475. else
  476. processaddress := 0;
  477. LoadElf32Beos:=false;
  478. stabofs:=-1;
  479. stabstrofs:=-1;
  480. { read and check header }
  481. if filesize(f)<sizeof(telf32header) then
  482. exit;
  483. blockread(f,elfheader,sizeof(telf32header));
  484. {$ifdef ENDIAN_LITTLE}
  485. if elfheader.magic0123<>$464c457f then
  486. exit;
  487. {$endif ENDIAN_LITTLE}
  488. {$ifdef ENDIAN_BIG}
  489. if elfheader.magic0123<>$7f454c46 then
  490. exit;
  491. {$endif ENDIAN_BIG}
  492. if elfheader.e_shentsize<>sizeof(telf32sechdr) then
  493. exit;
  494. { read section names }
  495. seek(f,elfheader.e_shoff+elfheader.e_shstrndx*cardinal(sizeof(telf32sechdr)));
  496. blockread(f,elfsec,sizeof(telf32sechdr));
  497. seek(f,elfsec.sh_offset);
  498. blockread(f,secnames,sizeof(secnames));
  499. { read section info }
  500. seek(f,elfheader.e_shoff);
  501. for i:=1to elfheader.e_shnum do
  502. begin
  503. blockread(f,elfsec,sizeof(telf32sechdr));
  504. pname:=@secnames[elfsec.sh_name];
  505. if (pname[4]='b') and
  506. (pname[1]='s') and
  507. (pname[2]='t') then
  508. begin
  509. if (pname[5]='s') and
  510. (pname[6]='t') then
  511. stabstrofs:=elfsec.sh_offset
  512. else
  513. begin
  514. stabofs:=elfsec.sh_offset;
  515. stabcnt:=elfsec.sh_size div sizeof(tstab);
  516. end;
  517. end;
  518. end;
  519. LoadElf32Beos:=(stabofs<>-1) and (stabstrofs<>-1);
  520. end;
  521. {$endif beos}
  522. {$ifdef netware}
  523. {the nlm format is not documented but we have the sources for
  524. binutils ;-) }
  525. function LoadNlmNetware:boolean;
  526. type str255 = string [255];
  527. Const NLM_FileBegin = 'NetWare Loadable Module'#$1A;
  528. NLM_InternalFixedHdrSize = 130;
  529. NLM_InternalVersionHdrSize = 32;
  530. NLM_InternalExtHdrSize = 124;
  531. var HdrChk : string[24];
  532. name : string [30];
  533. valid : boolean;
  534. dataOffset,align:longint;
  535. function getByte : byte;
  536. var b : byte;
  537. begin
  538. blockread (f, b, 1);
  539. getByte := b;
  540. end;
  541. procedure skip (bytes : integer);
  542. begin
  543. seek (f, filepos (f)+bytes);
  544. end;
  545. procedure skipLString;
  546. begin
  547. skip (getByte+1);
  548. end;
  549. function getNullString : str255;
  550. var c : char;
  551. s : str255;
  552. begin
  553. s := '';
  554. c := char (getbyte);
  555. while (c <> #0) do
  556. begin
  557. s := s + c;
  558. c := char (getbyte);
  559. end;
  560. getNullString := s;
  561. end;
  562. function getFixString (Len : byte) : str255;
  563. var i : byte;
  564. s : string;
  565. begin
  566. s := '';
  567. for i := 1 to Len do
  568. s := s + char (getbyte);
  569. getFixString := s;
  570. end;
  571. procedure getLongint (var l : longint);
  572. begin
  573. blockread (f, l, 4);
  574. end;
  575. begin
  576. LoadNlmNetware:=false;
  577. stabofs:=-1;
  578. stabstrofs:=-1;
  579. processaddress := System.NetwareCodeStartAddress;
  580. setlength(HdrChk,24);
  581. blockread (f,HdrChk[1],24);
  582. if HdrChk <> NLM_FileBegin then exit;
  583. Seek (f, NLM_InternalFixedHdrSize);
  584. {Read the Variable header}
  585. skipLString; {Description}
  586. skip (4 {Stacksize} + 4{Reserved} +5{oldThreadName});
  587. skipLString; {ScreenName}
  588. skipLString; {threadName}
  589. dataOffset := 0;
  590. valid := true;
  591. repeat
  592. name := getFixString (8);
  593. if (name = 'VeRsIoN#') then
  594. Skip (NLM_InternalVersionHdrSize-8)
  595. else
  596. if (name = 'CoPyRiGh') then
  597. begin
  598. skip(2); // T=
  599. skipLString; {Copyright}
  600. end else
  601. if (name = 'MeSsAgEs') then
  602. skip (NLM_InternalExtHdrSize - 8)
  603. else
  604. if (name = 'CuStHeAd') then
  605. begin
  606. Skip(4); {hdrLength}
  607. getLongint (dataOffset);
  608. Skip(4+8); {dataLength(4), dataStamp(8) or hdrLength-4 ?}
  609. valid := false;
  610. end else
  611. Valid := false;
  612. until not valid;
  613. if dataOffset = 0 then exit;
  614. Seek (F, dataOffset);
  615. Repeat
  616. Name := GetNullString;
  617. align := 4 - ((length (Name) + 1) MOD 4);
  618. Skip (align);
  619. if (Name = '.stab') then
  620. begin
  621. getLongint (stabofs);
  622. getLongint (stabcnt); {stabLength}
  623. stabcnt:=stabcnt div sizeof(tstab);
  624. end else
  625. if (Name = '.stabstr') then
  626. begin
  627. getLongint (stabStrOfs);
  628. Skip (4); {stabStrLength}
  629. if stabofs <> 0 then name := ''; {skip other sections}
  630. end else
  631. Skip (8);
  632. until Name = '';
  633. LoadNlmNetware := (stabofs<>-1) and (stabstrofs<>-1);
  634. end;
  635. {$endif}
  636. {****************************************************************************
  637. Executable Open/Close
  638. ****************************************************************************}
  639. procedure CloseStabs;
  640. begin
  641. close(f);
  642. opened:=false;
  643. end;
  644. function OpenStabs:boolean;
  645. var
  646. ofm : word;
  647. begin
  648. OpenStabs:=false;
  649. assign(f,paramstr(0));
  650. {$I-}
  651. ofm:=filemode;
  652. filemode:=$40;
  653. reset(f,1);
  654. filemode:=ofm;
  655. {$I+}
  656. if ioresult<>0 then
  657. exit;
  658. opened:=true;
  659. {$ifdef go32v2}
  660. if LoadGo32Coff then
  661. begin
  662. OpenStabs:=true;
  663. exit;
  664. end;
  665. {$endif}
  666. {$IFDEF EMX}
  667. if LoadEMXaout then
  668. begin
  669. OpenStabs:=true;
  670. exit;
  671. end;
  672. {$ENDIF EMX}
  673. {$ifdef win32}
  674. if LoadPECoff then
  675. begin
  676. OpenStabs:=true;
  677. exit;
  678. end;
  679. {$endif}
  680. {$ifdef ELF32}
  681. if LoadElf32 then
  682. begin
  683. OpenStabs:=true;
  684. exit;
  685. end;
  686. {$endif}
  687. {$ifdef Beos}
  688. if LoadElf32Beos then
  689. begin
  690. OpenStabs:=true;
  691. exit;
  692. end;
  693. {$endif}
  694. {$ifdef netware}
  695. if LoadNlmNetware then
  696. begin
  697. OpenStabs := true;
  698. exit;
  699. end;
  700. {$endif}
  701. CloseStabs;
  702. end;
  703. {$Q-}
  704. { this avoids problems with some targets PM }
  705. procedure GetLineInfo(addr:dword;var func,source:string;var line:longint);
  706. var
  707. res : {$ifdef tp}integer{$else}longint{$endif};
  708. stabsleft,
  709. stabscnt,i : longint;
  710. found : boolean;
  711. lastfunc : tstab;
  712. begin
  713. fillchar(func,high(func)+1,0);
  714. fillchar(source,high(source)+1,0);
  715. line:=0;
  716. if not opened then
  717. begin
  718. if not OpenStabs then
  719. exit;
  720. end;
  721. { correct the value to the correct address in the file }
  722. { processaddress is set in OpenStabs }
  723. addr := addr - processaddress;
  724. fillchar(funcstab,sizeof(tstab),0);
  725. fillchar(filestab,sizeof(tstab),0);
  726. fillchar(dirstab,sizeof(tstab),0);
  727. fillchar(linestab,sizeof(tstab),0);
  728. fillchar(lastfunc,sizeof(tstab),0);
  729. found:=false;
  730. seek(f,stabofs);
  731. stabsleft:=stabcnt;
  732. repeat
  733. if stabsleft>maxstabs then
  734. stabscnt:=maxstabs
  735. else
  736. stabscnt:=stabsleft;
  737. blockread(f,stabs,stabscnt*sizeof(tstab),res);
  738. stabscnt:=res div sizeof(tstab);
  739. for i:=0 to stabscnt-1 do
  740. begin
  741. case stabs[i].ntype of
  742. N_BssLine,
  743. N_DataLine,
  744. N_TextLine :
  745. begin
  746. if (stabs[i].ntype=N_TextLine) and StabsFunctionRelative then
  747. inc(stabs[i].nvalue,lastfunc.nvalue);
  748. if (stabs[i].nvalue<=addr) and
  749. (stabs[i].nvalue>linestab.nvalue) then
  750. begin
  751. { if it's equal we can stop and take the last info }
  752. if stabs[i].nvalue=addr then
  753. found:=true
  754. else
  755. linestab:=stabs[i];
  756. end;
  757. end;
  758. N_Function :
  759. begin
  760. lastfunc:=stabs[i];
  761. if (stabs[i].nvalue<=addr) and
  762. (stabs[i].nvalue>funcstab.nvalue) then
  763. begin
  764. funcstab:=stabs[i];
  765. fillchar(linestab,sizeof(tstab),0);
  766. end;
  767. end;
  768. N_SourceFile,
  769. N_IncludeFile :
  770. begin
  771. if (stabs[i].nvalue<=addr) and
  772. (stabs[i].nvalue>=filestab.nvalue) then
  773. begin
  774. { if same value and type then the first one
  775. contained the directory PM }
  776. if (stabs[i].nvalue=filestab.nvalue) and
  777. (stabs[i].ntype=filestab.ntype) then
  778. dirstab:=filestab
  779. else
  780. fillchar(dirstab,sizeof(tstab),0);
  781. filestab:=stabs[i];
  782. fillchar(linestab,sizeof(tstab),0);
  783. { if new file then func is not valid anymore PM }
  784. if stabs[i].ntype=N_SourceFile then
  785. begin
  786. fillchar(funcstab,sizeof(tstab),0);
  787. fillchar(lastfunc,sizeof(tstab),0);
  788. end;
  789. end;
  790. end;
  791. end;
  792. end;
  793. dec(stabsleft,stabscnt);
  794. until found or (stabsleft=0);
  795. { get the line,source,function info }
  796. line:=linestab.ndesc;
  797. if dirstab.ntype<>0 then
  798. begin
  799. seek(f,stabstrofs+dirstab.strpos);
  800. blockread(f,source[1],high(source)-1,res);
  801. dirlength:=strlen(@source[1]);
  802. source[0]:=chr(dirlength);
  803. end
  804. else
  805. dirlength:=0;
  806. if filestab.ntype<>0 then
  807. begin
  808. seek(f,stabstrofs+filestab.strpos);
  809. blockread(f,source[dirlength+1],high(source)-(dirlength+1),res);
  810. source[0]:=chr(strlen(@source[1]));
  811. end;
  812. if funcstab.ntype<>0 then
  813. begin
  814. seek(f,stabstrofs+funcstab.strpos);
  815. blockread(f,func[1],high(func)-1,res);
  816. func[0]:=chr(strlen(@func[1]));
  817. i:=pos(':',func);
  818. if i>0 then
  819. Delete(func,i,255);
  820. end;
  821. end;
  822. function StabBackTraceStr(addr:Pointer):shortstring;
  823. var
  824. func,
  825. source : string;
  826. hs : string[32];
  827. line : longint;
  828. Store : TBackTraceStrFunc;
  829. begin
  830. { reset to prevent infinite recursion if problems inside the code PM }
  831. Store:=BackTraceStrFunc;
  832. BackTraceStrFunc:=@SysBackTraceStr;
  833. GetLineInfo(dword(addr),func,source,line);
  834. { create string }
  835. StabBackTraceStr:=' 0x'+HexStr(Longint(addr),8);
  836. if func<>'' then
  837. StabBackTraceStr:=StabBackTraceStr+' '+func;
  838. if source<>'' then
  839. begin
  840. if func<>'' then
  841. StabBackTraceStr:=StabBackTraceStr+', ';
  842. if line<>0 then
  843. begin
  844. str(line,hs);
  845. StabBackTraceStr:=StabBackTraceStr+' line '+hs;
  846. end;
  847. StabBackTraceStr:=StabBackTraceStr+' of '+source;
  848. end;
  849. if Opened then
  850. BackTraceStrFunc:=Store;
  851. end;
  852. initialization
  853. BackTraceStrFunc:=@StabBackTraceStr;
  854. opened := false;
  855. finalization
  856. if opened then
  857. CloseStabs;
  858. end.
  859. {
  860. $Log$
  861. Revision 1.17 2003-03-17 15:30:06 armin
  862. + netware support
  863. + opened was not initialized
  864. Revision 1.16 2003/03/17 14:30:11 peter
  865. * changed address parameter/return values to pointer instead
  866. of longint
  867. Revision 1.15 2003/02/07 20:55:06 marco
  868. * fix from oco
  869. Revision 1.14 2003/02/01 22:31:34 marco
  870. * Last change broke beos. Fixed.
  871. Revision 1.13 2003/01/14 16:17:37 peter
  872. * remove wrong hasunix, replaced with elf32 define which
  873. is set for freebsd,netbsd,linux or sunos
  874. Revision 1.12 2003/01/10 21:35:48 marco
  875. * hasunix fix (my first commit from beos :-)
  876. Revision 1.11 2002/09/07 15:07:45 peter
  877. * old logs removed and tabs fixed
  878. Revision 1.10 2002/09/07 11:09:40 carl
  879. * stack checking supported for all systems
  880. Revision 1.9 2002/05/31 13:37:24 marco
  881. * more Renamefest
  882. }