lineinfo.pp 29 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135
  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. {$IFDEF OS2}
  14. {$DEFINE EMX} (* EMX is the only possibility under OS/2 at the moment *)
  15. {$ENDIF OS2}
  16. {$S-}
  17. procedure GetLineInfo(addr:ptruint;var func,source:string;var line:longint);
  18. implementation
  19. uses
  20. strings;
  21. const
  22. N_Function = $24;
  23. N_TextLine = $44;
  24. N_DataLine = $46;
  25. N_BssLine = $48;
  26. N_SourceFile = $64;
  27. N_IncludeFile = $84;
  28. maxstabs = 40; { size of the stabs buffer }
  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 = true;
  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. opened : boolean; { set if the file is already open }
  45. f : file; { current file }
  46. stabcnt, { amount of stabs }
  47. stabofs, { absolute stab section offset in executable }
  48. stabstrofs : longint; { absolute stabstr section offset in executable }
  49. dirlength : longint; { length of the dirctory part of the source file }
  50. stabs : array[0..maxstabs-1] of tstab; { buffer }
  51. funcstab, { stab with current function info }
  52. linestab, { stab with current line info }
  53. dirstab, { stab with current directory info }
  54. filestab : tstab; { stab with current file info }
  55. { value to subtract to addr parameter to get correct address on file }
  56. { this should be equal to the process start address in memory }
  57. processaddress : cardinal;
  58. {****************************************************************************
  59. Executable Loaders
  60. ****************************************************************************}
  61. {$if defined(netbsd) or defined(freebsd) or defined(linux) or defined(sunos)}
  62. {$ifdef cpu64}
  63. {$define ELF64}
  64. {$else}
  65. {$define ELF32}
  66. {$endif}
  67. {$endif}
  68. {$if defined(win32) or defined(wince)}
  69. {$define PE32}
  70. {$endif}
  71. {$ifdef netwlibc}
  72. {$define netware}
  73. {$endif}
  74. {$ifdef netware}
  75. const SIZE_OF_NLM_INTERNAL_FIXED_HEADER = 130;
  76. SIZE_OF_NLM_INTERNAL_VERSION_HEADER = 32;
  77. SIZE_OF_NLM_INTERNAL_EXTENDED_HEADER = 124;
  78. function loadNetwareNLM:boolean;
  79. var valid : boolean;
  80. name : string;
  81. StabLength,
  82. StabStrLength,
  83. alignAmount,
  84. hdrLength,
  85. dataOffset,
  86. dataLength : longint;
  87. function getByte:byte;
  88. begin
  89. BlockRead (f,getByte,1);
  90. end;
  91. procedure Skip (bytes : longint);
  92. var i : longint;
  93. begin
  94. for i := 1 to bytes do getbyte;
  95. end;
  96. function getLString : String;
  97. var Res:string;
  98. begin
  99. blockread (F, res, 1);
  100. if length (res) > 0 THEN
  101. blockread (F, res[1], length (res));
  102. getbyte;
  103. getLString := res;
  104. end;
  105. function getFixString (Len : byte) : string;
  106. var i : byte;
  107. begin
  108. getFixString := '';
  109. for I := 1 to Len do
  110. getFixString := getFixString + char (getbyte);
  111. end;
  112. function get0String : string;
  113. var c : char;
  114. begin
  115. get0String := '';
  116. c := char (getbyte);
  117. while (c <> #0) do
  118. begin
  119. get0String := get0String + c;
  120. c := char (getbyte);
  121. end;
  122. end;
  123. function getword : word;
  124. begin
  125. blockread (F, getword, 2);
  126. end;
  127. function getint32 : longint;
  128. begin
  129. blockread (F, getint32, 4);
  130. end;
  131. begin
  132. processaddress := 0;
  133. LoadNetwareNLM:=false;
  134. stabofs:=-1;
  135. stabstrofs:=-1;
  136. { read and check header }
  137. Skip (SIZE_OF_NLM_INTERNAL_FIXED_HEADER);
  138. getLString; // NLM Description
  139. getInt32; // Stacksize
  140. getInt32; // Reserved
  141. skip(5); // old Thread Name
  142. getLString; // Screen Name
  143. getLString; // Thread Name
  144. hdrLength := -1;
  145. dataOffset := -1;
  146. dataLength := -1;
  147. valid := true;
  148. repeat
  149. name := getFixString (8);
  150. if (name = 'VeRsIoN#') then
  151. begin
  152. Skip (SIZE_OF_NLM_INTERNAL_VERSION_HEADER-8);
  153. end else
  154. if (name = 'CoPyRiGh') then
  155. begin
  156. getword; // T=
  157. getLString; // Copyright String
  158. end else
  159. if (name = 'MeSsAgEs') then
  160. begin
  161. skip (SIZE_OF_NLM_INTERNAL_EXTENDED_HEADER - 8);
  162. end else
  163. if (name = 'CuStHeAd') then
  164. begin
  165. hdrLength := getInt32;
  166. dataOffset := getInt32;
  167. dataLength := getInt32;
  168. Skip (8); // dataStamp
  169. Valid := false;
  170. end else
  171. Valid := false;
  172. until not valid;
  173. if (hdrLength = -1) or (dataOffset = -1) or (dataLength = -1) then
  174. exit;
  175. (* The format of the section information is:
  176. null terminated section name
  177. zeroes to adjust to 4 byte boundary
  178. 4 byte section data file pointer
  179. 4 byte section size *)
  180. Seek (F, dataOffset);
  181. stabOfs := 0;
  182. stabStrOfs := 0;
  183. Repeat
  184. Name := Get0String;
  185. alignAmount := 4 - ((length (Name) + 1) MOD 4);
  186. Skip (alignAmount);
  187. if (Name = '.stab') then
  188. begin
  189. stabOfs := getInt32;
  190. stabLength := getInt32;
  191. stabcnt:=stabLength div sizeof(tstab);
  192. end else
  193. if (Name = '.stabstr') then
  194. begin
  195. stabStrOfs := getInt32;
  196. stabStrLength := getInt32;
  197. end else
  198. Skip (8);
  199. until (Name = '') or ((StabOfs <> 0) and (stabStrOfs <> 0));
  200. Seek (F,stabOfs);
  201. //if (StabOfs = 0) then __ConsolePrintf ('StabOfs = 0');
  202. //if (StabStrOfs = 0) then __ConsolePrintf ('StabStrOfs = 0');
  203. LoadNetwareNLM := ((stabOfs > 0) and (stabStrOfs > 0));
  204. end;
  205. {$endif}
  206. {$ifdef go32v2}
  207. function LoadGo32Coff:boolean;
  208. type
  209. tcoffheader=packed record
  210. mach : word;
  211. nsects : word;
  212. time : longint;
  213. sympos : longint;
  214. syms : longint;
  215. opthdr : word;
  216. flag : word;
  217. other : array[0..27] of byte;
  218. end;
  219. tcoffsechdr=packed record
  220. name : array[0..7] of char;
  221. vsize : longint;
  222. rvaofs : longint;
  223. datalen : longint;
  224. datapos : longint;
  225. relocpos : longint;
  226. lineno1 : longint;
  227. nrelocs : word;
  228. lineno2 : word;
  229. flags : longint;
  230. end;
  231. var
  232. coffheader : tcoffheader;
  233. coffsec : tcoffsechdr;
  234. i : longint;
  235. begin
  236. processaddress := 0;
  237. LoadGo32Coff:=false;
  238. stabofs:=-1;
  239. stabstrofs:=-1;
  240. { read and check header }
  241. if filesize(f)<2048+sizeof(tcoffheader) then
  242. exit;
  243. seek(f,2048);
  244. blockread(f,coffheader,sizeof(tcoffheader));
  245. if coffheader.mach<>$14c then
  246. exit;
  247. { read section info }
  248. for i:=1to coffheader.nSects do
  249. begin
  250. blockread(f,coffsec,sizeof(tcoffsechdr));
  251. if (coffsec.name[4]='b') and
  252. (coffsec.name[1]='s') and
  253. (coffsec.name[2]='t') then
  254. begin
  255. if (coffsec.name[5]='s') and
  256. (coffsec.name[6]='t') then
  257. stabstrofs:=coffsec.datapos+2048
  258. else
  259. begin
  260. stabofs:=coffsec.datapos+2048;
  261. stabcnt:=coffsec.datalen div sizeof(tstab);
  262. end;
  263. end;
  264. end;
  265. LoadGo32Coff:=(stabofs<>-1) and (stabstrofs<>-1);
  266. end;
  267. {$endif Go32v2}
  268. {$ifdef PE32}
  269. function LoadPeCoff:boolean;
  270. type
  271. tdosheader = packed record
  272. e_magic : word;
  273. e_cblp : word;
  274. e_cp : word;
  275. e_crlc : word;
  276. e_cparhdr : word;
  277. e_minalloc : word;
  278. e_maxalloc : word;
  279. e_ss : word;
  280. e_sp : word;
  281. e_csum : word;
  282. e_ip : word;
  283. e_cs : word;
  284. e_lfarlc : word;
  285. e_ovno : word;
  286. e_res : array[0..3] of word;
  287. e_oemid : word;
  288. e_oeminfo : word;
  289. e_res2 : array[0..9] of word;
  290. e_lfanew : longint;
  291. end;
  292. tpeheader = packed record
  293. PEMagic : longint;
  294. Machine : word;
  295. NumberOfSections : word;
  296. TimeDateStamp : longint;
  297. PointerToSymbolTable : longint;
  298. NumberOfSymbols : longint;
  299. SizeOfOptionalHeader : word;
  300. Characteristics : word;
  301. Magic : word;
  302. MajorLinkerVersion : byte;
  303. MinorLinkerVersion : byte;
  304. SizeOfCode : longint;
  305. SizeOfInitializedData : longint;
  306. SizeOfUninitializedData : longint;
  307. AddressOfEntryPoint : longint;
  308. BaseOfCode : longint;
  309. BaseOfData : longint;
  310. ImageBase : longint;
  311. SectionAlignment : longint;
  312. FileAlignment : longint;
  313. MajorOperatingSystemVersion : word;
  314. MinorOperatingSystemVersion : word;
  315. MajorImageVersion : word;
  316. MinorImageVersion : word;
  317. MajorSubsystemVersion : word;
  318. MinorSubsystemVersion : word;
  319. Reserved1 : longint;
  320. SizeOfImage : longint;
  321. SizeOfHeaders : longint;
  322. CheckSum : longint;
  323. Subsystem : word;
  324. DllCharacteristics : word;
  325. SizeOfStackReserve : longint;
  326. SizeOfStackCommit : longint;
  327. SizeOfHeapReserve : longint;
  328. SizeOfHeapCommit : longint;
  329. LoaderFlags : longint;
  330. NumberOfRvaAndSizes : longint;
  331. DataDirectory : array[1..$80] of byte;
  332. end;
  333. tcoffsechdr=packed record
  334. name : array[0..7] of char;
  335. vsize : longint;
  336. rvaofs : longint;
  337. datalen : longint;
  338. datapos : longint;
  339. relocpos : longint;
  340. lineno1 : longint;
  341. nrelocs : word;
  342. lineno2 : word;
  343. flags : longint;
  344. end;
  345. var
  346. dosheader : tdosheader;
  347. peheader : tpeheader;
  348. coffsec : tcoffsechdr;
  349. i : longint;
  350. begin
  351. processaddress := 0;
  352. LoadPeCoff:=false;
  353. stabofs:=-1;
  354. stabstrofs:=-1;
  355. { read and check header }
  356. if filesize(f)<sizeof(dosheader) then
  357. exit;
  358. blockread(f,dosheader,sizeof(tdosheader));
  359. seek(f,dosheader.e_lfanew);
  360. blockread(f,peheader,sizeof(tpeheader));
  361. if peheader.pemagic<>$4550 then
  362. exit;
  363. { read section info }
  364. for i:=1to peheader.NumberOfSections do
  365. begin
  366. blockread(f,coffsec,sizeof(tcoffsechdr));
  367. if (coffsec.name[4]='b') and
  368. (coffsec.name[1]='s') and
  369. (coffsec.name[2]='t') then
  370. begin
  371. if (coffsec.name[5]='s') and
  372. (coffsec.name[6]='t') then
  373. stabstrofs:=coffsec.datapos
  374. else
  375. begin
  376. stabofs:=coffsec.datapos;
  377. stabcnt:=coffsec.datalen div sizeof(tstab);
  378. end;
  379. end;
  380. end;
  381. LoadPeCoff:=(stabofs<>-1) and (stabstrofs<>-1);
  382. end;
  383. {$endif PE32}
  384. {$IFDEF EMX}
  385. function LoadEMXaout: boolean;
  386. type
  387. TDosHeader = packed record
  388. e_magic : word;
  389. e_cblp : word;
  390. e_cp : word;
  391. e_crlc : word;
  392. e_cparhdr : word;
  393. e_minalloc : word;
  394. e_maxalloc : word;
  395. e_ss : word;
  396. e_sp : word;
  397. e_csum : word;
  398. e_ip : word;
  399. e_cs : word;
  400. e_lfarlc : word;
  401. e_ovno : word;
  402. e_res : array[0..3] of word;
  403. e_oemid : word;
  404. e_oeminfo : word;
  405. e_res2 : array[0..9] of word;
  406. e_lfanew : longint;
  407. end;
  408. TEmxHeader = packed record
  409. Version: array [1..16] of char;
  410. Bound: word;
  411. AoutOfs: longint;
  412. Options: array [1..42] of char;
  413. end;
  414. TAoutHeader = packed record
  415. Magic: word;
  416. Machine: byte;
  417. Flags: byte;
  418. TextSize: longint;
  419. DataSize: longint;
  420. BssSize: longint;
  421. SymbSize: longint;
  422. EntryPoint: longint;
  423. TextRelocSize: longint;
  424. DataRelocSize: longint;
  425. end;
  426. const
  427. StartPageSize = $1000;
  428. var
  429. DosHeader: TDosHeader;
  430. EmxHeader: TEmxHeader;
  431. AoutHeader: TAoutHeader;
  432. S4: string [4];
  433. begin
  434. processaddress := 0;
  435. LoadEMXaout := false;
  436. StabOfs := -1;
  437. StabStrOfs := -1;
  438. { read and check header }
  439. if FileSize (F) > SizeOf (DosHeader) then
  440. begin
  441. BlockRead (F, DosHeader, SizeOf (TDosHeader));
  442. Seek (F, DosHeader.e_cparhdr shl 4);
  443. BlockRead (F, EmxHeader, SizeOf (TEmxHeader));
  444. S4 [0] := #4;
  445. Move (EmxHeader.Version, S4 [1], 4);
  446. if S4 = 'emx ' then
  447. begin
  448. Seek (F, EmxHeader.AoutOfs);
  449. BlockRead (F, AoutHeader, SizeOf (TAoutHeader));
  450. if AOutHeader.Magic=$10B then
  451. StabOfs := StartPageSize
  452. else
  453. StabOfs :=EmxHeader.AoutOfs + SizeOf (TAoutHeader);
  454. StabOfs := StabOfs
  455. + AoutHeader.TextSize
  456. + AoutHeader.DataSize
  457. + AoutHeader.TextRelocSize
  458. + AoutHeader.DataRelocSize;
  459. StabCnt := AoutHeader.SymbSize div SizeOf (TStab);
  460. StabStrOfs := StabOfs + AoutHeader.SymbSize;
  461. StabsFunctionRelative:=false;
  462. LoadEMXaout := (StabOfs <> -1) and (StabStrOfs <> -1);
  463. end;
  464. end;
  465. end;
  466. {$ENDIF EMX}
  467. {$ifdef ELF32}
  468. function LoadElf32:boolean;
  469. type
  470. telf32header=packed record
  471. magic0123 : longint;
  472. file_class : byte;
  473. data_encoding : byte;
  474. file_version : byte;
  475. padding : array[$07..$0f] of byte;
  476. e_type : word;
  477. e_machine : word;
  478. e_version : longword;
  479. e_entry : longword; // entrypoint
  480. e_phoff : longword; // program header offset
  481. e_shoff : longword; // sections header offset
  482. e_flags : longword;
  483. e_ehsize : word; // elf header size in bytes
  484. e_phentsize : word; // size of an entry in the program header array
  485. e_phnum : word; // 0..e_phnum-1 of entrys
  486. e_shentsize : word; // size of an entry in sections header array
  487. e_shnum : word; // 0..e_shnum-1 of entrys
  488. e_shstrndx : word; // index of string section header
  489. end;
  490. telf32sechdr=packed record
  491. sh_name : longword;
  492. sh_type : longword;
  493. sh_flags : longword;
  494. sh_addr : longword;
  495. sh_offset : longword;
  496. sh_size : longword;
  497. sh_link : longword;
  498. sh_info : longword;
  499. sh_addralign : longword;
  500. sh_entsize : longword;
  501. end;
  502. var
  503. elfheader : telf32header;
  504. elfsec : telf32sechdr;
  505. secnames : array[0..255] of char;
  506. pname : pchar;
  507. i : longint;
  508. begin
  509. processaddress := 0;
  510. LoadElf32:=false;
  511. stabofs:=-1;
  512. stabstrofs:=-1;
  513. { read and check header }
  514. if filesize(f)<sizeof(telf32header) then
  515. exit;
  516. blockread(f,elfheader,sizeof(telf32header));
  517. {$ifdef ENDIAN_LITTLE}
  518. if elfheader.magic0123<>$464c457f then
  519. exit;
  520. {$endif ENDIAN_LITTLE}
  521. {$ifdef ENDIAN_BIG}
  522. if elfheader.magic0123<>$7f454c46 then
  523. exit;
  524. { this seems to be at least the case for m68k cpu PM }
  525. {$ifdef cpum68k}
  526. {StabsFunctionRelative:=false;}
  527. {$endif cpum68k}
  528. {$endif ENDIAN_BIG}
  529. if elfheader.e_shentsize<>sizeof(telf32sechdr) then
  530. exit;
  531. { read section names }
  532. seek(f,elfheader.e_shoff+elfheader.e_shstrndx*cardinal(sizeof(telf32sechdr)));
  533. blockread(f,elfsec,sizeof(telf32sechdr));
  534. seek(f,elfsec.sh_offset);
  535. blockread(f,secnames,sizeof(secnames));
  536. { read section info }
  537. seek(f,elfheader.e_shoff);
  538. for i:=1to elfheader.e_shnum do
  539. begin
  540. blockread(f,elfsec,sizeof(telf32sechdr));
  541. pname:=@secnames[elfsec.sh_name];
  542. if (pname[4]='b') and
  543. (pname[1]='s') and
  544. (pname[2]='t') then
  545. begin
  546. if (pname[5]='s') and
  547. (pname[6]='t') then
  548. stabstrofs:=elfsec.sh_offset
  549. else
  550. begin
  551. stabofs:=elfsec.sh_offset;
  552. stabcnt:=elfsec.sh_size div sizeof(tstab);
  553. end;
  554. end;
  555. end;
  556. LoadElf32:=(stabofs<>-1) and (stabstrofs<>-1);
  557. end;
  558. {$endif ELF32}
  559. {$ifdef ELF64}
  560. function LoadElf64:boolean;
  561. type
  562. telf64header=packed record
  563. magic0123 : longint;
  564. file_class : byte;
  565. data_encoding : byte;
  566. file_version : byte;
  567. padding : array[$07..$0f] of byte;
  568. e_type : word;
  569. e_machine : word;
  570. e_version : longword;
  571. e_entry : int64; // entrypoint
  572. e_phoff : int64; // program header offset
  573. e_shoff : int64; // sections header offset
  574. e_flags : longword;
  575. e_ehsize : word; // elf header size in bytes
  576. e_phentsize : word; // size of an entry in the program header array
  577. e_phnum : word; // 0..e_phnum-1 of entrys
  578. e_shentsize : word; // size of an entry in sections header array
  579. e_shnum : word; // 0..e_shnum-1 of entrys
  580. e_shstrndx : word; // index of string section header
  581. end;
  582. telf64sechdr=packed record
  583. sh_name : longword;
  584. sh_type : longword;
  585. sh_flags : int64;
  586. sh_addr : int64;
  587. sh_offset : int64;
  588. sh_size : int64;
  589. sh_link : longword;
  590. sh_info : longword;
  591. sh_addralign : int64;
  592. sh_entsize : int64;
  593. end;
  594. var
  595. elfheader : telf64header;
  596. elfsec : telf64sechdr;
  597. secnames : array[0..255] of char;
  598. pname : pchar;
  599. i : longint;
  600. begin
  601. processaddress := 0;
  602. LoadElf64:=false;
  603. stabofs:=-1;
  604. stabstrofs:=-1;
  605. { read and check header }
  606. if filesize(f)<sizeof(telf64header) then
  607. exit;
  608. blockread(f,elfheader,sizeof(telf64header));
  609. {$ifdef ENDIAN_LITTLE}
  610. if elfheader.magic0123<>$464c457f then
  611. exit;
  612. {$endif ENDIAN_LITTLE}
  613. {$ifdef ENDIAN_BIG}
  614. if elfheader.magic0123<>$7f454c46 then
  615. exit;
  616. { this seems to be at least the case for m68k cpu PM }
  617. {$ifdef cpum68k}
  618. {StabsFunctionRelative:=false;}
  619. {$endif cpum68k}
  620. {$endif ENDIAN_BIG}
  621. if elfheader.e_shentsize<>sizeof(telf64sechdr) then
  622. exit;
  623. { read section names }
  624. seek(f,elfheader.e_shoff+elfheader.e_shstrndx*cardinal(sizeof(telf64sechdr)));
  625. blockread(f,elfsec,sizeof(telf64sechdr));
  626. seek(f,elfsec.sh_offset);
  627. blockread(f,secnames,sizeof(secnames));
  628. { read section info }
  629. seek(f,elfheader.e_shoff);
  630. for i:=1to elfheader.e_shnum do
  631. begin
  632. blockread(f,elfsec,sizeof(telf64sechdr));
  633. pname:=@secnames[elfsec.sh_name];
  634. if (pname[4]='b') and
  635. (pname[1]='s') and
  636. (pname[2]='t') then
  637. begin
  638. if (pname[5]='s') and
  639. (pname[6]='t') then
  640. stabstrofs:=elfsec.sh_offset
  641. else
  642. begin
  643. stabofs:=elfsec.sh_offset;
  644. stabcnt:=elfsec.sh_size div sizeof(tstab);
  645. end;
  646. end;
  647. end;
  648. LoadElf64:=(stabofs<>-1) and (stabstrofs<>-1);
  649. end;
  650. {$endif ELF64}
  651. {$ifdef beos}
  652. {$i osposixh.inc}
  653. {$i syscall.inc}
  654. {$i beos.inc}
  655. 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';
  656. function LoadElf32Beos:boolean;
  657. type
  658. telf32header=packed record
  659. magic0123 : longint;
  660. file_class : byte;
  661. data_encoding : byte;
  662. file_version : byte;
  663. padding : array[$07..$0f] of byte;
  664. e_type : word;
  665. e_machine : word;
  666. e_version : longword;
  667. e_entry : longword; // entrypoint
  668. e_phoff : longword; // program header offset
  669. e_shoff : longword; // sections header offset
  670. e_flags : longword;
  671. e_ehsize : word; // elf header size in bytes
  672. e_phentsize : word; // size of an entry in the program header array
  673. e_phnum : word; // 0..e_phnum-1 of entrys
  674. e_shentsize : word; // size of an entry in sections header array
  675. e_shnum : word; // 0..e_shnum-1 of entrys
  676. e_shstrndx : word; // index of string section header
  677. end;
  678. telf32sechdr=packed record
  679. sh_name : longword;
  680. sh_type : longword;
  681. sh_flags : longword;
  682. sh_addr : longword;
  683. sh_offset : longword;
  684. sh_size : longword;
  685. sh_link : longword;
  686. sh_info : longword;
  687. sh_addralign : longword;
  688. sh_entsize : longword;
  689. end;
  690. var
  691. elfheader : telf32header;
  692. elfsec : telf32sechdr;
  693. secnames : array[0..255] of char;
  694. pname : pchar;
  695. i : longint;
  696. cookie : longint;
  697. info : image_info;
  698. result : status_t;
  699. begin
  700. cookie := 0;
  701. fillchar(info, sizeof(image_info), 0);
  702. get_next_image_info(0,cookie,info,sizeof(info));
  703. if (info._type = B_APP_IMAGE) then
  704. processaddress := cardinal(info.text)
  705. else
  706. processaddress := 0;
  707. LoadElf32Beos:=false;
  708. stabofs:=-1;
  709. stabstrofs:=-1;
  710. { read and check header }
  711. if filesize(f)<sizeof(telf32header) then
  712. exit;
  713. blockread(f,elfheader,sizeof(telf32header));
  714. {$ifdef ENDIAN_LITTLE}
  715. if elfheader.magic0123<>$464c457f then
  716. exit;
  717. {$endif ENDIAN_LITTLE}
  718. {$ifdef ENDIAN_BIG}
  719. if elfheader.magic0123<>$7f454c46 then
  720. exit;
  721. {$endif ENDIAN_BIG}
  722. if elfheader.e_shentsize<>sizeof(telf32sechdr) then
  723. exit;
  724. { read section names }
  725. seek(f,elfheader.e_shoff+elfheader.e_shstrndx*cardinal(sizeof(telf32sechdr)));
  726. blockread(f,elfsec,sizeof(telf32sechdr));
  727. seek(f,elfsec.sh_offset);
  728. blockread(f,secnames,sizeof(secnames));
  729. { read section info }
  730. seek(f,elfheader.e_shoff);
  731. for i:=1to elfheader.e_shnum do
  732. begin
  733. blockread(f,elfsec,sizeof(telf32sechdr));
  734. pname:=@secnames[elfsec.sh_name];
  735. if (pname[4]='b') and
  736. (pname[1]='s') and
  737. (pname[2]='t') then
  738. begin
  739. if (pname[5]='s') and
  740. (pname[6]='t') then
  741. stabstrofs:=elfsec.sh_offset
  742. else
  743. begin
  744. stabofs:=elfsec.sh_offset;
  745. stabcnt:=elfsec.sh_size div sizeof(tstab);
  746. end;
  747. end;
  748. end;
  749. LoadElf32Beos:=(stabofs<>-1) and (stabstrofs<>-1);
  750. end;
  751. {$endif beos}
  752. {$ifdef darwin}
  753. type
  754. MachoFatHeader=
  755. packed record
  756. magic: longint;
  757. nfatarch: longint;
  758. end;
  759. MachoHeader=
  760. packed record
  761. magic: longword;
  762. cpu_type_t: longint;
  763. cpu_subtype_t: longint;
  764. filetype: longint;
  765. ncmds: longint;
  766. sizeofcmds: longint;
  767. flags: longint;
  768. end;
  769. cmdblock=
  770. packed record
  771. cmd: longint;
  772. cmdsize: longint;
  773. end;
  774. symbSeg=
  775. packed record
  776. symoff : longint;
  777. nsyms : longint;
  778. stroff : longint;
  779. strsize: longint;
  780. end;
  781. function readCommand: boolean;
  782. var
  783. block:cmdblock;
  784. readMore :boolean;
  785. symbolsSeg: symbSeg;
  786. begin
  787. readCommand := false;
  788. readMore := true;
  789. blockread (f, block, sizeof(block));
  790. if block.cmd = $2 then
  791. begin
  792. blockread (f, symbolsSeg, sizeof(symbolsSeg));
  793. stabstrofs:=symbolsSeg.stroff;
  794. stabofs:=symbolsSeg.symoff;
  795. stabcnt:=symbolsSeg.nsyms;
  796. readMore := false;
  797. readCommand := true;
  798. exit;
  799. end;
  800. if readMore then
  801. begin
  802. Seek(f, FilePos (f) + block.cmdsize - sizeof(block));
  803. end;
  804. end;
  805. function LoadMachO32PPC:boolean;
  806. var
  807. mh:MachoHeader;
  808. i: longint;
  809. begin
  810. StabsFunctionRelative:=false;
  811. LoadMachO32PPC := false;
  812. blockread (f, mh, sizeof(mh));
  813. for i:= 1 to mh.ncmds do
  814. begin
  815. if readCommand then
  816. begin
  817. LoadMachO32PPC := true;
  818. exit;
  819. end;
  820. end;
  821. end;
  822. {$endif darwin}
  823. {****************************************************************************
  824. Executable Open/Close
  825. ****************************************************************************}
  826. procedure CloseStabs;
  827. begin
  828. close(f);
  829. opened:=false;
  830. end;
  831. function OpenStabs:boolean;
  832. var
  833. ofm : word;
  834. begin
  835. OpenStabs:=false;
  836. assign(f,paramstr(0));
  837. {$I-}
  838. ofm:=filemode;
  839. filemode:=$40;
  840. reset(f,1);
  841. filemode:=ofm;
  842. {$I+}
  843. if ioresult<>0 then
  844. exit;
  845. opened:=true;
  846. {$ifdef go32v2}
  847. if LoadGo32Coff then
  848. begin
  849. OpenStabs:=true;
  850. exit;
  851. end;
  852. {$endif}
  853. {$IFDEF EMX}
  854. if LoadEMXaout then
  855. begin
  856. OpenStabs:=true;
  857. exit;
  858. end;
  859. {$ENDIF EMX}
  860. {$ifdef PE32}
  861. if LoadPECoff then
  862. begin
  863. OpenStabs:=true;
  864. exit;
  865. end;
  866. {$endif}
  867. {$ifdef ELF32}
  868. if LoadElf32 then
  869. begin
  870. OpenStabs:=true;
  871. exit;
  872. end;
  873. {$endif}
  874. {$ifdef ELF64}
  875. if LoadElf64 then
  876. begin
  877. OpenStabs:=true;
  878. exit;
  879. end;
  880. {$endif}
  881. {$ifdef Beos}
  882. if LoadElf32Beos then
  883. begin
  884. OpenStabs:=true;
  885. exit;
  886. end;
  887. {$endif}
  888. {$ifdef darwin}
  889. if LoadMachO32PPC then
  890. begin
  891. OpenStabs:=true;
  892. exit;
  893. end;
  894. {$endif darwin}
  895. {$ifdef netware}
  896. if LoadNetwareNLM then
  897. begin
  898. OpenStabs:=true;
  899. exit;
  900. end;
  901. {$endif}
  902. CloseStabs;
  903. end;
  904. {$Q-}
  905. { this avoids problems with some targets PM }
  906. procedure GetLineInfo(addr:ptruint;var func,source:string;var line:longint);
  907. var
  908. res : {$ifdef tp}integer{$else}longint{$endif};
  909. stabsleft,
  910. stabscnt,i : longint;
  911. found : boolean;
  912. lastfunc : tstab;
  913. begin
  914. fillchar(func,high(func)+1,0);
  915. fillchar(source,high(source)+1,0);
  916. line:=0;
  917. if not opened then
  918. begin
  919. if not OpenStabs then
  920. exit;
  921. end;
  922. { correct the value to the correct address in the file }
  923. { processaddress is set in OpenStabs }
  924. addr := addr - processaddress;
  925. //ScreenPrintfL1 (NWLoggerScreen,'addr: %x\n',addr);
  926. fillchar(funcstab,sizeof(tstab),0);
  927. fillchar(filestab,sizeof(tstab),0);
  928. fillchar(dirstab,sizeof(tstab),0);
  929. fillchar(linestab,sizeof(tstab),0);
  930. fillchar(lastfunc,sizeof(tstab),0);
  931. found:=false;
  932. seek(f,stabofs);
  933. stabsleft:=stabcnt;
  934. repeat
  935. if stabsleft>maxstabs then
  936. stabscnt:=maxstabs
  937. else
  938. stabscnt:=stabsleft;
  939. blockread(f,stabs,stabscnt*sizeof(tstab),res);
  940. stabscnt:=res div sizeof(tstab);
  941. for i:=0 to stabscnt-1 do
  942. begin
  943. case stabs[i].ntype of
  944. N_BssLine,
  945. N_DataLine,
  946. N_TextLine :
  947. begin
  948. if (stabs[i].ntype=N_TextLine) and StabsFunctionRelative then
  949. inc(stabs[i].nvalue,lastfunc.nvalue);
  950. if (stabs[i].nvalue<=addr) and
  951. (stabs[i].nvalue>linestab.nvalue) then
  952. begin
  953. { if it's equal we can stop and take the last info }
  954. if stabs[i].nvalue=addr then
  955. found:=true
  956. else
  957. linestab:=stabs[i];
  958. end;
  959. end;
  960. N_Function :
  961. begin
  962. lastfunc:=stabs[i];
  963. if (stabs[i].nvalue<=addr) and
  964. (stabs[i].nvalue>funcstab.nvalue) then
  965. begin
  966. funcstab:=stabs[i];
  967. fillchar(linestab,sizeof(tstab),0);
  968. end;
  969. end;
  970. N_SourceFile,
  971. N_IncludeFile :
  972. begin
  973. if (stabs[i].nvalue<=addr) and
  974. (stabs[i].nvalue>=filestab.nvalue) then
  975. begin
  976. { if same value and type then the first one
  977. contained the directory PM }
  978. if (stabs[i].nvalue=filestab.nvalue) and
  979. (stabs[i].ntype=filestab.ntype) then
  980. dirstab:=filestab
  981. else
  982. fillchar(dirstab,sizeof(tstab),0);
  983. filestab:=stabs[i];
  984. fillchar(linestab,sizeof(tstab),0);
  985. { if new file then func is not valid anymore PM }
  986. if stabs[i].ntype=N_SourceFile then
  987. begin
  988. fillchar(funcstab,sizeof(tstab),0);
  989. fillchar(lastfunc,sizeof(tstab),0);
  990. end;
  991. end;
  992. end;
  993. end;
  994. end;
  995. dec(stabsleft,stabscnt);
  996. until found or (stabsleft=0);
  997. { get the line,source,function info }
  998. line:=linestab.ndesc;
  999. if dirstab.ntype<>0 then
  1000. begin
  1001. seek(f,stabstrofs+dirstab.strpos);
  1002. blockread(f,source[1],high(source)-1,res);
  1003. dirlength:=strlen(@source[1]);
  1004. source[0]:=chr(dirlength);
  1005. end
  1006. else
  1007. dirlength:=0;
  1008. if filestab.ntype<>0 then
  1009. begin
  1010. seek(f,stabstrofs+filestab.strpos);
  1011. blockread(f,source[dirlength+1],high(source)-(dirlength+1),res);
  1012. source[0]:=chr(strlen(@source[1]));
  1013. end;
  1014. if funcstab.ntype<>0 then
  1015. begin
  1016. seek(f,stabstrofs+funcstab.strpos);
  1017. blockread(f,func[1],high(func)-1,res);
  1018. func[0]:=chr(strlen(@func[1]));
  1019. i:=pos(':',func);
  1020. if i>0 then
  1021. Delete(func,i,255);
  1022. end;
  1023. end;
  1024. function StabBackTraceStr(addr:Pointer):shortstring;
  1025. var
  1026. func,
  1027. source : string;
  1028. hs : string[32];
  1029. line : longint;
  1030. Store : TBackTraceStrFunc;
  1031. begin
  1032. { reset to prevent infinite recursion if problems inside the code PM }
  1033. {$ifdef netware}
  1034. dec(addr,system.NWGetCodeStart); {we need addr relative to code start on netware}
  1035. {$endif}
  1036. Store:=BackTraceStrFunc;
  1037. BackTraceStrFunc:=@SysBackTraceStr;
  1038. GetLineInfo(ptruint(addr),func,source,line);
  1039. { create string }
  1040. {$ifdef netware}
  1041. StabBackTraceStr:=' CodeStart + $'+HexStr(ptrint(addr),sizeof(ptrint)*2);
  1042. {$else}
  1043. StabBackTraceStr:=' $'+HexStr(ptrint(addr),sizeof(ptrint)*2);
  1044. {$endif}
  1045. if func<>'' then
  1046. StabBackTraceStr:=StabBackTraceStr+' '+func;
  1047. if source<>'' then
  1048. begin
  1049. if func<>'' then
  1050. StabBackTraceStr:=StabBackTraceStr+', ';
  1051. if line<>0 then
  1052. begin
  1053. str(line,hs);
  1054. StabBackTraceStr:=StabBackTraceStr+' line '+hs;
  1055. end;
  1056. StabBackTraceStr:=StabBackTraceStr+' of '+source;
  1057. end;
  1058. if Opened then
  1059. BackTraceStrFunc:=Store;
  1060. end;
  1061. initialization
  1062. BackTraceStrFunc:=@StabBackTraceStr;
  1063. finalization
  1064. if opened then
  1065. CloseStabs;
  1066. end.