lnfodwrf.pp 37 KB

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