lineinfo.pp 33 KB

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