lnfodwrf.pp 41 KB

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