]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Add support for ldsoexec on Solaris.
authorIvo Raisr <ivosh@ivosh.net>
Mon, 31 Aug 2015 21:31:09 +0000 (21:31 +0000)
committerIvo Raisr <ivosh@ivosh.net>
Mon, 31 Aug 2015 21:31:09 +0000 (21:31 +0000)
Solaris runtime linker allows to run dynamically linked programs indirectly, as:
    ld.so.1 <dynamic_executable>
This is now possible under Valgrind as well.

Fixes BZ#351858.

git-svn-id: svn://svn.valgrind.org/valgrind/trunk@15607

13 files changed:
NEWS
coregrind/m_aspacemgr/aspacemgr-linux.c
coregrind/m_syswrap/syswrap-solaris.c
coregrind/pub_core_aspacemgr.h
include/vki/vki-solaris.h
memcheck/tests/amd64-solaris/Makefile.am
memcheck/tests/amd64-solaris/ldsoexec.c [new file with mode: 0644]
memcheck/tests/amd64-solaris/ldsoexec.stderr.exp [new file with mode: 0644]
memcheck/tests/amd64-solaris/ldsoexec.vgtest [new file with mode: 0644]
memcheck/tests/x86-solaris/Makefile.am
memcheck/tests/x86-solaris/ldsoexec.c [new file with mode: 0644]
memcheck/tests/x86-solaris/ldsoexec.stderr.exp [new file with mode: 0644]
memcheck/tests/x86-solaris/ldsoexec.vgtest [new file with mode: 0644]

diff --git a/NEWS b/NEWS
index 3aada0d600c5f2692eeaa13aeed0f7d2ebb37d4f..49bcb1bd088721ddd5beefa457e7e9cdc9ef04bc 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -363,6 +363,7 @@ where XXXXXX is the bug number as listed below.
 351474  Fix VG_(iseqsigset) as obvious
 351534  Fix incorrect header guard
 351756  Intercept platform_memchr$VARIANT$Haswell on OS X
+351858  ldsoexec support on Solaris
 n-i-bz  Provide implementations of certain compiler builtins to support
         compilers that may not provide those
 n-i-bz  Old STABS code is still being compiled, but never used. Remove it.
index 51c9bc5bbe4869239384d94c9b72cd4423817af4..2cc8f8eb0fa2f031d4088e59d306eaa4b503b5f2 100644 (file)
@@ -1265,6 +1265,15 @@ Bool VG_(am_is_valid_for_client_or_free_or_resvn)
    return is_valid_for(kinds, start, len, prot);
 }
 
