lnfodwrf.pp 40 KB

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