lnfodwrf.pp 41 KB

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