+/* Checks if a piece of memory consists of either free or reservation
+   segments. */
+Bool VG_(am_is_free_or_resvn)( Addr start, SizeT len )
+{
+   const UInt kinds = SkFree | SkResvn;
+
+   return is_valid_for(kinds, start, len, 0);
+}
+
 
 Bool VG_(am_is_valid_for_valgrind) ( Addr start, SizeT len, UInt prot )
 {
index 54ad280f87b78e0d02eabaa738b5586d56ccf316..25029d4d1d205ee581cf6f04040eda878ef6b59f 100644 (file)
@@ -5416,6 +5416,7 @@ static SysRes mmapobj_process_phdrs(ThreadId tid, Int fd,
    UInt segments = 0; /* loadable segments */
    Addr start_addr = 0;
    Addr end_addr = 0;
+   Addr elfbrk = 0;
    SizeT max_align = VKI_PAGE_SIZE;
 
    /* 1. First pass over phdrs - determine number, span and max alignment. */
@@ -5489,7 +5490,7 @@ static SysRes mmapobj_process_phdrs(ThreadId tid, Int fd,
             return VG_(mk_SysRes_Error)(VKI_ENOTSUP);
          }
 
-         end_addr = phdr->p_vaddr + phdr->p_memsz + offset;
+         end_addr = elfbrk = phdr->p_vaddr + phdr->p_memsz + offset;
          end_addr = VG_PGROUNDUP(end_addr);
          if (phdr->p_align > max_align) {
             max_align = phdr->p_align;
@@ -5550,21 +5551,27 @@ static SysRes mmapobj_process_phdrs(ThreadId tid, Int fd,
    /* Now get the aspacemgr oraculum advisory.
       Later on we mmap file-based and BSS mappings into this address space area
       as required and leave the holes unmapped. */
-   MapRequest mreq = {MAlign, max_align, span};
-   Bool ok;
-   start_addr = VG_(am_get_advisory)(&mreq, True /* forClient */, &ok);
-   if (!ok) {
+   if (ehdr->e_type == VKI_ET_DYN) {
+      MapRequest mreq = {MAlign, max_align, span};
+      Bool ok;
+      start_addr = VG_(am_get_advisory)(&mreq, True /* forClient */, &ok);
+      if (!ok) {
+         if (VG_(clo_trace_syscalls))
+            VG_(debugLog)(3, "syswrap-solaris", "mmapobj_process_phdrs: "
+                             "failed to reserve address space of %#lx bytes "
+                             "with alignment %#lx\n", span, max_align);
+         return VG_(mk_SysRes_Error)(VKI_ENOMEM);
+      }
+      vg_assert(VG_ROUNDUP(start_addr, max_align) == start_addr);
+
       if (VG_(clo_trace_syscalls))
-         VG_(debugLog)(3, "syswrap-solaris", "mmapobj_process_phdrs: "
-                          "failed to reserve address space of %#lx bytes "
-                          "with alignment %#lx\n", span, max_align);
-      return VG_(mk_SysRes_Error)(VKI_ENOMEM);
+         VG_(debugLog)(2, "syswrap-solaris", "PRE(sys_mmapobj): address space "
+                          "reserved at: vaddr=%#lx size=%#lx\n",
+                          start_addr, span);
+   } else {
+      vg_assert(ehdr->e_type == VKI_ET_EXEC);
+      /* ET_EXEC uses fixed mappings. Will be checked when processing phdrs. */
    }
-   vg_assert(VG_ROUNDUP(start_addr, max_align) == start_addr);
-
-   if (VG_(clo_trace_syscalls))
-      VG_(debugLog)(2, "syswrap-solaris", "PRE(sys_mmapobj): address space "
-                       "reserved at: vaddr=%#lx size=%#lx\n", start_addr, span);
 
    /* This is an utterly ugly hack, the aspacemgr assumes that only one
       segment is added at the time. However we add here multiple segments so
@@ -5593,7 +5600,6 @@ static SysRes mmapobj_process_phdrs(ThreadId tid, Int fd,
             prot |= VKI_PROT_EXEC;
 
          vki_mmapobj_result_t *mrp = &storage[*elements];
-         mrp->mr_addr = (vki_caddr_t) (start_addr + phdr->p_vaddr);
          mrp->mr_msize = phdr->p_memsz;
          mrp->mr_fsize = phdr->p_filesz;
          mrp->mr_offset = 0;
@@ -5602,16 +5608,27 @@ static SysRes mmapobj_process_phdrs(ThreadId tid, Int fd,
          Off64T file_offset = phdr->p_offset;
          if (idx == first_segment_idx) {
             mrp->mr_flags = VKI_MR_HDR_ELF;
-            if (phdr->p_offset > 0) {
-               /* Include the ELF header into the first segment.
-                  This means we ignore p_offset from the program header
-                  and map from file offset 0. */
-               mrp->mr_msize += phdr->p_offset;
-               mrp->mr_fsize += phdr->p_offset;
-               file_offset = 0;
+            if (ehdr->e_type == VKI_ET_DYN) {
+               if (phdr->p_offset > 0) {
+                  /* Include the ELF header into the first segment.
+                     This means we ignore p_offset from the program header
+                     and map from file offset 0. */
+                  mrp->mr_msize += phdr->p_offset;
+                  mrp->mr_fsize += phdr->p_offset;
+                  file_offset = 0;
+               }
+            } else {
+               vg_assert(ehdr->e_type == VKI_ET_EXEC);
+               start_addr = phdr->p_vaddr;
             }
          }
 
+         /* p_vaddr is absolute for ET_EXEC, and relative for ET_DYN. */
+         mrp->mr_addr = (vki_caddr_t) phdr->p_vaddr;
+         if (ehdr->e_type == VKI_ET_DYN) {
+            mrp->mr_addr += start_addr;
+         }
+
          SizeT page_offset = (Addr) mrp->mr_addr & VKI_PAGEOFFSET;
          if (page_offset > 0) {
             vg_assert(file_offset >= page_offset);
@@ -5650,6 +5667,19 @@ static SysRes mmapobj_process_phdrs(ThreadId tid, Int fd,
             mprotect_needed = True;
          }
 
+         if (ehdr->e_type == VKI_ET_EXEC) {
+            /* Now check if the requested address space is available. */
+            if (!VG_(am_is_free_or_resvn)((Addr) mrp->mr_addr, mrp->mr_msize)) {
+               if (VG_(clo_trace_syscalls))
+                  VG_(debugLog)(3, "syswrap-solaris", "mmapobj_process_phdrs: "
+                                   "requested segment at %#lx with size of "
+                                   "%#lx bytes is not available\n",
+                                   (Addr) mrp->mr_addr, (UWord) mrp->mr_msize);
+               res = VG_(mk_SysRes_Error)(VKI_EADDRINUSE);
+               goto mmap_error;
+            }
+         }
+
          if (file_size > 0) {
             res = VG_(am_mmap_file_fixed_client_flags)((Addr) mrp->mr_addr,
                                        file_size, prot, flags, fd, file_offset);
@@ -5728,6 +5758,21 @@ static SysRes mmapobj_process_phdrs(ThreadId tid, Int fd,
       }
    }
 
+   if ((ehdr->e_type == VKI_ET_EXEC) && (!brk_segment_established)) {
+      vg_assert(VG_(brk_base) == VG_(brk_limit));
+      vg_assert(VG_(brk_base) == -1);
+      VG_(brk_base) = VG_(brk_limit) = elfbrk;
+
+      if (!VG_(setup_client_dataseg)()) {
+         VG_(umsg)("Cannot map memory to initialize brk segment in thread #%d "
+                   "at %#lx\n", tid, VG_(brk_base));
+         res = VG_(mk_SysRes_Error)(VKI_ENOMEM);
+         goto mmap_error;
+      }
+
+      VG_(track_client_dataseg)(tid);
+   }
+
    /* Restore VG_(clo_sanity_level). The scheduler will perform the aspacemgr
       sanity check after the syscall. */
    VG_(clo_sanity_level) = sanity_level;
@@ -5804,7 +5849,7 @@ static SysRes mmapobj_interpret(ThreadId tid, Int fd,
    }
 
    VKI_ESZ(Ehdr) *ehdr = (VKI_ESZ(Ehdr) *) header;
-   if (ehdr->e_type != VKI_ET_DYN) {
+   if ((ehdr->e_type != VKI_ET_EXEC) && (ehdr->e_type != VKI_ET_DYN)) {
       VG_(unimplemented)("Syswrap of the mmapobj call with ELF type %u.",
                          ehdr->e_type);
       /*NOTREACHED*/
index 5aeb8cc0d006687f4bbe701bb54f2ce60da14042..003d94e44b14a0bb84543f59b19f4955be7b42d7 100644 (file)
@@ -94,6 +94,10 @@ extern Bool VG_(am_is_valid_for_valgrind)
 extern Bool VG_(am_is_valid_for_client_or_free_or_resvn)
    ( Addr start, SizeT len, UInt prot );
 
+/* Checks if a piece of memory consists of either free or reservation
+   segments. */
+extern Bool VG_(am_is_free_or_resvn)( Addr start, SizeT len );
+
 /* Check whether ADDR looks like an address or address-to-be located in an
    extensible client stack segment. */
 extern Bool VG_(am_addr_is_in_extensible_client_stack)( Addr addr );
index e17e33f322f984870708dbc0535e5f03a913d64c..a5f7ece5b8300df4112a748d00c08dd907b90a21 100644 (file)
@@ -452,6 +452,7 @@ typedef struct vki_kcf_door_arg_s {
 #define VKI_EOVERFLOW EOVERFLOW
 #define VKI_ENOSYS ENOSYS
 #define VKI_ERESTART ERESTART
+#define VKI_EADDRINUSE EADDRINUSE
 
 
 #if defined(SOLARIS_EXECVE_SYSCALL_TAKES_FLAGS)
index c44ec2137463e46701c75ce280217c5ae4990277..4d0ea14e4731ac5266f3045688fa2764184034b8 100644 (file)
@@ -8,14 +8,16 @@ EXTRA_DIST = \
        context_gpr.stderr.exp context_gpr.stdout.exp context_gpr.vgtest \
        context_rflags.stderr.exp context_rflags.stdout.exp context_rflags.vgtest \
        context_rflags2.stderr.exp context_rflags2.stdout.exp context_rflags2.vgtest \
-       context_sse.stderr.exp context_sse.stdout.exp context_sse.vgtest
+       context_sse.stderr.exp context_sse.stdout.exp context_sse.vgtest \
+       ldsoexec.stderr.exp ldsoexec.vgtest
 
 check_PROGRAMS = \
        context_fpu \
        context_gpr \
        context_rflags \
        context_rflags2 \
-       context_sse
+       context_sse \
+       ldsoexec
 
 AM_CFLAGS    += @FLAG_M64@
 AM_CXXFLAGS  += @FLAG_M64@
diff --git a/memcheck/tests/amd64-solaris/ldsoexec.c b/memcheck/tests/amd64-solaris/ldsoexec.c
new file mode 100644 (file)
index 0000000..9b6bdc2
--- /dev/null
@@ -0,0 +1,3 @@
+int main(void) {
+    return 0;
+}
diff --git a/memcheck/tests/amd64-solaris/ldsoexec.stderr.exp b/memcheck/tests/amd64-solaris/ldsoexec.stderr.exp
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/memcheck/tests/amd64-solaris/ldsoexec.vgtest b/memcheck/tests/amd64-solaris/ldsoexec.vgtest
new file mode 100644 (file)
index 0000000..7f6160c
--- /dev/null
@@ -0,0 +1,2 @@
+prog: /lib/64/ld.so.1 ./ldsoexec
+vgopts: -q
index 78ae0a70aa43fdd030e002691d6de6e6ddafa6ab..3759fe667d36059f32b598870ee85e1443b61f46 100644 (file)
@@ -10,7 +10,8 @@ EXTRA_DIST = \
        context_eflags2.stderr.exp context_eflags2.stdout.exp context_eflags2.vgtest \
        context_fpu.stderr.exp context_fpu.stdout.exp context_fpu.vgtest \
        context_gpr.stderr.exp context_gpr.stdout.exp context_gpr.vgtest \
-       context_sse.stderr.exp context_sse.stdout.exp context_sse.vgtest
+       context_sse.stderr.exp context_sse.stdout.exp context_sse.vgtest \
+       ldsoexec.stderr.exp ldsoexec.vgtest
 
 check_PROGRAMS = \
        scalar \
@@ -18,7 +19,8 @@ check_PROGRAMS = \
        context_eflags2 \
        context_fpu \
        context_gpr \
-       context_sse
+       context_sse \
+       ldsoexec
 
 if SOLARIS_OLD_SYSCALLS
 check_PROGRAMS += scalar_obsolete
diff --git a/memcheck/tests/x86-solaris/ldsoexec.c b/memcheck/tests/x86-solaris/ldsoexec.c
new file mode 100644 (file)
index 0000000..9b6bdc2
--- /dev/null
@@ -0,0 +1,3 @@
+int main(void) {
+    return 0;
+}
diff --git a/memcheck/tests/x86-solaris/ldsoexec.stderr.exp b/memcheck/tests/x86-solaris/ldsoexec.stderr.exp
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/memcheck/tests/x86-solaris/ldsoexec.vgtest b/memcheck/tests/x86-solaris/ldsoexec.vgtest
new file mode 100644 (file)
index 0000000..5fa0460
--- /dev/null
@@ -0,0 +1,2 @@
+prog: /lib/ld.so.1 ./ldsoexec
+vgopts: -q