Browse Source

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 years ago
parent
commit
4ec5b45a3f
4 changed files with 1311 additions and 1480 deletions
  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/dynlibs.pas svneol=native#text/plain
 rtl/inc/elfres32.inc svneol=native#text/plain
 rtl/inc/elfres32.inc svneol=native#text/plain
 rtl/inc/except.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/fexpand.inc svneol=native#text/plain
 rtl/inc/file.inc svneol=native#text/plain
 rtl/inc/file.inc svneol=native#text/plain
 rtl/inc/filerec.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
     Copyright (c) 2006 by Thomas Schatzl, member of the FreePascal
     Development team
     Development team
-    Parts (c) 2000 Peter Vreman (adapted from original stabs line
+    Parts (c) 2000 Peter Vreman (adapted from original dwarfs line
     reader)
     reader)
 
 
     Dwarf LineInfo Retriever
     Dwarf LineInfo Retriever
@@ -16,38 +16,21 @@
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
     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;
 unit lnfodwrf;
 interface
 interface
 
 
-{ disable stack checking }
 {$S-}
 {$S-}
 
 
 procedure GetLineInfo(addr:ptruint;var func,source:string;var line:longint);
 procedure GetLineInfo(addr:ptruint;var func,source:string;var line:longint);
 
 
 implementation
 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:
 { Current issues:
 
 
@@ -55,365 +38,29 @@ implementation
   - slow
   - 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}
 {$MACRO ON}
 
 
 //{$DEFINE DEBUG_DWARF_PARSER}
 //{$DEFINE DEBUG_DWARF_PARSER}
 {$ifdef DEBUG_DWARF_PARSER}
 {$ifdef DEBUG_DWARF_PARSER}
-{$define DEBUG_WRITELN := WriteLn}
-{$define DEBUG_COMMENT :=  }
+  {$define DEBUG_WRITELN := WriteLn}
+  {$define DEBUG_COMMENT :=  }
 {$else}
 {$else}
