lnfodwrf.pp 41 KB

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