Bladeren bron

Merged revisions 9780,9800-9803,9805-9808,9810,9812-9814,9822,9825,9837-9850,9852,9855-9856,9863-9864,9867,9881,10082,10129-10130,10137-10138,10140-10146,10148-10154,10160-10161,10168,10170,10172,10176-10178,10180,10183-10184,10187-10188,10191-10192,10200-10202 via svnmerge from
http://svn.freepascal.org/svn/fpc/trunk

........
r9780 | peter | 2008-01-18 00:47:42 +0100 (Fri, 18 Jan 2008) | 3 lines

* refactor executable loading into exeinfo unit so
it can be reused also for lnfodwrf
........
r9800 | peter | 2008-01-19 23:09:42 +0100 (Sat, 19 Jan 2008) | 3 lines

* cache filesize
* fix result setting for elf
........
r9801 | peter | 2008-01-19 23:09:58 +0100 (Sat, 19 Jan 2008) | 2 lines

* use exeinfo unit to find .debug_line section
........
r9802 | hajny | 2008-01-20 02:55:27 +0100 (Sun, 20 Jan 2008) | 1 line

* fix OS/2 compilation after exeinfo creation
........
r9803 | hajny | 2008-01-20 02:55:48 +0100 (Sun, 20 Jan 2008) | 1 line

* fix OS/2 compilation after exeinfo creation
........
r9805 | jonas | 2008-01-20 12:26:31 +0100 (Sun, 20 Jan 2008) | 2 lines

* fixed darwin/stabs code
........
r9806 | hajny | 2008-01-20 12:49:41 +0100 (Sun, 20 Jan 2008) | 1 line

* partial fix for Win64 (CoffSymbol not resolved yet - is it equal in PE32 and PE32PLUS?)
........
r9807 | hajny | 2008-01-20 12:57:47 +0100 (Sun, 20 Jan 2008) | 1 line

* E.Size changed to int64 for consistency with FileSize result
........
r9808 | hajny | 2008-01-20 13:06:28 +0100 (Sun, 20 Jan 2008) | 1 line

* one more change from FileSize (F) to E.Size, although it's in not yet adapted BEOS section
........
r9810 | hajny | 2008-01-20 13:12:01 +0100 (Sun, 20 Jan 2008) | 1 line

* StabsFunctionRelative initialization hopefully fixed
........
r9812 | florian | 2008-01-20 14:04:21 +0100 (Sun, 20 Jan 2008) | 2 lines

* win64 compilation fix
........
r9813 | peter | 2008-01-20 14:13:55 +0100 (Sun, 20 Jan 2008) | 3 lines

* support .gnu_debuglink section to have the debug info in an
external file
........
r9881 | peter | 2008-01-23 16:59:20 +0100 (Wed, 23 Jan 2008) | 4 lines

* go32v2 fixed
* moved all targets using the same executbale structure together so
the reuse of the generic functions is more clear
........
r10154 | peter | 2008-02-02 17:16:21 +0100 (Sat, 02 Feb 2008) | 2 lines

* remove objpas dependency, patch by Giulio
........
r10202 | jonas | 2008-02-04 11:45:35 +0100 (Mon, 04 Feb 2008) | 3 lines

* set FunctionRelative to false for Mach-O so -gl works again
for stabs
........

git-svn-id: branches/fixes_2_2@10238 -

peter 17 jaren geleden
bovenliggende
commit
4ec5b45a3f
4 gewijzigde bestanden met toevoegingen van 1311 en 1480 verwijderingen
  1. 1 0
      .gitattributes
  2. 1090 0
      rtl/inc/exeinfo.pp
  3. 35 1057
      rtl/inc/lineinfo.pp
  4. 185 423
      rtl/inc/lnfodwrf.pp

+ 1 - 0
.gitattributes

@@ -4924,6 +4924,7 @@ rtl/inc/dynarrh.inc svneol=native#text/plain
 rtl/inc/dynlibs.pas svneol=native#text/plain
 rtl/inc/elfres32.inc svneol=native#text/plain
 rtl/inc/except.inc svneol=native#text/plain
+rtl/inc/exeinfo.pp svneol=native#text/plain
 rtl/inc/fexpand.inc svneol=native#text/plain
 rtl/inc/file.inc svneol=native#text/plain
 rtl/inc/filerec.inc svneol=native#text/plain

+ 1090 - 0
rtl/inc/exeinfo.pp

