lnfodwrf.pp 21 KB

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