lnfodwrf.pp 39 KB

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