-{$define DEBUG_WRITELN := //}
-{$define DEBUG_COMMENT := //}
+  {$define DEBUG_WRITELN := //}
+  {$define DEBUG_COMMENT := //}
 {$endif}
 {$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
 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
 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}
 { DWARF 2 default opcodes}
 const
 const
   { Extended opcodes }
   { Extended opcodes }
@@ -475,60 +122,139 @@ type
     opcode_base : Byte;
     opcode_base : Byte;
   end;
   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
 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;
   end;
+  ReadNext := (bytesread = size);
 end;
 end;
 
 
+
 { Reads an unsigned LEB encoded number from the input stream }
 { Reads an unsigned LEB encoded number from the input stream }
 function ReadULEB128() : QWord;
 function ReadULEB128() : QWord;
 var
 var
   shift : Byte;
   shift : Byte;
-  data : Int;
+  data : PtrInt;
   val : QWord;
   val : QWord;
-  result : QWord;
 begin
 begin
   shift := 0;
   shift := 0;
-  result := 0;
+  ReadULEB128 := 0;
   data := ReadNext();
   data := ReadNext();
   while (data <> -1) do begin
   while (data <> -1) do begin
     val := data and $7f;
     val := data and $7f;
-    result := result or (val shl shift);
+    ReadULEB128 := ReadULEB128 or (val shl shift);
     inc(shift, 7);
     inc(shift, 7);
     if ((data and $80) = 0) then
     if ((data and $80) = 0) then
       break;
       break;
     data := ReadNext();
     data := ReadNext();
   end;
   end;
-  ReadULEB128 := result;
 end;
 end;
 
 
 { Reads a signed LEB encoded number from the input stream }
 { Reads a signed LEB encoded number from the input stream }
 function ReadLEB128() : Int64;
 function ReadLEB128() : Int64;
 var
 var
   shift : Byte;
   shift : Byte;
-  data : Int;
+  data : PtrInt;
   val : Int64;
   val : Int64;
-  result : Int64;
 begin
 begin
   shift := 0;
   shift := 0;
-  result := 0;
+  ReadLEB128 := 0;
   data := ReadNext();
   data := ReadNext();
   while (data <> -1) do begin
   while (data <> -1) do begin
     val := data and $7f;
     val := data and $7f;
-    result := result or (val shl shift);
+    ReadLEB128 := ReadLEB128 or (val shl shift);
     inc(shift, 7);
     inc(shift, 7);
     if ((data and $80) = 0) then
     if ((data and $80) = 0) then
       break;
       break;
@@ -536,32 +262,29 @@ begin
   end;
   end;
   { extend sign. Note that we can not use shl/shr since the latter does not
   { extend sign. Note that we can not use shl/shr since the latter does not
     translate to arithmetic shifting for signed types }
     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;
 end;
 
 
+
 { Reads an address from the current input stream }
 { Reads an address from the current input stream }
 function ReadAddress() : PtrUInt;
 function ReadAddress() : PtrUInt;
-var
-  result : PtrUInt;
 begin
 begin
-  ReadNext(result, sizeof(result));
-  ReadAddress := result;
+  ReadNext(ReadAddress, sizeof(ReadAddress));
 end;
 end;
 
 
+
 { Reads a zero-terminated string from the current input stream. If the
 { Reads a zero-terminated string from the current input stream. If the
   string is larger than 255 chars (maximum allowed number of elements in
   string is larger than 255 chars (maximum allowed number of elements in
   a ShortString, excess characters will be chopped off. }
   a ShortString, excess characters will be chopped off. }
 function ReadString() : ShortString;
 function ReadString() : ShortString;
 var
 var
-  temp : Int;
-  i : UInt;
-  result : ShortString;
+  temp : PtrInt;
+  i : PtrUInt;
 begin
 begin
   i := 1;
   i := 1;
   temp := ReadNext();
   temp := ReadNext();
   while (temp > 0) do begin
   while (temp > 0) do begin
-    result[i] := char(temp);
+    ReadString[i] := char(temp);
     if (i = 255) then begin
     if (i = 255) then begin
       { skip remaining characters }
       { skip remaining characters }
       repeat
       repeat
@@ -574,21 +297,57 @@ begin
   end;
   end;
   { unexpected end of file occurred? }
   { unexpected end of file occurred? }
   if (temp = -1) then
   if (temp = -1) then
-    result := ''
+    ReadString := ''
   else
   else
-    Byte(result[0]) := i-1;
-  ReadString := result;
+    Byte(ReadString[0]) := i-1;
 end;
 end;
 
 
+
 { Reads an unsigned Half from the current input stream }
 { Reads an unsigned Half from the current input stream }
 function ReadUHalf() : Word;
 function ReadUHalf() : Word;
-var
-  result : Word;
 begin
 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;
 end;
 
 
+
 { Skips all line info directory entries }
 { Skips all line info directory entries }
 procedure SkipDirectories();
 procedure SkipDirectories();
 var s : ShortString;
 var s : ShortString;
@@ -625,11 +384,8 @@ begin
 end;
 end;
 
 
 function CalculateAddressIncrement(opcode : Byte; const header : TLineNumberProgramHeader64) : Int64;
 function CalculateAddressIncrement(opcode : Byte; const header : TLineNumberProgramHeader64) : Int64;
-var
-  result : Int64;
 begin
 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;
 end;
 
 
 function GetFullFilename(const filenameStart, directoryStart : Int64; const file_id : DWord) : ShortString;
 function GetFullFilename(const filenameStart, directoryStart : Int64; const file_id : DWord) : ShortString;
@@ -669,6 +425,7 @@ begin
   GetFullFilename := directory + filename;
   GetFullFilename := directory + filename;
 end;
 end;
 
 
+
 function ParseCompilationUnit(const addr : PtrUInt; const file_offset : QWord;
 function ParseCompilationUnit(const addr : PtrUInt; const file_offset : QWord;
   var source : String; var line : longint; var found : Boolean) : QWord;
   var source : String; var line : longint; var found : Boolean) : QWord;
 var
 var
@@ -679,10 +436,10 @@ var
 
 
   adjusted_opcode : Int64;
   adjusted_opcode : Int64;
 
 
-  opcode : Int;
+  opcode : PtrInt;
   extended_opcode : Byte;
   extended_opcode : Byte;
-  extended_opcode_length : Int;
-  i, addrIncrement, lineIncrement : Int;
+  extended_opcode_length : PtrInt;
+  i, addrIncrement, lineIncrement : PtrInt;
 
 
   {$ifdef DEBUG_DWARF_PARSER}
   {$ifdef DEBUG_DWARF_PARSER}
   s : ShortString;
   s : ShortString;
@@ -921,8 +678,13 @@ begin
   source := '';
   source := '';
   found := false;
   found := false;
 
 
-  if (not DwarfOpened) and (not OpenDwarf()) then
+  if DwarfErr then
     exit;
     exit;
+  if not e.isopen then
+   begin
+     if not OpenDwarf then
+      exit;
+   end;
 
 
   current_offset := DwarfOffset;
   current_offset := DwarfOffset;
   end_offset := DwarfOffset + DwarfSize;
   end_offset := DwarfOffset + DwarfSize;
@@ -961,15 +723,15 @@ begin
     end;
     end;
     DwarfBackTraceStr := DwarfBackTraceStr + ' of ' + source;
     DwarfBackTraceStr := DwarfBackTraceStr + ' of ' + source;
   end;
   end;
-  if (DwarfOpened) then
+  if e.IsOpen then
     BackTraceStrFunc := Store;
     BackTraceStrFunc := Store;
 end;
 end;
 
 
 
 
 initialization
 initialization
-  DwarfOpened := false;
   BackTraceStrFunc := @DwarfBacktraceStr;
   BackTraceStrFunc := @DwarfBacktraceStr;
 
 
 finalization
 finalization
-  CloseDwarf();
+  if e.isopen then
+    CloseDwarf();
 end.
 end.

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