lnfodwrf.pp 20 KB

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