lnfodwrf.pp 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434
  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:codeptruint;var func,source:string;var line:longint) : boolean;
  26. function DwarfBackTraceStr(addr: CodePointer): shortstring;
  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. {$IFDEF FPC_DOTTEDUNITS}
  36. uses
  37. System.ExeInfo;
  38. {$ELSE FPC_DOTTEDUNITS}
  39. uses
  40. exeinfo;
  41. {$ENDIF FPC_DOTTEDUNITS}
  42. { Current issues:
  43. - ignores DW_LNS_SET_FILE
  44. }
  45. {$MACRO ON}
  46. { $DEFINE DEBUG_DWARF_PARSER}
  47. {$ifdef DEBUG_DWARF_PARSER}
  48. {$define DEBUG_WRITELN := WriteLn}
  49. {$define DEBUG_COMMENT := }
  50. {$else}
  51. {$define DEBUG_WRITELN := //}
  52. {$define DEBUG_COMMENT := //}
  53. {$endif}
  54. { some type definitions }
  55. type
  56. Bool8 = ByteBool;
  57. {$ifdef CPUI8086}
  58. TOffset = Word;
  59. {$else CPUI8086}
  60. TOffset = PtrUInt;
  61. {$endif CPUI8086}
  62. TSegment = Word;
  63. {$WARNING This code is not thread-safe, and needs improvement}
  64. var
  65. { the input file to read DWARF debug info from, i.e. paramstr(0) }
  66. e : TExeFile;
  67. { the offset and size of the DWARF debug_line section in the file }
  68. Dwarf_Debug_Line_Section_Offset,
  69. Dwarf_Debug_Line_Section_Size,
  70. { the offset and size of the DWARF debug_info section in the file }
  71. Dwarf_Debug_Info_Section_Offset,
  72. Dwarf_Debug_Info_Section_Size,
  73. { the offset and size of the DWARF debug_aranges section in the file }
  74. Dwarf_Debug_Aranges_Section_Offset,
  75. Dwarf_Debug_Aranges_Section_Size,
  76. { the offset and size of the DWARF debug_abbrev section in the file }
  77. Dwarf_Debug_Abbrev_Section_Offset,
  78. Dwarf_Debug_Abbrev_Section_Size : longint;
  79. { DWARF 2 default opcodes}
  80. const
  81. { Extended opcodes }
  82. DW_LNE_END_SEQUENCE = 1;
  83. DW_LNE_SET_ADDRESS = 2;
  84. DW_LNE_DEFINE_FILE = 3;
  85. {$ifdef CPUI8086}
  86. { non-standard Open Watcom extension; might conflict with future versions of
  87. the DWARF standard }
  88. DW_LNE_SET_SEGMENT = 4;
  89. {$endif CPUI8086}
  90. { Standard opcodes }
  91. DW_LNS_COPY = 1;
  92. DW_LNS_ADVANCE_PC = 2;
  93. DW_LNS_ADVANCE_LINE = 3;
  94. DW_LNS_SET_FILE = 4;
  95. DW_LNS_SET_COLUMN = 5;
  96. DW_LNS_NEGATE_STMT = 6;
  97. DW_LNS_SET_BASIC_BLOCK = 7;
  98. DW_LNS_CONST_ADD_PC = 8;
  99. DW_LNS_FIXED_ADVANCE_PC = 9;
  100. DW_LNS_SET_PROLOGUE_END = 10;
  101. DW_LNS_SET_EPILOGUE_BEGIN = 11;
  102. DW_LNS_SET_ISA = 12;
  103. DW_FORM_addr = $1;
  104. DW_FORM_block2 = $3;
  105. DW_FORM_block4 = $4;
  106. DW_FORM_data2 = $5;
  107. DW_FORM_data4 = $6;
  108. DW_FORM_data8 = $7;
  109. DW_FORM_string = $8;
  110. DW_FORM_block = $9;
  111. DW_FORM_block1 = $a;
  112. DW_FORM_data1 = $b;
  113. DW_FORM_flag = $c;
  114. DW_FORM_sdata = $d;
  115. DW_FORM_strp = $e;
  116. DW_FORM_udata = $f;
  117. DW_FORM_ref_addr = $10;
  118. DW_FORM_ref1 = $11;
  119. DW_FORM_ref2 = $12;
  120. DW_FORM_ref4 = $13;
  121. DW_FORM_ref8 = $14;
  122. DW_FORM_ref_udata = $15;
  123. DW_FORM_indirect = $16;
  124. DW_FORM_sec_offset = $17;
  125. DW_FORM_exprloc = $18;
  126. DW_FORM_flag_present = $19;
  127. type
  128. { state record for the line info state machine }
  129. TMachineState = record
  130. address : QWord;
  131. segment : TSegment;
  132. file_id : DWord;
  133. line : QWord;
  134. column : DWord;
  135. is_stmt : Boolean;
  136. basic_block : Boolean;
  137. end_sequence : Boolean;
  138. prolouge_end : Boolean;
  139. epilouge_begin : Boolean;
  140. isa : DWord;
  141. append_row : Boolean;
  142. end;
  143. { DWARF line number program header preceding the line number program, 64 bit version }
  144. TLineNumberProgramHeader64 = packed record
  145. magic : DWord;
  146. unit_length : QWord;
  147. version : Word;
  148. length : QWord;
  149. minimum_instruction_length : Byte;
  150. default_is_stmt : Bool8;
  151. line_base : ShortInt;
  152. line_range : Byte;
  153. opcode_base : Byte;
  154. end;
  155. { DWARF line number program header preceding the line number program, 32 bit version }
  156. TLineNumberProgramHeader32 = packed record
  157. unit_length : DWord;
  158. version : Word;
  159. length : DWord;
  160. minimum_instruction_length : Byte;
  161. default_is_stmt : Bool8;
  162. line_base : ShortInt;
  163. line_range : Byte;
  164. opcode_base : Byte;
  165. end;
  166. TDebugInfoProgramHeader64 = packed record
  167. magic : DWord;
  168. unit_length : QWord;
  169. version : Word;
  170. debug_abbrev_offset : QWord;
  171. address_size : Byte;
  172. end;
  173. TDebugInfoProgramHeader32= packed record
  174. unit_length : DWord;
  175. version : Word;
  176. debug_abbrev_offset : DWord;
  177. address_size : Byte;
  178. end;
  179. TDebugArangesHeader64 = packed record
  180. magic : DWord;
  181. unit_length : QWord;
  182. version : Word;
  183. debug_info_offset : QWord;
  184. address_size : Byte;
  185. segment_size : Byte;
  186. {$ifndef CPUI8086}
  187. padding : DWord;
  188. {$endif CPUI8086}
  189. end;
  190. TDebugArangesHeader32= packed record
  191. unit_length : DWord;
  192. version : Word;
  193. debug_info_offset : DWord;
  194. address_size : Byte;
  195. segment_size : Byte;
  196. {$ifndef CPUI8086}
  197. padding : DWord;
  198. {$endif CPUI8086}
  199. end;
  200. {---------------------------------------------------------------------------
  201. I/O utility functions
  202. ---------------------------------------------------------------------------}
  203. type
  204. {$ifdef cpui8086}
  205. TFilePos = LongInt;
  206. {$else cpui8086}
  207. TFilePos = SizeInt;
  208. {$endif cpui8086}
  209. var
  210. lastfilename: string; { store last processed file }
  211. lastbaseaddr: {$ifdef cpui8086}farpointer{$else}pointer{$endif}; { store last base address }
  212. lastopendwarf: Boolean; { store last result of processing a file }
  213. {$ifdef cpui8086}
  214. function tofar(fp: FarPointer): FarPointer; inline;
  215. begin
  216. tofar:=fp;
  217. end;
  218. function tofar(cp: NearCsPointer): FarPointer; inline;
  219. begin
  220. tofar:=Ptr(CSeg,Word(cp));
  221. end;
  222. function tofar(cp: NearPointer): FarPointer; inline;
  223. begin
  224. tofar:=Ptr(DSeg,Word(cp));
  225. end;
  226. {$else cpui8086}
  227. type
  228. tofar=Pointer;
  229. {$endif cpui8086}
  230. function OpenDwarf(addr : codepointer) : boolean;
  231. var
  232. oldprocessaddress: TExeProcessAddress;
  233. baseaddr : {$ifdef cpui8086}farpointer{$else}pointer{$endif};
  234. filename,dbgfn : ansistring;
  235. begin
  236. // False by default
  237. OpenDwarf:=false;
  238. // Empty so can test if GetModuleByAddr has worked
  239. filename := '';
  240. // Get filename by address using GetModuleByAddr
  241. GetModuleByAddr(tofar(addr),baseaddr,filename);
  242. {$ifdef DEBUG_LINEINFO}
  243. writeln(stderr,filename,' Baseaddr: ',hexstr(baseaddr));
  244. {$endif DEBUG_LINEINFO}
  245. // Check if GetModuleByAddr has worked
  246. if filename = '' then
  247. exit;
  248. // If target filename same as previous, then re-use previous result
  249. if AllowReuseOfLineInfoData and (filename = lastfilename) and (baseaddr = lastbaseaddr) then
  250. begin
  251. {$ifdef DEBUG_LINEINFO}
  252. writeln(stderr,'Reusing debug data');
  253. {$endif DEBUG_LINEINFO}
  254. OpenDwarf:=lastopendwarf;
  255. exit;
  256. end;
  257. // Close previously opened Dwarf
  258. CloseDwarf;
  259. // Reset last open dwarf result
  260. lastopendwarf := false;
  261. // Save newly processed filename
  262. lastfilename := filename;
  263. // Save newly processed file's base address
  264. lastbaseaddr := baseaddr;
  265. // Open exe file or debug link
  266. if not OpenExeFile(e,filename) then
  267. exit;
  268. if ReadDebugLink(e,dbgfn) then
  269. begin
  270. oldprocessaddress:=e.processaddress;
  271. CloseExeFile(e);
  272. if not OpenExeFile(e,dbgfn) then
  273. exit;
  274. e.processaddress:=oldprocessaddress;
  275. end;
  276. // Find debug data section
  277. e.processaddress:=ptruint(baseaddr)-e.processaddress;
  278. if FindExeSection(e,'.debug_line',Dwarf_Debug_Line_Section_offset,dwarf_Debug_Line_Section_size) and
  279. FindExeSection(e,'.debug_info',Dwarf_Debug_Info_Section_offset,dwarf_Debug_Info_Section_size) and
  280. FindExeSection(e,'.debug_abbrev',Dwarf_Debug_Abbrev_Section_offset,dwarf_Debug_Abbrev_Section_size) and
  281. FindExeSection(e,'.debug_aranges',Dwarf_Debug_Aranges_Section_offset,dwarf_Debug_Aranges_Section_size) then
  282. begin
  283. lastopendwarf:=true;
  284. OpenDwarf:=true;
  285. DEBUG_WRITELN('.debug_line starts at offset $',hexstr(Dwarf_Debug_Line_Section_offset,8),' with a size of ',Dwarf_Debug_Line_Section_Size,' Bytes');
  286. DEBUG_WRITELN('.debug_info starts at offset $',hexstr(Dwarf_Debug_Info_Section_offset,8),' with a size of ',Dwarf_Debug_Info_Section_Size,' Bytes');
  287. DEBUG_WRITELN('.debug_abbrev starts at offset $',hexstr(Dwarf_Debug_Abbrev_Section_offset,8),' with a size of ',Dwarf_Debug_Abbrev_Section_Size,' Bytes');
  288. DEBUG_WRITELN('.debug_aranges starts at offset $',hexstr(Dwarf_Debug_Aranges_Section_offset,8),' with a size of ',Dwarf_Debug_Aranges_Section_Size,' Bytes');
  289. end
  290. else
  291. CloseExeFile(e);
  292. end;
  293. procedure CloseDwarf;
  294. begin
  295. if e.isopen then
  296. CloseExeFile(e);
  297. // Reset last processed filename
  298. lastfilename := '';
  299. end;
  300. type
  301. TEReader = object
  302. bufstart, base, limit: Int64; { All of these are absolute. }
  303. bufp, bufe: pByte; { bufp = pointer into buf, bufe - bufp = available bytes. }
  304. buf: array[0 .. 1023] of byte;
  305. procedure Init;
  306. procedure SetRange(aBase, aSize : Int64);
  307. function Pos : TFilePos; { Relative to base. }
  308. procedure Seek(newIndex : Int64); { Relative to base. }
  309. function ReadNext : longint; inline;
  310. function ReadNext(var dest; size : SizeInt) : Boolean;
  311. function ReadULEB128 : QWord;
  312. function ReadLEB128 : Int64;
  313. function ReadAddress(addr_size: smallint) : PtrUInt;
  314. {$ifdef CPUI8086}
  315. function ReadSegment() : Word;
  316. {$endif CPUI8086}
  317. function ReadString : ShortString;
  318. function ReadUHalf : Word;
  319. private
  320. function ReadNextBuffer : longint;
  321. end;
  322. procedure TEReader.Init;
  323. begin
  324. bufstart := 0;
  325. base := 0;
  326. limit := 0;
  327. bufp := pByte(buf);
  328. bufe := bufp;
  329. end;
  330. procedure TEReader.SetRange(aBase, aSize : Int64);
  331. begin
  332. base := aBase;
  333. limit := base + aSize;
  334. Seek(0);
  335. if limit < bufstart + (bufe - pByte(buf)) then
  336. begin
  337. bufe := pByte(buf) + (limit - bufstart); { Respect the limit if the buffer was reused. Probably unreachable, but just in case... }
  338. System.Seek(e.f, limit);
  339. end;
  340. end;
  341. function TEReader.Pos() : TFilePos;
  342. begin
  343. Pos := (bufstart - base) + (bufp - pByte(buf));
  344. end;
  345. procedure TEReader.Seek(newIndex : Int64);
  346. var
  347. gpos : Int64;
  348. begin
  349. gpos := base + newIndex;
  350. if (gpos >= bufstart) and (gpos <= bufstart + (bufe - pByte(buf))) then
  351. bufp := pByte(buf) + (gpos - bufstart) { Reuse the buffer. }
  352. else
  353. begin
  354. bufstart := gpos;
  355. System.Seek(e.f, gpos);
  356. bufp := pByte(buf);
  357. bufe := bufp;
  358. end;
  359. end;
  360. { Returns the next Byte from the input stream, or -1 if there has been
  361. an error }
  362. function TEReader.ReadNext() : Longint;
  363. begin
  364. if (bufp = bufe) and (ReadNextBuffer <= 0) then
  365. exit(-1);
  366. ReadNext := bufp^;
  367. inc(bufp);
  368. end;
  369. { Reads the next size bytes into dest. Returns true if successful,
  370. false otherwise. Note that dest may be partially overwritten after
  371. returning false. dest = nil^ — skip size bytes. }
  372. function TEReader.ReadNext(var dest; size : SizeInt) : Boolean;
  373. var
  374. bytesread : SizeInt;
  375. d: PByte;
  376. begin
  377. d := @dest;
  378. while (size > 0) and ((bufp < bufe) or (ReadNextBuffer > 0)) do
  379. begin
  380. bytesread := bufe - bufp;
  381. if bytesread > size then bytesread := size;
  382. if Assigned(d) then
  383. begin
  384. Move(bufp^, d^, bytesread);
  385. inc(d, bytesread);
  386. end;
  387. inc(bufp, bytesread);
  388. dec(size, bytesread);
  389. end;
  390. ReadNext := size = 0;
  391. end;
  392. { Reads an unsigned LEB encoded number from the input stream }
  393. function TEReader.ReadULEB128() : QWord;
  394. var
  395. shift : cardinal;
  396. begin
  397. shift := 0;
  398. ReadULEB128 := 0;
  399. repeat
  400. if (bufp = bufe) and (ReadNextBuffer <= 0) then break;
  401. ReadULEB128 := ReadULEB128 or (QWord(bufp^ and $7f) shl shift);
  402. inc(bufp);
  403. inc(shift, 7);
  404. until ((bufp[-1] and $80) = 0);
  405. end;
  406. { Reads a signed LEB encoded number from the input stream }
  407. function TEReader.ReadLEB128() : Int64;
  408. var
  409. shift : cardinal;
  410. begin
  411. shift := 0;
  412. ReadLEB128 := 0;
  413. repeat
  414. if (bufp = bufe) and (ReadNextBuffer <= 0) then break;
  415. ReadLEB128 := ReadLEB128 or (Int64(bufp^ and $7f) shl shift);
  416. inc(bufp);
  417. inc(shift, 7);
  418. until ((bufp[-1] and $80) = 0);
  419. { extend sign. Note that we can not use shl/shr since the latter does not
  420. translate to arithmetic shifting for signed types }
  421. ReadLEB128 := (not ((ReadLEB128 and (Int64(1) shl (shift-1)))-1)) or ReadLEB128;
  422. end;
  423. { Reads an address from the current input stream }
  424. function TEReader.ReadAddress(addr_size: smallint) : PtrUInt;
  425. begin
  426. {$ifdef CPUI8086}
  427. ReadAddress := 0;
  428. if (addr_size = 4) or (addr_size = 2) then
  429. {$endif}
  430. ReadNext(ReadAddress, sizeof(ReadAddress));
  431. end;
  432. {$ifdef CPUI8086}
  433. { Reads a segment from the current input stream }
  434. function TEReader.ReadSegment() : Word;
  435. begin
  436. ReadNext(ReadSegment, sizeof(ReadSegment));
  437. end;
  438. {$endif CPUI8086}
  439. { Reads a zero-terminated string from the current input stream. If the
  440. string is larger than 255 chars (maximum allowed number of elements in
  441. a ShortString, excess characters will be chopped off. }
  442. function TEReader.ReadString() : ShortString;
  443. var
  444. nbufpart,zp,nmove : SizeInt;
  445. begin
  446. ReadString[0] := #0;
  447. repeat
  448. if (bufp = bufe) and (ReadNextBuffer <= 0) then exit(''); { unexpected end of file occurred }
  449. nbufpart := bufe - bufp;
  450. zp := IndexByte(bufp^, nbufpart, 0); { Search #0 in the available buffer. }
  451. if zp >= 0 then nbufpart := zp; { #0 found, copy up to it (otherwise copy the entire available buffer, and don’t end). }
  452. nmove := 255 - length(ReadString);
  453. if nmove <> 0 then begin
  454. if nmove > nbufpart then nmove := nbufpart;
  455. Move(bufp^, ReadString[1 + length(ReadString)], nmove);
  456. inc(byte(ReadString[0]), nmove);
  457. end;
  458. inc(bufp, nbufpart);
  459. until zp >= 0;
  460. inc(bufp); { Null terminator. }
  461. end;
  462. { Reads an unsigned Half from the current input stream }
  463. function TEReader.ReadUHalf() : Word;
  464. begin
  465. ReadNext(ReadUHalf, sizeof(ReadUHalf));
  466. end;
  467. function TEReader.ReadNextBuffer : longint;
  468. begin
  469. inc(bufstart, bufp - pByte(buf));
  470. ReadNextBuffer := limit - bufstart;
  471. if ReadNextBuffer > 0 then begin
  472. if ReadNextBuffer > length(buf) then ReadNextBuffer := length(buf);
  473. BlockRead(e.f, buf, ReadNextBuffer, ReadNextBuffer);
  474. end;
  475. bufp := pByte(buf);
  476. bufe := pByte(buf) + ReadNextBuffer;
  477. end;
  478. {---------------------------------------------------------------------------
  479. Generic Dwarf lineinfo reader
  480. The line info reader is based on the information contained in
  481. DWARF Debugging Information Format Version 3
  482. Chapter 6.2 "Line Number Information"
  483. from the
  484. DWARF Debugging Information Format Workgroup.
  485. For more information on this document see also
  486. http://dwarf.freestandards.org/
  487. ---------------------------------------------------------------------------}
  488. { initializes the line info state to the default values }
  489. procedure InitStateRegisters(var state : TMachineState; const aIs_Stmt : Bool8);
  490. begin
  491. with state do begin
  492. address := 0;
  493. segment := 0;
  494. file_id := 1;
  495. line := 1;
  496. column := 0;
  497. is_stmt := aIs_Stmt;
  498. basic_block := false;
  499. end_sequence := false;
  500. prolouge_end := false;
  501. epilouge_begin := false;
  502. isa := 0;
  503. append_row := false;
  504. end;
  505. end;
  506. { Skips all line info directory entries }
  507. procedure SkipDirectories(var er: TEReader);
  508. var s : ShortString;
  509. begin
  510. while (true) do begin
  511. s := er.ReadString();
  512. if (s = '') then break;
  513. DEBUG_WRITELN('Skipping directory : ', s);
  514. end;
  515. end;
  516. { Skips an LEB128 }
  517. procedure SkipLEB128(var er: TEReader);
  518. {$ifdef DEBUG_DWARF_PARSER}
  519. var temp : QWord;
  520. {$endif}
  521. begin
  522. {$ifdef DEBUG_DWARF_PARSER}temp := {$endif}er.ReadLEB128();
  523. DEBUG_WRITELN('Skipping LEB128 : ', temp);
  524. end;
  525. { Skips the filename section from the current file stream }
  526. procedure SkipFilenames(var er: TEReader);
  527. var s : ShortString;
  528. begin
  529. while (true) do begin
  530. s := er.ReadString();
  531. if (s = '') then break;
  532. DEBUG_WRITELN('Skipping filename : ', s);
  533. SkipLEB128(er); { skip the directory index for the file }
  534. SkipLEB128(er); { skip last modification time for file }
  535. SkipLEB128(er); { skip length of file }
  536. end;
  537. end;
  538. function CalculateAddressIncrement(opcode : Byte; const header : TLineNumberProgramHeader64) : Int64;
  539. begin
  540. CalculateAddressIncrement := (Int64(opcode) - header.opcode_base) div header.line_range * header.minimum_instruction_length;
  541. end;
  542. function GetFullFilename(var er: TEReader; const filenameStart, directoryStart : Int64; const file_id : DWord) : ShortString;
  543. var
  544. i : DWord;
  545. filename, directory : ShortString;
  546. dirindex : Int64;
  547. begin
  548. filename := '';
  549. directory := '';
  550. i := 1;
  551. er.Seek(filenameStart);
  552. while (i <= file_id) do begin
  553. filename := er.ReadString();
  554. DEBUG_WRITELN('Found "', filename, '"');
  555. if (filename = '') then break;
  556. dirindex := er.ReadLEB128(); { read the directory index for the file }
  557. SkipLEB128(er); { skip last modification time for file }
  558. SkipLEB128(er); { skip length of file }
  559. inc(i);
  560. end;
  561. { if we could not find the file index, exit }
  562. if (filename = '') then begin
  563. GetFullFilename := '(Unknown file)';
  564. exit;
  565. end;
  566. er.Seek(directoryStart);
  567. i := 1;
  568. while (i <= dirindex) do begin
  569. directory := er.ReadString();
  570. if (directory = '') then break;
  571. inc(i);
  572. end;
  573. if (directory<>'') and (directory[length(directory)]<>'/') then
  574. directory:=directory+'/';
  575. GetFullFilename := directory + filename;
  576. end;
  577. function ParseCompilationUnit(var er : TEReader; const addr : TOffset; const segment : TSegment; const file_offset : QWord;
  578. var source : String; var line : longint; var found : Boolean) : QWord;
  579. var
  580. state : TMachineState;
  581. { we need both headers on the stack, although we only use the 64 bit one internally }
  582. header64 : TLineNumberProgramHeader64;
  583. header32 : TLineNumberProgramHeader32;
  584. adjusted_opcode : Int64;
  585. opcode : PtrInt;
  586. extended_opcode : PtrInt;
  587. extended_opcode_length : PtrInt;
  588. i, addrIncrement, lineIncrement : PtrInt;
  589. {$ifdef DEBUG_DWARF_PARSER}
  590. s : ShortString;
  591. {$endif}
  592. numoptable : array[1..255] of Byte;
  593. { the offset into the file where the include directories are stored for this compilation unit }
  594. include_directories : QWord;
  595. { the offset into the file where the file names are stored for this compilation unit }
  596. file_names : Int64;
  597. temp_length : DWord;
  598. unit_length : QWord;
  599. header_length : SizeInt;
  600. first_row : Boolean;
  601. prev_line : QWord;
  602. prev_file : DWord;
  603. begin
  604. prev_line := 0;
  605. prev_file := 0;
  606. first_row := true;
  607. found := false;
  608. er.ReadNext(temp_length, sizeof(temp_length));
  609. if (temp_length <> $ffffffff) then begin
  610. unit_length := temp_length + sizeof(temp_length)
  611. end else begin
  612. er.ReadNext(unit_length, sizeof(unit_length));
  613. inc(unit_length, 12);
  614. end;
  615. ParseCompilationUnit := file_offset + unit_length;
  616. er.SetRange(file_offset, unit_length);
  617. DEBUG_WRITELN('Unit length: ', unit_length);
  618. if (temp_length <> $ffffffff) then begin
  619. DEBUG_WRITELN('32 bit DWARF detected');
  620. er.ReadNext(header32, sizeof(header32));
  621. header64.magic := $ffffffff;
  622. header64.unit_length := header32.unit_length;
  623. header64.version := header32.version;
  624. header64.length := header32.length;
  625. header64.minimum_instruction_length := header32.minimum_instruction_length;
  626. header64.default_is_stmt := header32.default_is_stmt;
  627. header64.line_base := header32.line_base;
  628. header64.line_range := header32.line_range;
  629. header64.opcode_base := header32.opcode_base;
  630. header_length :=
  631. sizeof(header32.length) + sizeof(header32.version) +
  632. sizeof(header32.unit_length);
  633. end else begin
  634. DEBUG_WRITELN('64 bit DWARF detected');
  635. er.ReadNext(header64, sizeof(header64));
  636. header_length :=
  637. sizeof(header64.magic) + sizeof(header64.version) +
  638. sizeof(header64.length) + sizeof(header64.unit_length);
  639. end;
  640. inc(header_length, header64.length);
  641. fillchar(numoptable, sizeof(numoptable), #0);
  642. er.ReadNext(numoptable, header64.opcode_base-1);
  643. DEBUG_WRITELN('Opcode parameter count table');
  644. for i := 1 to header64.opcode_base-1 do begin
  645. DEBUG_WRITELN('Opcode[', i, '] - ', numoptable[i], ' parameters');
  646. end;
  647. DEBUG_WRITELN('Reading directories...');
  648. include_directories := er.Pos();
  649. SkipDirectories(er);
  650. DEBUG_WRITELN('Reading filenames...');
  651. file_names := er.Pos();
  652. SkipFilenames(er);
  653. er.Seek(header_length);
  654. with header64 do begin
  655. InitStateRegisters(state, default_is_stmt);
  656. end;
  657. opcode := er.ReadNext();
  658. while (opcode <> -1) and (not found) do begin
  659. DEBUG_WRITELN('Next opcode: ');
  660. case (opcode) of
  661. { extended opcode }
  662. 0 : begin
  663. extended_opcode_length := er.ReadULEB128();
  664. extended_opcode := er.ReadNext();
  665. case (extended_opcode) of
  666. -1: begin
  667. exit;
  668. end;
  669. DW_LNE_END_SEQUENCE : begin
  670. state.end_sequence := true;
  671. state.append_row := true;
  672. DEBUG_WRITELN('DW_LNE_END_SEQUENCE');
  673. end;
  674. DW_LNE_SET_ADDRESS : begin
  675. state.address := er.ReadAddress(extended_opcode_length-1);
  676. DEBUG_WRITELN('DW_LNE_SET_ADDRESS (', hexstr(state.address, sizeof(state.address)*2), ')');
  677. end;
  678. {$ifdef CPUI8086}
  679. DW_LNE_SET_SEGMENT : begin
  680. state.segment := er.ReadSegment();
  681. DEBUG_WRITELN('DW_LNE_SET_SEGMENT (', hexstr(state.segment, sizeof(state.segment)*2), ')');
  682. end;
  683. {$endif CPUI8086}
  684. DW_LNE_DEFINE_FILE : begin
  685. {$ifdef DEBUG_DWARF_PARSER}s := {$endif}er.ReadString();
  686. SkipLEB128(er);
  687. SkipLEB128(er);
  688. SkipLEB128(er);
  689. DEBUG_WRITELN('DW_LNE_DEFINE_FILE (', s, ')');
  690. end;
  691. else begin
  692. DEBUG_WRITELN('Unknown extended opcode (opcode ', extended_opcode, ' length ', extended_opcode_length, ')');
  693. if (extended_opcode_length>1) and not er.ReadNext(nil^, extended_opcode_length-1) then
  694. exit;
  695. end;
  696. end;
  697. end;
  698. DW_LNS_COPY : begin
  699. state.basic_block := false;
  700. state.prolouge_end := false;
  701. state.epilouge_begin := false;
  702. state.append_row := true;
  703. DEBUG_WRITELN('DW_LNS_COPY');
  704. end;
  705. DW_LNS_ADVANCE_PC : begin
  706. inc(state.address, er.ReadULEB128() * header64.minimum_instruction_length);
  707. DEBUG_WRITELN('DW_LNS_ADVANCE_PC (', hexstr(state.address, sizeof(state.address)*2), ')');
  708. end;
  709. DW_LNS_ADVANCE_LINE : begin
  710. // inc(state.line, ReadLEB128()); negative values are allowed
  711. // but those may generate a range check error
  712. state.line := state.line + er.ReadLEB128();
  713. DEBUG_WRITELN('DW_LNS_ADVANCE_LINE (', state.line, ')');
  714. end;
  715. DW_LNS_SET_FILE : begin
  716. state.file_id := er.ReadULEB128();
  717. DEBUG_WRITELN('DW_LNS_SET_FILE (', state.file_id, ')');
  718. end;
  719. DW_LNS_SET_COLUMN : begin
  720. state.column := er.ReadULEB128();
  721. DEBUG_WRITELN('DW_LNS_SET_COLUMN (', state.column, ')');
  722. end;
  723. DW_LNS_NEGATE_STMT : begin
  724. state.is_stmt := not state.is_stmt;
  725. DEBUG_WRITELN('DW_LNS_NEGATE_STMT (', state.is_stmt, ')');
  726. end;
  727. DW_LNS_SET_BASIC_BLOCK : begin
  728. state.basic_block := true;
  729. DEBUG_WRITELN('DW_LNS_SET_BASIC_BLOCK');
  730. end;
  731. DW_LNS_CONST_ADD_PC : begin
  732. inc(state.address, CalculateAddressIncrement(255, header64));
  733. DEBUG_WRITELN('DW_LNS_CONST_ADD_PC (', hexstr(state.address, sizeof(state.address)*2), ')');
  734. end;
  735. DW_LNS_FIXED_ADVANCE_PC : begin
  736. inc(state.address, er.ReadUHalf());
  737. DEBUG_WRITELN('DW_LNS_FIXED_ADVANCE_PC (', hexstr(state.address, sizeof(state.address)*2), ')');
  738. end;
  739. DW_LNS_SET_PROLOGUE_END : begin
  740. state.prolouge_end := true;
  741. DEBUG_WRITELN('DW_LNS_SET_PROLOGUE_END');
  742. end;
  743. DW_LNS_SET_EPILOGUE_BEGIN : begin
  744. state.epilouge_begin := true;
  745. DEBUG_WRITELN('DW_LNS_SET_EPILOGUE_BEGIN');
  746. end;
  747. DW_LNS_SET_ISA : begin
  748. state.isa := er.ReadULEB128();
  749. DEBUG_WRITELN('DW_LNS_SET_ISA (', state.isa, ')');
  750. end;
  751. else begin { special opcode }
  752. if (opcode < header64.opcode_base) then begin
  753. DEBUG_WRITELN('Unknown standard opcode $', hexstr(opcode, 2), '; skipping');
  754. for i := 1 to numoptable[opcode] do
  755. SkipLEB128(er);
  756. end else begin
  757. adjusted_opcode := opcode - header64.opcode_base;
  758. addrIncrement := CalculateAddressIncrement(opcode, header64);
  759. inc(state.address, addrIncrement);
  760. lineIncrement := header64.line_base + (adjusted_opcode mod header64.line_range);
  761. inc(state.line, lineIncrement);
  762. DEBUG_WRITELN('Special opcode $', hexstr(opcode, 2), ' address increment: ', addrIncrement, ' new line: ', lineIncrement);
  763. state.basic_block := false;
  764. state.prolouge_end := false;
  765. state.epilouge_begin := false;
  766. state.append_row := true;
  767. end;
  768. end;
  769. end;
  770. if (state.append_row) then begin
  771. DEBUG_WRITELN('Current state : address = ', hexstr(state.address, sizeof(state.address) * 2),
  772. {$ifdef CPUI8086}
  773. DEBUG_COMMENT ' segment = ', hexstr(state.segment, sizeof(state.segment) * 2),
  774. {$endif CPUI8086}
  775. DEBUG_COMMENT ' file_id = ', state.file_id, ' line = ', state.line, ' column = ', state.column,
  776. DEBUG_COMMENT ' is_stmt = ', state.is_stmt, ' basic_block = ', state.basic_block,
  777. DEBUG_COMMENT ' end_sequence = ', state.end_sequence, ' prolouge_end = ', state.prolouge_end,
  778. DEBUG_COMMENT ' epilouge_begin = ', state.epilouge_begin, ' isa = ', state.isa);
  779. if (first_row) then begin
  780. if (state.segment > segment) or
  781. ((state.segment = segment) and
  782. (state.address > addr)) then
  783. break;
  784. first_row := false;
  785. end;
  786. { when we have found the address we need to return the previous
  787. line because that contains the call instruction
  788. Note that there may not be any call instruction, because this may
  789. be the actual instruction that crashed, and it may be on the first
  790. line of the function }
  791. if (state.segment > segment) or
  792. ((state.segment = segment) and
  793. (state.address >= addr)) then
  794. found:=true
  795. else
  796. begin
  797. { save line information }
  798. prev_file := state.file_id;
  799. prev_line := state.line;
  800. end;
  801. state.append_row := false;
  802. if (state.end_sequence) then begin
  803. InitStateRegisters(state, header64.default_is_stmt);
  804. first_row := true;
  805. end;
  806. end;
  807. opcode := er.ReadNext();
  808. end;
  809. if (found) then
  810. begin
  811. { can happen if the crash happens on the first instruction with line info }
  812. if prev_line = 0 then
  813. begin
  814. prev_line := state.line;
  815. prev_file := state.file_id;
  816. end;
  817. line := prev_line;
  818. source := GetFullFilename(er, file_names, include_directories, prev_file);
  819. end;
  820. end;
  821. type
  822. TAbbrevs = record
  823. Tags : array of QWord;
  824. Children : array of Byte;
  825. Attrs : array of array of record attr,form : QWord; end;
  826. end;
  827. procedure ReadAbbrevTable(var er: TEReader; var abbrevs: TAbbrevs);
  828. var
  829. i : PtrInt;
  830. tag,
  831. nr,
  832. attr,
  833. form : Int64;
  834. begin
  835. DEBUG_WRITELN('Starting to read abbrev. section at $',hexstr(Dwarf_Debug_Abbrev_Section_Offset+er.Pos,16));
  836. repeat
  837. nr:=er.ReadULEB128;
  838. if nr=0 then
  839. break;
  840. if nr>high(abbrevs.Tags) then
  841. begin
  842. SetLength(abbrevs.Tags,SizeUint(nr)+128+SizeUint(nr) div 4);
  843. SetLength(abbrevs.Attrs,length(abbrevs.Tags));
  844. SetLength(abbrevs.Children,length(abbrevs.Tags));
  845. end;
  846. { read tag }
  847. tag:=er.ReadULEB128;
  848. abbrevs.Tags[nr]:=tag;
  849. DEBUG_WRITELN('Abbrev ',nr,' at offset ',er.Pos,' has tag $',hexstr(tag,4));
  850. { read flag for children }
  851. abbrevs.Children[nr]:=er.ReadNext;
  852. i:=0;
  853. { ensure that length(Abbrev_Attrs)=0 if an entry is overwritten (not sure if this will ever happen) and
  854. the new entry has no attributes }
  855. abbrevs.Attrs[nr]:=nil;
  856. repeat
  857. attr:=er.ReadULEB128;
  858. form:=er.ReadULEB128;
  859. if attr<>0 then
  860. begin
  861. SetLength(abbrevs.Attrs[nr],i+1);
  862. abbrevs.Attrs[nr][i].attr:=attr;
  863. abbrevs.Attrs[nr][i].form:=form;
  864. end;
  865. inc(i);
  866. until attr=0;
  867. DEBUG_WRITELN('Abbrev ',nr,' has ',Length(abbrevs.Attrs[nr]),' attributes');
  868. until false;
  869. end;
  870. function ParseCompilationUnitForDebugInfoOffset(var er: TEReader; const addr : TOffset; const segment : TSegment; const file_offset : QWord;
  871. var debug_info_offset : QWord; var found : Boolean) : QWord;
  872. {$ifndef CPUI8086}
  873. const
  874. arange_segment = 0;
  875. {$endif CPUI8086}
  876. var
  877. { we need both headers on the stack, although we only use the 64 bit one internally }
  878. header64 : TDebugArangesHeader64;
  879. header32 : TDebugArangesHeader32;
  880. temp_length : DWord;
  881. unit_length : QWord;
  882. {$ifdef CPUI8086}
  883. arange_start, arange_size: DWord;
  884. arange_segment: Word;
  885. {$else CPUI8086}
  886. arange_start, arange_size: PtrUInt;
  887. {$endif CPUI8086}
  888. begin
  889. found := false;
  890. er.ReadNext(temp_length, sizeof(temp_length));
  891. if (temp_length <> $ffffffff) then begin
  892. unit_length := temp_length + sizeof(temp_length)
  893. end else begin
  894. er.ReadNext(unit_length, sizeof(unit_length));
  895. inc(unit_length, 12);
  896. end;
  897. ParseCompilationUnitForDebugInfoOffset := file_offset + unit_length;
  898. er.SetRange(file_offset, unit_length);
  899. DEBUG_WRITELN('Unit length: ', unit_length);
  900. if (temp_length <> $ffffffff) then
  901. begin
  902. DEBUG_WRITELN('32 bit DWARF detected');
  903. er.ReadNext(header32, sizeof(header32));
  904. header64.magic := $ffffffff;
  905. header64.unit_length := header32.unit_length;
  906. header64.version := header32.version;
  907. header64.debug_info_offset := header32.debug_info_offset;
  908. header64.address_size := header32.address_size;
  909. header64.segment_size := header32.segment_size;
  910. end
  911. else
  912. begin
  913. DEBUG_WRITELN('64 bit DWARF detected');
  914. er.ReadNext(header64, sizeof(header64));
  915. end;
  916. DEBUG_WRITELN('debug_info_offset: ',header64.debug_info_offset);
  917. DEBUG_WRITELN('address_size: ', header64.address_size);
  918. DEBUG_WRITELN('segment_size: ', header64.segment_size);
  919. arange_start:=er.ReadAddress(header64.address_size);
  920. {$ifdef CPUI8086}
  921. arange_segment:=er.ReadSegment();
  922. {$endif CPUI8086}
  923. arange_size:=er.ReadAddress(header64.address_size);
  924. while not((arange_start=0) and (arange_segment=0) and (arange_size=0)) and (not found) do
  925. begin
  926. if (segment=arange_segment) and (addr>=arange_start) and (addr<=arange_start+arange_size) then
  927. begin
  928. found:=true;
  929. debug_info_offset:=header64.debug_info_offset;
  930. DEBUG_WRITELN('Matching aranges entry $',hexStr(arange_start,header64.address_size*2),', $',hexStr(arange_size,header64.address_size*2));
  931. end;
  932. arange_start:=er.ReadAddress(header64.address_size);
  933. {$ifdef CPUI8086}
  934. arange_segment:=er.ReadSegment();
  935. {$endif CPUI8086}
  936. arange_size:=er.ReadAddress(header64.address_size);
  937. end;
  938. end;
  939. function ParseCompilationUnitForFunctionName(var er: TEReader; const addr : TOffset; const segment : TSegment; const file_offset : QWord;
  940. var func : String; var found : Boolean) : QWord;
  941. var
  942. { we need both headers on the stack, although we only use the 64 bit one internally }
  943. header64 : TDebugInfoProgramHeader64;
  944. header32 : TDebugInfoProgramHeader32;
  945. isdwarf64 : boolean;
  946. abbrev,
  947. high_pc,
  948. low_pc : QWord;
  949. temp_length : DWord;
  950. unit_length : QWord;
  951. name : String;
  952. level : Integer;
  953. procedure SkipAttr(var er: TEReader; form : QWord);
  954. var
  955. dl,nskip : dword;
  956. begin
  957. nskip := 0;
  958. case form of
  959. DW_FORM_addr:
  960. nskip := header64.address_size;
  961. DW_FORM_block2:
  962. nskip := er.ReadUHalf;
  963. DW_FORM_block4:
  964. begin
  965. er.ReadNext(dl,SizeOf(dl));
  966. nskip := dl;
  967. end;
  968. DW_FORM_data2, DW_FORM_data4, DW_FORM_data8:
  969. nskip := 2 shl (form - DW_FORM_data2);
  970. DW_FORM_string:
  971. er.ReadString;
  972. DW_FORM_block,
  973. DW_FORM_exprloc:
  974. nskip := er.ReadULEB128;
  975. DW_FORM_block1:
  976. nskip := er.ReadNext;
  977. DW_FORM_data1,
  978. DW_FORM_flag:
  979. er.ReadNext;
  980. DW_FORM_sdata:
  981. er.ReadLEB128;
  982. DW_FORM_ref_addr:
  983. { the size of DW_FORM_ref_addr changed between DWAWRF2 and later versions:
  984. in DWARF2 it depends on the architecture address size, in later versions on the DWARF type (32 bit/64 bit)
  985. }
  986. if header64.version>2 then
  987. begin
  988. if isdwarf64 then
  989. nskip := 8
  990. else
  991. nskip := 4;
  992. end
  993. else
  994. begin
  995. { address size for DW_FORM_ref_addr must be at least 32 bits }
  996. { this is compatible with Open Watcom on i8086 }
  997. if header64.address_size<4 then
  998. nskip := 4
  999. else
  1000. nskip := header64.address_size;
  1001. end;
  1002. DW_FORM_strp,
  1003. DW_FORM_sec_offset:
  1004. if isdwarf64 then
  1005. nskip := 8
  1006. else
  1007. nskip := 4;
  1008. DW_FORM_udata:
  1009. er.ReadULEB128;
  1010. DW_FORM_ref1, DW_FORM_ref2, DW_FORM_ref4, DW_FORM_ref8:
  1011. nskip := 1 shl (form - DW_FORM_ref1);
  1012. DW_FORM_ref_udata:
  1013. er.ReadULEB128;
  1014. DW_FORM_indirect:
  1015. SkipAttr(er, er.ReadULEB128);
  1016. DW_FORM_flag_present: {none};
  1017. else
  1018. begin
  1019. writeln(stderr,'Internal error: unknown dwarf form: $',hexstr(form,2));
  1020. nskip := 1;
  1021. end;
  1022. end;
  1023. er.ReadNext(nil^, nskip);
  1024. end;
  1025. var
  1026. i : PtrInt;
  1027. prev_base,prev_size,prev_pos : TFilePos;
  1028. abbrevs : TAbbrevs;
  1029. begin
  1030. found := false;
  1031. er.ReadNext(temp_length, sizeof(temp_length));
  1032. if (temp_length <> $ffffffff) then begin
  1033. unit_length := temp_length + sizeof(temp_length)
  1034. end else begin
  1035. er.ReadNext(unit_length, sizeof(unit_length));
  1036. inc(unit_length, 12);
  1037. end;
  1038. ParseCompilationUnitForFunctionName := file_offset + unit_length;
  1039. er.SetRange(file_offset, unit_length);
  1040. DEBUG_WRITELN('Unit length: ', unit_length);
  1041. if (temp_length <> $ffffffff) then begin
  1042. DEBUG_WRITELN('32 bit DWARF detected');
  1043. er.ReadNext(header32, sizeof(header32));
  1044. header64.magic := $ffffffff;
  1045. header64.unit_length := header32.unit_length;
  1046. header64.version := header32.version;
  1047. header64.debug_abbrev_offset := header32.debug_abbrev_offset;
  1048. header64.address_size := header32.address_size;
  1049. isdwarf64:=false;
  1050. end else begin
  1051. DEBUG_WRITELN('64 bit DWARF detected');
  1052. er.ReadNext(header64, sizeof(header64));
  1053. isdwarf64:=true;
  1054. end;
  1055. DEBUG_WRITELN('debug_abbrev_offset: ',header64.debug_abbrev_offset);
  1056. DEBUG_WRITELN('address_size: ',header64.address_size);
  1057. { not nice, but we have to read the abbrev section after the start of the debug_info section has been read }
  1058. prev_size:=er.limit-er.base;
  1059. prev_base:=er.base;
  1060. prev_pos:=er.Pos;
  1061. er.SetRange(Dwarf_Debug_Abbrev_Section_Offset+header64.debug_abbrev_offset,Dwarf_Debug_Abbrev_Section_Size);
  1062. ReadAbbrevTable(er, abbrevs);
  1063. { restore previous reading state and position }
  1064. er.SetRange(prev_base,prev_size);
  1065. er.Seek(prev_pos);
  1066. abbrev:=er.ReadULEB128;
  1067. level:=0;
  1068. while (abbrev <> 0) and (not found) do
  1069. begin
  1070. DEBUG_WRITELN('Next abbrev: ',abbrev);
  1071. if abbrevs.Children[abbrev]<>0 then
  1072. inc(level);
  1073. { DW_TAG_subprogram? }
  1074. if abbrevs.Tags[abbrev]=$2e then
  1075. begin
  1076. low_pc:=1;
  1077. high_pc:=0;
  1078. name:='';
  1079. for i:=0 to high(abbrevs.Attrs[abbrev]) do
  1080. begin
  1081. { DW_AT_low_pc }
  1082. if (abbrevs.Attrs[abbrev][i].attr=$11) and
  1083. (abbrevs.Attrs[abbrev][i].form=DW_FORM_addr) then
  1084. begin
  1085. low_pc:=0;
  1086. er.ReadNext(low_pc,header64.address_size);
  1087. end
  1088. { DW_AT_high_pc }
  1089. else if (abbrevs.Attrs[abbrev][i].attr=$12) and
  1090. (abbrevs.Attrs[abbrev][i].form=DW_FORM_addr) then
  1091. begin
  1092. high_pc:=0;
  1093. er.ReadNext(high_pc,header64.address_size);
  1094. end
  1095. { DW_AT_name }
  1096. else if (abbrevs.Attrs[abbrev][i].attr=$3) and
  1097. { avoid that we accidently read an DW_FORM_strp entry accidently }
  1098. (abbrevs.Attrs[abbrev][i].form=DW_FORM_string) then
  1099. begin
  1100. name:=er.ReadString;
  1101. end
  1102. else
  1103. SkipAttr(er, abbrevs.Attrs[abbrev][i].form);
  1104. end;
  1105. 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);
  1106. if (addr>low_pc) and (addr<high_pc) then
  1107. begin
  1108. found:=true;
  1109. func:=name;
  1110. end;
  1111. end
  1112. else
  1113. begin
  1114. for i:=0 to high(abbrevs.Attrs[abbrev]) do
  1115. SkipAttr(er, abbrevs.Attrs[abbrev][i].form);
  1116. end;
  1117. abbrev:=er.ReadULEB128;
  1118. { skip entries signaling that no more child entries are following }
  1119. while (level>0) and (abbrev=0) do
  1120. begin
  1121. dec(level);
  1122. abbrev:=er.ReadULEB128;
  1123. end;
  1124. end;
  1125. end;
  1126. const
  1127. { 64 bit and 32 bit CPUs tend to have more memory }
  1128. {$if defined(CPU64)}
  1129. LineInfoCacheLength = 2039;
  1130. {$elseif defined(CPU32)}
  1131. LineInfoCacheLength = 251;
  1132. {$else}
  1133. LineInfoCacheLength = 1;
  1134. {$endif CPU64}
  1135. var
  1136. LineInfoCache : array[0..LineInfoCacheLength-1] of
  1137. record
  1138. addr : codeptruint;
  1139. func, source : string;
  1140. line : longint;
  1141. end;
  1142. function GetLineInfo(addr : codeptruint; var func, source : string; var line : longint) : boolean;
  1143. var
  1144. current_offset,
  1145. end_offset, debug_info_offset_from_aranges : QWord;
  1146. segment : Word = 0;
  1147. found, found_aranges : Boolean;
  1148. CacheIndex: CodePtrUInt;
  1149. er: TEReader;
  1150. begin
  1151. func := '';
  1152. source := '';
  1153. GetLineInfo:=false;
  1154. CacheIndex:=addr mod LineInfoCacheLength;
  1155. if LineInfoCache[CacheIndex].addr=addr then
  1156. begin
  1157. func:=LineInfoCache[CacheIndex].func;
  1158. source:=LineInfoCache[CacheIndex].source;
  1159. line:=LineInfoCache[CacheIndex].line;
  1160. GetLineInfo:=true;
  1161. exit;
  1162. end;
  1163. if not OpenDwarf(codepointer(addr)) then
  1164. exit;
  1165. {$ifdef CPUI8086}
  1166. {$if defined(FPC_MM_MEDIUM) or defined(FPC_MM_LARGE) or defined(FPC_MM_HUGE)}
  1167. segment := (addr shr 16) - e.processsegment;
  1168. addr := Word(addr);
  1169. {$else}
  1170. segment := CSeg - e.processsegment;
  1171. {$endif}
  1172. {$endif CPUI8086}
  1173. addr := addr - e.processaddress;
  1174. current_offset := Dwarf_Debug_Line_Section_Offset;
  1175. end_offset := Dwarf_Debug_Line_Section_Offset + Dwarf_Debug_Line_Section_Size;
  1176. er.Init;
  1177. found := false;
  1178. while (current_offset < end_offset) and (not found) do begin
  1179. er.SetRange(current_offset, end_offset - current_offset);
  1180. current_offset := ParseCompilationUnit(er, addr, segment, current_offset,
  1181. source, line, found);
  1182. end;
  1183. current_offset := Dwarf_Debug_Aranges_Section_Offset;
  1184. end_offset := Dwarf_Debug_Aranges_Section_Offset + Dwarf_Debug_Aranges_Section_Size;
  1185. found_aranges := false;
  1186. while (current_offset < end_offset) and (not found_aranges) do begin
  1187. er.SetRange(current_offset, end_offset - current_offset);
  1188. current_offset := ParseCompilationUnitForDebugInfoOffset(er, addr, segment, current_offset, debug_info_offset_from_aranges, found_aranges);
  1189. end;
  1190. { no function name found yet }
  1191. found := false;
  1192. if found_aranges then
  1193. begin
  1194. DEBUG_WRITELN('Found .debug_info offset $',hexstr(debug_info_offset_from_aranges,8),' from .debug_aranges');
  1195. current_offset := Dwarf_Debug_Info_Section_Offset + debug_info_offset_from_aranges;
  1196. end_offset := Dwarf_Debug_Info_Section_Offset + debug_info_offset_from_aranges + Dwarf_Debug_Info_Section_Size;
  1197. DEBUG_WRITELN('Reading .debug_info at section offset $',hexStr(current_offset-Dwarf_Debug_Info_Section_Offset,16));
  1198. er.SetRange(current_offset, end_offset - current_offset);
  1199. current_offset := ParseCompilationUnitForFunctionName(er, addr, segment, current_offset, func, found);
  1200. if found then
  1201. DEBUG_WRITELN('Found .debug_info entry by using .debug_aranges information');
  1202. end
  1203. else
  1204. DEBUG_WRITELN('No .debug_info offset found from .debug_aranges');
  1205. current_offset := Dwarf_Debug_Info_Section_Offset;
  1206. end_offset := Dwarf_Debug_Info_Section_Offset + Dwarf_Debug_Info_Section_Size;
  1207. while (current_offset < end_offset) and (not found) do begin
  1208. DEBUG_WRITELN('Reading .debug_info at section offset $',hexStr(current_offset-Dwarf_Debug_Info_Section_Offset,16));
  1209. er.SetRange(current_offset, end_offset - current_offset);
  1210. current_offset := ParseCompilationUnitForFunctionName(er, addr, segment, current_offset, func, found);
  1211. end;
  1212. if not AllowReuseOfLineInfoData then
  1213. CloseDwarf;
  1214. LineInfoCache[CacheIndex].addr:=addr;
  1215. LineInfoCache[CacheIndex].func:=func;
  1216. LineInfoCache[CacheIndex].source:=source;
  1217. LineInfoCache[CacheIndex].line:=line;
  1218. GetLineInfo:=true;
  1219. end;
  1220. function DwarfBackTraceStr(addr: CodePointer): shortstring;
  1221. var
  1222. func,
  1223. source : string;
  1224. hs : string;
  1225. line : longint;
  1226. Store : TBackTraceStrFunc;
  1227. Success : boolean;
  1228. begin
  1229. {$ifdef DEBUG_LINEINFO}
  1230. writeln(stderr,'DwarfBackTraceStr called');
  1231. {$endif DEBUG_LINEINFO}
  1232. { reset to prevent infinite recursion if problems inside the code }
  1233. Success:=false;
  1234. Store := BackTraceStrFunc;
  1235. BackTraceStrFunc := @SysBackTraceStr;
  1236. Success:=GetLineInfo(codeptruint(addr), func, source, line);
  1237. { create string }
  1238. DwarfBackTraceStr :=' $' + HexStr(addr);
  1239. if Success then
  1240. begin
  1241. if func<>'' then
  1242. DwarfBackTraceStr := DwarfBackTraceStr + ' ' + func;
  1243. if source<>'' then
  1244. begin
  1245. if func<>'' then
  1246. DwarfBackTraceStr := DwarfBackTraceStr + ', ';
  1247. if line<>0 then
  1248. begin
  1249. str(line, hs);
  1250. DwarfBackTraceStr := DwarfBackTraceStr + ' line ' + hs;
  1251. end;
  1252. DwarfBackTraceStr := DwarfBackTraceStr + ' of ' + source;
  1253. end;
  1254. end;
  1255. BackTraceStrFunc := Store;
  1256. end;
  1257. initialization
  1258. lastfilename := '';
  1259. lastopendwarf := false;
  1260. BackTraceStrFunc := @DwarfBacktraceStr;
  1261. finalization
  1262. CloseDwarf;
  1263. end.