lnfodwrf.pp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737
  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. procedure GetLineInfo(addr:ptruint;var func,source:string;var line:longint);
  22. implementation
  23. uses
  24. exeinfo;
  25. { Current issues:
  26. - ignores DW_LNS_SET_FILE
  27. - slow
  28. }
  29. {$MACRO ON}
  30. //{$DEFINE DEBUG_DWARF_PARSER}
  31. {$ifdef DEBUG_DWARF_PARSER}
  32. {$define DEBUG_WRITELN := WriteLn}
  33. {$define DEBUG_COMMENT := }
  34. {$else}
  35. {$define DEBUG_WRITELN := //}
  36. {$define DEBUG_COMMENT := //}
  37. {$endif}
  38. { some type definitions }
  39. type
  40. Bool8 = ByteBool;
  41. var
  42. { the input file to read DWARF debug info from, i.e. paramstr(0) }
  43. e : TExeFile;
  44. DwarfErr : boolean;
  45. { the offset and size of the DWARF debug_line section in the file }
  46. DwarfOffset : longint;
  47. DwarfSize : longint;
  48. { DWARF 2 default opcodes}
  49. const
  50. { Extended opcodes }
  51. DW_LNE_END_SEQUENCE = 1;
  52. DW_LNE_SET_ADDRESS = 2;
  53. DW_LNE_DEFINE_FILE = 3;
  54. { Standard opcodes }
  55. DW_LNS_COPY = 1;
  56. DW_LNS_ADVANCE_PC = 2;
  57. DW_LNS_ADVANCE_LINE = 3;
  58. DW_LNS_SET_FILE = 4;
  59. DW_LNS_SET_COLUMN = 5;
  60. DW_LNS_NEGATE_STMT = 6;
  61. DW_LNS_SET_BASIC_BLOCK = 7;
  62. DW_LNS_CONST_ADD_PC = 8;
  63. DW_LNS_FIXED_ADVANCE_PC = 9;
  64. DW_LNS_SET_PROLOGUE_END = 10;
  65. DW_LNS_SET_EPILOGUE_BEGIN = 11;
  66. DW_LNS_SET_ISA = 12;
  67. type
  68. { state record for the line info state machine }
  69. TMachineState = record
  70. address : QWord;
  71. file_id : DWord;
  72. line : QWord;
  73. column : DWord;
  74. is_stmt : Boolean;
  75. basic_block : Boolean;
  76. end_sequence : Boolean;
  77. prolouge_end : Boolean;
  78. epilouge_begin : Boolean;
  79. isa : DWord;
  80. append_row : Boolean;
  81. end;
  82. { DWARF line number program header preceding the line number program, 64 bit version }
  83. TLineNumberProgramHeader64 = packed record
  84. magic : DWord;
  85. unit_length : QWord;
  86. version : Word;
  87. length : QWord;
  88. minimum_instruction_length : Byte;
  89. default_is_stmt : Bool8;
  90. line_base : ShortInt;
  91. line_range : Byte;
  92. opcode_base : Byte;
  93. end;
  94. { DWARF line number program header preceding the line number program, 32 bit version }
  95. TLineNumberProgramHeader32 = packed record
  96. unit_length : DWord;
  97. version : Word;
  98. length : DWord;
  99. minimum_instruction_length : Byte;
  100. default_is_stmt : Bool8;
  101. line_base : ShortInt;
  102. line_range : Byte;
  103. opcode_base : Byte;
  104. end;
  105. {---------------------------------------------------------------------------
  106. I/O utility functions
  107. ---------------------------------------------------------------------------}
  108. var
  109. base, limit : SizeInt;
  110. index : SizeInt;
  111. function Opendwarf:boolean;
  112. var
  113. dbgfn : string;
  114. begin
  115. Opendwarf:=false;
  116. if dwarferr then
  117. exit;
  118. if not OpenExeFile(e,paramstr(0)) then
  119. exit;
  120. if ReadDebugLink(e,dbgfn) then
  121. begin
  122. CloseExeFile(e);
  123. if not OpenExeFile(e,dbgfn) then
  124. exit;
  125. end;
  126. if FindExeSection(e,'.debug_line',dwarfoffset,dwarfsize) then
  127. Opendwarf:=true
  128. else
  129. begin
  130. dwarferr:=true;
  131. exit;
  132. end;
  133. end;
  134. procedure Closedwarf;
  135. begin
  136. CloseExeFile(e);
  137. end;
  138. function Init(aBase, aLimit : Int64) : Boolean;
  139. begin
  140. base := aBase;
  141. limit := aLimit;
  142. Init := (aBase + limit) <= e.size;
  143. seek(e.f, base);
  144. index := 0;
  145. end;
  146. function Init(aBase : Int64) : Boolean;
  147. begin
  148. Init := Init(aBase, limit - (aBase - base));
  149. end;
  150. function Pos() : Int64;
  151. begin
  152. Pos := index;
  153. end;
  154. procedure Seek(const newIndex : Int64);
  155. begin
  156. index := newIndex;
  157. system.seek(e.f, base + index);
  158. end;
  159. { Returns the next Byte from the input stream, or -1 if there has been
  160. an error }
  161. function ReadNext() : Longint;
  162. var
  163. bytesread : SizeInt;
  164. b : Byte;
  165. begin
  166. ReadNext := -1;
  167. if (index < limit) then begin
  168. blockread(e.f, b, 1, bytesread);
  169. ReadNext := b;
  170. inc(index);
  171. end;
  172. if (bytesread <> 1) then
  173. ReadNext := -1;
  174. end;
  175. { Reads the next size bytes into dest. Returns true if successful,
  176. false otherwise. Note that dest may be partially overwritten after
  177. returning false. }
  178. function ReadNext(var dest; size : SizeInt) : Boolean;
  179. var
  180. bytesread : SizeInt;
  181. begin
  182. bytesread := 0;
  183. if ((index + size) < limit) then begin
  184. blockread(e.f, dest, size, bytesread);
  185. inc(index, size);
  186. end;
  187. ReadNext := (bytesread = size);
  188. end;
  189. { Reads an unsigned LEB encoded number from the input stream }
  190. function ReadULEB128() : QWord;
  191. var
  192. shift : Byte;
  193. data : PtrInt;
  194. val : QWord;
  195. begin
  196. shift := 0;
  197. ReadULEB128 := 0;
  198. data := ReadNext();
  199. while (data <> -1) do begin
  200. val := data and $7f;
  201. ReadULEB128 := ReadULEB128 or (val shl shift);
  202. inc(shift, 7);
  203. if ((data and $80) = 0) then
  204. break;
  205. data := ReadNext();
  206. end;
  207. end;
  208. { Reads a signed LEB encoded number from the input stream }
  209. function ReadLEB128() : Int64;
  210. var
  211. shift : Byte;
  212. data : PtrInt;
  213. val : Int64;
  214. begin
  215. shift := 0;
  216. ReadLEB128 := 0;
  217. data := ReadNext();
  218. while (data <> -1) do begin
  219. val := data and $7f;
  220. ReadLEB128 := ReadLEB128 or (val shl shift);
  221. inc(shift, 7);
  222. if ((data and $80) = 0) then
  223. break;
  224. data := ReadNext();
  225. end;
  226. { extend sign. Note that we can not use shl/shr since the latter does not
  227. translate to arithmetic shifting for signed types }
  228. ReadLEB128 := (not ((ReadLEB128 and (1 shl (shift-1)))-1)) or ReadLEB128;
  229. end;
  230. { Reads an address from the current input stream }
  231. function ReadAddress() : PtrUInt;
  232. begin
  233. ReadNext(ReadAddress, sizeof(ReadAddress));
  234. end;
  235. { Reads a zero-terminated string from the current input stream. If the
  236. string is larger than 255 chars (maximum allowed number of elements in
  237. a ShortString, excess characters will be chopped off. }
  238. function ReadString() : ShortString;
  239. var
  240. temp : PtrInt;
  241. i : PtrUInt;
  242. begin
  243. i := 1;
  244. temp := ReadNext();
  245. while (temp > 0) do begin
  246. ReadString[i] := char(temp);
  247. if (i = 255) then begin
  248. { skip remaining characters }
  249. repeat
  250. temp := ReadNext();
  251. until (temp <= 0);
  252. break;
  253. end;
  254. inc(i);
  255. temp := ReadNext();
  256. end;
  257. { unexpected end of file occurred? }
  258. if (temp = -1) then
  259. ReadString := ''
  260. else
  261. Byte(ReadString[0]) := i-1;
  262. end;
  263. { Reads an unsigned Half from the current input stream }
  264. function ReadUHalf() : Word;
  265. begin
  266. ReadNext(ReadUHalf, sizeof(ReadUHalf));
  267. end;
  268. {---------------------------------------------------------------------------
  269. Generic Dwarf lineinfo reader
  270. The line info reader is based on the information contained in
  271. DWARF Debugging Information Format Version 3
  272. Chapter 6.2 "Line Number Information"
  273. from the
  274. DWARF Debugging Information Format Workgroup.
  275. For more information on this document see also
  276. http://dwarf.freestandards.org/
  277. ---------------------------------------------------------------------------}
  278. { initializes the line info state to the default values }
  279. procedure InitStateRegisters(var state : TMachineState; const aIs_Stmt : Bool8);
  280. begin
  281. with state do begin
  282. address := 0;
  283. file_id := 1;
  284. line := 1;
  285. column := 0;
  286. is_stmt := aIs_Stmt;
  287. basic_block := false;
  288. end_sequence := false;
  289. prolouge_end := false;
  290. epilouge_begin := false;
  291. isa := 0;
  292. append_row := false;
  293. end;
  294. end;
  295. { Skips all line info directory entries }
  296. procedure SkipDirectories();
  297. var s : ShortString;
  298. begin
  299. while (true) do begin
  300. s := ReadString();
  301. if (s = '') then break;
  302. DEBUG_WRITELN('Skipping directory : ', s);
  303. end;
  304. end;
  305. { Skips an LEB128 }
  306. procedure SkipLEB128();
  307. {$ifdef DEBUG_DWARF_PARSER}
  308. var temp : QWord;
  309. {$endif}
  310. begin
  311. {$ifdef DEBUG_DWARF_PARSER}temp := {$endif}ReadLEB128();
  312. DEBUG_WRITELN('Skipping LEB128 : ', temp);
  313. end;
  314. { Skips the filename section from the current file stream }
  315. procedure SkipFilenames();
  316. var s : ShortString;
  317. begin
  318. while (true) do begin
  319. s := ReadString();
  320. if (s = '') then break;
  321. DEBUG_WRITELN('Skipping filename : ', s);
  322. SkipLEB128(); { skip the directory index for the file }
  323. SkipLEB128(); { skip last modification time for file }
  324. SkipLEB128(); { skip length of file }
  325. end;
  326. end;
  327. function CalculateAddressIncrement(opcode : Byte; const header : TLineNumberProgramHeader64) : Int64;
  328. begin
  329. CalculateAddressIncrement := (Int64(opcode) - header.opcode_base) div header.line_range * header.minimum_instruction_length;
  330. end;
  331. function GetFullFilename(const filenameStart, directoryStart : Int64; const file_id : DWord) : ShortString;
  332. var
  333. i : DWord;
  334. filename, directory : ShortString;
  335. dirindex : Int64;
  336. begin
  337. filename := '';
  338. directory := '';
  339. i := 1;
  340. Seek(filenameStart);
  341. while (i <= file_id) do begin
  342. filename := ReadString();
  343. DEBUG_WRITELN('Found "', filename, '"');
  344. if (filename = '') then break;
  345. dirindex := ReadLEB128(); { read the directory index for the file }
  346. SkipLEB128(); { skip last modification time for file }
  347. SkipLEB128(); { skip length of file }
  348. inc(i);
  349. end;
  350. { if we could not find the file index, exit }
  351. if (filename = '') then begin
  352. GetFullFilename := '(Unknown file)';
  353. exit;
  354. end;
  355. Seek(directoryStart);
  356. i := 1;
  357. while (i <= dirindex) do begin
  358. directory := ReadString();
  359. if (directory = '') then break;
  360. inc(i);
  361. end;
  362. if (directory<>'') and (directory[length(directory)]<>'/') then
  363. directory:=directory+'/';
  364. GetFullFilename := directory + filename;
  365. end;
  366. function ParseCompilationUnit(const addr : PtrUInt; const file_offset : QWord;
  367. var source : String; var line : longint; var found : Boolean) : QWord;
  368. var
  369. state : TMachineState;
  370. { we need both headers on the stack, although we only use the 64 bit one internally }
  371. header64 : TLineNumberProgramHeader64;
  372. header32 : TLineNumberProgramHeader32;
  373. adjusted_opcode : Int64;
  374. opcode : PtrInt;
  375. extended_opcode : Byte;
  376. extended_opcode_length : PtrInt;
  377. i, addrIncrement, lineIncrement : PtrInt;
  378. {$ifdef DEBUG_DWARF_PARSER}
  379. s : ShortString;
  380. {$endif}
  381. numoptable : array[1..255] of Byte;
  382. { the offset into the file where the include directories are stored for this compilation unit }
  383. include_directories : QWord;
  384. { the offset into the file where the file names are stored for this compilation unit }
  385. file_names : Int64;
  386. temp_length : DWord;
  387. unit_length : QWord;
  388. header_length : SizeInt;
  389. first_row : Boolean;
  390. prev_line : QWord;
  391. prev_file : DWord;
  392. begin
  393. prev_line := 0;
  394. prev_file := 0;
  395. first_row := true;
  396. found := false;
  397. ReadNext(temp_length, sizeof(temp_length));
  398. if (temp_length <> $ffffffff) then begin
  399. unit_length := temp_length + sizeof(temp_length)
  400. end else begin
  401. ReadNext(unit_length, sizeof(unit_length));
  402. inc(unit_length, 12);
  403. end;
  404. ParseCompilationUnit := file_offset + unit_length;
  405. Init(file_offset, unit_length);
  406. DEBUG_WRITELN('Unit length: ', unit_length);
  407. if (temp_length <> $ffffffff) then begin
  408. DEBUG_WRITELN('32 bit DWARF detected');
  409. ReadNext(header32, sizeof(header32));
  410. header64.magic := $ffffffff;
  411. header64.unit_length := header32.unit_length;
  412. header64.version := header32.version;
  413. header64.length := header32.length;
  414. header64.minimum_instruction_length := header32.minimum_instruction_length;
  415. header64.default_is_stmt := header32.default_is_stmt;
  416. header64.line_base := header32.line_base;
  417. header64.line_range := header32.line_range;
  418. header64.opcode_base := header32.opcode_base;
  419. header_length :=
  420. sizeof(header32.length) + sizeof(header32.version) +
  421. sizeof(header32.unit_length);
  422. end else begin
  423. DEBUG_WRITELN('64 bit DWARF detected');
  424. ReadNext(header64, sizeof(header64));
  425. header_length :=
  426. sizeof(header64.magic) + sizeof(header64.version) +
  427. sizeof(header64.length) + sizeof(header64.unit_length);
  428. end;
  429. inc(header_length, header64.length);
  430. fillchar(numoptable, sizeof(numoptable), #0);
  431. ReadNext(numoptable, header64.opcode_base-1);
  432. DEBUG_WRITELN('Opcode parameter count table');
  433. for i := 1 to header64.opcode_base-1 do begin
  434. DEBUG_WRITELN('Opcode[', i, '] - ', numoptable[i], ' parameters');
  435. end;
  436. DEBUG_WRITELN('Reading directories...');
  437. include_directories := Pos();
  438. SkipDirectories();
  439. DEBUG_WRITELN('Reading filenames...');
  440. file_names := Pos();
  441. SkipFilenames();
  442. Seek(header_length);
  443. with header64 do begin
  444. InitStateRegisters(state, default_is_stmt);
  445. end;
  446. opcode := ReadNext();
  447. while (opcode <> -1) and (not found) do begin
  448. DEBUG_WRITELN('Next opcode: ');
  449. case (opcode) of
  450. { extended opcode }
  451. 0 : begin
  452. extended_opcode_length := ReadULEB128();
  453. extended_opcode := ReadNext();
  454. case (extended_opcode) of
  455. DW_LNE_END_SEQUENCE : begin
  456. state.end_sequence := true;
  457. state.append_row := true;
  458. DEBUG_WRITELN('DW_LNE_END_SEQUENCE');
  459. end;
  460. DW_LNE_SET_ADDRESS : begin
  461. state.address := ReadAddress();
  462. DEBUG_WRITELN('DW_LNE_SET_ADDRESS (', hexstr(state.address, sizeof(state.address)*2), ')');
  463. end;
  464. DW_LNE_DEFINE_FILE : begin
  465. {$ifdef DEBUG_DWARF_PARSER}s := {$endif}ReadString();
  466. SkipLEB128();
  467. SkipLEB128();
  468. SkipLEB128();
  469. DEBUG_WRITELN('DW_LNE_DEFINE_FILE (', s, ')');
  470. end;
  471. else begin
  472. DEBUG_WRITELN('Unknown extended opcode (opcode ', extended_opcode, ' length ', extended_opcode_length, ')');
  473. for i := 0 to extended_opcode_length-2 do
  474. ReadNext();
  475. end;
  476. end;
  477. end;
  478. DW_LNS_COPY : begin
  479. state.basic_block := false;
  480. state.prolouge_end := false;
  481. state.epilouge_begin := false;
  482. state.append_row := true;
  483. DEBUG_WRITELN('DW_LNS_COPY');
  484. end;
  485. DW_LNS_ADVANCE_PC : begin
  486. inc(state.address, ReadULEB128() * header64.minimum_instruction_length);
  487. DEBUG_WRITELN('DW_LNS_ADVANCE_PC (', hexstr(state.address, sizeof(state.address)*2), ')');
  488. end;
  489. DW_LNS_ADVANCE_LINE : begin
  490. inc(state.line, ReadLEB128());
  491. DEBUG_WRITELN('DW_LNS_ADVANCE_LINE (', state.line, ')');
  492. end;
  493. DW_LNS_SET_FILE : begin
  494. state.file_id := ReadULEB128();
  495. DEBUG_WRITELN('DW_LNS_SET_FILE (', state.file_id, ')');
  496. end;
  497. DW_LNS_SET_COLUMN : begin
  498. state.column := ReadULEB128();
  499. DEBUG_WRITELN('DW_LNS_SET_COLUMN (', state.column, ')');
  500. end;
  501. DW_LNS_NEGATE_STMT : begin
  502. state.is_stmt := not state.is_stmt;
  503. DEBUG_WRITELN('DW_LNS_NEGATE_STMT (', state.is_stmt, ')');
  504. end;
  505. DW_LNS_SET_BASIC_BLOCK : begin
  506. state.basic_block := true;
  507. DEBUG_WRITELN('DW_LNS_SET_BASIC_BLOCK');
  508. end;
  509. DW_LNS_CONST_ADD_PC : begin
  510. inc(state.address, CalculateAddressIncrement(255, header64));
  511. DEBUG_WRITELN('DW_LNS_CONST_ADD_PC (', hexstr(state.address, sizeof(state.address)*2), ')');
  512. end;
  513. DW_LNS_FIXED_ADVANCE_PC : begin
  514. inc(state.address, ReadUHalf());
  515. DEBUG_WRITELN('DW_LNS_FIXED_ADVANCE_PC (', hexstr(state.address, sizeof(state.address)*2), ')');
  516. end;
  517. DW_LNS_SET_PROLOGUE_END : begin
  518. state.prolouge_end := true;
  519. DEBUG_WRITELN('DW_LNS_SET_PROLOGUE_END');
  520. end;
  521. DW_LNS_SET_EPILOGUE_BEGIN : begin
  522. state.epilouge_begin := true;
  523. DEBUG_WRITELN('DW_LNS_SET_EPILOGUE_BEGIN');
  524. end;
  525. DW_LNS_SET_ISA : begin
  526. state.isa := ReadULEB128();
  527. DEBUG_WRITELN('DW_LNS_SET_ISA (', state.isa, ')');
  528. end;
  529. else begin { special opcode }
  530. if (opcode < header64.opcode_base) then begin
  531. DEBUG_WRITELN('Unknown standard opcode $', hexstr(opcode, 2), '; skipping');
  532. for i := 1 to numoptable[opcode] do
  533. SkipLEB128();
  534. end else begin
  535. adjusted_opcode := opcode - header64.opcode_base;
  536. addrIncrement := CalculateAddressIncrement(opcode, header64);
  537. inc(state.address, addrIncrement);
  538. lineIncrement := header64.line_base + (adjusted_opcode mod header64.line_range);
  539. inc(state.line, lineIncrement);
  540. DEBUG_WRITELN('Special opcode $', hexstr(opcode, 2), ' address increment: ', addrIncrement, ' new line: ', lineIncrement);
  541. state.basic_block := false;
  542. state.prolouge_end := false;
  543. state.epilouge_begin := false;
  544. state.append_row := true;
  545. end;
  546. end;
  547. end;
  548. if (state.append_row) then begin
  549. DEBUG_WRITELN('Current state : address = ', hexstr(state.address, sizeof(state.address) * 2),
  550. DEBUG_COMMENT ' file_id = ', state.file_id, ' line = ', state.line, ' column = ', state.column,
  551. DEBUG_COMMENT ' is_stmt = ', state.is_stmt, ' basic_block = ', state.basic_block,
  552. DEBUG_COMMENT ' end_sequence = ', state.end_sequence, ' prolouge_end = ', state.prolouge_end,
  553. DEBUG_COMMENT ' epilouge_begin = ', state.epilouge_begin, ' isa = ', state.isa);
  554. if (first_row) then begin
  555. if (state.address > addr) then
  556. break;
  557. first_row := false;
  558. end;
  559. { when we have found the address we need to return the previous
  560. line because that contains the call instruction }
  561. if (state.address >= addr) then
  562. found:=true
  563. else
  564. begin
  565. { save line information }
  566. prev_file := state.file_id;
  567. prev_line := state.line;
  568. end;
  569. state.append_row := false;
  570. if (state.end_sequence) then begin
  571. InitStateRegisters(state, header64.default_is_stmt);
  572. end;
  573. end;
  574. opcode := ReadNext();
  575. end;
  576. if (found) then begin
  577. line := prev_line;
  578. source := GetFullFilename(file_names, include_directories, prev_file);
  579. end;
  580. end;
  581. procedure GetLineInfo(addr : ptruint; var func, source : string; var line : longint);
  582. var
  583. current_offset : QWord;
  584. end_offset : QWord;
  585. found : Boolean;
  586. begin
  587. func := '';
  588. source := '';
  589. found := false;
  590. if DwarfErr then
  591. exit;
  592. if not e.isopen then
  593. begin
  594. if not OpenDwarf then
  595. exit;
  596. end;
  597. current_offset := DwarfOffset;
  598. end_offset := DwarfOffset + DwarfSize;
  599. while (current_offset < end_offset) and (not found) do begin
  600. Init(current_offset, end_offset - current_offset);
  601. current_offset := ParseCompilationUnit(addr, current_offset,
  602. source, line, found);
  603. end;
  604. end;
  605. function DwarfBackTraceStr(addr : Pointer) : shortstring;
  606. var
  607. func,
  608. source : string;
  609. hs : string[32];
  610. line : longint;
  611. Store : TBackTraceStrFunc;
  612. begin
  613. { reset to prevent infinite recursion if problems inside the code }
  614. Store := BackTraceStrFunc;
  615. BackTraceStrFunc := @SysBackTraceStr;
  616. GetLineInfo(ptruint(addr), func, source, line);
  617. { create string }
  618. DwarfBackTraceStr :=' $' + HexStr(ptruint(addr), sizeof(ptruint) * 2);
  619. if func<>'' then
  620. DwarfBackTraceStr := DwarfBackTraceStr + ' ' + func;
  621. if source<>'' then begin
  622. if func<>'' then
  623. DwarfBackTraceStr := DwarfBackTraceStr + ', ';
  624. if line<>0 then begin
  625. str(line, hs);
  626. DwarfBackTraceStr := DwarfBackTraceStr + ' line ' + hs;
  627. end;
  628. DwarfBackTraceStr := DwarfBackTraceStr + ' of ' + source;
  629. end;
  630. if e.IsOpen then
  631. BackTraceStrFunc := Store;
  632. end;
  633. initialization
  634. BackTraceStrFunc := @DwarfBacktraceStr;
  635. finalization
  636. if e.isopen then
  637. CloseDwarf();
  638. end.