lnfodwrf.pp 37 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2006 by Thomas Schatzl, member of the FreePascal
  4. Development team
  5. Parts (c) 2000 Peter Vreman (adapted from original dwarfs line
  6. reader)
  7. Dwarf LineInfo Retriever
  8. See the file COPYING.FPC, included in this distribution,
  9. for details about the copyright.
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  13. **********************************************************************}
  14. {
  15. This unit should not be compiled in objfpc mode, since this would make it
  16. dependent on objpas unit.
  17. }
  18. unit lnfodwrf;
  19. interface
  20. {$S-}
  21. {$IF FPC_VERSION<3}
  22. type
  23. CodePointer = Pointer;
  24. {$ENDIF}
  25. function GetLineInfo(addr:ptruint;var func,source:string;var line:longint) : boolean;
  26. function DwarfBackTraceStr(addr: CodePointer): string;
  27. procedure CloseDwarf;
  28. var
  29. // Allows more efficient operation by reusing previously loaded debug data
  30. // when the target module filename is the same. However, if an invalid memory
  31. // address is supplied then further calls may result in an undefined behaviour.
  32. // In summary: enable for speed, disable for resilience.
  33. AllowReuseOfLineInfoData: Boolean = True;
  34. implementation
  35. uses
  36. exeinfo;
  37. { Current issues:
  38. - ignores DW_LNS_SET_FILE
  39. }
  40. {$MACRO ON}
  41. { $DEFINE DEBUG_DWARF_PARSER}
  42. {$ifdef DEBUG_DWARF_PARSER}
  43. {$define DEBUG_WRITELN := WriteLn}
  44. {$define DEBUG_COMMENT := }
  45. {$else}
  46. {$define DEBUG_WRITELN := //}
  47. {$define DEBUG_COMMENT := //}
  48. {$endif}
  49. { some type definitions }
  50. type
  51. Bool8 = ByteBool;
  52. const
  53. EBUF_SIZE = 100;
  54. {$WARNING This code is not thread-safe, and needs improvement}
  55. var
  56. { the input file to read DWARF debug info from, i.e. paramstr(0) }
  57. e : TExeFile;
  58. EBuf: Array [0..EBUF_SIZE-1] of Byte;
  59. EBufCnt, EBufPos: Integer;
  60. { the offset and size of the DWARF debug_line section in the file }
  61. Dwarf_Debug_Line_Section_Offset,
  62. Dwarf_Debug_Line_Section_Size,
  63. { the offset and size of the DWARF debug_info section in the file }
  64. Dwarf_Debug_Info_Section_Offset,
  65. Dwarf_Debug_Info_Section_Size,
  66. { the offset and size of the DWARF debug_aranges section in the file }
  67. Dwarf_Debug_Aranges_Section_Offset,
  68. Dwarf_Debug_Aranges_Section_Size,
  69. { the offset and size of the DWARF debug_abbrev section in the file }
  70. Dwarf_Debug_Abbrev_Section_Offset,
  71. Dwarf_Debug_Abbrev_Section_Size : longint;
  72. { DWARF 2 default opcodes}
  73. const
  74. { Extended opcodes }
  75. DW_LNE_END_SEQUENCE = 1;
  76. DW_LNE_SET_ADDRESS = 2;
  77. DW_LNE_DEFINE_FILE = 3;
  78. { Standard opcodes }
  79. DW_LNS_COPY = 1;
  80. DW_LNS_ADVANCE_PC = 2;
  81. DW_LNS_ADVANCE_LINE = 3;
  82. DW_LNS_SET_FILE = 4;
  83. DW_LNS_SET_COLUMN = 5;
  84. DW_LNS_NEGATE_STMT = 6;
  85. DW_LNS_SET_BASIC_BLOCK = 7;
  86. DW_LNS_CONST_ADD_PC = 8;
  87. DW_LNS_FIXED_ADVANCE_PC = 9;
  88. DW_LNS_SET_PROLOGUE_END = 10;
  89. DW_LNS_SET_EPILOGUE_BEGIN = 11;
  90. DW_LNS_SET_ISA = 12;
  91. DW_FORM_addr = $1;
  92. DW_FORM_block2 = $3;
  93. DW_FORM_block4 = $4;
  94. DW_FORM_data2 = $5;
  95. DW_FORM_data4 = $6;
  96. DW_FORM_data8 = $7;
  97. DW_FORM_string = $8;
  98. DW_FORM_block = $9;
  99. DW_FORM_block1 = $a;
  100. DW_FORM_data1 = $b;
  101. DW_FORM_flag = $c;
  102. DW_FORM_sdata = $d;
  103. DW_FORM_strp = $e;
  104. DW_FORM_udata = $f;
  105. DW_FORM_ref_addr = $10;
  106. DW_FORM_ref1 = $11;
  107. DW_FORM_ref2 = $12;
  108. DW_FORM_ref4 = $13;
  109. DW_FORM_ref8 = $14;
  110. DW_FORM_ref_udata = $15;
  111. DW_FORM_indirect = $16;
  112. type
  113. { state record for the line info state machine }
  114. TMachineState = record
  115. address : QWord;
  116. file_id : DWord;
  117. line : QWord;
  118. column : DWord;
  119. is_stmt : Boolean;
  120. basic_block : Boolean;
  121. end_sequence : Boolean;
  122. prolouge_end : Boolean;
  123. epilouge_begin : Boolean;
  124. isa : DWord;
  125. append_row : Boolean;
  126. end;
  127. { DWARF line number program header preceding the line number program, 64 bit version }
  128. TLineNumberProgramHeader64 = packed record
  129. magic : DWord;
  130. unit_length : QWord;
  131. version : Word;
  132. length : QWord;
  133. minimum_instruction_length : Byte;
  134. default_is_stmt : Bool8;
  135. line_base : ShortInt;
  136. line_range : Byte;
  137. opcode_base : Byte;
  138. end;
  139. { DWARF line number program header preceding the line number program, 32 bit version }
  140. TLineNumberProgramHeader32 = packed record
  141. unit_length : DWord;
  142. version : Word;
  143. length : DWord;
  144. minimum_instruction_length : Byte;
  145. default_is_stmt : Bool8;
  146. line_base : ShortInt;
  147. line_range : Byte;
  148. opcode_base : Byte;
  149. end;
  150. TDebugInfoProgramHeader64 = packed record
  151. magic : DWord;
  152. unit_length : QWord;
  153. version : Word;
  154. debug_abbrev_offset : QWord;
  155. address_size : Byte;
  156. end;
  157. TDebugInfoProgramHeader32= packed record
  158. unit_length : DWord;
  159. version : Word;
  160. debug_abbrev_offset : DWord;
  161. address_size : Byte;
  162. end;
  163. TDebugArangesHeader64 = packed record
  164. magic : DWord;
  165. unit_length : QWord;
  166. version : Word;
  167. debug_info_offset : QWord;
  168. address_size : Byte;
  169. segment_size : Byte;
  170. padding : DWord;
  171. end;
  172. TDebugArangesHeader32= packed record
  173. unit_length : DWord;
  174. version : Word;
  175. debug_info_offset : DWord;
  176. address_size : Byte;
  177. segment_size : Byte;
  178. padding : DWord;
  179. end;
  180. {---------------------------------------------------------------------------
  181. I/O utility functions
  182. ---------------------------------------------------------------------------}
  183. var
  184. base, limit : SizeInt;
  185. index : SizeInt;
  186. baseaddr : pointer;
  187. filename,
  188. dbgfn : string;
  189. lastfilename: string; { store last processed file }
  190. lastopendwarf: Boolean; { store last result of processing a file }
  191. function OpenDwarf(addr : pointer) : boolean;
  192. begin
  193. // False by default
  194. OpenDwarf:=false;
  195. // Empty so can test if GetModuleByAddr has worked
  196. filename := '';
  197. // Get filename by address using GetModuleByAddr
  198. GetModuleByAddr(addr,baseaddr,filename);
  199. {$ifdef DEBUG_LINEINFO}
  200. writeln(stderr,filename,' Baseaddr: ',hexstr(ptruint(baseaddr),sizeof(baseaddr)*2));
  201. {$endif DEBUG_LINEINFO}
  202. // Check if GetModuleByAddr has worked
  203. if filename = '' then
  204. exit;
  205. // If target filename same as previous, then re-use previous result
  206. if AllowReuseOfLineInfoData and (filename = lastfilename) then
  207. begin
  208. {$ifdef DEBUG_LINEINFO}
  209. writeln(stderr,'Reusing debug data');
  210. {$endif DEBUG_LINEINFO}
  211. OpenDwarf:=lastopendwarf;
  212. exit;
  213. end;
  214. // Close previously opened Dwarf
  215. CloseDwarf;
  216. // Reset last open dwarf result
  217. lastopendwarf := false;
  218. // Save newly processed filename
  219. lastfilename := filename;
  220. // Open exe file or debug link
  221. if not OpenExeFile(e,filename) then
  222. exit;
  223. if ReadDebugLink(e,dbgfn) then
  224. begin
  225. CloseExeFile(e);
  226. if not OpenExeFile(e,dbgfn) then
  227. exit;
  228. end;
  229. // Find debug data section
  230. e.processaddress:=ptruint(baseaddr)-e.processaddress;
  231. if FindExeSection(e,'.debug_line',Dwarf_Debug_Line_Section_offset,dwarf_Debug_Line_Section_size) and
  232. FindExeSection(e,'.debug_info',Dwarf_Debug_Info_Section_offset,dwarf_Debug_Info_Section_size) and
  233. FindExeSection(e,'.debug_abbrev',Dwarf_Debug_Abbrev_Section_offset,dwarf_Debug_Abbrev_Section_size) and
  234. FindExeSection(e,'.debug_aranges',Dwarf_Debug_Aranges_Section_offset,dwarf_Debug_Aranges_Section_size) then
  235. begin
  236. lastopendwarf:=true;
  237. OpenDwarf:=true;
  238. DEBUG_WRITELN('.debug_line starts at offset $',hexstr(Dwarf_Debug_Line_Section_offset,8),' with a size of ',Dwarf_Debug_Line_Section_Size,' Bytes');
  239. DEBUG_WRITELN('.debug_info starts at offset $',hexstr(Dwarf_Debug_Info_Section_offset,8),' with a size of ',Dwarf_Debug_Info_Section_Size,' Bytes');
  240. DEBUG_WRITELN('.debug_abbrev starts at offset $',hexstr(Dwarf_Debug_Abbrev_Section_offset,8),' with a size of ',Dwarf_Debug_Abbrev_Section_Size,' Bytes');
  241. DEBUG_WRITELN('.debug_aranges starts at offset $',hexstr(Dwarf_Debug_Aranges_Section_offset,8),' with a size of ',Dwarf_Debug_Aranges_Section_Size,' Bytes');
  242. end
  243. else
  244. CloseExeFile(e);
  245. end;
  246. procedure CloseDwarf;
  247. begin
  248. if e.isopen then
  249. CloseExeFile(e);
  250. // Reset last processed filename
  251. lastfilename := '';
  252. end;
  253. function Init(aBase, aLimit : Int64) : Boolean;
  254. begin
  255. base := aBase;
  256. limit := aLimit;
  257. Init := (aBase + limit) <= e.size;
  258. seek(e.f, base);
  259. EBufCnt := 0;
  260. EBufPos := 0;
  261. index := 0;
  262. end;
  263. function Init(aBase : Int64) : Boolean;
  264. begin
  265. Init := Init(aBase, limit - (aBase - base));
  266. end;
  267. function Pos() : Int64;
  268. begin
  269. Pos := index;
  270. end;
  271. procedure Seek(const newIndex : Int64);
  272. begin
  273. index := newIndex;
  274. system.seek(e.f, base + index);
  275. EBufCnt := 0;
  276. EBufPos := 0;
  277. end;
  278. { Returns the next Byte from the input stream, or -1 if there has been
  279. an error }
  280. function ReadNext() : Longint; inline;
  281. var
  282. bytesread : SizeInt;
  283. begin
  284. ReadNext := -1;
  285. if EBufPos >= EBufCnt then begin
  286. EBufPos := 0;
  287. EBufCnt := EBUF_SIZE;
  288. if EBufCnt > limit - index then
  289. EBufCnt := limit - index;
  290. blockread(e.f, EBuf, EBufCnt, bytesread);
  291. EBufCnt := bytesread;
  292. end;
  293. if EBufPos < EBufCnt then begin
  294. ReadNext := EBuf[EBufPos];
  295. inc(EBufPos);
  296. inc(index);
  297. end
  298. else
  299. ReadNext := -1;
  300. end;
  301. { Reads the next size bytes into dest. Returns true if successful,
  302. false otherwise. Note that dest may be partially overwritten after
  303. returning false. }
  304. function ReadNext(var dest; size : SizeInt) : Boolean;
  305. var
  306. bytesread, totalread : SizeInt;
  307. r: Boolean;
  308. d: PByte;
  309. begin
  310. d := @dest;
  311. totalread := 0;
  312. r := True;
  313. while (totalread < size) and r do begin;
  314. if EBufPos >= EBufCnt then begin
  315. EBufPos := 0;
  316. EBufCnt := EBUF_SIZE;
  317. if EBufCnt > limit - index then
  318. EBufCnt := limit - index;
  319. blockread(e.f, EBuf, EBufCnt, bytesread);
  320. EBufCnt := bytesread;
  321. if bytesread <= 0 then
  322. r := False;
  323. end;
  324. if EBufPos < EBufCnt then begin
  325. bytesread := EBufCnt - EBufPos;
  326. if bytesread > size - totalread then bytesread := size - totalread;
  327. System.Move(EBuf[EBufPos], d[totalread], bytesread);
  328. inc(EBufPos, bytesread);
  329. inc(index, bytesread);
  330. inc(totalread, bytesread);
  331. end;
  332. end;
  333. ReadNext := r;
  334. end;
  335. { Reads an unsigned LEB encoded number from the input stream }
  336. function ReadULEB128() : QWord;
  337. var
  338. shift : Byte;
  339. data : PtrInt;
  340. val : QWord;
  341. begin
  342. shift := 0;
  343. ReadULEB128 := 0;
  344. data := ReadNext();
  345. while (data <> -1) do begin
  346. val := data and $7f;
  347. ReadULEB128 := ReadULEB128 or (val shl shift);
  348. inc(shift, 7);
  349. if ((data and $80) = 0) then
  350. break;
  351. data := ReadNext();
  352. end;
  353. end;
  354. { Reads a signed LEB encoded number from the input stream }
  355. function ReadLEB128() : Int64;
  356. var
  357. shift : Byte;
  358. data : PtrInt;
  359. val : Int64;
  360. begin
  361. shift := 0;
  362. ReadLEB128 := 0;
  363. data := ReadNext();
  364. while (data <> -1) do begin
  365. val := data and $7f;
  366. ReadLEB128 := ReadLEB128 or (val shl shift);
  367. inc(shift, 7);
  368. if ((data and $80) = 0) then
  369. break;
  370. data := ReadNext();
  371. end;
  372. { extend sign. Note that we can not use shl/shr since the latter does not
  373. translate to arithmetic shifting for signed types }
  374. ReadLEB128 := (not ((ReadLEB128 and (1 shl (shift-1)))-1)) or ReadLEB128;
  375. end;
  376. { Reads an address from the current input stream }
  377. function ReadAddress() : PtrUInt;
  378. begin
  379. ReadNext(ReadAddress, sizeof(ReadAddress));
  380. end;
  381. { Reads a zero-terminated string from the current input stream. If the
  382. string is larger than 255 chars (maximum allowed number of elements in
  383. a ShortString, excess characters will be chopped off. }
  384. function ReadString() : ShortString;
  385. var
  386. temp : PtrInt;
  387. i : PtrUInt;
  388. begin
  389. i := 1;
  390. temp := ReadNext();
  391. while (temp > 0) do begin
  392. ReadString[i] := char(temp);
  393. if (i = 255) then begin
  394. { skip remaining characters }
  395. repeat
  396. temp := ReadNext();
  397. until (temp <= 0);
  398. break;
  399. end;
  400. inc(i);
  401. temp := ReadNext();
  402. end;
  403. { unexpected end of file occurred? }
  404. if (temp = -1) then
  405. ReadString := ''
  406. else
  407. Byte(ReadString[0]) := i-1;
  408. end;
  409. { Reads an unsigned Half from the current input stream }
  410. function ReadUHalf() : Word;
  411. begin
  412. ReadNext(ReadUHalf, sizeof(ReadUHalf));
  413. end;
  414. {---------------------------------------------------------------------------
  415. Generic Dwarf lineinfo reader
  416. The line info reader is based on the information contained in
  417. DWARF Debugging Information Format Version 3
  418. Chapter 6.2 "Line Number Information"
  419. from the
  420. DWARF Debugging Information Format Workgroup.
  421. For more information on this document see also
  422. http://dwarf.freestandards.org/
  423. ---------------------------------------------------------------------------}
  424. { initializes the line info state to the default values }
  425. procedure InitStateRegisters(var state : TMachineState; const aIs_Stmt : Bool8);
  426. begin
  427. with state do begin
  428. address := 0;
  429. file_id := 1;
  430. line := 1;
  431. column := 0;
  432. is_stmt := aIs_Stmt;
  433. basic_block := false;
  434. end_sequence := false;
  435. prolouge_end := false;
  436. epilouge_begin := false;
  437. isa := 0;
  438. append_row := false;
  439. end;
  440. end;
  441. { Skips all line info directory entries }
  442. procedure SkipDirectories();
  443. var s : ShortString;
  444. begin
  445. while (true) do begin
  446. s := ReadString();
  447. if (s = '') then break;
  448. DEBUG_WRITELN('Skipping directory : ', s);
  449. end;
  450. end;
  451. { Skips an LEB128 }
  452. procedure SkipLEB128();
  453. {$ifdef DEBUG_DWARF_PARSER}
  454. var temp : QWord;
  455. {$endif}
  456. begin
  457. {$ifdef DEBUG_DWARF_PARSER}temp := {$endif}ReadLEB128();
  458. DEBUG_WRITELN('Skipping LEB128 : ', temp);
  459. end;
  460. { Skips the filename section from the current file stream }
  461. procedure SkipFilenames();
  462. var s : ShortString;
  463. begin
  464. while (true) do begin
  465. s := ReadString();
  466. if (s = '') then break;
  467. DEBUG_WRITELN('Skipping filename : ', s);
  468. SkipLEB128(); { skip the directory index for the file }
  469. SkipLEB128(); { skip last modification time for file }
  470. SkipLEB128(); { skip length of file }
  471. end;
  472. end;
  473. function CalculateAddressIncrement(opcode : Byte; const header : TLineNumberProgramHeader64) : Int64;
  474. begin
  475. CalculateAddressIncrement := (Int64(opcode) - header.opcode_base) div header.line_range * header.minimum_instruction_length;
  476. end;
  477. function GetFullFilename(const filenameStart, directoryStart : Int64; const file_id : DWord) : ShortString;
  478. var
  479. i : DWord;
  480. filename, directory : ShortString;
  481. dirindex : Int64;
  482. begin
  483. filename := '';
  484. directory := '';
  485. i := 1;
  486. Seek(filenameStart);
  487. while (i <= file_id) do begin
  488. filename := ReadString();
  489. DEBUG_WRITELN('Found "', filename, '"');
  490. if (filename = '') then break;
  491. dirindex := ReadLEB128(); { read the directory index for the file }
  492. SkipLEB128(); { skip last modification time for file }
  493. SkipLEB128(); { skip length of file }
  494. inc(i);
  495. end;
  496. { if we could not find the file index, exit }
  497. if (filename = '') then begin
  498. GetFullFilename := '(Unknown file)';
  499. exit;
  500. end;
  501. Seek(directoryStart);
  502. i := 1;
  503. while (i <= dirindex) do begin
  504. directory := ReadString();
  505. if (directory = '') then break;
  506. inc(i);
  507. end;
  508. if (directory<>'') and (directory[length(directory)]<>'/') then
  509. directory:=directory+'/';
  510. GetFullFilename := directory + filename;
  511. end;
  512. function ParseCompilationUnit(const addr : PtrUInt; const file_offset : QWord;
  513. var source : String; var line : longint; var found : Boolean) : QWord;
  514. var
  515. state : TMachineState;
  516. { we need both headers on the stack, although we only use the 64 bit one internally }
  517. header64 : TLineNumberProgramHeader64;
  518. header32 : TLineNumberProgramHeader32;
  519. adjusted_opcode : Int64;
  520. opcode : PtrInt;
  521. extended_opcode : PtrInt;
  522. extended_opcode_length : PtrInt;
  523. i, addrIncrement, lineIncrement : PtrInt;
  524. {$ifdef DEBUG_DWARF_PARSER}
  525. s : ShortString;
  526. {$endif}
  527. numoptable : array[1..255] of Byte;
  528. { the offset into the file where the include directories are stored for this compilation unit }
  529. include_directories : QWord;
  530. { the offset into the file where the file names are stored for this compilation unit }
  531. file_names : Int64;
  532. temp_length : DWord;
  533. unit_length : QWord;
  534. header_length : SizeInt;
  535. first_row : Boolean;
  536. prev_line : QWord;
  537. prev_file : DWord;
  538. begin
  539. prev_line := 0;
  540. prev_file := 0;
  541. first_row := true;
  542. found := false;
  543. ReadNext(temp_length, sizeof(temp_length));
  544. if (temp_length <> $ffffffff) then begin
  545. unit_length := temp_length + sizeof(temp_length)
  546. end else begin
  547. ReadNext(unit_length, sizeof(unit_length));
  548. inc(unit_length, 12);
  549. end;
  550. ParseCompilationUnit := file_offset + unit_length;
  551. Init(file_offset, unit_length);
  552. DEBUG_WRITELN('Unit length: ', unit_length);
  553. if (temp_length <> $ffffffff) then begin
  554. DEBUG_WRITELN('32 bit DWARF detected');
  555. ReadNext(header32, sizeof(header32));
  556. header64.magic := $ffffffff;
  557. header64.unit_length := header32.unit_length;
  558. header64.version := header32.version;
  559. header64.length := header32.length;
  560. header64.minimum_instruction_length := header32.minimum_instruction_length;
  561. header64.default_is_stmt := header32.default_is_stmt;
  562. header64.line_base := header32.line_base;
  563. header64.line_range := header32.line_range;
  564. header64.opcode_base := header32.opcode_base;
  565. header_length :=
  566. sizeof(header32.length) + sizeof(header32.version) +
  567. sizeof(header32.unit_length);
  568. end else begin
  569. DEBUG_WRITELN('64 bit DWARF detected');
  570. ReadNext(header64, sizeof(header64));
  571. header_length :=
  572. sizeof(header64.magic) + sizeof(header64.version) +
  573. sizeof(header64.length) + sizeof(header64.unit_length);
  574. end;
  575. inc(header_length, header64.length);
  576. fillchar(numoptable, sizeof(numoptable), #0);
  577. ReadNext(numoptable, header64.opcode_base-1);
  578. DEBUG_WRITELN('Opcode parameter count table');
  579. for i := 1 to header64.opcode_base-1 do begin
  580. DEBUG_WRITELN('Opcode[', i, '] - ', numoptable[i], ' parameters');
  581. end;
  582. DEBUG_WRITELN('Reading directories...');
  583. include_directories := Pos();
  584. SkipDirectories();
  585. DEBUG_WRITELN('Reading filenames...');
  586. file_names := Pos();
  587. SkipFilenames();
  588. Seek(header_length);
  589. with header64 do begin
  590. InitStateRegisters(state, default_is_stmt);
  591. end;
  592. opcode := ReadNext();
  593. while (opcode <> -1) and (not found) do begin
  594. DEBUG_WRITELN('Next opcode: ');
  595. case (opcode) of
  596. { extended opcode }
  597. 0 : begin
  598. extended_opcode_length := ReadULEB128();
  599. extended_opcode := ReadNext();
  600. case (extended_opcode) of
  601. -1: begin
  602. exit;
  603. end;
  604. DW_LNE_END_SEQUENCE : begin
  605. state.end_sequence := true;
  606. state.append_row := true;
  607. DEBUG_WRITELN('DW_LNE_END_SEQUENCE');
  608. end;
  609. DW_LNE_SET_ADDRESS : begin
  610. state.address := ReadAddress();
  611. DEBUG_WRITELN('DW_LNE_SET_ADDRESS (', hexstr(state.address, sizeof(state.address)*2), ')');
  612. end;
  613. DW_LNE_DEFINE_FILE : begin
  614. {$ifdef DEBUG_DWARF_PARSER}s := {$endif}ReadString();
  615. SkipLEB128();
  616. SkipLEB128();
  617. SkipLEB128();
  618. DEBUG_WRITELN('DW_LNE_DEFINE_FILE (', s, ')');
  619. end;
  620. else begin
  621. DEBUG_WRITELN('Unknown extended opcode (opcode ', extended_opcode, ' length ', extended_opcode_length, ')');
  622. for i := 0 to extended_opcode_length-2 do
  623. if ReadNext() = -1 then
  624. exit;
  625. end;
  626. end;
  627. end;
  628. DW_LNS_COPY : begin
  629. state.basic_block := false;
  630. state.prolouge_end := false;
  631. state.epilouge_begin := false;
  632. state.append_row := true;
  633. DEBUG_WRITELN('DW_LNS_COPY');
  634. end;
  635. DW_LNS_ADVANCE_PC : begin
  636. inc(state.address, ReadULEB128() * header64.minimum_instruction_length);
  637. DEBUG_WRITELN('DW_LNS_ADVANCE_PC (', hexstr(state.address, sizeof(state.address)*2), ')');
  638. end;
  639. DW_LNS_ADVANCE_LINE : begin
  640. // inc(state.line, ReadLEB128()); negative values are allowed
  641. // but those may generate a range check error
  642. state.line := state.line + ReadLEB128();
  643. DEBUG_WRITELN('DW_LNS_ADVANCE_LINE (', state.line, ')');
  644. end;
  645. DW_LNS_SET_FILE : begin
  646. state.file_id := ReadULEB128();
  647. DEBUG_WRITELN('DW_LNS_SET_FILE (', state.file_id, ')');
  648. end;
  649. DW_LNS_SET_COLUMN : begin
  650. state.column := ReadULEB128();
  651. DEBUG_WRITELN('DW_LNS_SET_COLUMN (', state.column, ')');
  652. end;
  653. DW_LNS_NEGATE_STMT : begin
  654. state.is_stmt := not state.is_stmt;
  655. DEBUG_WRITELN('DW_LNS_NEGATE_STMT (', state.is_stmt, ')');
  656. end;
  657. DW_LNS_SET_BASIC_BLOCK : begin
  658. state.basic_block := true;
  659. DEBUG_WRITELN('DW_LNS_SET_BASIC_BLOCK');
  660. end;
  661. DW_LNS_CONST_ADD_PC : begin
  662. inc(state.address, CalculateAddressIncrement(255, header64));
  663. DEBUG_WRITELN('DW_LNS_CONST_ADD_PC (', hexstr(state.address, sizeof(state.address)*2), ')');
  664. end;
  665. DW_LNS_FIXED_ADVANCE_PC : begin
  666. inc(state.address, ReadUHalf());
  667. DEBUG_WRITELN('DW_LNS_FIXED_ADVANCE_PC (', hexstr(state.address, sizeof(state.address)*2), ')');
  668. end;
  669. DW_LNS_SET_PROLOGUE_END : begin
  670. state.prolouge_end := true;
  671. DEBUG_WRITELN('DW_LNS_SET_PROLOGUE_END');
  672. end;
  673. DW_LNS_SET_EPILOGUE_BEGIN : begin
  674. state.epilouge_begin := true;
  675. DEBUG_WRITELN('DW_LNS_SET_EPILOGUE_BEGIN');
  676. end;
  677. DW_LNS_SET_ISA : begin
  678. state.isa := ReadULEB128();
  679. DEBUG_WRITELN('DW_LNS_SET_ISA (', state.isa, ')');
  680. end;
  681. else begin { special opcode }
  682. if (opcode < header64.opcode_base) then begin
  683. DEBUG_WRITELN('Unknown standard opcode $', hexstr(opcode, 2), '; skipping');
  684. for i := 1 to numoptable[opcode] do
  685. SkipLEB128();
  686. end else begin
  687. adjusted_opcode := opcode - header64.opcode_base;
  688. addrIncrement := CalculateAddressIncrement(opcode, header64);
  689. inc(state.address, addrIncrement);
  690. lineIncrement := header64.line_base + (adjusted_opcode mod header64.line_range);
  691. inc(state.line, lineIncrement);
  692. DEBUG_WRITELN('Special opcode $', hexstr(opcode, 2), ' address increment: ', addrIncrement, ' new line: ', lineIncrement);
  693. state.basic_block := false;
  694. state.prolouge_end := false;
  695. state.epilouge_begin := false;
  696. state.append_row := true;
  697. end;
  698. end;
  699. end;
  700. if (state.append_row) then begin
  701. DEBUG_WRITELN('Current state : address = ', hexstr(state.address, sizeof(state.address) * 2),
  702. DEBUG_COMMENT ' file_id = ', state.file_id, ' line = ', state.line, ' column = ', state.column,
  703. DEBUG_COMMENT ' is_stmt = ', state.is_stmt, ' basic_block = ', state.basic_block,
  704. DEBUG_COMMENT ' end_sequence = ', state.end_sequence, ' prolouge_end = ', state.prolouge_end,
  705. DEBUG_COMMENT ' epilouge_begin = ', state.epilouge_begin, ' isa = ', state.isa);
  706. if (first_row) then begin
  707. if (state.address > addr) then
  708. break;
  709. first_row := false;
  710. end;
  711. { when we have found the address we need to return the previous
  712. line because that contains the call instruction }
  713. if (state.address >= addr) then
  714. found:=true
  715. else
  716. begin
  717. { save line information }
  718. prev_file := state.file_id;
  719. prev_line := state.line;
  720. end;
  721. state.append_row := false;
  722. if (state.end_sequence) then begin
  723. InitStateRegisters(state, header64.default_is_stmt);
  724. first_row := true;
  725. end;
  726. end;
  727. opcode := ReadNext();
  728. end;
  729. if (found) then begin
  730. line := prev_line;
  731. source := GetFullFilename(file_names, include_directories, prev_file);
  732. end;
  733. end;
  734. var
  735. Abbrev_Offsets : array of QWord;
  736. Abbrev_Tags : array of QWord;
  737. Abbrev_Children : array of Byte;
  738. Abbrev_Attrs : array of array of record attr,form : QWord; end;
  739. procedure ReadAbbrevTable;
  740. var
  741. i : PtrInt;
  742. tag,
  743. nr,
  744. attr,
  745. form,
  746. PrevHigh : Int64;
  747. begin
  748. DEBUG_WRITELN('Starting to read abbrev. section at $',hexstr(Dwarf_Debug_Abbrev_Section_Offset+Pos,16));
  749. repeat
  750. nr:=ReadULEB128;
  751. if nr=0 then
  752. break;
  753. if nr>high(Abbrev_Offsets) then
  754. begin
  755. SetLength(Abbrev_Offsets,nr+1024);
  756. SetLength(Abbrev_Tags,nr+1024);
  757. SetLength(Abbrev_Attrs,nr+1024);
  758. SetLength(Abbrev_Children,nr+1024);
  759. end;
  760. Abbrev_Offsets[nr]:=Pos;
  761. { read tag }
  762. tag:=ReadULEB128;
  763. Abbrev_Tags[nr]:=tag;
  764. DEBUG_WRITELN('Abbrev ',nr,' at offset ',Pos,' has tag $',hexstr(tag,4));
  765. { read flag for children }
  766. Abbrev_Children[nr]:=ReadNext;
  767. i:=0;
  768. { ensure that length(Abbrev_Attrs)=0 if an entry is overwritten (not sure if this will ever happen) and
  769. the new entry has no attributes }
  770. Abbrev_Attrs[nr]:=nil;
  771. repeat
  772. attr:=ReadULEB128;
  773. form:=ReadULEB128;
  774. if attr<>0 then
  775. begin
  776. SetLength(Abbrev_Attrs[nr],i+1);
  777. Abbrev_Attrs[nr][i].attr:=attr;
  778. Abbrev_Attrs[nr][i].form:=form;
  779. end;
  780. inc(i);
  781. until attr=0;
  782. DEBUG_WRITELN('Abbrev ',nr,' has ',Length(Abbrev_Attrs[nr]),' attributes');
  783. until false;
  784. end;
  785. function ParseCompilationUnitForDebugInfoOffset(const addr : PtrUInt; const file_offset : QWord;
  786. var debug_info_offset : QWord; var found : Boolean) : QWord;
  787. var
  788. { we need both headers on the stack, although we only use the 64 bit one internally }
  789. header64 : TDebugArangesHeader64;
  790. header32 : TDebugArangesHeader32;
  791. isdwarf64 : boolean;
  792. temp_length : DWord;
  793. unit_length : QWord;
  794. arange_start, arange_size: PtrUInt;
  795. begin
  796. found := false;
  797. ReadNext(temp_length, sizeof(temp_length));
  798. if (temp_length <> $ffffffff) then begin
  799. unit_length := temp_length + sizeof(temp_length)
  800. end else begin
  801. ReadNext(unit_length, sizeof(unit_length));
  802. inc(unit_length, 12);
  803. end;
  804. ParseCompilationUnitForDebugInfoOffset := file_offset + unit_length;
  805. Init(file_offset, unit_length);
  806. DEBUG_WRITELN('Unit length: ', unit_length);
  807. if (temp_length <> $ffffffff) then
  808. begin
  809. DEBUG_WRITELN('32 bit DWARF detected');
  810. ReadNext(header32, sizeof(header32));
  811. header64.magic := $ffffffff;
  812. header64.unit_length := header32.unit_length;
  813. header64.version := header32.version;
  814. header64.debug_info_offset := header32.debug_info_offset;
  815. header64.address_size := header32.address_size;
  816. header64.segment_size := header32.segment_size;
  817. isdwarf64:=false;
  818. end
  819. else
  820. begin
  821. DEBUG_WRITELN('64 bit DWARF detected');
  822. ReadNext(header64, sizeof(header64));
  823. isdwarf64:=true;
  824. end;
  825. DEBUG_WRITELN('debug_info_offset: ',header64.debug_info_offset);
  826. arange_start:=ReadAddress;
  827. arange_size:=ReadAddress;
  828. while not((arange_start=0) and (arange_size=0)) and (not found) do
  829. begin
  830. if (addr>=arange_start) and (addr<=arange_start+arange_size) then
  831. begin
  832. found:=true;
  833. debug_info_offset:=header64.debug_info_offset;
  834. DEBUG_WRITELN('Matching aranges entry $',hexStr(arange_start,header64.address_size*2),', $',hexStr(arange_size,header64.address_size*2));
  835. end;
  836. arange_start:=ReadAddress;
  837. arange_size:=ReadAddress;
  838. end;
  839. end;
  840. function ParseCompilationUnitForFunctionName(const addr : PtrUInt; const file_offset : QWord;
  841. var func : String; var found : Boolean) : QWord;
  842. var
  843. { we need both headers on the stack, although we only use the 64 bit one internally }
  844. header64 : TDebugInfoProgramHeader64;
  845. header32 : TDebugInfoProgramHeader32;
  846. isdwarf64 : boolean;
  847. abbrev,
  848. high_pc,
  849. low_pc : QWord;
  850. temp_length : DWord;
  851. unit_length : QWord;
  852. name : String;
  853. level : Integer;
  854. procedure SkipAttr(form : QWord);
  855. var
  856. dummy : array[0..7] of byte;
  857. bl : byte;
  858. wl : word;
  859. dl : dword;
  860. ql : qword;
  861. i : PtrUInt;
  862. begin
  863. case form of
  864. DW_FORM_addr:
  865. ReadNext(dummy,header64.address_size);
  866. DW_FORM_block2:
  867. begin
  868. ReadNext(wl,SizeOf(wl));
  869. for i:=1 to wl do
  870. ReadNext;
  871. end;
  872. DW_FORM_block4:
  873. begin
  874. ReadNext(dl,SizeOf(dl));
  875. for i:=1 to dl do
  876. ReadNext;
  877. end;
  878. DW_FORM_data2:
  879. ReadNext(dummy,2);
  880. DW_FORM_data4:
  881. ReadNext(dummy,4);
  882. DW_FORM_data8:
  883. ReadNext(dummy,8);
  884. DW_FORM_string:
  885. ReadString;
  886. DW_FORM_block:
  887. begin
  888. ql:=ReadULEB128;
  889. for i:=1 to ql do
  890. ReadNext;
  891. end;
  892. DW_FORM_block1:
  893. begin
  894. bl:=ReadNext;
  895. for i:=1 to bl do
  896. ReadNext;
  897. end;
  898. DW_FORM_data1,
  899. DW_FORM_flag:
  900. ReadNext(dummy,1);
  901. DW_FORM_sdata:
  902. ReadLEB128;
  903. DW_FORM_ref_addr:
  904. { the size of DW_FORM_ref_addr changed between DWAWRF2 and later versions:
  905. in DWARF2 it depends on the architecture address size, in later versions on the DWARF type (32 bit/64 bit)
  906. }
  907. if header64.version>2 then
  908. begin
  909. if isdwarf64 then
  910. ReadNext(dummy,8)
  911. else
  912. ReadNext(dummy,4);
  913. end
  914. else
  915. ReadNext(dummy,header64.address_size);
  916. DW_FORM_strp:
  917. if isdwarf64 then
  918. ReadNext(dummy,8)
  919. else
  920. ReadNext(dummy,4);
  921. DW_FORM_udata:
  922. ReadULEB128;
  923. DW_FORM_ref1:
  924. ReadNext(dummy,1);
  925. DW_FORM_ref2:
  926. ReadNext(dummy,2);
  927. DW_FORM_ref4:
  928. ReadNext(dummy,4);
  929. DW_FORM_ref8:
  930. ReadNext(dummy,8);
  931. DW_FORM_ref_udata:
  932. ReadULEB128;
  933. DW_FORM_indirect:
  934. SkipAttr(ReadULEB128);
  935. else
  936. begin
  937. writeln(stderr,'Internal error: unknown dwarf form: $',hexstr(form,2));
  938. ReadNext;
  939. exit;
  940. end;
  941. end;
  942. end;
  943. var
  944. i : PtrInt;
  945. prev_base,prev_limit : SizeInt;
  946. prev_pos : Int64;
  947. begin
  948. found := false;
  949. ReadNext(temp_length, sizeof(temp_length));
  950. if (temp_length <> $ffffffff) then begin
  951. unit_length := temp_length + sizeof(temp_length)
  952. end else begin
  953. ReadNext(unit_length, sizeof(unit_length));
  954. inc(unit_length, 12);
  955. end;
  956. ParseCompilationUnitForFunctionName := file_offset + unit_length;
  957. Init(file_offset, unit_length);
  958. DEBUG_WRITELN('Unit length: ', unit_length);
  959. if (temp_length <> $ffffffff) then begin
  960. DEBUG_WRITELN('32 bit DWARF detected');
  961. ReadNext(header32, sizeof(header32));
  962. header64.magic := $ffffffff;
  963. header64.unit_length := header32.unit_length;
  964. header64.version := header32.version;
  965. header64.debug_abbrev_offset := header32.debug_abbrev_offset;
  966. header64.address_size := header32.address_size;
  967. isdwarf64:=false;
  968. end else begin
  969. DEBUG_WRITELN('64 bit DWARF detected');
  970. ReadNext(header64, sizeof(header64));
  971. isdwarf64:=true;
  972. end;
  973. DEBUG_WRITELN('debug_abbrev_offset: ',header64.debug_abbrev_offset);
  974. { not nice, but we have to read the abbrev section after the start of the debug_info section has been read }
  975. prev_limit:=limit;
  976. prev_base:=base;
  977. prev_pos:=Pos;
  978. Init(Dwarf_Debug_Abbrev_Section_Offset+header64.debug_abbrev_offset,Dwarf_Debug_Abbrev_Section_Size);
  979. ReadAbbrevTable;
  980. { restore previous reading state and position }
  981. Init(prev_base,prev_limit);
  982. Seek(prev_pos);
  983. abbrev:=ReadULEB128;
  984. level:=0;
  985. while (abbrev <> 0) and (not found) do
  986. begin
  987. DEBUG_WRITELN('Next abbrev: ',abbrev);
  988. if Abbrev_Children[abbrev]<>0 then
  989. inc(level);
  990. { DW_TAG_subprogram? }
  991. if Abbrev_Tags[abbrev]=$2e then
  992. begin
  993. low_pc:=1;
  994. high_pc:=0;
  995. name:='';
  996. for i:=0 to high(Abbrev_Attrs[abbrev]) do
  997. begin
  998. { DW_AT_low_pc }
  999. if (Abbrev_Attrs[abbrev][i].attr=$11) and
  1000. (Abbrev_Attrs[abbrev][i].form=DW_FORM_addr) then
  1001. begin
  1002. low_pc:=0;
  1003. ReadNext(low_pc,header64.address_size);
  1004. end
  1005. { DW_AT_high_pc }
  1006. else if (Abbrev_Attrs[abbrev][i].attr=$12) and
  1007. (Abbrev_Attrs[abbrev][i].form=DW_FORM_addr) then
  1008. begin
  1009. high_pc:=0;
  1010. ReadNext(high_pc,header64.address_size);
  1011. end
  1012. { DW_AT_name }
  1013. else if (Abbrev_Attrs[abbrev][i].attr=$3) and
  1014. { avoid that we accidently read an DW_FORM_strp entry accidently }
  1015. (Abbrev_Attrs[abbrev][i].form=DW_FORM_string) then
  1016. begin
  1017. name:=ReadString;
  1018. end
  1019. else
  1020. SkipAttr(Abbrev_Attrs[abbrev][i].form);
  1021. end;
  1022. DEBUG_WRITELN('Got DW_TAG_subprogram with low pc = $',hexStr(low_pc,header64.address_size*2),', high pc = $',hexStr(high_pc,header64.address_size*2),', name = ',name);
  1023. if (addr>low_pc) and (addr<high_pc) then
  1024. begin
  1025. found:=true;
  1026. func:=name;
  1027. end;
  1028. end
  1029. else
  1030. begin
  1031. for i:=0 to high(Abbrev_Attrs[abbrev]) do
  1032. SkipAttr(Abbrev_Attrs[abbrev][i].form);
  1033. end;
  1034. abbrev:=ReadULEB128;
  1035. { skip entries signaling that no more child entries are following }
  1036. while (level>0) and (abbrev=0) do
  1037. begin
  1038. dec(level);
  1039. abbrev:=ReadULEB128;
  1040. end;
  1041. end;
  1042. end;
  1043. function GetLineInfo(addr : ptruint; var func, source : string; var line : longint) : boolean;
  1044. var
  1045. current_offset,
  1046. end_offset, debug_info_offset_from_aranges : QWord;
  1047. found, found_aranges : Boolean;
  1048. begin
  1049. func := '';
  1050. source := '';
  1051. GetLineInfo:=false;
  1052. if not OpenDwarf(pointer(addr)) then
  1053. exit;
  1054. addr := addr - e.processaddress;
  1055. current_offset := Dwarf_Debug_Line_Section_Offset;
  1056. end_offset := Dwarf_Debug_Line_Section_Offset + Dwarf_Debug_Line_Section_Size;
  1057. found := false;
  1058. while (current_offset < end_offset) and (not found) do begin
  1059. Init(current_offset, end_offset - current_offset);
  1060. current_offset := ParseCompilationUnit(addr, current_offset,
  1061. source, line, found);
  1062. end;
  1063. current_offset := Dwarf_Debug_Aranges_Section_Offset;
  1064. end_offset := Dwarf_Debug_Aranges_Section_Offset + Dwarf_Debug_Aranges_Section_Size;
  1065. found_aranges := false;
  1066. while (current_offset < end_offset) and (not found_aranges) do begin
  1067. Init(current_offset, end_offset - current_offset);
  1068. current_offset := ParseCompilationUnitForDebugInfoOffset(addr, current_offset, debug_info_offset_from_aranges, found_aranges);
  1069. end;
  1070. { no function name found yet }
  1071. found := false;
  1072. if found_aranges then
  1073. begin
  1074. DEBUG_WRITELN('Found .debug_info offset $',hexstr(debug_info_offset_from_aranges,8),' from .debug_aranges');
  1075. current_offset := Dwarf_Debug_Info_Section_Offset + debug_info_offset_from_aranges;
  1076. end_offset := Dwarf_Debug_Info_Section_Offset + debug_info_offset_from_aranges + Dwarf_Debug_Info_Section_Size;
  1077. DEBUG_WRITELN('Reading .debug_info at section offset $',hexStr(current_offset-Dwarf_Debug_Info_Section_Offset,16));
  1078. Init(current_offset, end_offset - current_offset);
  1079. current_offset := ParseCompilationUnitForFunctionName(addr, current_offset, func, found);
  1080. if found then
  1081. DEBUG_WRITELN('Found .debug_info entry by using .debug_aranges information');
  1082. end
  1083. else
  1084. DEBUG_WRITELN('No .debug_info offset found from .debug_aranges');
  1085. current_offset := Dwarf_Debug_Info_Section_Offset;
  1086. end_offset := Dwarf_Debug_Info_Section_Offset + Dwarf_Debug_Info_Section_Size;
  1087. while (current_offset < end_offset) and (not found) do begin
  1088. DEBUG_WRITELN('Reading .debug_info at section offset $',hexStr(current_offset-Dwarf_Debug_Info_Section_Offset,16));
  1089. Init(current_offset, end_offset - current_offset);
  1090. current_offset := ParseCompilationUnitForFunctionName(addr, current_offset, func, found);
  1091. end;
  1092. if not AllowReuseOfLineInfoData then
  1093. CloseDwarf;
  1094. GetLineInfo:=true;
  1095. end;
  1096. function DwarfBackTraceStr(addr: CodePointer): string;
  1097. var
  1098. func,
  1099. source : string;
  1100. hs : string;
  1101. line : longint;
  1102. Store : TBackTraceStrFunc;
  1103. Success : boolean;
  1104. begin
  1105. {$ifdef DEBUG_LINEINFO}
  1106. writeln(stderr,'DwarfBackTraceStr called');
  1107. {$endif DEBUG_LINEINFO}
  1108. { reset to prevent infinite recursion if problems inside the code }
  1109. Success:=false;
  1110. Store := BackTraceStrFunc;
  1111. BackTraceStrFunc := @SysBackTraceStr;
  1112. Success:=GetLineInfo(ptruint(addr), func, source, line);
  1113. { create string }
  1114. DwarfBackTraceStr :=' $' + HexStr(ptruint(addr), sizeof(ptruint) * 2);
  1115. if Success then
  1116. begin
  1117. if func<>'' then
  1118. DwarfBackTraceStr := DwarfBackTraceStr + ' ' + func;
  1119. if source<>'' then
  1120. begin
  1121. if func<>'' then
  1122. DwarfBackTraceStr := DwarfBackTraceStr + ', ';
  1123. if line<>0 then
  1124. begin
  1125. str(line, hs);
  1126. DwarfBackTraceStr := DwarfBackTraceStr + ' line ' + hs;
  1127. end;
  1128. DwarfBackTraceStr := DwarfBackTraceStr + ' of ' + source;
  1129. end;
  1130. end;
  1131. BackTraceStrFunc := Store;
  1132. end;
  1133. initialization
  1134. lastfilename := '';
  1135. lastopendwarf := false;
  1136. BackTraceStrFunc := @DwarfBacktraceStr;
  1137. finalization
  1138. CloseDwarf;
  1139. end.