lnfodwrf.pp 32 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172
  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. {$IF FPC_VERSION<3}
  22. type
  23. CodePointer = Pointer;
  24. {$ENDIF}
  25. function GetLineInfo(addr:ptruint;var func,source:string;var line:longint) : boolean;
  26. function DwarfBackTraceStr(addr: CodePointer): string;
  27. procedure CloseDwarf;
  28. var
  29. // Allows more efficient operation by reusing previously loaded debug data
  30. // when the target module filename is the same. However, if an invalid memory
  31. // address is supplied then further calls may result in an undefined behaviour.
  32. // In summary: enable for speed, disable for resilience.
  33. AllowReuseOfLineInfoData: Boolean = True;
  34. implementation
  35. uses
  36. exeinfo;
  37. { Current issues:
  38. - ignores DW_LNS_SET_FILE
  39. }
  40. {$MACRO ON}
  41. { $DEFINE DEBUG_DWARF_PARSER}
  42. {$ifdef DEBUG_DWARF_PARSER}
  43. {$define DEBUG_WRITELN := WriteLn}
  44. {$define DEBUG_COMMENT := }
  45. {$else}
  46. {$define DEBUG_WRITELN := //}
  47. {$define DEBUG_COMMENT := //}
  48. {$endif}
  49. { some type definitions }
  50. type
  51. Bool8 = ByteBool;
  52. const
  53. EBUF_SIZE = 100;
  54. {$WARNING This code is not thread-safe, and needs improvement}
  55. var
  56. { the input file to read DWARF debug info from, i.e. paramstr(0) }
  57. e : TExeFile;
  58. EBuf: Array [0..EBUF_SIZE-1] of Byte;
  59. EBufCnt, EBufPos: Integer;
  60. { the offset and size of the DWARF debug_line section in the file }
  61. Dwarf_Debug_Line_Section_Offset,
  62. Dwarf_Debug_Line_Section_Size,
  63. { the offset and size of the DWARF debug_info section in the file }
  64. Dwarf_Debug_Info_Section_Offset,
  65. Dwarf_Debug_Info_Section_Size,
  66. { the offset and size of the DWARF debug_abbrev section in the file }
  67. Dwarf_Debug_Abbrev_Section_Offset,
  68. Dwarf_Debug_Abbrev_Section_Size : longint;
  69. { DWARF 2 default opcodes}
  70. const
  71. { Extended opcodes }
  72. DW_LNE_END_SEQUENCE = 1;
  73. DW_LNE_SET_ADDRESS = 2;
  74. DW_LNE_DEFINE_FILE = 3;
  75. { Standard opcodes }
  76. DW_LNS_COPY = 1;
  77. DW_LNS_ADVANCE_PC = 2;
  78. DW_LNS_ADVANCE_LINE = 3;
  79. DW_LNS_SET_FILE = 4;
  80. DW_LNS_SET_COLUMN = 5;
  81. DW_LNS_NEGATE_STMT = 6;
  82. DW_LNS_SET_BASIC_BLOCK = 7;
  83. DW_LNS_CONST_ADD_PC = 8;
  84. DW_LNS_FIXED_ADVANCE_PC = 9;
  85. DW_LNS_SET_PROLOGUE_END = 10;
  86. DW_LNS_SET_EPILOGUE_BEGIN = 11;
  87. DW_LNS_SET_ISA = 12;
  88. DW_FORM_addr = $1;
  89. DW_FORM_block2 = $3;
  90. DW_FORM_block4 = $4;
  91. DW_FORM_data2 = $5;
  92. DW_FORM_data4 = $6;
  93. DW_FORM_data8 = $7;
  94. DW_FORM_string = $8;
  95. DW_FORM_block = $9;
  96. DW_FORM_block1 = $a;
  97. DW_FORM_data1 = $b;
  98. DW_FORM_flag = $c;
  99. DW_FORM_sdata = $d;
  100. DW_FORM_strp = $e;
  101. DW_FORM_udata = $f;
  102. DW_FORM_ref_addr = $10;
  103. DW_FORM_ref1 = $11;
  104. DW_FORM_ref2 = $12;
  105. DW_FORM_ref4 = $13;
  106. DW_FORM_ref8 = $14;
  107. DW_FORM_ref_udata = $15;
  108. DW_FORM_indirect = $16;
  109. type
  110. { state record for the line info state machine }
  111. TMachineState = record
  112. address : QWord;
  113. file_id : DWord;
  114. line : QWord;
  115. column : DWord;
  116. is_stmt : Boolean;
  117. basic_block : Boolean;
  118. end_sequence : Boolean;
  119. prolouge_end : Boolean;
  120. epilouge_begin : Boolean;
  121. isa : DWord;
  122. append_row : Boolean;
  123. end;
  124. { DWARF line number program header preceding the line number program, 64 bit version }
  125. TLineNumberProgramHeader64 = packed record
  126. magic : DWord;
  127. unit_length : QWord;
  128. version : Word;
  129. length : QWord;
  130. minimum_instruction_length : Byte;
  131. default_is_stmt : Bool8;
  132. line_base : ShortInt;
  133. line_range : Byte;
  134. opcode_base : Byte;
  135. end;
  136. { DWARF line number program header preceding the line number program, 32 bit version }
  137. TLineNumberProgramHeader32 = packed record
  138. unit_length : DWord;
  139. version : Word;
  140. length : DWord;
  141. minimum_instruction_length : Byte;
  142. default_is_stmt : Bool8;
  143. line_base : ShortInt;
  144. line_range : Byte;
  145. opcode_base : Byte;
  146. end;
  147. TDebugInfoProgramHeader64 = packed record
  148. magic : DWord;
  149. unit_length : QWord;
  150. version : Word;
  151. debug_abbrev_offset : QWord;
  152. address_size : Byte;
  153. end;
  154. TDebugInfoProgramHeader32= packed record
  155. unit_length : DWord;
  156. version : Word;
  157. debug_abbrev_offset : DWord;
  158. address_size : Byte;
  159. end;
  160. {---------------------------------------------------------------------------
  161. I/O utility functions
  162. ---------------------------------------------------------------------------}
  163. var
  164. base, limit : SizeInt;
  165. index : SizeInt;
  166. baseaddr : pointer;
  167. filename,
  168. dbgfn : string;
  169. lastfilename: string; { store last processed file }
  170. lastopendwarf: Boolean; { store last result of processing a file }
  171. function OpenDwarf(addr : pointer) : boolean;
  172. begin
  173. // False by default
  174. OpenDwarf:=false;
  175. // Empty so can test if GetModuleByAddr has worked
  176. filename := '';
  177. // Get filename by address using GetModuleByAddr
  178. GetModuleByAddr(addr,baseaddr,filename);
  179. {$ifdef DEBUG_LINEINFO}
  180. writeln(stderr,filename,' Baseaddr: ',hexstr(ptruint(baseaddr),sizeof(baseaddr)*2));
  181. {$endif DEBUG_LINEINFO}
  182. // Check if GetModuleByAddr has worked
  183. if filename = '' then
  184. exit;
  185. // If target filename same as previous, then re-use previous result
  186. if AllowReuseOfLineInfoData and (filename = lastfilename) then
  187. begin
  188. {$ifdef DEBUG_LINEINFO}
  189. writeln(stderr,'Reusing debug data');
  190. {$endif DEBUG_LINEINFO}
  191. OpenDwarf:=lastopendwarf;
  192. exit;
  193. end;
  194. // Close previously opened Dwarf
  195. CloseDwarf;
  196. // Reset last open dwarf result
  197. lastopendwarf := false;
  198. // Save newly processed filename
  199. lastfilename := filename;
  200. // Open exe file or debug link
  201. if not OpenExeFile(e,filename) then
  202. exit;
  203. if ReadDebugLink(e,dbgfn) then
  204. begin
  205. CloseExeFile(e);
  206. if not OpenExeFile(e,dbgfn) then
  207. exit;
  208. end;
  209. // Find debug data section
  210. e.processaddress:=ptruint(baseaddr)-e.processaddress;
  211. if FindExeSection(e,'.debug_line',Dwarf_Debug_Line_Section_offset,dwarf_Debug_Line_Section_size) and
  212. FindExeSection(e,'.debug_info',Dwarf_Debug_Info_Section_offset,dwarf_Debug_Info_Section_size) and
  213. FindExeSection(e,'.debug_abbrev',Dwarf_Debug_Abbrev_Section_offset,dwarf_Debug_Abbrev_Section_size) then
  214. begin
  215. lastopendwarf:=true;
  216. OpenDwarf:=true;
  217. DEBUG_WRITELN('.debug_line starts at offset $',hexstr(Dwarf_Debug_Line_Section_offset,8),' with a size of ',Dwarf_Debug_Line_Section_Size,' Bytes');
  218. DEBUG_WRITELN('.debug_info starts at offset $',hexstr(Dwarf_Debug_Info_Section_offset,8),' with a size of ',Dwarf_Debug_Info_Section_Size,' Bytes');
  219. DEBUG_WRITELN('.debug_abbrev starts at offset $',hexstr(Dwarf_Debug_Abbrev_Section_offset,8),' with a size of ',Dwarf_Debug_Abbrev_Section_Size,' Bytes');
  220. end
  221. else
  222. CloseExeFile(e);
  223. end;
  224. procedure CloseDwarf;
  225. begin
  226. if e.isopen then
  227. CloseExeFile(e);
  228. // Reset last processed filename
  229. lastfilename := '';
  230. end;
  231. function Init(aBase, aLimit : Int64) : Boolean;
  232. begin
  233. base := aBase;
  234. limit := aLimit;
  235. Init := (aBase + limit) <= e.size;
  236. seek(e.f, base);
  237. EBufCnt := 0;
  238. EBufPos := 0;
  239. index := 0;
  240. end;
  241. function Init(aBase : Int64) : Boolean;
  242. begin
  243. Init := Init(aBase, limit - (aBase - base));
  244. end;
  245. function Pos() : Int64;
  246. begin
  247. Pos := index;
  248. end;
  249. procedure Seek(const newIndex : Int64);
  250. begin
  251. index := newIndex;
  252. system.seek(e.f, base + index);
  253. EBufCnt := 0;
  254. EBufPos := 0;
  255. end;
  256. { Returns the next Byte from the input stream, or -1 if there has been
  257. an error }
  258. function ReadNext() : Longint; inline;
  259. var
  260. bytesread : SizeInt;
  261. begin
  262. ReadNext := -1;
  263. if EBufPos >= EBufCnt then begin
  264. EBufPos := 0;
  265. EBufCnt := EBUF_SIZE;
  266. if EBufCnt > limit - index then
  267. EBufCnt := limit - index;
  268. blockread(e.f, EBuf, EBufCnt, bytesread);
  269. EBufCnt := bytesread;
  270. end;
  271. if EBufPos < EBufCnt then begin
  272. ReadNext := EBuf[EBufPos];
  273. inc(EBufPos);
  274. inc(index);
  275. end
  276. else
  277. ReadNext := -1;
  278. end;
  279. { Reads the next size bytes into dest. Returns true if successful,
  280. false otherwise. Note that dest may be partially overwritten after
  281. returning false. }
  282. function ReadNext(var dest; size : SizeInt) : Boolean;
  283. var
  284. bytesread, totalread : SizeInt;
  285. r: Boolean;
  286. d: PByte;
  287. begin
  288. d := @dest;
  289. totalread := 0;
  290. r := True;
  291. while (totalread < size) and r do begin;
  292. if EBufPos >= EBufCnt then begin
  293. EBufPos := 0;
  294. EBufCnt := EBUF_SIZE;
  295. if EBufCnt > limit - index then
  296. EBufCnt := limit - index;
  297. blockread(e.f, EBuf, EBufCnt, bytesread);
  298. EBufCnt := bytesread;
  299. if bytesread <= 0 then
  300. r := False;
  301. end;
  302. if EBufPos < EBufCnt then begin
  303. bytesread := EBufCnt - EBufPos;
  304. if bytesread > size - totalread then bytesread := size - totalread;
  305. System.Move(EBuf[EBufPos], d[totalread], bytesread);
  306. inc(EBufPos, bytesread);
  307. inc(index, bytesread);
  308. inc(totalread, bytesread);
  309. end;
  310. end;
  311. ReadNext := r;
  312. end;
  313. { Reads an unsigned LEB encoded number from the input stream }
  314. function ReadULEB128() : QWord;
  315. var
  316. shift : Byte;
  317. data : PtrInt;
  318. val : QWord;
  319. begin
  320. shift := 0;
  321. ReadULEB128 := 0;
  322. data := ReadNext();
  323. while (data <> -1) do begin
  324. val := data and $7f;
  325. ReadULEB128 := ReadULEB128 or (val shl shift);
  326. inc(shift, 7);
  327. if ((data and $80) = 0) then
  328. break;
  329. data := ReadNext();
  330. end;
  331. end;
  332. { Reads a signed LEB encoded number from the input stream }
  333. function ReadLEB128() : Int64;
  334. var
  335. shift : Byte;
  336. data : PtrInt;
  337. val : Int64;
  338. begin
  339. shift := 0;
  340. ReadLEB128 := 0;
  341. data := ReadNext();
  342. while (data <> -1) do begin
  343. val := data and $7f;
  344. ReadLEB128 := ReadLEB128 or (val shl shift);
  345. inc(shift, 7);
  346. if ((data and $80) = 0) then
  347. break;
  348. data := ReadNext();
  349. end;
  350. { extend sign. Note that we can not use shl/shr since the latter does not
  351. translate to arithmetic shifting for signed types }
  352. ReadLEB128 := (not ((ReadLEB128 and (1 shl (shift-1)))-1)) or ReadLEB128;
  353. end;
  354. { Reads an address from the current input stream }
  355. function ReadAddress() : PtrUInt;
  356. begin
  357. ReadNext(ReadAddress, sizeof(ReadAddress));
  358. end;
  359. { Reads a zero-terminated string from the current input stream. If the
  360. string is larger than 255 chars (maximum allowed number of elements in
  361. a ShortString, excess characters will be chopped off. }
  362. function ReadString() : ShortString;
  363. var
  364. temp : PtrInt;
  365. i : PtrUInt;
  366. begin
  367. i := 1;
  368. temp := ReadNext();
  369. while (temp > 0) do begin
  370. ReadString[i] := char(temp);
  371. if (i = 255) then begin
  372. { skip remaining characters }
  373. repeat
  374. temp := ReadNext();
  375. until (temp <= 0);
  376. break;
  377. end;
  378. inc(i);
  379. temp := ReadNext();
  380. end;
  381. { unexpected end of file occurred? }
  382. if (temp = -1) then
  383. ReadString := ''
  384. else
  385. Byte(ReadString[0]) := i-1;
  386. end;
  387. { Reads an unsigned Half from the current input stream }
  388. function ReadUHalf() : Word;
  389. begin
  390. ReadNext(ReadUHalf, sizeof(ReadUHalf));
  391. end;
  392. {---------------------------------------------------------------------------
  393. Generic Dwarf lineinfo reader
  394. The line info reader is based on the information contained in
  395. DWARF Debugging Information Format Version 3
  396. Chapter 6.2 "Line Number Information"
  397. from the
  398. DWARF Debugging Information Format Workgroup.
  399. For more information on this document see also
  400. http://dwarf.freestandards.org/
  401. ---------------------------------------------------------------------------}
  402. { initializes the line info state to the default values }
  403. procedure InitStateRegisters(var state : TMachineState; const aIs_Stmt : Bool8);
  404. begin
  405. with state do begin
  406. address := 0;
  407. file_id := 1;
  408. line := 1;
  409. column := 0;
  410. is_stmt := aIs_Stmt;
  411. basic_block := false;
  412. end_sequence := false;
  413. prolouge_end := false;
  414. epilouge_begin := false;
  415. isa := 0;
  416. append_row := false;
  417. end;
  418. end;
  419. { Skips all line info directory entries }
  420. procedure SkipDirectories();
  421. var s : ShortString;
  422. begin
  423. while (true) do begin
  424. s := ReadString();
  425. if (s = '') then break;
  426. DEBUG_WRITELN('Skipping directory : ', s);
  427. end;
  428. end;
  429. { Skips an LEB128 }
  430. procedure SkipLEB128();
  431. {$ifdef DEBUG_DWARF_PARSER}
  432. var temp : QWord;
  433. {$endif}
  434. begin
  435. {$ifdef DEBUG_DWARF_PARSER}temp := {$endif}ReadLEB128();
  436. DEBUG_WRITELN('Skipping LEB128 : ', temp);
  437. end;
  438. { Skips the filename section from the current file stream }
  439. procedure SkipFilenames();
  440. var s : ShortString;
  441. begin
  442. while (true) do begin
  443. s := ReadString();
  444. if (s = '') then break;
  445. DEBUG_WRITELN('Skipping filename : ', s);
  446. SkipLEB128(); { skip the directory index for the file }
  447. SkipLEB128(); { skip last modification time for file }
  448. SkipLEB128(); { skip length of file }
  449. end;
  450. end;
  451. function CalculateAddressIncrement(opcode : Byte; const header : TLineNumberProgramHeader64) : Int64;
  452. begin
  453. CalculateAddressIncrement := (Int64(opcode) - header.opcode_base) div header.line_range * header.minimum_instruction_length;
  454. end;
  455. function GetFullFilename(const filenameStart, directoryStart : Int64; const file_id : DWord) : ShortString;
  456. var
  457. i : DWord;
  458. filename, directory : ShortString;
  459. dirindex : Int64;
  460. begin
  461. filename := '';
  462. directory := '';
  463. i := 1;
  464. Seek(filenameStart);
  465. while (i <= file_id) do begin
  466. filename := ReadString();
  467. DEBUG_WRITELN('Found "', filename, '"');
  468. if (filename = '') then break;
  469. dirindex := ReadLEB128(); { read the directory index for the file }
  470. SkipLEB128(); { skip last modification time for file }
  471. SkipLEB128(); { skip length of file }
  472. inc(i);
  473. end;
  474. { if we could not find the file index, exit }
  475. if (filename = '') then begin
  476. GetFullFilename := '(Unknown file)';
  477. exit;
  478. end;
  479. Seek(directoryStart);
  480. i := 1;
  481. while (i <= dirindex) do begin
  482. directory := ReadString();
  483. if (directory = '') then break;
  484. inc(i);
  485. end;
  486. if (directory<>'') and (directory[length(directory)]<>'/') then
  487. directory:=directory+'/';
  488. GetFullFilename := directory + filename;
  489. end;
  490. function ParseCompilationUnit(const addr : PtrUInt; const file_offset : QWord;
  491. var source : String; var line : longint; var found : Boolean) : QWord;
  492. var
  493. state : TMachineState;
  494. { we need both headers on the stack, although we only use the 64 bit one internally }
  495. header64 : TLineNumberProgramHeader64;
  496. header32 : TLineNumberProgramHeader32;
  497. adjusted_opcode : Int64;
  498. opcode : PtrInt;
  499. extended_opcode : PtrInt;
  500. extended_opcode_length : PtrInt;
  501. i, addrIncrement, lineIncrement : PtrInt;
  502. {$ifdef DEBUG_DWARF_PARSER}
  503. s : ShortString;
  504. {$endif}
  505. numoptable : array[1..255] of Byte;
  506. { the offset into the file where the include directories are stored for this compilation unit }
  507. include_directories : QWord;
  508. { the offset into the file where the file names are stored for this compilation unit }
  509. file_names : Int64;
  510. temp_length : DWord;
  511. unit_length : QWord;
  512. header_length : SizeInt;
  513. first_row : Boolean;
  514. prev_line : QWord;
  515. prev_file : DWord;
  516. begin
  517. prev_line := 0;
  518. prev_file := 0;
  519. first_row := true;
  520. found := false;
  521. ReadNext(temp_length, sizeof(temp_length));
  522. if (temp_length <> $ffffffff) then begin
  523. unit_length := temp_length + sizeof(temp_length)
  524. end else begin
  525. ReadNext(unit_length, sizeof(unit_length));
  526. inc(unit_length, 12);
  527. end;
  528. ParseCompilationUnit := file_offset + unit_length;
  529. Init(file_offset, unit_length);
  530. DEBUG_WRITELN('Unit length: ', unit_length);
  531. if (temp_length <> $ffffffff) then begin
  532. DEBUG_WRITELN('32 bit DWARF detected');
  533. ReadNext(header32, sizeof(header32));
  534. header64.magic := $ffffffff;
  535. header64.unit_length := header32.unit_length;
  536. header64.version := header32.version;
  537. header64.length := header32.length;
  538. header64.minimum_instruction_length := header32.minimum_instruction_length;
  539. header64.default_is_stmt := header32.default_is_stmt;
  540. header64.line_base := header32.line_base;
  541. header64.line_range := header32.line_range;
  542. header64.opcode_base := header32.opcode_base;
  543. header_length :=
  544. sizeof(header32.length) + sizeof(header32.version) +
  545. sizeof(header32.unit_length);
  546. end else begin
  547. DEBUG_WRITELN('64 bit DWARF detected');
  548. ReadNext(header64, sizeof(header64));
  549. header_length :=
  550. sizeof(header64.magic) + sizeof(header64.version) +
  551. sizeof(header64.length) + sizeof(header64.unit_length);
  552. end;
  553. inc(header_length, header64.length);
  554. fillchar(numoptable, sizeof(numoptable), #0);
  555. ReadNext(numoptable, header64.opcode_base-1);
  556. DEBUG_WRITELN('Opcode parameter count table');
  557. for i := 1 to header64.opcode_base-1 do begin
  558. DEBUG_WRITELN('Opcode[', i, '] - ', numoptable[i], ' parameters');
  559. end;
  560. DEBUG_WRITELN('Reading directories...');
  561. include_directories := Pos();
  562. SkipDirectories();
  563. DEBUG_WRITELN('Reading filenames...');
  564. file_names := Pos();
  565. SkipFilenames();
  566. Seek(header_length);
  567. with header64 do begin
  568. InitStateRegisters(state, default_is_stmt);
  569. end;
  570. opcode := ReadNext();
  571. while (opcode <> -1) and (not found) do begin
  572. DEBUG_WRITELN('Next opcode: ');
  573. case (opcode) of
  574. { extended opcode }
  575. 0 : begin
  576. extended_opcode_length := ReadULEB128();
  577. extended_opcode := ReadNext();
  578. case (extended_opcode) of
  579. -1: begin
  580. exit;
  581. end;
  582. DW_LNE_END_SEQUENCE : begin
  583. state.end_sequence := true;
  584. state.append_row := true;
  585. DEBUG_WRITELN('DW_LNE_END_SEQUENCE');
  586. end;
  587. DW_LNE_SET_ADDRESS : begin
  588. state.address := ReadAddress();
  589. DEBUG_WRITELN('DW_LNE_SET_ADDRESS (', hexstr(state.address, sizeof(state.address)*2), ')');
  590. end;
  591. DW_LNE_DEFINE_FILE : begin
  592. {$ifdef DEBUG_DWARF_PARSER}s := {$endif}ReadString();
  593. SkipLEB128();
  594. SkipLEB128();
  595. SkipLEB128();
  596. DEBUG_WRITELN('DW_LNE_DEFINE_FILE (', s, ')');
  597. end;
  598. else begin
  599. DEBUG_WRITELN('Unknown extended opcode (opcode ', extended_opcode, ' length ', extended_opcode_length, ')');
  600. for i := 0 to extended_opcode_length-2 do
  601. if ReadNext() = -1 then
  602. exit;
  603. end;
  604. end;
  605. end;
  606. DW_LNS_COPY : begin
  607. state.basic_block := false;
  608. state.prolouge_end := false;
  609. state.epilouge_begin := false;
  610. state.append_row := true;
  611. DEBUG_WRITELN('DW_LNS_COPY');
  612. end;
  613. DW_LNS_ADVANCE_PC : begin
  614. inc(state.address, ReadULEB128() * header64.minimum_instruction_length);
  615. DEBUG_WRITELN('DW_LNS_ADVANCE_PC (', hexstr(state.address, sizeof(state.address)*2), ')');
  616. end;
  617. DW_LNS_ADVANCE_LINE : begin
  618. // inc(state.line, ReadLEB128()); negative values are allowed
  619. // but those may generate a range check error
  620. state.line := state.line + ReadLEB128();
  621. DEBUG_WRITELN('DW_LNS_ADVANCE_LINE (', state.line, ')');
  622. end;
  623. DW_LNS_SET_FILE : begin
  624. state.file_id := ReadULEB128();
  625. DEBUG_WRITELN('DW_LNS_SET_FILE (', state.file_id, ')');
  626. end;
  627. DW_LNS_SET_COLUMN : begin
  628. state.column := ReadULEB128();
  629. DEBUG_WRITELN('DW_LNS_SET_COLUMN (', state.column, ')');
  630. end;
  631. DW_LNS_NEGATE_STMT : begin
  632. state.is_stmt := not state.is_stmt;
  633. DEBUG_WRITELN('DW_LNS_NEGATE_STMT (', state.is_stmt, ')');
  634. end;
  635. DW_LNS_SET_BASIC_BLOCK : begin
  636. state.basic_block := true;
  637. DEBUG_WRITELN('DW_LNS_SET_BASIC_BLOCK');
  638. end;
  639. DW_LNS_CONST_ADD_PC : begin
  640. inc(state.address, CalculateAddressIncrement(255, header64));
  641. DEBUG_WRITELN('DW_LNS_CONST_ADD_PC (', hexstr(state.address, sizeof(state.address)*2), ')');
  642. end;
  643. DW_LNS_FIXED_ADVANCE_PC : begin
  644. inc(state.address, ReadUHalf());
  645. DEBUG_WRITELN('DW_LNS_FIXED_ADVANCE_PC (', hexstr(state.address, sizeof(state.address)*2), ')');
  646. end;
  647. DW_LNS_SET_PROLOGUE_END : begin
  648. state.prolouge_end := true;
  649. DEBUG_WRITELN('DW_LNS_SET_PROLOGUE_END');
  650. end;
  651. DW_LNS_SET_EPILOGUE_BEGIN : begin
  652. state.epilouge_begin := true;
  653. DEBUG_WRITELN('DW_LNS_SET_EPILOGUE_BEGIN');
  654. end;
  655. DW_LNS_SET_ISA : begin
  656. state.isa := ReadULEB128();
  657. DEBUG_WRITELN('DW_LNS_SET_ISA (', state.isa, ')');
  658. end;
  659. else begin { special opcode }
  660. if (opcode < header64.opcode_base) then begin
  661. DEBUG_WRITELN('Unknown standard opcode $', hexstr(opcode, 2), '; skipping');
  662. for i := 1 to numoptable[opcode] do
  663. SkipLEB128();
  664. end else begin
  665. adjusted_opcode := opcode - header64.opcode_base;
  666. addrIncrement := CalculateAddressIncrement(opcode, header64);
  667. inc(state.address, addrIncrement);
  668. lineIncrement := header64.line_base + (adjusted_opcode mod header64.line_range);
  669. inc(state.line, lineIncrement);
  670. DEBUG_WRITELN('Special opcode $', hexstr(opcode, 2), ' address increment: ', addrIncrement, ' new line: ', lineIncrement);
  671. state.basic_block := false;
  672. state.prolouge_end := false;
  673. state.epilouge_begin := false;
  674. state.append_row := true;
  675. end;
  676. end;
  677. end;
  678. if (state.append_row) then begin
  679. DEBUG_WRITELN('Current state : address = ', hexstr(state.address, sizeof(state.address) * 2),
  680. DEBUG_COMMENT ' file_id = ', state.file_id, ' line = ', state.line, ' column = ', state.column,
  681. DEBUG_COMMENT ' is_stmt = ', state.is_stmt, ' basic_block = ', state.basic_block,
  682. DEBUG_COMMENT ' end_sequence = ', state.end_sequence, ' prolouge_end = ', state.prolouge_end,
  683. DEBUG_COMMENT ' epilouge_begin = ', state.epilouge_begin, ' isa = ', state.isa);
  684. if (first_row) then begin
  685. if (state.address > addr) then
  686. break;
  687. first_row := false;
  688. end;
  689. { when we have found the address we need to return the previous
  690. line because that contains the call instruction }
  691. if (state.address >= addr) then
  692. found:=true
  693. else
  694. begin
  695. { save line information }
  696. prev_file := state.file_id;
  697. prev_line := state.line;
  698. end;
  699. state.append_row := false;
  700. if (state.end_sequence) then begin
  701. InitStateRegisters(state, header64.default_is_stmt);
  702. first_row := true;
  703. end;
  704. end;
  705. opcode := ReadNext();
  706. end;
  707. if (found) then begin
  708. line := prev_line;
  709. source := GetFullFilename(file_names, include_directories, prev_file);
  710. end;
  711. end;
  712. var
  713. Abbrev_Offsets : array of QWord;
  714. Abbrev_Tags : array of QWord;
  715. Abbrev_Children : array of Byte;
  716. Abbrev_Attrs : array of array of record attr,form : QWord; end;
  717. procedure ReadAbbrevTable;
  718. var
  719. i : PtrInt;
  720. tag,
  721. nr,
  722. attr,
  723. form,
  724. PrevHigh : Int64;
  725. begin
  726. DEBUG_WRITELN('Starting to read abbrev. section at $',hexstr(Dwarf_Debug_Abbrev_Section_Offset+Pos,16));
  727. repeat
  728. nr:=ReadULEB128;
  729. if nr=0 then
  730. break;
  731. if nr>high(Abbrev_Offsets) then
  732. begin
  733. SetLength(Abbrev_Offsets,nr+1024);
  734. SetLength(Abbrev_Tags,nr+1024);
  735. SetLength(Abbrev_Attrs,nr+1024);
  736. SetLength(Abbrev_Children,nr+1024);
  737. end;
  738. Abbrev_Offsets[nr]:=Pos;
  739. { read tag }
  740. tag:=ReadULEB128;
  741. Abbrev_Tags[nr]:=tag;
  742. DEBUG_WRITELN('Abbrev ',nr,' at offset ',Pos,' has tag $',hexstr(tag,4));
  743. { read flag for children }
  744. Abbrev_Children[nr]:=ReadNext;
  745. i:=0;
  746. { ensure that length(Abbrev_Attrs)=0 if an entry is overwritten (not sure if this will ever happen) and
  747. the new entry has no attributes }
  748. Abbrev_Attrs[nr]:=nil;
  749. repeat
  750. attr:=ReadULEB128;
  751. form:=ReadULEB128;
  752. if attr<>0 then
  753. begin
  754. SetLength(Abbrev_Attrs[nr],i+1);
  755. Abbrev_Attrs[nr][i].attr:=attr;
  756. Abbrev_Attrs[nr][i].form:=form;
  757. end;
  758. inc(i);
  759. until attr=0;
  760. DEBUG_WRITELN('Abbrev ',nr,' has ',Length(Abbrev_Attrs[nr]),' attributes');
  761. until false;
  762. end;
  763. function ParseCompilationUnitForFunctionName(const addr : PtrUInt; const file_offset : QWord;
  764. var func : String; var found : Boolean) : QWord;
  765. var
  766. state : TMachineState;
  767. { we need both headers on the stack, although we only use the 64 bit one internally }
  768. header64 : TDebugInfoProgramHeader64;
  769. header32 : TDebugInfoProgramHeader32;
  770. isdwarf64 : boolean;
  771. abbrev,
  772. high_pc,
  773. low_pc : QWord;
  774. temp_length : DWord;
  775. unit_length : QWord;
  776. name : String;
  777. level : Integer;
  778. procedure SkipAttr(form : QWord);
  779. var
  780. dummy : array[0..7] of byte;
  781. bl : byte;
  782. wl : word;
  783. dl : dword;
  784. ql : qword;
  785. i : PtrUInt;
  786. begin
  787. case form of
  788. DW_FORM_addr:
  789. ReadNext(dummy,header64.address_size);
  790. DW_FORM_block2:
  791. begin
  792. ReadNext(wl,SizeOf(wl));
  793. for i:=1 to wl do
  794. ReadNext;
  795. end;
  796. DW_FORM_block4:
  797. begin
  798. ReadNext(dl,SizeOf(dl));
  799. for i:=1 to dl do
  800. ReadNext;
  801. end;
  802. DW_FORM_data2:
  803. ReadNext(dummy,2);
  804. DW_FORM_data4:
  805. ReadNext(dummy,4);
  806. DW_FORM_data8:
  807. ReadNext(dummy,8);
  808. DW_FORM_string:
  809. ReadString;
  810. DW_FORM_block:
  811. begin
  812. ql:=ReadULEB128;
  813. for i:=1 to ql do
  814. ReadNext;
  815. end;
  816. DW_FORM_block1:
  817. begin
  818. bl:=ReadNext;
  819. for i:=1 to bl do
  820. ReadNext;
  821. end;
  822. DW_FORM_data1,
  823. DW_FORM_flag:
  824. ReadNext(dummy,1);
  825. DW_FORM_sdata:
  826. ReadLEB128;
  827. DW_FORM_ref_addr,
  828. DW_FORM_strp:
  829. if isdwarf64 then
  830. ReadNext(dummy,8)
  831. else
  832. ReadNext(dummy,4);
  833. DW_FORM_udata:
  834. ReadULEB128;
  835. DW_FORM_ref1:
  836. ReadNext(dummy,1);
  837. DW_FORM_ref2:
  838. ReadNext(dummy,2);
  839. DW_FORM_ref4:
  840. ReadNext(dummy,4);
  841. DW_FORM_ref8:
  842. ReadNext(dummy,8);
  843. DW_FORM_ref_udata:
  844. ReadULEB128;
  845. DW_FORM_indirect:
  846. SkipAttr(ReadULEB128);
  847. else
  848. begin
  849. writeln(stderr,'Internal error: unknown dwarf form: $',hexstr(form,2));
  850. ReadNext;
  851. exit;
  852. end;
  853. end;
  854. end;
  855. var
  856. i : PtrInt;
  857. prev_base,prev_limit : SizeInt;
  858. prev_pos : Int64;
  859. begin
  860. found := false;
  861. ReadNext(temp_length, sizeof(temp_length));
  862. if (temp_length <> $ffffffff) then begin
  863. unit_length := temp_length + sizeof(temp_length)
  864. end else begin
  865. ReadNext(unit_length, sizeof(unit_length));
  866. inc(unit_length, 12);
  867. end;
  868. ParseCompilationUnitForFunctionName := file_offset + unit_length;
  869. Init(file_offset, unit_length);
  870. DEBUG_WRITELN('Unit length: ', unit_length);
  871. if (temp_length <> $ffffffff) then begin
  872. DEBUG_WRITELN('32 bit DWARF detected');
  873. ReadNext(header32, sizeof(header32));
  874. header64.magic := $ffffffff;
  875. header64.unit_length := header32.unit_length;
  876. header64.version := header32.version;
  877. header64.debug_abbrev_offset := header32.debug_abbrev_offset;
  878. header64.address_size := header32.address_size;
  879. isdwarf64:=false;
  880. end else begin
  881. DEBUG_WRITELN('64 bit DWARF detected');
  882. ReadNext(header64, sizeof(header64));
  883. isdwarf64:=true;
  884. end;
  885. DEBUG_WRITELN('debug_abbrev_offset: ',header64.debug_abbrev_offset);
  886. { not nice, but we have to read the abbrev section after the start of the debug_info section has been read }
  887. prev_limit:=limit;
  888. prev_base:=base;
  889. prev_pos:=Pos;
  890. Init(Dwarf_Debug_Abbrev_Section_Offset+header64.debug_abbrev_offset,Dwarf_Debug_Abbrev_Section_Size);
  891. ReadAbbrevTable;
  892. { restore previous reading state and position }
  893. Init(prev_base,prev_limit);
  894. Seek(prev_pos);
  895. abbrev:=ReadULEB128;
  896. level:=0;
  897. while (abbrev <> 0) and (not found) do
  898. begin
  899. DEBUG_WRITELN('Next abbrev: ',abbrev);
  900. if Abbrev_Children[abbrev]<>0 then
  901. inc(level);
  902. { DW_TAG_subprogram? }
  903. if Abbrev_Tags[abbrev]=$2e then
  904. begin
  905. low_pc:=1;
  906. high_pc:=0;
  907. name:='';
  908. for i:=0 to high(Abbrev_Attrs[abbrev]) do
  909. begin
  910. { DW_AT_low_pc }
  911. if (Abbrev_Attrs[abbrev][i].attr=$11) and
  912. (Abbrev_Attrs[abbrev][i].form=DW_FORM_addr) then
  913. begin
  914. low_pc:=0;
  915. ReadNext(low_pc,header64.address_size);
  916. end
  917. { DW_AT_high_pc }
  918. else if (Abbrev_Attrs[abbrev][i].attr=$12) and
  919. (Abbrev_Attrs[abbrev][i].form=DW_FORM_addr) then
  920. begin
  921. high_pc:=0;
  922. ReadNext(high_pc,header64.address_size);
  923. end
  924. { DW_AT_name }
  925. else if (Abbrev_Attrs[abbrev][i].attr=$3) and
  926. { avoid that we accidently read an DW_FORM_strp entry accidently }
  927. (Abbrev_Attrs[abbrev][i].form=DW_FORM_string) then
  928. begin
  929. name:=ReadString;
  930. end
  931. else
  932. SkipAttr(Abbrev_Attrs[abbrev][i].form);
  933. end;
  934. DEBUG_WRITELN('Got DW_TAG_subprogram with low pc = $',hexStr(low_pc,header64.address_size*2),', high pc = $',hexStr(high_pc,header64.address_size*2),', name = ',name);
  935. if (addr>low_pc) and (addr<high_pc) then
  936. begin
  937. found:=true;
  938. func:=name;
  939. end;
  940. end
  941. else
  942. begin
  943. for i:=0 to high(Abbrev_Attrs[abbrev]) do
  944. SkipAttr(Abbrev_Attrs[abbrev][i].form);
  945. end;
  946. abbrev:=ReadULEB128;
  947. { skip entries signaling that no more child entries are following }
  948. while (level>0) and (abbrev=0) do
  949. begin
  950. dec(level);
  951. abbrev:=ReadULEB128;
  952. end;
  953. end;
  954. end;
  955. function GetLineInfo(addr : ptruint; var func, source : string; var line : longint) : boolean;
  956. var
  957. current_offset : QWord;
  958. end_offset : QWord;
  959. found : Boolean;
  960. begin
  961. func := '';
  962. source := '';
  963. GetLineInfo:=false;
  964. if not OpenDwarf(pointer(addr)) then
  965. exit;
  966. addr := addr - e.processaddress;
  967. current_offset := Dwarf_Debug_Line_Section_Offset;
  968. end_offset := Dwarf_Debug_Line_Section_Offset + Dwarf_Debug_Line_Section_Size;
  969. found := false;
  970. while (current_offset < end_offset) and (not found) do begin
  971. Init(current_offset, end_offset - current_offset);
  972. current_offset := ParseCompilationUnit(addr, current_offset,
  973. source, line, found);
  974. end;
  975. current_offset := Dwarf_Debug_Info_Section_Offset;
  976. end_offset := Dwarf_Debug_Info_Section_Offset + Dwarf_Debug_Info_Section_Size;
  977. found := false;
  978. while (current_offset < end_offset) and (not found) do begin
  979. Init(current_offset, end_offset - current_offset);
  980. current_offset := ParseCompilationUnitForFunctionName(addr, current_offset, func, found);
  981. end;
  982. if not AllowReuseOfLineInfoData then
  983. CloseDwarf;
  984. GetLineInfo:=true;
  985. end;
  986. function DwarfBackTraceStr(addr: CodePointer): string;
  987. var
  988. func,
  989. source : string;
  990. hs : string;
  991. line : longint;
  992. Store : TBackTraceStrFunc;
  993. Success : boolean;
  994. begin
  995. {$ifdef DEBUG_LINEINFO}
  996. writeln(stderr,'DwarfBackTraceStr called');
  997. {$endif DEBUG_LINEINFO}
  998. { reset to prevent infinite recursion if problems inside the code }
  999. Success:=false;
  1000. Store := BackTraceStrFunc;
  1001. BackTraceStrFunc := @SysBackTraceStr;
  1002. Success:=GetLineInfo(ptruint(addr), func, source, line);
  1003. { create string }
  1004. DwarfBackTraceStr :=' $' + HexStr(ptruint(addr), sizeof(ptruint) * 2);
  1005. if Success then
  1006. begin
  1007. if func<>'' then
  1008. DwarfBackTraceStr := DwarfBackTraceStr + ' ' + func;
  1009. if source<>'' then
  1010. begin
  1011. if func<>'' then
  1012. DwarfBackTraceStr := DwarfBackTraceStr + ', ';
  1013. if line<>0 then
  1014. begin
  1015. str(line, hs);
  1016. DwarfBackTraceStr := DwarfBackTraceStr + ' line ' + hs;
  1017. end;
  1018. DwarfBackTraceStr := DwarfBackTraceStr + ' of ' + source;
  1019. end;
  1020. end;
  1021. BackTraceStrFunc := Store;
  1022. end;
  1023. initialization
  1024. lastfilename := '';
  1025. lastopendwarf := false;
  1026. BackTraceStrFunc := @DwarfBacktraceStr;
  1027. finalization
  1028. CloseDwarf;
  1029. end.