lnfodwrf.pp 21 KB

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