lnfodwrf.pp 19 KB

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