Browse Source

Add code to find base address in unix ELF aux vector above enviroment in startup stack

git-svn-id: trunk@33007 -
pierre 9 years ago
parent
commit
90359bcb3c
1 changed files with 106 additions and 1 deletions
  1. 106 1
      rtl/inc/exeinfo.pp

+ 106 - 1
rtl/inc/exeinfo.pp

@@ -16,6 +16,9 @@
   This unit should not be compiled in objfpc mode, since this would make it
   This unit should not be compiled in objfpc mode, since this would make it
   dependent on objpas unit.
   dependent on objpas unit.
 }
 }
+
+{$mode objfpc}
+
 unit exeinfo;
 unit exeinfo;
 interface
 interface
 
 
@@ -51,7 +54,7 @@ procedure GetModuleByAddr(addr: pointer; var baseaddr: pointer; var filename: st
 implementation
 implementation
 
 
 uses
 uses
-  strings{$ifdef windows},windows{$endif windows};
+  sysutils,strings{$ifdef windows},windows{$endif windows};
 
 
 {$ifdef unix}
 {$ifdef unix}
 
 
@@ -116,8 +119,10 @@ uses
 {$if defined(freebsd) or defined(netbsd) or defined (openbsd) or defined(linux) or defined(sunos) or defined(android) or defined(dragonfly)}
 {$if defined(freebsd) or defined(netbsd) or defined (openbsd) or defined(linux) or defined(sunos) or defined(android) or defined(dragonfly)}
   {$ifdef cpu64}
   {$ifdef cpu64}
     {$define ELF64}
     {$define ELF64}
+    {$define FIND_BASEADDR_ELF}
   {$else}
   {$else}
     {$define ELF32}
     {$define ELF32}
+    {$define FIND_BASEADDR_ELF}
   {$endif}
   {$endif}
 {$endif}
 {$endif}
 
 
@@ -793,6 +798,102 @@ type
 
 
 
 
 {$if defined(ELF32) or defined(ELF64) or defined(BEOS)}
 {$if defined(ELF32) or defined(ELF64) or defined(BEOS)}
+
+{$ifdef FIND_BASEADDR_ELF}
+var
+  envp : ppchar external name 'operatingsystem_parameter_envp';
+
+procedure GetExeInMemoryBaseAddr(addr : pointer; var BaseAddr : pointer;
+                                 var filename : openstring);
+type
+  AT_HDR = record
+    typ : ptruint;
+    value : ptruint;
+  end;
+  P_AT_HDR = ^AT_HDR;
+
+{ Values taken from /usr/include/linux/auxvec.h }
+const
+  AT_HDR_COUNT = 5;{ AT_PHNUM }
+  AT_HDR_SIZE = 4; { AT_PHENT }
+  AT_HDR_Addr = 3; { AT_PHDR }
+  AT_EXE_FN = 31;  {AT_EXECFN }
+
+var
+  pc : ppchar;
+  pat_hdr : P_AT_HDR;
+  i, phdr_count : ptrint;
+  phdr_size : ptruint;
+  phdr :  ^telfproghdr;
+  found_addr : ptruint;
+
+begin
+  filename:=ParamStr(0);
+  Try
+    pc:=envp;
+    phdr_count:=-1;
+    phdr_size:=0;
+    phdr:=nil;
+    found_addr:=ptruint(-1);
+    while (assigned(pc^)) do
+      inc (pointer(pc), sizeof(ptruint));
+    inc(pointer(pc), sizeof(ptruint));
+    pat_hdr:=P_AT_HDR(pc);
+    while assigned(pat_hdr) do
+      begin
+        if (pat_hdr^.typ=0) and (pat_hdr^.value=0) then
+          break;
+        if pat_hdr^.typ = AT_HDR_COUNT then
+          phdr_count:=pat_hdr^.value;
+        if pat_hdr^.typ = AT_HDR_SIZE then
+          phdr_size:=pat_hdr^.value;
+        if pat_hdr^.typ = AT_HDR_Addr then
+          phdr := pointer(pat_hdr^.value);
+        if pat_hdr^.typ = AT_EXE_FN then
+          filename:=strpas(pchar(pat_hdr^.value));
+        inc (pointer(pat_hdr),sizeof(AT_HDR));
+      end;
+    if (phdr_count>0) and (phdr_size = sizeof (telfproghdr))
+       and  assigned(phdr) then
+      begin
+        for i:=0 to phdr_count -1 do
+          begin
+            if (phdr^.p_type = 1 {PT_LOAD}) and (ptruint(phdr^.p_vaddr) < found_addr) then
+              found_addr:=phdr^.p_vaddr;
+            inc(phdr, phdr_size);
+          end;
+      {$ifdef DEBUG}
+      end
+    else
+      begin
+        if (phdr_count=-1) then
+           writeln(stderr,'AUX entry AT_PHNUM not found');
+        if (phdr_size=0) then
+           writeln(stderr,'AUX entry AT_PHENT not found');
+        if (phdr=nil) then
+           writeln(stderr,'AUX entry AT_PHDR not found');
+      {$endif DEBUG}
+      end;
+
+     if found_addr<>ptruint(-1) then
+       begin
+          {$ifdef DEBUG}
+          Writeln(stderr,'Found addr = $',hexstr(found_addr,2 * sizeof(ptruint)));
+          {$endif}
+          BaseAddr:=pointer(found_addr);
+       end
+  {$ifdef DEBUG}
+     else
+    writeln(stderr,'Error parsing stack');
+  {$endif DEBUG}
+  except
+  {$ifdef DEBUG}
+    writeln(stderr,'Exception parsing stack');
+  {$endif DEBUG}
+  end
+end;
+{$endif FIND_BASEADDR_ELF}
+
 function OpenElf(var e:TExeFile):boolean;
 function OpenElf(var e:TExeFile):boolean;
 var
 var
   elfheader : telfheader;
   elfheader : telfheader;
@@ -1240,4 +1341,8 @@ begin
 end;
 end;
 
 
 
 
+begin
+{$ifdef FIND_BASEADDR_ELF}
+  UnixGetModuleByAddrHook:=@GetExeInMemoryBaseAddr;
+{$endif FIND_BASEADDR_ELF}
 end.
 end.