lnfodwrf.pp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794
  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()); negative values are allowed
  533. // but those may generate a range check error
  534. state.line := state.line + ReadLEB128();
  535. DEBUG_WRITELN('DW_LNS_ADVANCE_LINE (', state.line, ')');
  536. end;
  537. DW_LNS_SET_FILE : begin
  538. state.file_id := ReadULEB128();
  539. DEBUG_WRITELN('DW_LNS_SET_FILE (', state.file_id, ')');
  540. end;
  541. DW_LNS_SET_COLUMN : begin
  542. state.column := ReadULEB128();
  543. DEBUG_WRITELN('DW_LNS_SET_COLUMN (', state.column, ')');
  544. end;
  545. DW_LNS_NEGATE_STMT : begin
  546. state.is_stmt := not state.is_stmt;
  547. DEBUG_WRITELN('DW_LNS_NEGATE_STMT (', state.is_stmt, ')');
  548. end;
  549. DW_LNS_SET_BASIC_BLOCK : begin
  550. state.basic_block := true;
  551. DEBUG_WRITELN('DW_LNS_SET_BASIC_BLOCK');
  552. end;
  553. DW_LNS_CONST_ADD_PC : begin
  554. inc(state.address, CalculateAddressIncrement(255, header64));
  555. DEBUG_WRITELN('DW_LNS_CONST_ADD_PC (', hexstr(state.address, sizeof(state.address)*2), ')');
  556. end;
  557. DW_LNS_FIXED_ADVANCE_PC : begin
  558. inc(state.address, ReadUHalf());
  559. DEBUG_WRITELN('DW_LNS_FIXED_ADVANCE_PC (', hexstr(state.address, sizeof(state.address)*2), ')');
  560. end;
  561. DW_LNS_SET_PROLOGUE_END : begin
  562. state.prolouge_end := true;
  563. DEBUG_WRITELN('DW_LNS_SET_PROLOGUE_END');
  564. end;
  565. DW_LNS_SET_EPILOGUE_BEGIN : begin
  566. state.epilouge_begin := true;
  567. DEBUG_WRITELN('DW_LNS_SET_EPILOGUE_BEGIN');
  568. end;
  569. DW_LNS_SET_ISA : begin
  570. state.isa := ReadULEB128();
  571. DEBUG_WRITELN('DW_LNS_SET_ISA (', state.isa, ')');
  572. end;
  573. else begin { special opcode }
  574. if (opcode < header64.opcode_base) then begin
  575. DEBUG_WRITELN('Unknown standard opcode $', hexstr(opcode, 2), '; skipping');
  576. for i := 1 to numoptable[opcode] do
  577. SkipLEB128();
  578. end else begin
  579. adjusted_opcode := opcode - header64.opcode_base;
  580. addrIncrement := CalculateAddressIncrement(opcode, header64);
  581. inc(state.address, addrIncrement);
  582. lineIncrement := header64.line_base + (adjusted_opcode mod header64.line_range);
  583. inc(state.line, lineIncrement);
  584. DEBUG_WRITELN('Special opcode $', hexstr(opcode, 2), ' address increment: ', addrIncrement, ' new line: ', lineIncrement);
  585. state.basic_block := false;
  586. state.prolouge_end := false;
  587. state.epilouge_begin := false;
  588. state.append_row := true;
  589. end;
  590. end;
  591. end;
  592. if (state.append_row) then begin
  593. DEBUG_WRITELN('Current state : address = ', hexstr(state.address, sizeof(state.address) * 2),
  594. DEBUG_COMMENT ' file_id = ', state.file_id, ' line = ', state.line, ' column = ', state.column,
  595. DEBUG_COMMENT ' is_stmt = ', state.is_stmt, ' basic_block = ', state.basic_block,
  596. DEBUG_COMMENT ' end_sequence = ', state.end_sequence, ' prolouge_end = ', state.prolouge_end,
  597. DEBUG_COMMENT ' epilouge_begin = ', state.epilouge_begin, ' isa = ', state.isa);
  598. if (first_row) then begin
  599. if (state.address > addr) then
  600. break;
  601. first_row := false;
  602. end;
  603. { when we have found the address we need to return the previous
  604. line because that contains the call instruction }
  605. if (state.address >= addr) then
  606. found:=true
  607. else
  608. begin
  609. { save line information }
  610. prev_file := state.file_id;
  611. prev_line := state.line;
  612. end;
  613. state.append_row := false;
  614. if (state.end_sequence) then begin
  615. InitStateRegisters(state, header64.default_is_stmt);
  616. first_row := true;
  617. end;
  618. end;
  619. opcode := ReadNext();
  620. end;
  621. if (found) then begin
  622. line := prev_line;
  623. source := GetFullFilename(file_names, include_directories, prev_file);
  624. end;
  625. end;
  626. function GetLineInfo(addr : ptruint; var func, source : string; var line : longint) : boolean;
  627. var
  628. current_offset : QWord;
  629. end_offset : QWord;
  630. found : Boolean;
  631. begin
  632. func := '';
  633. source := '';
  634. found := false;
  635. GetLineInfo:=false;
  636. if DwarfErr then
  637. exit;
  638. if not e.isopen then
  639. begin
  640. if not OpenDwarf(pointer(addr)) then
  641. exit;
  642. end;
  643. addr := addr - e.processaddress;
  644. current_offset := DwarfOffset;
  645. end_offset := DwarfOffset + DwarfSize;
  646. while (current_offset < end_offset) and (not found) do begin
  647. Init(current_offset, end_offset - current_offset);
  648. current_offset := ParseCompilationUnit(addr, current_offset,
  649. source, line, found);
  650. end;
  651. if e.isopen then
  652. CloseDwarf;
  653. GetLineInfo:=true;
  654. end;
  655. function DwarfBackTraceStr(addr : Pointer) : shortstring;
  656. var
  657. func,
  658. source : string;
  659. hs : string[32];
  660. line : longint;
  661. Store : TBackTraceStrFunc;
  662. Success : boolean;
  663. begin
  664. { reset to prevent infinite recursion if problems inside the code }
  665. Success:=false;
  666. Store := BackTraceStrFunc;
  667. BackTraceStrFunc := @SysBackTraceStr;
  668. Success:=GetLineInfo(ptruint(addr), func, source, line);
  669. { create string }
  670. DwarfBackTraceStr :=' $' + HexStr(ptruint(addr), sizeof(ptruint) * 2);
  671. if func<>'' then
  672. DwarfBackTraceStr := DwarfBackTraceStr + ' ' + func;
  673. if source<>'' then begin
  674. if func<>'' then
  675. DwarfBackTraceStr := DwarfBackTraceStr + ', ';
  676. if line<>0 then begin
  677. str(line, hs);
  678. DwarfBackTraceStr := DwarfBackTraceStr + ' line ' + hs;
  679. end;
  680. DwarfBackTraceStr := DwarfBackTraceStr + ' of ' + source;
  681. end;
  682. if Success then
  683. BackTraceStrFunc := Store;
  684. end;
  685. initialization
  686. BackTraceStrFunc := @DwarfBacktraceStr;
  687. finalization
  688. if e.isopen then
  689. CloseDwarf();
  690. end.