lineinfo.pp 32 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265
  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. {$i syscall.inc}
  773. {$i beos.inc}
  774. 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';
  775. function LoadElf32Beos:boolean;
  776. type
  777. telf32header=packed record
  778. magic0123 : longint;
  779. file_class : byte;
  780. data_encoding : byte;
  781. file_version : byte;
  782. padding : array[$07..$0f] of byte;
  783. e_type : word;
  784. e_machine : word;
  785. e_version : longword;
  786. e_entry : longword; // entrypoint
  787. e_phoff : longword; // program header offset
  788. e_shoff : longword; // sections header offset
  789. e_flags : longword;
  790. e_ehsize : word; // elf header size in bytes
  791. e_phentsize : word; // size of an entry in the program header array
  792. e_phnum : word; // 0..e_phnum-1 of entrys
  793. e_shentsize : word; // size of an entry in sections header array
  794. e_shnum : word; // 0..e_shnum-1 of entrys
  795. e_shstrndx : word; // index of string section header
  796. end;
  797. telf32sechdr=packed record
  798. sh_name : longword;
  799. sh_type : longword;
  800. sh_flags : longword;
  801. sh_addr : longword;
  802. sh_offset : longword;
  803. sh_size : longword;
  804. sh_link : longword;
  805. sh_info : longword;
  806. sh_addralign : longword;
  807. sh_entsize : longword;
  808. end;
  809. var
  810. elfheader : telf32header;
  811. elfsec : telf32sechdr;
  812. secnames : array[0..255] of char;
  813. pname : pchar;
  814. i : longint;
  815. cookie : longint;
  816. info : image_info;
  817. result : status_t;
  818. begin
  819. cookie := 0;
  820. fillchar(info, sizeof(image_info), 0);
  821. get_next_image_info(0,cookie,info,sizeof(info));
  822. if (info._type = B_APP_IMAGE) then
  823. processaddress := cardinal(info.text)
  824. else
  825. processaddress := 0;
  826. LoadElf32Beos:=false;
  827. stabofs:=-1;
  828. stabstrofs:=-1;
  829. { read and check header }
  830. if filesize(f)<sizeof(telf32header) then
  831. exit;
  832. blockread(f,elfheader,sizeof(telf32header));
  833. {$ifdef ENDIAN_LITTLE}
  834. if elfheader.magic0123<>$464c457f then
  835. exit;
  836. {$endif ENDIAN_LITTLE}
  837. {$ifdef ENDIAN_BIG}
  838. if elfheader.magic0123<>$7f454c46 then
  839. exit;
  840. {$endif ENDIAN_BIG}
  841. if elfheader.e_shentsize<>sizeof(telf32sechdr) then
  842. exit;
  843. { read section names }
  844. seek(f,elfheader.e_shoff+elfheader.e_shstrndx*cardinal(sizeof(telf32sechdr)));
  845. blockread(f,elfsec,sizeof(telf32sechdr));
  846. seek(f,elfsec.sh_offset);
  847. blockread(f,secnames,sizeof(secnames));
  848. { read section info }
  849. seek(f,elfheader.e_shoff);
  850. for i:=1to elfheader.e_shnum do
  851. begin
  852. blockread(f,elfsec,sizeof(telf32sechdr));
  853. pname:=@secnames[elfsec.sh_name];
  854. if (pname[4]='b') and
  855. (pname[1]='s') and
  856. (pname[2]='t') then
  857. begin
  858. if (pname[5]='s') and
  859. (pname[6]='t') then
  860. stabstrofs:=elfsec.sh_offset
  861. else
  862. begin
  863. stabofs:=elfsec.sh_offset;
  864. stabcnt:=elfsec.sh_size div sizeof(tstab);
  865. end;
  866. end;
  867. end;
  868. LoadElf32Beos:=(stabofs<>-1) and (stabstrofs<>-1);
  869. end;
  870. {$endif beos}
  871. {$ifdef darwin}
  872. type
  873. MachoFatHeader=
  874. packed record
  875. magic: longint;
  876. nfatarch: longint;
  877. end;
  878. MachoHeader=
  879. packed record
  880. magic: longword;
  881. cpu_type_t: longint;
  882. cpu_subtype_t: longint;
  883. filetype: longint;
  884. ncmds: longint;
  885. sizeofcmds: longint;
  886. flags: longint;
  887. end;
  888. cmdblock=
  889. packed record
  890. cmd: longint;
  891. cmdsize: longint;
  892. end;
  893. symbSeg=
  894. packed record
  895. symoff : longint;
  896. nsyms : longint;
  897. stroff : longint;
  898. strsize: longint;
  899. end;
  900. function readCommand: boolean;
  901. var
  902. block:cmdblock;
  903. readMore :boolean;
  904. symbolsSeg: symbSeg;
  905. begin
  906. readCommand := false;
  907. readMore := true;
  908. blockread (f, block, sizeof(block));
  909. if block.cmd = $2 then
  910. begin
  911. blockread (f, symbolsSeg, sizeof(symbolsSeg));
  912. stabstrofs:=symbolsSeg.stroff;
  913. stabofs:=symbolsSeg.symoff;
  914. stabcnt:=symbolsSeg.nsyms;
  915. readMore := false;
  916. readCommand := true;
  917. exit;
  918. end;
  919. if readMore then
  920. begin
  921. Seek(f, FilePos (f) + block.cmdsize - sizeof(block));
  922. end;
  923. end;
  924. function LoadMachO32PPC:boolean;
  925. var
  926. mh:MachoHeader;
  927. i: longint;
  928. begin
  929. processaddress := 0;
  930. StabsFunctionRelative:=false;
  931. LoadMachO32PPC := false;
  932. blockread (f, mh, sizeof(mh));
  933. for i:= 1 to mh.ncmds do
  934. begin
  935. if readCommand then
  936. begin
  937. LoadMachO32PPC := true;
  938. exit;
  939. end;
  940. end;
  941. end;
  942. {$endif darwin}
  943. {****************************************************************************
  944. Executable Open/Close
  945. ****************************************************************************}
  946. procedure CloseStabs;
  947. begin
  948. close(f);
  949. opened:=false;
  950. end;
  951. function OpenStabs:boolean;
  952. var
  953. ofm : word;
  954. begin
  955. OpenStabs:=false;
  956. assign(f,paramstr(0));
  957. {$I-}
  958. ofm:=filemode;
  959. filemode:=$40;
  960. reset(f,1);
  961. filemode:=ofm;
  962. {$I+}
  963. if ioresult<>0 then
  964. exit;
  965. opened:=true;
  966. {$ifdef go32v2}
  967. if LoadGo32Coff then
  968. begin
  969. OpenStabs:=true;
  970. exit;
  971. end;
  972. {$endif}
  973. {$IFDEF EMX}
  974. if LoadEMXaout then
  975. begin
  976. OpenStabs:=true;
  977. exit;
  978. end;
  979. {$ENDIF EMX}
  980. {$ifdef PE32}
  981. if LoadPECoff then
  982. begin
  983. OpenStabs:=true;
  984. exit;
  985. end;
  986. {$endif}
  987. {$ifdef PE32PLUS}
  988. if LoadPECoff then
  989. begin
  990. OpenStabs:=true;
  991. exit;
  992. end;
  993. {$endif PE32PLUS}
  994. {$ifdef ELF32}
  995. if LoadElf32 then
  996. begin
  997. OpenStabs:=true;
  998. exit;
  999. end;
  1000. {$endif}
  1001. {$ifdef ELF64}
  1002. if LoadElf64 then
  1003. begin
  1004. OpenStabs:=true;
  1005. exit;
  1006. end;
  1007. {$endif}
  1008. {$ifdef Beos}
  1009. if LoadElf32Beos then
  1010. begin
  1011. OpenStabs:=true;
  1012. exit;
  1013. end;
  1014. {$endif}
  1015. {$ifdef darwin}
  1016. if LoadMachO32PPC then
  1017. begin
  1018. OpenStabs:=true;
  1019. exit;
  1020. end;
  1021. {$endif darwin}
  1022. {$ifdef netware}
  1023. if LoadNetwareNLM then
  1024. begin
  1025. OpenStabs:=true;
  1026. exit;
  1027. end;
  1028. {$endif}
  1029. CloseStabs;
  1030. end;
  1031. {$Q-}
  1032. { this avoids problems with some targets PM }
  1033. procedure GetLineInfo(addr:ptruint;var func,source:string;var line:longint);
  1034. var
  1035. res : {$ifdef tp}integer{$else}longint{$endif};
  1036. stabsleft,
  1037. stabscnt,i : longint;
  1038. found : boolean;
  1039. lastfunc : tstab;
  1040. begin
  1041. fillchar(func,high(func)+1,0);
  1042. fillchar(source,high(source)+1,0);
  1043. line:=0;
  1044. if not opened then
  1045. begin
  1046. if not OpenStabs then
  1047. exit;
  1048. end;
  1049. { correct the value to the correct address in the file }
  1050. { processaddress is set in OpenStabs }
  1051. addr := addr - processaddress;
  1052. //ScreenPrintfL1 (NWLoggerScreen,'addr: %x\n',addr);
  1053. fillchar(funcstab,sizeof(tstab),0);
  1054. fillchar(filestab,sizeof(tstab),0);
  1055. fillchar(dirstab,sizeof(tstab),0);
  1056. fillchar(linestab,sizeof(tstab),0);
  1057. fillchar(lastfunc,sizeof(tstab),0);
  1058. found:=false;
  1059. seek(f,stabofs);
  1060. stabsleft:=stabcnt;
  1061. repeat
  1062. if stabsleft>maxstabs then
  1063. stabscnt:=maxstabs
  1064. else
  1065. stabscnt:=stabsleft;
  1066. blockread(f,stabs,stabscnt*sizeof(tstab),res);
  1067. stabscnt:=res div sizeof(tstab);
  1068. for i:=0 to stabscnt-1 do
  1069. begin
  1070. case stabs[i].ntype of
  1071. N_BssLine,
  1072. N_DataLine,
  1073. N_TextLine :
  1074. begin
  1075. if (stabs[i].ntype=N_TextLine) and StabsFunctionRelative then
  1076. inc(stabs[i].nvalue,lastfunc.nvalue);
  1077. if (stabs[i].nvalue<=addr) and
  1078. (stabs[i].nvalue>linestab.nvalue) then
  1079. begin
  1080. { if it's equal we can stop and take the last info }
  1081. if stabs[i].nvalue=addr then
  1082. found:=true
  1083. else
  1084. linestab:=stabs[i];
  1085. end;
  1086. end;
  1087. N_Function :
  1088. begin
  1089. lastfunc:=stabs[i];
  1090. if (stabs[i].nvalue<=addr) and
  1091. (stabs[i].nvalue>funcstab.nvalue) then
  1092. begin
  1093. funcstab:=stabs[i];
  1094. fillchar(linestab,sizeof(tstab),0);
  1095. end;
  1096. end;
  1097. N_SourceFile,
  1098. N_IncludeFile :
  1099. begin
  1100. if (stabs[i].nvalue<=addr) and
  1101. (stabs[i].nvalue>=filestab.nvalue) then
  1102. begin
  1103. { if same value and type then the first one
  1104. contained the directory PM }
  1105. if (stabs[i].nvalue=filestab.nvalue) and
  1106. (stabs[i].ntype=filestab.ntype) then
  1107. dirstab:=filestab
  1108. else
  1109. fillchar(dirstab,sizeof(tstab),0);
  1110. filestab:=stabs[i];
  1111. fillchar(linestab,sizeof(tstab),0);
  1112. { if new file then func is not valid anymore PM }
  1113. if stabs[i].ntype=N_SourceFile then
  1114. begin
  1115. fillchar(funcstab,sizeof(tstab),0);
  1116. fillchar(lastfunc,sizeof(tstab),0);
  1117. end;
  1118. end;
  1119. end;
  1120. end;
  1121. end;
  1122. dec(stabsleft,stabscnt);
  1123. until found or (stabsleft=0);
  1124. { get the line,source,function info }
  1125. line:=linestab.ndesc;
  1126. if dirstab.ntype<>0 then
  1127. begin
  1128. seek(f,stabstrofs+dirstab.strpos);
  1129. blockread(f,source[1],high(source)-1,res);
  1130. dirlength:=strlen(@source[1]);
  1131. source[0]:=chr(dirlength);
  1132. end
  1133. else
  1134. dirlength:=0;
  1135. if filestab.ntype<>0 then
  1136. begin
  1137. seek(f,stabstrofs+filestab.strpos);
  1138. blockread(f,source[dirlength+1],high(source)-(dirlength+1),res);
  1139. source[0]:=chr(strlen(@source[1]));
  1140. end;
  1141. if funcstab.ntype<>0 then
  1142. begin
  1143. seek(f,stabstrofs+funcstab.strpos);
  1144. blockread(f,func[1],high(func)-1,res);
  1145. func[0]:=chr(strlen(@func[1]));
  1146. i:=pos(':',func);
  1147. if i>0 then
  1148. Delete(func,i,255);
  1149. end;
  1150. end;
  1151. function StabBackTraceStr(addr:Pointer):shortstring;
  1152. var
  1153. func,
  1154. source : string;
  1155. hs : string[32];
  1156. line : longint;
  1157. Store : TBackTraceStrFunc;
  1158. begin
  1159. { reset to prevent infinite recursion if problems inside the code PM }
  1160. {$ifdef netware}
  1161. dec(addr,ptruint(system.NWGetCodeStart)); {we need addr relative to code start on netware}
  1162. {$endif}
  1163. Store:=BackTraceStrFunc;
  1164. BackTraceStrFunc:=@SysBackTraceStr;
  1165. GetLineInfo(ptruint(addr),func,source,line);
  1166. { create string }
  1167. {$ifdef netware}
  1168. StabBackTraceStr:=' CodeStart + $'+HexStr(ptrint(addr),sizeof(ptrint)*2);
  1169. {$else}
  1170. StabBackTraceStr:=' $'+HexStr(ptrint(addr),sizeof(ptrint)*2);
  1171. {$endif}
  1172. if func<>'' then
  1173. StabBackTraceStr:=StabBackTraceStr+' '+func;
  1174. if source<>'' then
  1175. begin
  1176. if func<>'' then
  1177. StabBackTraceStr:=StabBackTraceStr+', ';
  1178. if line<>0 then
  1179. begin
  1180. str(line,hs);
  1181. StabBackTraceStr:=StabBackTraceStr+' line '+hs;
  1182. end;
  1183. StabBackTraceStr:=StabBackTraceStr+' of '+source;
  1184. end;
  1185. if Opened then
  1186. BackTraceStrFunc:=Store;
  1187. end;
  1188. initialization
  1189. BackTraceStrFunc:=@StabBackTraceStr;
  1190. finalization
  1191. if opened then
  1192. CloseStabs;
  1193. end.