@@ -0,0 +1,1090 @@
+{
+    This file is part of the Free Pascal run time library.
+    Copyright (c) 2008 by Peter Vreman
+
+    Executable file reading functions
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ **********************************************************************}
+{
+  This unit should not be compiled in objfpc mode, since this would make it
+  dependent on objpas unit.
+}
+unit exeinfo;
+interface
+
+{$S-}
+
+type
+  TExeFile=record
+    f : file;
+    // cached filesize
+    size      : int64;
+    isopen    : boolean;
+    nsects    : longint;
+    sechdrofs,
+    secstrofs : ptruint;
+    processaddress : ptruint;
+    FunctionRelative: boolean;
+    filename  : string;
+    // Allocate static buffer for reading data
+    buf       : array[0..4095] of byte;
+    bufsize,
+    bufcnt    : longint;
+  end;
+
+function OpenExeFile(var e:TExeFile;const fn:string):boolean;
+function FindExeSection(var e:TExeFile;const secname:string;var secofs,seclen:longint):boolean;
+function CloseExeFile(var e:TExeFile):boolean;
+function ReadDebugLink(var e:TExeFile;var dbgfn:string):boolean;
+
+
+implementation
+
+uses
+  strings;
+
+
+{****************************************************************************
+                             Executable Loaders
+****************************************************************************}
+
+{$if defined(netbsd) or defined(freebsd) or defined(linux) or defined(sunos)}
+  {$ifdef cpu64}
+    {$define ELF64}
+  {$else}
+    {$define ELF32}
+  {$endif}
+{$endif}
+
+{$if defined(win32) or defined(wince)}
+  {$define PE32}
+{$endif}
+
+{$if defined(win64)}
+  {$define PE32PLUS}
+{$endif}
+
+{$ifdef netwlibc}
+  {$define netware}
+{$endif}
+
+{$IFDEF OS2}
+  {$DEFINE EMX}
+{$ENDIF OS2}
+
+
+{****************************************************************************
+                              DOS Stub
+****************************************************************************}
+
+{$if defined(EMX) or defined(PE32) or defined(PE32PLUS)}
+type
+  tdosheader = packed record
+     e_magic : word;
+     e_cblp : word;
+     e_cp : word;
+     e_crlc : word;
+     e_cparhdr : word;
+     e_minalloc : word;
+     e_maxalloc : word;
+     e_ss : word;
+     e_sp : word;
+     e_csum : word;
+     e_ip : word;
+     e_cs : word;
+     e_lfarlc : word;
+     e_ovno : word;
+     e_res : array[0..3] of word;
+     e_oemid : word;
+     e_oeminfo : word;
+     e_res2 : array[0..9] of word;
+     e_lfanew : longint;
+  end;
+{$endif EMX or PE32 or PE32PLUS}
+
+
+{****************************************************************************
+                                  NLM
+****************************************************************************}
+
+{$ifdef netware}
+
+const SIZE_OF_NLM_INTERNAL_FIXED_HEADER = 130;
+      SIZE_OF_NLM_INTERNAL_VERSION_HEADER = 32;
+      SIZE_OF_NLM_INTERNAL_EXTENDED_HEADER = 124;
+
+function loadNetwareNLM:boolean;
+var valid : boolean;
+    name  : string;
+    StabLength,
+    StabStrLength,
+    alignAmount,
+    hdrLength,
+    dataOffset,
+    dataLength : longint;
+
+  function getByte:byte;
+  begin
+    BlockRead (f,getByte,1);
+  end;
+
+  procedure Skip (bytes : longint);
+  var i : longint;
+  begin
+    for i := 1 to bytes do getbyte;
+  end;
+
+  function getLString : String;
+  var Res:string;
+  begin
+    blockread (F, res, 1);
+    if length (res) > 0 THEN
+      blockread (F, res[1], length (res));
+    getbyte;
+    getLString := res;
+  end;
+
+  function getFixString (Len : byte) : string;
+  var i : byte;
+  begin
+    getFixString := '';
+    for I := 1 to Len do
+      getFixString := getFixString + char (getbyte);
+  end;
+
+  function get0String : string;
+  var c : char;
+  begin
+    get0String := '';
+    c := char (getbyte);
+    while (c <> #0) do
+    begin
+      get0String := get0String + c;
+      c := char (getbyte);
+    end;
+  end;
+
+  function getword : word;
+  begin
+    blockread (F, getword, 2);
+  end;
+
+  function getint32 : longint;
+  begin
+    blockread (F, getint32, 4);
+  end;
+
+begin
+  processaddress := 0;
+  LoadNetwareNLM:=false;
+  stabofs:=-1;
+  stabstrofs:=-1;
+  { read and check header }
+  Skip (SIZE_OF_NLM_INTERNAL_FIXED_HEADER);
+  getLString;  // NLM Description
+  getInt32;    // Stacksize
+  getInt32;    // Reserved
+  skip(5);     // old Thread Name
+  getLString;  // Screen Name
+  getLString;  // Thread Name
+  hdrLength := -1;
+  dataOffset := -1;
+  dataLength := -1;
+  valid := true;
+  repeat
+    name := getFixString (8);
+    if (name = 'VeRsIoN#') then
+    begin
+      Skip (SIZE_OF_NLM_INTERNAL_VERSION_HEADER-8);
+    end else
+    if (name = 'CoPyRiGh') then
+    begin
+      getword;     // T=
+      getLString;  // Copyright String
+    end else
+    if (name = 'MeSsAgEs') then
+    begin
+      skip (SIZE_OF_NLM_INTERNAL_EXTENDED_HEADER - 8);
+    end else
+    if (name = 'CuStHeAd') then
+    begin
+      hdrLength := getInt32;
+      dataOffset := getInt32;
+      dataLength := getInt32;
+      Skip (8); // dataStamp
+      Valid := false;
+    end else
+      Valid := false;
+  until not valid;
+  if (hdrLength = -1) or (dataOffset = -1) or (dataLength = -1) then
+    exit;
+  (* The format of the section information is:
+       null terminated section name
+       zeroes to adjust to 4 byte boundary
+       4 byte section data file pointer
+       4 byte section size *)
+  Seek (F, dataOffset);
+  stabOfs := 0;
+  stabStrOfs := 0;
+  Repeat
+    Name := Get0String;
+    alignAmount := 4 - ((length (Name) + 1) MOD 4);
+    Skip (alignAmount);
+    if (Name = '.stab') then
+    begin
+      stabOfs := getInt32;
+      stabLength := getInt32;
+      stabcnt:=stabLength div sizeof(tstab);
+    end else
+    if (Name = '.stabstr') then
+    begin
+      stabStrOfs := getInt32;
+      stabStrLength := getInt32;
+    end else
+      Skip (8);
+  until (Name = '') or ((StabOfs <> 0) and (stabStrOfs <> 0));
+  Seek (F,stabOfs);
+  //if (StabOfs = 0) then __ConsolePrintf ('StabOfs = 0');
+  //if (StabStrOfs = 0) then __ConsolePrintf ('StabStrOfs = 0');
+  LoadNetwareNLM := ((stabOfs > 0) and (stabStrOfs > 0));
+end;
+{$endif}
+
+
+{****************************************************************************
+                               COFF
+****************************************************************************}
+
+{$if defined(PE32) or defined(PE32PLUS) or defined(GO32V2)}
+type
+  tcoffsechdr=packed record
+    name     : array[0..7] of char;
+    vsize    : longint;
+    rvaofs   : longint;
+    datalen  : longint;
+    datapos  : longint;
+    relocpos : longint;
+    lineno1  : longint;
+    nrelocs  : word;
+    lineno2  : word;
+    flags    : longint;
+  end;
+  coffsymbol=packed record
+    name    : array[0..3] of char; { real is [0..7], which overlaps the strofs ! }
+    strofs  : longint;
+    value   : longint;
+    section : smallint;
+    empty   : word;
+    typ     : byte;
+    aux     : byte;
+  end;
+
+function FindSectionCoff(var e:TExeFile;const asecname:string;var secofs,seclen:longint):boolean;
+var
+  i : longint;
+  sechdr     : tcoffsechdr;
+  secname    : string;
+  secnamebuf : array[0..255] of char;
+  code,
+  oldofs,
+  bufsize    : longint;
+  strofs     : cardinal;
+begin
+  FindSectionCoff:=false;
+  { read section info }
+  seek(e.f,e.sechdrofs);
+  for i:=1 to e.nsects do
+   begin
+     blockread(e.f,sechdr,sizeof(sechdr),bufsize);
+     move(sechdr.name,secnamebuf,8);
+     secnamebuf[8]:=#0;
+     secname:=strpas(secnamebuf);
+     if secname[1]='/' then
+       begin
+         Val(Copy(secname,2,8),strofs,code);
+         if code=0 then
+           begin
+             fillchar(secnamebuf,sizeof(secnamebuf),0);
+             oldofs:=filepos(e.f);
+             seek(e.f,e.secstrofs+strofs);
+             blockread(e.f,secnamebuf,sizeof(secnamebuf),bufsize);
+             seek(e.f,oldofs);
+             secname:=strpas(secnamebuf);
+           end
+         else
+           secname:='';
+       end;
+     if asecname=secname then
+       begin
+         secofs:=sechdr.datapos;
+         seclen:=sechdr.datalen;
+         FindSectionCoff:=true;
+         exit;
+       end;
+   end;
+end;
+{$endif PE32 or PE32PLUS or GO32V2}
+
+
+{$ifdef go32v2}
+function OpenGo32Coff(var e:TExeFile):boolean;
+type
+  tgo32coffheader=packed record
+    mach   : word;
+    nsects : word;
+    time   : longint;
+    sympos : longint;
+    syms   : longint;
+    opthdr : word;
+    flag   : word;
+    other  : array[0..27] of byte;
+  end;
+var
+  coffheader : tgo32coffheader;
+begin
+  OpenGo32Coff:=false;
+  { read and check header }
+  if e.size<2048+sizeof(coffheader) then
+   exit;
+  seek(e.f,2048);
+  blockread(e.f,coffheader,sizeof(coffheader));
+  if coffheader.mach<>$14c then
+    exit;
+  e.sechdrofs:=filepos(e.f);
+  e.nsects:=coffheader.nsects;
+  e.secstrofs:=coffheader.sympos+coffheader.syms*sizeof(coffsymbol)+4;
+  if e.secstrofs>e.size then
+    exit;
+  OpenGo32Coff:=true;
+end;
+{$endif Go32v2}
+
+
+{$ifdef PE32}
+function OpenPeCoff(var e:TExeFile):boolean;
+type
+  tpeheader = packed record
+     PEMagic : longint;
+     Machine : word;
+     NumberOfSections : word;
+     TimeDateStamp : longint;
+     PointerToSymbolTable : longint;
+     NumberOfSymbols : longint;
+     SizeOfOptionalHeader : word;
+     Characteristics : word;
+     Magic : word;
+     MajorLinkerVersion : byte;
+     MinorLinkerVersion : byte;
+     SizeOfCode : longint;
+     SizeOfInitializedData : longint;
+     SizeOfUninitializedData : longint;
+     AddressOfEntryPoint : longint;
+     BaseOfCode : longint;
+     BaseOfData : longint;
+     ImageBase : longint;
+     SectionAlignment : longint;
+     FileAlignment : longint;
+     MajorOperatingSystemVersion : word;
+     MinorOperatingSystemVersion : word;
+     MajorImageVersion : word;
+     MinorImageVersion : word;
+     MajorSubsystemVersion : word;
+     MinorSubsystemVersion : word;
+     Reserved1 : longint;
+     SizeOfImage : longint;
+     SizeOfHeaders : longint;
+     CheckSum : longint;
+     Subsystem : word;
+     DllCharacteristics : word;
+     SizeOfStackReserve : longint;
+     SizeOfStackCommit : longint;
+     SizeOfHeapReserve : longint;
+     SizeOfHeapCommit : longint;
+     LoaderFlags : longint;
+     NumberOfRvaAndSizes : longint;
+     DataDirectory : array[1..$80] of byte;
+  end;
+var
+  dosheader  : tdosheader;
+  peheader   : tpeheader;
+begin
+  OpenPeCoff:=false;
+  { read and check header }
+  if e.size<sizeof(dosheader) then
+    exit;
+  blockread(e.f,dosheader,sizeof(tdosheader));
+  seek(e.f,dosheader.e_lfanew);
+  blockread(e.f,peheader,sizeof(tpeheader));
+  if peheader.pemagic<>$4550 then
+    exit;
+  e.sechdrofs:=filepos(e.f);
+  e.nsects:=peheader.NumberOfSections;
+  e.secstrofs:=peheader.PointerToSymbolTable+peheader.NumberOfSymbols*sizeof(coffsymbol)+4;
+  if e.secstrofs>e.size then
+    exit;
+  OpenPeCoff:=true;
+end;
+{$endif PE32}
+
+
+{$ifdef PE32PLUS}
+function OpenPePlusCoff(var e:TExeFile):boolean;
+type
+  tpeheader = packed record
+     PEMagic : longint;
+     Machine : word;
+     NumberOfSections : word;
+     TimeDateStamp : longint;
+     PointerToSymbolTable : longint;
+     NumberOfSymbols : longint;
+     SizeOfOptionalHeader : word;
+     Characteristics : word;
+     Magic : word;
+     MajorLinkerVersion : byte;
+     MinorLinkerVersion : byte;
+     SizeOfCode : longint;
+     SizeOfInitializedData : longint;
+     SizeOfUninitializedData : longint;
+     AddressOfEntryPoint : longint;
+     BaseOfCode : longint;
+     BaseOfData : longint;
+     ImageBase : longint;
+     SectionAlignment : longint;
+     FileAlignment : longint;
+     MajorOperatingSystemVersion : word;
+     MinorOperatingSystemVersion : word;
+     MajorImageVersion : word;
+     MinorImageVersion : word;
+     MajorSubsystemVersion : word;
+     MinorSubsystemVersion : word;
+     Reserved1 : longint;
+     SizeOfImage : longint;
+     SizeOfHeaders : longint;
+     CheckSum : longint;
+     Subsystem : word;
+     DllCharacteristics : word;
+     SizeOfStackReserve : int64;
+     SizeOfStackCommit : int64;
+     SizeOfHeapReserve : int64;
+     SizeOfHeapCommit : int64;
+     LoaderFlags : longint;
+     NumberOfRvaAndSizes : longint;
+     DataDirectory : array[1..$80] of byte;
+  end;
+var
+  dosheader  : tdosheader;
+  peheader   : tpeheader;
+begin
+  OpenPePlusCoff:=false;
+  { read and check header }
+  if E.Size<sizeof(dosheader) then
+   exit;
+  blockread(E.F,dosheader,sizeof(tdosheader));
+  seek(E.F,dosheader.e_lfanew);
+  blockread(E.F,peheader,sizeof(tpeheader));
+  if peheader.pemagic<>$4550 then
+   exit;
+  e.sechdrofs:=filepos(e.f);
+  e.nsects:=peheader.NumberOfSections;
+  e.secstrofs:=peheader.PointerToSymbolTable+peheader.NumberOfSymbols*sizeof(coffsymbol)+4;
+  if e.secstrofs>e.size then
+    exit;
+  OpenPePlusCoff:=true;
+end;
+{$endif PE32PLUS}
+
+
+{****************************************************************************
+                                 AOUT
+****************************************************************************}
+
+{$IFDEF EMX}
+type
+  TEmxHeader = packed record
+     Version: array [1..16] of char;
+     Bound: word;
+     AoutOfs: longint;
+     Options: array [1..42] of char;
+  end;
+
+  TAoutHeader = packed record
+     Magic: word;
+     Machine: byte;
+     Flags: byte;
+     TextSize: longint;
+     DataSize: longint;
+     BssSize: longint;
+     SymbSize: longint;
+     EntryPoint: longint;
+     TextRelocSize: longint;
+     DataRelocSize: longint;
+  end;
+
+const
+ StartPageSize = $1000;
+
+var
+ DosHeader: TDosHeader;
+ EmxHeader: TEmxHeader;
+ AoutHeader: TAoutHeader;
+ StabOfs: PtrUInt;
+ S4: string [4];
+
+function OpenEMXaout (var E: TExeFile): boolean;
+begin
+ OpenEMXaout := false;
+{ GDB after 4.18 uses offset to function begin
+  in text section but OS/2 version still uses 4.16 PM }
+ E.FunctionRelative := false;
+{ read and check header }
+ if E.Size > SizeOf (DosHeader) then
+ begin
+  BlockRead (E.F, DosHeader, SizeOf (TDosHeader));
+  if E.Size > DosHeader.e_cparhdr shl 4 + SizeOf (TEmxHeader) then
+  begin
+   Seek (E.F, DosHeader.e_cparhdr shl 4);
+   BlockRead (E.F, EmxHeader, SizeOf (TEmxHeader));
+  S4 [0] := #4;
+  Move (EmxHeader.Version, S4 [1], 4);
+   if (S4 = 'emx ') and
+                       (E.Size > EmxHeader.AoutOfs + SizeOf (TAoutHeader)) then
+   begin
+    Seek (E.F, EmxHeader.AoutOfs);
+    BlockRead (E.F, AoutHeader, SizeOf (TAoutHeader));
+   if AOutHeader.Magic = $10B then
+     StabOfs := StartPageSize
+   else
+     StabOfs := EmxHeader.AoutOfs + SizeOf (TAoutHeader);
+   StabOfs := StabOfs
+                + AoutHeader.TextSize
+                + AoutHeader.DataSize
+                + AoutHeader.TextRelocSize
+                + AoutHeader.DataRelocSize;
+    if E.Size > StabOfs + AoutHeader.SymbSize then
+     OpenEMXaout := true;
+   end;
+  end;
+ end;
+end;
+
+
+function FindSectionEMXaout (var E: TExeFile; const ASecName: string;
+                                         var SecOfs, SecLen: longint): boolean;
+begin
+ FindSectionEMXaout := false;
+ if ASecName = '.stab' then
+ begin
+  SecOfs := StabOfs;
+  SecLen := AoutHeader.SymbSize;
+  FindSectionEMXaout := true;
+ end else
+ if ASecName = '.stabstr' then
+ begin
+  SecOfs := StabOfs + AoutHeader.SymbSize;
+  SecLen := E.Size - Pred (SecOfs);
+  FindSectionEMXaout := true;
+ end;
+end;
+{$ENDIF EMX}
+
+
+{****************************************************************************
+                                 ELF
+****************************************************************************}
+
+{$if defined(ELF32) or defined(BEOS)}
+type
+  telfheader=packed record
+      magic0123         : longint;
+      file_class        : byte;
+      data_encoding     : byte;
+      file_version      : byte;
+      padding           : array[$07..$0f] of byte;
+      e_type            : word;
+      e_machine         : word;
+      e_version         : longword;
+      e_entry           : longword;                  // entrypoint
+      e_phoff           : longword;                  // program header offset
+      e_shoff           : longword;                  // sections header offset
+      e_flags           : longword;
+      e_ehsize          : word;             // elf header size in bytes
+      e_phentsize       : word;             // size of an entry in the program header array
+      e_phnum           : word;             // 0..e_phnum-1 of entrys
+      e_shentsize       : word;             // size of an entry in sections header array
+      e_shnum           : word;             // 0..e_shnum-1 of entrys
+      e_shstrndx        : word;             // index of string section header
+  end;
+  telfsechdr=packed record
+      sh_name           : longword;
+      sh_type           : longword;
+      sh_flags          : longword;
+      sh_addr           : longword;
+      sh_offset         : longword;
+      sh_size           : longword;
+      sh_link           : longword;
+      sh_info           : longword;
+      sh_addralign      : longword;
+      sh_entsize        : longword;
+    end;
+{$endif ELF32 or BEOS}
+{$ifdef ELF64}
+type
+  telfheader=packed record
+      magic0123         : longint;
+      file_class        : byte;
+      data_encoding     : byte;
+      file_version      : byte;
+      padding           : array[$07..$0f] of byte;
+      e_type            : word;
+      e_machine         : word;
+      e_version         : longword;
+      e_entry           : int64;                  // entrypoint
+      e_phoff           : int64;                  // program header offset
+      e_shoff           : int64;                  // sections header offset
+      e_flags           : longword;
+      e_ehsize          : word;             // elf header size in bytes
+      e_phentsize       : word;             // size of an entry in the program header array
+      e_phnum           : word;             // 0..e_phnum-1 of entrys
+      e_shentsize       : word;             // size of an entry in sections header array
+      e_shnum           : word;             // 0..e_shnum-1 of entrys
+      e_shstrndx        : word;             // index of string section header
+  end;
+type
+  telfsechdr=packed record
+      sh_name           : longword;
+      sh_type           : longword;
+      sh_flags          : int64;
+      sh_addr           : int64;
+      sh_offset         : int64;
+      sh_size           : int64;
+      sh_link           : longword;
+      sh_info           : longword;
+      sh_addralign      : int64;
+      sh_entsize        : int64;
+    end;
+{$endif ELF64}
+
+
+{$if defined(ELF32) or defined(ELF64) or defined(BEOS)}
+function OpenElf(var e:TExeFile):boolean;
+var
+  elfheader : telfheader;
+  elfsec    : telfsechdr;
+begin
+  OpenElf:=false;
+  { read and check header }
+  if e.size<sizeof(telfheader) then
+   exit;
+  blockread(e.f,elfheader,sizeof(telfheader));
+ if elfheader.magic0123<>{$ifdef ENDIAN_LITTLE}$464c457f{$else}$7f454c46{$endif} then
+   exit;
+  if elfheader.e_shentsize<>sizeof(telfsechdr) then
+   exit;
+  { read section names }
+  seek(e.f,elfheader.e_shoff+elfheader.e_shstrndx*cardinal(sizeof(telfsechdr)));
+  blockread(e.f,elfsec,sizeof(telfsechdr));
+  e.secstrofs:=elfsec.sh_offset;
+  e.sechdrofs:=elfheader.e_shoff;
+  e.nsects:=elfheader.e_shnum;
+  OpenElf:=true;
+end;
+
+
+function FindSectionElf(var e:TExeFile;const asecname:string;var secofs,seclen:longint):boolean;
+var
+  elfsec     : telfsechdr;
+  secname    : string;
+  secnamebuf : array[0..255] of char;
+  oldofs,
+  bufsize,i  : longint;
+begin
+  FindSectionElf:=false;
+  seek(e.f,e.sechdrofs);
+  for i:=1 to e.nsects do
+   begin
+     blockread(e.f,elfsec,sizeof(telfsechdr));
+     fillchar(secnamebuf,sizeof(secnamebuf),0);
+     oldofs:=filepos(e.f);
+     seek(e.f,e.secstrofs+elfsec.sh_name);
+     blockread(e.f,secnamebuf,sizeof(secnamebuf),bufsize);
+     seek(e.f,oldofs);
+     secname:=strpas(secnamebuf);
+     if asecname=secname then
+       begin
+         secofs:=elfsec.sh_offset;
+         seclen:=elfsec.sh_size;
+         FindSectionElf:=true;
+         exit;
+       end;
+   end;
+end;
+{$endif ELF32 or ELF64 or BEOS}
+
+
+{$ifdef beos}
+
+{$i ptypes.inc}
+
+type
+  // Descriptive formats
+  status_t = Longint;
+  team_id   = Longint;
+  image_id = Longint;
+
+    { image types }
+const
+   B_APP_IMAGE     = 1;
+   B_LIBRARY_IMAGE = 2;
+   B_ADD_ON_IMAGE  = 3;
+   B_SYSTEM_IMAGE  = 4;
+
+type
+    image_info = packed record
+     id      : image_id;
+     _type   : longint;
+     sequence: longint;
+     init_order: longint;
+     init_routine: pointer;
+     term_routine: pointer;
+     device: dev_t;
+     node: ino_t;
+     name: array[0..MAXPATHLEN-1] of char;
+{     name: string[255];
+     name2: string[255];
+     name3: string[255];
+     name4: string[255];
+     name5: string[5];
+}
+     text: pointer;
+     data: pointer;
+     text_size: longint;
+     data_size: longint;
+    end;
+
+function get_next_image_info(team: team_id; var cookie:longint; var info:image_info; size: size_t) : status_t;cdecl; external 'root' name '_get_next_image_info';
+
+function OpenElf32Beos(var e:TExeFile):boolean;
+var
+  cookie    : longint;
+  info      : image_info;
+begin
+  // The only BeOS specific part is setting the processaddress
+  cookie := 0;
+  fillchar(info, sizeof(image_info), 0);
+  get_next_image_info(0,cookie,info,sizeof(info));
+  if (info._type = B_APP_IMAGE) then
+     e.processaddress := cardinal(info.text)
+  else
+     e.processaddress := 0;
+  OpenElf32Beos := OpenElf(e);
+end;
+{$endif beos}
+
+
+{****************************************************************************
+                                 MACHO
+****************************************************************************}
+
+{$ifdef darwin}
+type
+  MachoFatHeader= packed record
+    magic: longint;
+    nfatarch: longint;
+  end;
+  MachoHeader=packed record
+    magic: longword;
+    cpu_type_t: longint;
+    cpu_subtype_t: longint;
+    filetype: longint;
+    ncmds: longint;
+    sizeofcmds: longint;
+    flags: longint;
+  end;
+  cmdblock=packed record
+    cmd: longint;
+    cmdsize: longint;
+  end;
+  symbSeg=packed record
+    symoff :      longint;
+    nsyms  :      longint;
+    stroff :      longint;
+    strsize:      longint;
+  end;
+  tstab=packed record
+    strpos  : longint;
+    ntype   : byte;
+    nother  : byte;
+    ndesc   : word;
+    nvalue  : dword;
+  end;
+
+
+function OpenMachO32PPC(var e:TExeFile):boolean;
+var
+   mh:MachoHeader;
+begin
+  OpenMachO32PPC:= false;
+  E.FunctionRelative:=false;
+  if e.size<sizeof(mh) then
+    exit;
+  blockread (e.f, mh, sizeof(mh));
+  e.sechdrofs:=filepos(e.f);
+  e.nsects:=mh.ncmds;
+  OpenMachO32PPC:=true;
+end;
+
+
+function FindSectionMachO32PPC(var e:TExeFile;const asecname:string;var secofs,seclen:longint):boolean;
+var
+   i: longint;
+   block:cmdblock;
+   symbolsSeg:  symbSeg;
+begin
+  seek(e.f,e.sechdrofs);
+  for i:= 1 to e.nsects do
+    begin
+      blockread (e.f, block, sizeof(block));
+      if block.cmd = $2   then
+      begin
+          blockread (e.f, symbolsSeg, sizeof(symbolsSeg));
+          if asecname='.stab' then
+            begin
+              secofs:=symbolsSeg.symoff;
+              { the caller will divide again by sizeof(tstab) }
+              seclen:=symbolsSeg.nsyms*sizeof(tstab);
+            end
+          else if asecname='.stabstr' then
+            begin
+              secofs:=symbolsSeg.stroff;
+              seclen:=symbolsSeg.strsize;
+            end;
+          FindSectionMachO32PPC:=true;
+          exit;
+      end;
+      Seek(e.f, FilePos (e.f) + block.cmdsize - sizeof(block));
+    end;
+end;
+{$endif darwin}
+
+
+{****************************************************************************
+                                   CRC
+****************************************************************************}
+
+var
+  Crc32Tbl : array[0..255] of cardinal;
+
+procedure MakeCRC32Tbl;
+var
+  crc : cardinal;
+  i,n : integer;
+begin
+  for i:=0 to 255 do
+   begin
+     crc:=i;
+     for n:=1 to 8 do
+      if (crc and 1)<>0 then
+       crc:=(crc shr 1) xor cardinal($edb88320)
+      else
+       crc:=crc shr 1;
+     Crc32Tbl[i]:=crc;
+   end;
+end;
+
+
+Function UpdateCrc32(InitCrc:cardinal;const InBuf;InLen:LongInt):cardinal;
+var
+  i : LongInt;
+  p : pchar;
+begin
+  if Crc32Tbl[1]=0 then
+   MakeCrc32Tbl;
+  p:=@InBuf;
+  UpdateCrc32:=not InitCrc;
+  for i:=1 to InLen do
+   begin
+     UpdateCrc32:=Crc32Tbl[byte(UpdateCrc32) xor byte(p^)] xor (UpdateCrc32 shr 8);
+     inc(p);
+   end;
+  UpdateCrc32:=not UpdateCrc32;
+end;
+
+
+{****************************************************************************
+                         Generic Executable Open/Close
+****************************************************************************}
+
+type
+  TOpenProc=function(var e:TExeFile):boolean;
+  TFindSectionProc=function(var e:TExeFile;const asecname:string;var secofs,seclen:longint):boolean;
+
+  TExeProcRec=record
+    openproc : TOpenProc;
+    findproc : TFindSectionProc;
+  end;
+
+const
+  ExeProcs : TExeProcRec = (
+{$ifdef go32v2}
+     openproc : @OpenGo32Coff;
+     findproc : @FindSectionCoff;
+{$endif}
+{$ifdef PE32}
+     openproc : @OpenPeCoff;
+     findproc : @FindSectionCoff;
+{$endif}
+{$ifdef PE32PLUS}
+     openproc : @OpenPePlusCoff;
+     findproc : @FindSectionCoff;
+{$endif PE32PLUS}
+{$if defined(ELF32) or defined(ELF64)}
+     openproc : @OpenElf;
+     findproc : @FindSectionElf;
+{$endif ELF32 or ELF64}
+{$ifdef BEOS}
+     openproc : @OpenElf32Beos;
+     findproc : @FindSectionElf;
+{$endif BEOS}
+{$ifdef darwin}
+     openproc : @OpenMachO32PPC;
+     findproc : @FindSectionMachO32PPC;
+{$endif darwin}
+{$IFDEF EMX}
+     openproc : @OpenEMXaout;
+     findproc : @FindSectionEMXaout;
+{$ENDIF EMX}
+{$ifdef netware}
+     openproc : @OpenNetwareNLM;
+     findproc : @FindSectionNetwareNLM;
+{$endif}
+   );
+
+function OpenExeFile(var e:TExeFile;const fn:string):boolean;
+var
+  ofm : word;
+begin
+  OpenExeFile:=false;
+  fillchar(e,sizeof(e),0);
+  e.bufsize:=sizeof(e.buf);
+  e.filename:=fn;
+  assign(e.f,fn);
+  {$I-}
+   ofm:=filemode;
+   filemode:=$40;
+   reset(e.f,1);
+   filemode:=ofm;
+  {$I+}
+  if ioresult<>0 then
+   exit;
+  e.isopen:=true;
+  // cache filesize
+  e.size:=filesize(e.f);
+
+  E.FunctionRelative := true;
+  if ExeProcs.OpenProc<>nil then
+    OpenExeFile:=ExeProcs.OpenProc(e);
+end;
+
+
+function CloseExeFile(var e:TExeFile):boolean;
+begin
+  CloseExeFile:=false;
+  if not e.isopen then
+    exit;
+  e.isopen:=false;
+  close(e.f);
+  CloseExeFile:=true;
+end;
+
+
+function FindExeSection(var e:TExeFile;const secname:string;var secofs,seclen:longint):boolean;
+begin
+  FindExeSection:=false;
+  if not e.isopen then
+    exit;
+  if ExeProcs.FindProc<>nil then
+    FindExeSection:=ExeProcs.FindProc(e,secname,secofs,seclen);
+end;
+
+
+
+function CheckDbgFile(var e:TExeFile;const fn:string;dbgcrc:cardinal):boolean;
+var
+  c      : cardinal;
+  ofm    : word;
+  g      : file;
+begin
+  CheckDbgFile:=false;
+  assign(g,fn);
+  {$I-}
+   ofm:=filemode;
+   filemode:=$40;
+   reset(g,1);
+   filemode:=ofm;
+  {$I+}
+  if ioresult<>0 then
+   exit;
+  { We reuse the buffer from e here to prevent too much stack allocation }
+  c:=0;
+  repeat
+    blockread(g,e.buf,e.bufsize,e.bufcnt);
+    c:=UpdateCrc32(c,e.buf,e.bufcnt);
+  until e.bufcnt<e.bufsize;
+  close(g);
+  CheckDbgFile:=(dbgcrc=c);
+end;
+
+
+function ReadDebugLink(var e:TExeFile;var dbgfn:string):boolean;
+var
+  dbglink : array[0..255] of char;
+  i,
+  dbglinklen,
+  dbglinkofs : longint;
+  dbgcrc     : cardinal;
+begin
+  ReadDebugLink:=false;
+  if not FindExeSection(e,'.gnu_debuglink',dbglinkofs,dbglinklen) then
+    exit;
+  if dbglinklen>sizeof(dbglink)-1 then
+    exit;
+  fillchar(dbglink,sizeof(dbglink),0);
+  seek(e.f,dbglinkofs);
+  blockread(e.f,dbglink,dbglinklen);
+  dbgfn:=strpas(dbglink);
+  if length(dbgfn)=0 then
+    exit;
+  i:=align(length(dbgfn)+1,4);
+  if i>dbglinklen then
+    exit;
+  move(dbglink[i],dbgcrc,4);
+  { current dir }
+  if CheckDbgFile(e,dbgfn,dbgcrc) then
+    begin
+      ReadDebugLink:=true;
+      exit;
+    end;
+  { executable dir }
+  i:=length(e.filename);
+  while (i>0) and not(e.filename[i] in AllowDirectorySeparators) do
+    dec(i);
+  if i>0 then
+    begin
+      dbgfn:=copy(e.filename,1,i)+dbgfn;
+      if CheckDbgFile(e,dbgfn,dbgcrc) then
+        begin
+          ReadDebugLink:=true;
+          exit;
+        end;
+    end;
+end;
+
+
+end.

File diff suppressed because it is too large
+ 35 - 1057
rtl/inc/lineinfo.pp


+ 185 - 423
rtl/inc/lnfodwrf.pp

@@ -3,7 +3,7 @@
 
     Copyright (c) 2006 by Thomas Schatzl, member of the FreePascal
     Development team
-    Parts (c) 2000 Peter Vreman (adapted from original stabs line
+    Parts (c) 2000 Peter Vreman (adapted from original dwarfs line
     reader)
 
     Dwarf LineInfo Retriever
@@ -16,38 +16,21 @@
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
  **********************************************************************}
+{
+  This unit should not be compiled in objfpc mode, since this would make it
+  dependent on objpas unit.
+}
 unit lnfodwrf;
 interface
 
-{ disable stack checking }
 {$S-}
 
 procedure GetLineInfo(addr:ptruint;var func,source:string;var line:longint);
 
 implementation
 
-{ Note to implementors of other OS loaders:
-
-  - add a LoadXXX() function which has no parameters and returns a Boolean
-   in the "OS loaders section" enclosing it using the OS specific define.
-   This method should set the
-
-     DwarfOpened,
-     DwarfOffset and
-     DwarfSize
-
-   global variables properly (see comments at variable definition for more
-   information).
-   Additionally this method should return true if DWARF line info information
-   could be found.
-
-   The file variable which can be used for file I/O is the global "infile"
-   variable.
-
-  - in OpenDwarf(), add a call to this initializer function after the
-   "run OS specific initializer" comment, again enclosed in the system
-   specific define.
-}
+uses
+  exeinfo;
 
 { Current issues:
 
@@ -55,365 +38,29 @@ implementation
   - slow
 }
 
-{ some type definitions }
-type
-{$IFDEF CPU32}
-  UInt = DWord;
-  Int = Longint;
-{$ENDIF}
-{$IFDEF CPU64}
-  UInt = QWord;
-  Int = Int64;
-{$ENDIF}
-  Bool8 = ByteBool;
-
-var
-  { the input file to read DWARF debug info from, i.e. paramstr(0) }
-  infile : File;
-  { size of the current file, cached }
-  DwarfFilesize : Int64;
-
-{ these variables should be set by the LoadXXX() methods for proper function }
-
-  { set to true if DWARF debug info could be found in the file.
-    The DwarfOffset and DwarfSize variables must be valid after setting this }
-  DwarfOpened : Boolean;
-  { the offset to the DWARF debug_line section in the file }
-  DwarfOffset : Int64;
-  { the size of the DWARF .debug_line section in the file in bytes }
-  DwarfSize : SizeInt;
-
 {$MACRO ON}
 
 //{$DEFINE DEBUG_DWARF_PARSER}
 {$ifdef DEBUG_DWARF_PARSER}
-{$define DEBUG_WRITELN := WriteLn}
-{$define DEBUG_COMMENT :=  }
+  {$define DEBUG_WRITELN := WriteLn}
+  {$define DEBUG_COMMENT :=  }
 {$else}
-{$define DEBUG_WRITELN := //}
-{$define DEBUG_COMMENT := //}
+  {$define DEBUG_WRITELN := //}
+  {$define DEBUG_COMMENT := //}
 {$endif}
 
-{---------------------------------------------------------------------------
- I/O utility functions
----------------------------------------------------------------------------}
-
-var
-  base, limit : SizeInt;
-  index : SizeInt;
-
-function Init(aBase, aLimit : Int64) : Boolean;
-begin
-  base := aBase;
-  limit := aLimit;
-  Init := (aBase + limit) <= DwarfFilesize;
-  seek(infile, base);
-  index := 0;
-end;
-
-function Init(aBase : Int64) : Boolean;
-begin
-  Init := Init(aBase, limit - (aBase - base));
-end;
-
-function Pos() : Int64;
-begin
-  Pos := index;
-end;
-
-procedure Seek(const newIndex : Int64);
-begin
-  index := newIndex;
-  system.seek(infile, base + index);
-end;
-
-{ Returns the next Byte from the input stream, or -1 if there has been
-  an error }
-function ReadNext() : Int;
-var
-  bytesread : SizeInt;
-  b : Byte;
-begin
-  ReadNext := -1;
-  if (index < limit) then begin
-    blockread(infile, b, 1, bytesread);
-    ReadNext := b;
-    inc(index);
-  end;
-  if (bytesread <> 1) then
-    ReadNext := -1;
-end;
-
-{ Reads the next size bytes into dest. Returns true if successful,
-  false otherwise. Note that dest may be partially overwritten after
-  returning false. }
-function ReadNext(var dest; size : SizeInt) : Boolean;
-var
-  bytesread : SizeInt;
-begin
-  bytesread := 0;
-  if ((index + size) < limit) then begin
-    blockread(infile, dest, size, bytesread);
-    inc(index, size);
-  end;
-  ReadNext := (bytesread = size);
-end;
-
-
-{---------------------------------------------------------------------------
- OS specific loaders
----------------------------------------------------------------------------}
-
-{$ifdef LINUX}
-{$packrecords c}
-
-{ ELF Header structures types}
-type
-  Elf32_Half = Word;
-  Elf64_Half = Word;
-  { Types for signed and unsigned 32-bit quantities.   }
-  Elf32_Word = DWord;
-  Elf32_Sword = Longint;
-  Elf64_Word = DWord;
-  Elf64_Sword = Longint;
-  { Types for signed and unsigned 64-bit quantities.   }
-  Elf32_Xword = QWord;
-  Elf32_Sxword = Int64;
-  Elf64_Xword = QWord;
-  Elf64_Sxword = Int64;
-  { Type of addresses.   }
-  Elf32_Addr = DWord;
-  Elf64_Addr = QWord;
-  { Type of file offsets.   }
-  Elf32_Off = DWord;
-  Elf64_Off = QWord;
-  { Type for section indices, which are 16-bit quantities.   }
-  Elf32_Section = Word;
-  Elf64_Section = Word;
-  { Type for version symbol information.   }
-  Elf32_Versym = Elf32_Half;
-  Elf64_Versym = Elf64_Half;
-{ some constants from the corresponding header files }
-const
-  El_NIDENT = 16;
-  { some important indices into the e_ident signature of an ELF file }
-  EI_MAG0 = 0;
-  EI_MAG1 = 1;
-  EI_MAG2 = 2;
-  EI_MAG3 = 3;
-  EI_CLASS = 4;
-  { the first byte of the e_ident array must be of this value }
-  ELFMAG0 = $7f;
-  { the second byte of the e_ident array must be of this value }
-  ELFMAG1 = Byte('E');
-  { the third byte of the e_ident array must be of this value }
-  ELFMAG2 = Byte('L');
-  { the fourth byte of the e_ident array must be of this value }
-  ELFMAG3 = Byte('F');
-
-  { the fifth byte specifies the bitness of the header; all other values are invalid }
-  ELFCLASS32 = 1;
-  ELFCLASS64 = 2;
-
-  ELFCLASS = {$IFDEF CPU32}ELFCLASS32{$ENDIF}{$IFDEF CPU64}ELFCLASS64{$ENDIF};
-
+{ some type definitions }
 type
-  { The ELF file header.  This appears at the start of every ELF file, 32 bit version }
-  TElf32_Ehdr = record
-    e_ident : array[0..El_NIDENT-1] of Byte; { file identification }
-    e_type : Elf32_Half; { file type }
-    e_machine : Elf32_Half; { machine architecture }
-    e_version : Elf32_Word; { ELF format version }
-    e_entry : Elf32_Addr; { entry point }
-    e_phoff : Elf32_Off; { program header file offset }
-    e_shoff : Elf32_Off; { section header file offset }
-    e_flags : Elf32_Word; { architecture specific flags }
-    e_ehsize : Elf32_Half; { size of ELF header in bytes }
-    e_phentsize : Elf32_Half; { size of program header entry }
-    e_phnum : Elf32_Half; { number of program header entries }
-    e_shentsize : Elf32_Half; { size of section header entry }
-    e_shnum : Elf32_Half; { number of section header entry }
-    e_shstrndx : Elf32_Half; { section name strings section index }
-  end;
-
-  { ELF32 Section header }
-  TElf32_Shdr = record
-    sh_name : Elf32_Word; { section name }
-    sh_type : Elf32_Word; { section type }
-    sh_flags : Elf32_Word; { section flags }
-    sh_addr : Elf32_Addr; { virtual address }
-    sh_offset : Elf32_Off; { file offset }
-    sh_size : Elf32_Word; { section size }
-    sh_link : Elf32_Word; { misc info }
-    sh_info : Elf32_Word; { misc info }
-    sh_addralign : Elf32_Word; { memory alignment }
-    sh_entsize : Elf32_Word; { entry size if table }
-  end;
-
-  { The ELF file header.  This appears at the start of every ELF file, 64 bit version }
-  TElf64_Ehdr = record
-    e_ident : array[0..El_NIDENT-1] of Byte;
-    e_type : Elf64_Half;
-    e_machine : Elf64_Half;
-    e_version : Elf64_Word;
-    e_entry : Elf64_Addr;
-    e_phoff : Elf64_Off;
-    e_shoff : Elf64_Off;
-    e_flags : Elf64_Word;
-    e_ehsize : Elf64_Half;
-    e_phentsize : Elf64_Half;
-    e_phnum : Elf64_Half;
-    e_shentsize : Elf64_Half;
-    e_shnum : Elf64_Half;
-    e_shstrndx : Elf64_Half;
-  end;
-
-  { ELF64 Section header }
-  TElf64_Shdr = record
-    sh_name : Elf64_Word;
-    sh_type : Elf64_Word;
-    sh_flags : Elf64_Xword;
-    sh_addr : Elf64_Addr;
-    sh_offset : Elf64_Off;
-    sh_size : Elf64_Xword;
-    sh_link : Elf64_Word;
-    sh_info : Elf64_Word;
-    sh_addralign : Elf64_Xword;
-    sh_entsize : Elf64_Xword;
-  end;
-
-  TElf_Shdr = {$ifdef cpu32}TElf32_Shdr{$endif}{$ifdef cpu64}TElf64_Shdr{$endif};
-  TElf_Ehdr = {$ifdef cpu32}TElf32_Ehdr{$endif}{$ifdef cpu64}TElf64_Ehdr{$endif};
-
-{ use globals to save stack space }
-var
-  header : TElf_Ehdr;
-  strtab_header : TElf_Shdr;
-  cursec_header : TElf_Shdr;
-
-  buf : array[0..20] of char;
-
-function LoadLinux() : Boolean;
-var
-  i : Integer;
-begin
-  LoadLinux := false;
-
-  Init(0, DwarfFilesize);
-
-  if (not ReadNext(header, sizeof(header))) then begin
-    DEBUG_WRITELN('Could not read header');
-    exit;
-  end;
-
-  { more paranoia checks }
-  if ((header.e_ident[EI_MAG0] <> ELFMAG0) or (header.e_ident[EI_MAG1] <> ELFMAG1) or
-    (header.e_ident[EI_MAG2] <> ELFMAG2) or (header.e_ident[EI_MAG3] <> ELFMAG3)) then begin
-    DEBUG_WRITELN('Invalid ELF magic header. Exiting');
-    exit;
-  end;
-
-  if (header.e_ident[EI_CLASS] <> ELFCLASS) then begin
-    DEBUG_WRITELN('Invalid ELF header bitness. Exiting');
-    exit;
-  end;
-
-  { check e_version = , e_shentsize > 0, e_shnum > 0 }
-
-
-  { seek to the start of section headers }
-
-  { first get string section header }
-  Init(header.e_shoff + (header.e_shstrndx * header.e_shentsize));
-  if (not ReadNext(strtab_header, sizeof(strtab_header))) then begin
-    DEBUG_WRITELN('Could not read string section header');
-    exit;
-  end;
-
-  for i := 0 to (header.e_shnum-1) do begin
-    Init(header.e_shoff + (i * header.e_shentsize));
-    if (not ReadNext(cursec_header, sizeof(cursec_header))) then begin
-      DEBUG_WRITELN('Could not read next section header');
-      exit;
-    end;
-    { paranoia TODO: check cursec_header.e_shentsize }
-
-    Init(strtab_header.sh_offset + cursec_header.sh_name);
-    if (not ReadNext(buf, sizeof(buf))) then begin
-      DEBUG_WRITELN('Could not read section name');
-      exit;
-    end;
-    buf[sizeof(buf)-1] := #0;
-
-    DEBUG_WRITELN('This section is "', pchar(@buf[0]), '", offset ', cursec_header.sh_offset, ' size ', cursec_header.sh_size);
-    if (pchar(@buf[0]) = '.debug_line') then begin
-      DEBUG_WRITELN('.debug_line section found');
-      DwarfOffset := cursec_header.sh_offset;
-      DwarfSize := cursec_header.sh_size;
-      { more checks }
-      LoadLinux := (DwarfOffset >= 0) and (DwarfSize > 0);
-    end;
-  end;
-end;
-{$endif LINUX}
-
-
-{---------------------------------------------------------------------------
-
- Generic Dwarf lineinfo reader
-
- The line info reader is based on the information contained in
-
-   DWARF Debugging Information Format Version 3
-   Chapter 6.2 "Line Number Information"
-
- from the
-
-   DWARF Debugging Information Format Workgroup.
-
- For more information on this document see also
-
-   http://dwarf.freestandards.org/
-
----------------------------------------------------------------------------}
-
-procedure CloseDwarf();
-begin
-  if (DwarfOpened) then
-    close(infile);
-  DwarfOpened := false;
-end;
+  Bool8 = ByteBool;
 
-function OpenDwarf() : Boolean;
 var
-  oldfilemode : Word;
-begin
-  OpenDwarf := false;
-  { open input file }
-  assign(infile, paramstr(0));
-  {$I-}
-  oldfilemode := filemode;
-  filemode := $40;
-  reset(infile, 1);
-  filemode := oldfilemode;
-  {$I+}
-  if (ioresult <> 0) then begin
-    DEBUG_WRITELN('Could not open file');
-    exit;
-  end;
-  DwarfFilesize := filesize(infile);
-  DwarfOpened := true;
-  { run OS specific initializer }
-  {$ifdef linux}
-  if (LoadLinux()) then begin
-    OpenDwarf := true;
-    exit;
-  end;
-  {$endif}
-  CloseDwarf();
-end;
+  { the input file to read DWARF debug info from, i.e. paramstr(0) }
+  e : TExeFile;
+  DwarfErr : boolean;
+  { the offset and size of the DWARF debug_line section in the file }
+  DwarfOffset : longint;
+  DwarfSize : longint;
 
-{$packrecords default}
 { DWARF 2 default opcodes}
 const
   { Extended opcodes }
@@ -475,60 +122,139 @@ type
     opcode_base : Byte;
   end;
 
-{ initializes the line info state to the default values }
-procedure InitStateRegisters(var state : TMachineState; const aIs_Stmt : Bool8);
+{---------------------------------------------------------------------------
+ I/O utility functions
+---------------------------------------------------------------------------}
+
+var
+  base, limit : SizeInt;
+  index : SizeInt;
+
+function Opendwarf:boolean;
+var
+  dbgfn : string;
 begin
-  with state do begin
-    address := 0;
-    file_id := 1;
-    line := 1;
-    column := 0;
-    is_stmt := aIs_Stmt;
-    basic_block := false;
-    end_sequence := false;
-    prolouge_end := false;
-    epilouge_begin := false;
-    isa := 0;
-    append_row := false;
+  Opendwarf:=false;
+  if dwarferr then
+    exit;
+  if not OpenExeFile(e,paramstr(0)) then
+    exit;
+  if ReadDebugLink(e,dbgfn) then
+    begin
+      CloseExeFile(e);
+      if not OpenExeFile(e,dbgfn) then
+        exit;
+    end;
+  if FindExeSection(e,'.debug_line',dwarfoffset,dwarfsize) then
+    Opendwarf:=true
+  else
+    begin
+      dwarferr:=true;
+      exit;
+    end;
+end;
+
+
+procedure Closedwarf;
+begin
+  CloseExeFile(e);
+end;
+
+
+function Init(aBase, aLimit : Int64) : Boolean;
+begin
+  base := aBase;
+  limit := aLimit;
+  Init := (aBase + limit) <= e.size;
+  seek(e.f, base);
+  index := 0;
+end;
+
+function Init(aBase : Int64) : Boolean;
+begin
+  Init := Init(aBase, limit - (aBase - base));
+end;
+
+
+function Pos() : Int64;
+begin
+  Pos := index;
+end;
+
+
+procedure Seek(const newIndex : Int64);
+begin
+  index := newIndex;
+  system.seek(e.f, base + index);
+end;
+
+
+{ Returns the next Byte from the input stream, or -1 if there has been
+  an error }
+function ReadNext() : Longint;
+var
+  bytesread : SizeInt;
+  b : Byte;
+begin
+  ReadNext := -1;
+  if (index < limit) then begin
+    blockread(e.f, b, 1, bytesread);
+    ReadNext := b;
+    inc(index);
+  end;
+  if (bytesread <> 1) then
+    ReadNext := -1;
+end;
+
+{ Reads the next size bytes into dest. Returns true if successful,
+  false otherwise. Note that dest may be partially overwritten after
+  returning false. }
+function ReadNext(var dest; size : SizeInt) : Boolean;
+var
+  bytesread : SizeInt;
+begin
+  bytesread := 0;
+  if ((index + size) < limit) then begin
+    blockread(e.f, dest, size, bytesread);
+    inc(index, size);
   end;
+  ReadNext := (bytesread = size);
 end;
 
+
 { Reads an unsigned LEB encoded number from the input stream }
 function ReadULEB128() : QWord;
 var
   shift : Byte;
-  data : Int;
+  data : PtrInt;
   val : QWord;
-  result : QWord;
 begin
   shift := 0;
-  result := 0;
+  ReadULEB128 := 0;
   data := ReadNext();
   while (data <> -1) do begin
     val := data and $7f;
-    result := result or (val shl shift);
+    ReadULEB128 := ReadULEB128 or (val shl shift);
     inc(shift, 7);
     if ((data and $80) = 0) then
       break;
     data := ReadNext();
   end;
-  ReadULEB128 := result;
 end;
 
 { Reads a signed LEB encoded number from the input stream }
 function ReadLEB128() : Int64;
 var
   shift : Byte;
-  data : Int;
+  data : PtrInt;
   val : Int64;
-  result : Int64;
 begin
   shift := 0;
-  result := 0;
+  ReadLEB128 := 0;
   data := ReadNext();
   while (data <> -1) do begin
     val := data and $7f;
-    result := result or (val shl shift);
+    ReadLEB128 := ReadLEB128 or (val shl shift);
     inc(shift, 7);
     if ((data and $80) = 0) then
       break;
@@ -536,32 +262,29 @@ begin
   end;
   { extend sign. Note that we can not use shl/shr since the latter does not
     translate to arithmetic shifting for signed types }
-  result := (not ((result and (1 shl (shift-1)))-1)) or result;
-  ReadLEB128 := result;
+  ReadLEB128 := (not ((ReadLEB128 and (1 shl (shift-1)))-1)) or ReadLEB128;
 end;
 
+
 { Reads an address from the current input stream }
 function ReadAddress() : PtrUInt;
-var
-  result : PtrUInt;
 begin
-  ReadNext(result, sizeof(result));
-  ReadAddress := result;
+  ReadNext(ReadAddress, sizeof(ReadAddress));
 end;
 
+
 { Reads a zero-terminated string from the current input stream. If the
   string is larger than 255 chars (maximum allowed number of elements in
   a ShortString, excess characters will be chopped off. }
 function ReadString() : ShortString;
 var
-  temp : Int;
-  i : UInt;
-  result : ShortString;
+  temp : PtrInt;
+  i : PtrUInt;
 begin
   i := 1;
   temp := ReadNext();
   while (temp > 0) do begin
-    result[i] := char(temp);
+    ReadString[i] := char(temp);
     if (i = 255) then begin
       { skip remaining characters }
       repeat
@@ -574,21 +297,57 @@ begin
   end;
   { unexpected end of file occurred? }
   if (temp = -1) then
-    result := ''
+    ReadString := ''
   else
-    Byte(result[0]) := i-1;
-  ReadString := result;
+    Byte(ReadString[0]) := i-1;
 end;
 
+
 { Reads an unsigned Half from the current input stream }
 function ReadUHalf() : Word;
-var
-  result : Word;
 begin
-  ReadNext(result, sizeof(result));
-  ReadUHalf := result;
+  ReadNext(ReadUHalf, sizeof(ReadUHalf));
+end;
+
+
+{---------------------------------------------------------------------------
+
+ Generic Dwarf lineinfo reader
+
+ The line info reader is based on the information contained in
+
+   DWARF Debugging Information Format Version 3
+   Chapter 6.2 "Line Number Information"
+
+ from the
+
+   DWARF Debugging Information Format Workgroup.
+
+ For more information on this document see also
+
+   http://dwarf.freestandards.org/
+
+---------------------------------------------------------------------------}
+
+{ initializes the line info state to the default values }
+procedure InitStateRegisters(var state : TMachineState; const aIs_Stmt : Bool8);
+begin
+  with state do begin
+    address := 0;
+    file_id := 1;
+    line := 1;
+    column := 0;
+    is_stmt := aIs_Stmt;
+    basic_block := false;
+    end_sequence := false;
+    prolouge_end := false;
+    epilouge_begin := false;
+    isa := 0;
+    append_row := false;
+  end;
 end;
 
+
 { Skips all line info directory entries }
 procedure SkipDirectories();
 var s : ShortString;
@@ -625,11 +384,8 @@ begin
 end;
 
 function CalculateAddressIncrement(opcode : Byte; const header : TLineNumberProgramHeader64) : Int64;
-var
-  result : Int64;
 begin
-  result := (Int64(opcode) - header.opcode_base) div header.line_range * header.minimum_instruction_length;
-  CalculateAddressIncrement := result;
+  CalculateAddressIncrement := (Int64(opcode) - header.opcode_base) div header.line_range * header.minimum_instruction_length;
 end;
 
 function GetFullFilename(const filenameStart, directoryStart : Int64; const file_id : DWord) : ShortString;
@@ -669,6 +425,7 @@ begin
   GetFullFilename := directory + filename;
 end;
 
+
 function ParseCompilationUnit(const addr : PtrUInt; const file_offset : QWord;
   var source : String; var line : longint; var found : Boolean) : QWord;
 var
@@ -679,10 +436,10 @@ var
 
   adjusted_opcode : Int64;
 
-  opcode : Int;
+  opcode : PtrInt;
   extended_opcode : Byte;
-  extended_opcode_length : Int;
-  i, addrIncrement, lineIncrement : Int;
+  extended_opcode_length : PtrInt;
+  i, addrIncrement, lineIncrement : PtrInt;
 
   {$ifdef DEBUG_DWARF_PARSER}
   s : ShortString;
@@ -921,8 +678,13 @@ begin
   source := '';
   found := false;
 
-  if (not DwarfOpened) and (not OpenDwarf()) then
+  if DwarfErr then
     exit;
+  if not e.isopen then
+   begin
+     if not OpenDwarf then
+      exit;
+   end;
 
   current_offset := DwarfOffset;
   end_offset := DwarfOffset + DwarfSize;
@@ -961,15 +723,15 @@ begin
     end;
     DwarfBackTraceStr := DwarfBackTraceStr + ' of ' + source;
   end;
-  if (DwarfOpened) then
+  if e.IsOpen then
     BackTraceStrFunc := Store;
 end;
 
 
 initialization
-  DwarfOpened := false;
   BackTraceStrFunc := @DwarfBacktraceStr;
 
 finalization
-  CloseDwarf();
+  if e.isopen then
+    CloseDwarf();
 end.

Some files were not shown because too many files changed in this diff