From: Ivo Raisr Date: Mon, 31 Aug 2015 21:31:09 +0000 (+0000) Subject: Add support for ldsoexec on Solaris. X-Git-Tag: svn/VALGRIND_3_11_0~50 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7a4cc7d5fdd165e0882c5a02a52d54353804aae0;p=thirdparty%2Fvalgrind.git Add support for ldsoexec on Solaris. Solaris runtime linker allows to run dynamically linked programs indirectly, as: ld.so.1 This is now possible under Valgrind as well. Fixes BZ#351858. git-svn-id: svn://svn.valgrind.org/valgrind/trunk@15607 --- diff --git a/NEWS b/NEWS index 3aada0d600..49bcb1bd08 100644 --- 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. diff --git a/coregrind/m_aspacemgr/aspacemgr-linux.c b/coregrind/m_aspacemgr/aspacemgr-linux.c index 51c9bc5bbe..2cc8f8eb0f 100644 --- a/coregrind/m_aspacemgr/aspacemgr-linux.c +++ b/coregrind/m_aspacemgr/aspacemgr-linux.c @@ -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 ) { diff --git a/coregrind/m_syswrap/syswrap-solaris.c b/coregrind/m_syswrap/syswrap-solaris.c index 54ad280f87..25029d4d1d 100644 --- a/coregrind/m_syswrap/syswrap-solaris.c +++ b/coregrind/m_syswrap/syswrap-solaris.c @@ -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*/ diff --git a/coregrind/pub_core_aspacemgr.h b/coregrind/pub_core_aspacemgr.h index 5aeb8cc0d0..003d94e44b 100644 --- a/coregrind/pub_core_aspacemgr.h +++ b/coregrind/pub_core_aspacemgr.h @@ -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 ); diff --git a/include/vki/vki-solaris.h b/include/vki/vki-solaris.h index e17e33f322..a5f7ece5b8 100644 --- a/include/vki/vki-solaris.h +++ b/include/vki/vki-solaris.h @@ -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) diff --git a/memcheck/tests/amd64-solaris/Makefile.am b/memcheck/tests/amd64-solaris/Makefile.am index c44ec21374..4d0ea14e47 100644 --- a/memcheck/tests/amd64-solaris/Makefile.am +++ b/memcheck/tests/amd64-solaris/Makefile.am @@ -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 index 0000000000..9b6bdc2ec2 --- /dev/null +++ b/memcheck/tests/amd64-solaris/ldsoexec.c @@ -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 index 0000000000..e69de29bb2 diff --git a/memcheck/tests/amd64-solaris/ldsoexec.vgtest b/memcheck/tests/amd64-solaris/ldsoexec.vgtest new file mode 100644 index 0000000000..7f6160cb0e --- /dev/null +++ b/memcheck/tests/amd64-solaris/ldsoexec.vgtest @@ -0,0 +1,2 @@ +prog: /lib/64/ld.so.1 ./ldsoexec +vgopts: -q diff --git a/memcheck/tests/x86-solaris/Makefile.am b/memcheck/tests/x86-solaris/Makefile.am index 78ae0a70aa..3759fe667d 100644 --- a/memcheck/tests/x86-solaris/Makefile.am +++ b/memcheck/tests/x86-solaris/Makefile.am @@ -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 index 0000000000..9b6bdc2ec2 --- /dev/null +++ b/memcheck/tests/x86-solaris/ldsoexec.c @@ -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 index 0000000000..e69de29bb2 diff --git a/memcheck/tests/x86-solaris/ldsoexec.vgtest b/memcheck/tests/x86-solaris/ldsoexec.vgtest new file mode 100644 index 0000000000..5fa046097b --- /dev/null +++ b/memcheck/tests/x86-solaris/ldsoexec.vgtest @@ -0,0 +1,2 @@ +prog: /lib/ld.so.1 ./ldsoexec +vgopts: -q