From owner-p4-projects@FreeBSD.ORG Thu Sep 3 15:46:39 2009 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 3F3831065697; Thu, 3 Sep 2009 15:46:39 +0000 (UTC) Delivered-To: perforce@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 03249106568D for ; Thu, 3 Sep 2009 15:46:39 +0000 (UTC) (envelope-from stas@freebsd.org) Received: from repoman.freebsd.org (repoman.freebsd.org [IPv6:2001:4f8:fff6::29]) by mx1.freebsd.org (Postfix) with ESMTP id E55058FC22 for ; Thu, 3 Sep 2009 15:46:38 +0000 (UTC) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.14.3/8.14.3) with ESMTP id n83FkcPx086259 for ; Thu, 3 Sep 2009 15:46:38 GMT (envelope-from stas@freebsd.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.14.3/8.14.3/Submit) id n83FkcM2086257 for perforce@freebsd.org; Thu, 3 Sep 2009 15:46:38 GMT (envelope-from stas@freebsd.org) Date: Thu, 3 Sep 2009 15:46:38 GMT Message-Id: <200909031546.n83FkcM2086257@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to stas@freebsd.org using -f From: Stanislav Sedov To: Perforce Change Reviews Cc: Subject: PERFORCE change 168109 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 03 Sep 2009 15:46:39 -0000 http://perforce.freebsd.org/chv.cgi?CH=168109 Change 168109 by stas@stas_yandex on 2009/09/03 15:46:07 - Fix x86 support (I have not checked signals yet, though). - Rework the elf loader algotihm to match what rtld does: map a chunk of anonymous memory on top of entire object's address space and then map sections above it. Affected files ... .. //depot/projects/valgrind/coregrind/m_aspacemgr/aspacemgr-common.c#8 edit .. //depot/projects/valgrind/coregrind/m_syswrap/syscall-x86-freebsd.S#9 edit .. //depot/projects/valgrind/coregrind/m_ume/elf.c#3 edit .. //depot/projects/valgrind/coregrind/pub_core_aspacemgr.h#4 edit Differences ... ==== //depot/projects/valgrind/coregrind/m_aspacemgr/aspacemgr-common.c#8 (text+ko) ==== @@ -176,8 +176,8 @@ # elif defined(VGP_x86_freebsd) if (flags & VKI_MAP_ANONYMOUS && fd == 0) fd = -1; - res = VG_(do_syscall8)(__NR_mmap, (UWord)start, length, - prot, flags, fd, 0, offset, offset >> 32ul); + res = VG_(do_syscall7)(__NR_mmap, (UWord)start, length, + prot, flags, fd, offset, offset >> 32ul); # elif defined(VGP_amd64_freebsd) if (flags & VKI_MAP_ANONYMOUS && fd == 0) fd = -1; @@ -189,8 +189,7 @@ return res; } -static -SysRes local_do_mprotect_NO_NOTIFY(Addr start, SizeT length, UInt prot) +SysRes VG_(am_do_mprotect_NO_NOTIFY)(Addr start, SizeT length, UInt prot) { return VG_(do_syscall3)(__NR_mprotect, (UWord)start, length, prot ); } @@ -438,7 +437,7 @@ aspacem_assert(VG_IS_PAGE_ALIGNED(stack)); /* Protect the guard areas. */ - sres = local_do_mprotect_NO_NOTIFY( + sres = VG_(am_do_mprotect_NO_NOTIFY)( (Addr) &stack[0], VG_STACK_GUARD_SZB, VKI_PROT_NONE ); @@ -448,7 +447,7 @@ VG_STACK_GUARD_SZB, VKI_PROT_NONE ); - sres = local_do_mprotect_NO_NOTIFY( + sres = VG_(am_do_mprotect_NO_NOTIFY)( (Addr) &stack->bytes[VG_STACK_GUARD_SZB + VG_STACK_ACTIVE_SZB], VG_STACK_GUARD_SZB, VKI_PROT_NONE ); ==== //depot/projects/valgrind/coregrind/m_syswrap/syscall-x86-freebsd.S#9 (text+ko) ==== @@ -1,13 +1,13 @@ /*--------------------------------------------------------------------*/ -/*--- Support for doing system calls. syscall-x86-linux.S ---*/ +/*--- Support for doing system calls. syscall-x86-freebsd.S ---*/ /*--------------------------------------------------------------------*/ /* This file is part of Valgrind, a dynamic binary instrumentation framework. - Copyright (C) 2000-2008 Julian Seward + Copyright (C) 2000-2007 Julian Seward jseward@acm.org This program is free software; you can redistribute it and/or @@ -53,10 +53,9 @@ back to regs->m_eax on completion. Returns 0 if the syscall was successfully called (even if the - syscall itself failed), or a nonzero error code in the lowest - 8 bits if one of the sigprocmasks failed (there's no way to - determine which one failed). And there's no obvious way to - recover from that either, but nevertheless we want to know. + syscall itself failed), or a -ve error code if one of the + sigprocmasks failed (there's no way to determine which one + failed). VG_(fixup_guest_state_after_syscall_interrupted) does the thread state fixup in the case where we were interrupted by a @@ -64,153 +63,135 @@ Prototype: - UWord ML_(do_syscall_for_client_WRK)( - Int syscallno, // 0 - void* guest_state, // 4 - const vki_sigset_t *sysmask, // 8 - const vki_sigset_t *postmask, // 12 - Int nsigwords, // 16 - SyscallArgs *args) // 20 + Int ML_(do_syscall_for_client_WRK)( + Int syscallno, // ebp+8 + void* guest_state, // ebp+12 + const vki_sigset_t *sysmask, // ebp+16 + const vki_sigset_t *postmask, // ebp+20 + Int sigsetSzB) // ebp+24 -See priv_types_n_macros.h for SyscallArgs layout: - UWord sysno; // 0 - UWord arg1; // 4 - UWord arg2; // 8 - UWord arg3; // 12 - UWord arg4; // 16 - UWord arg5; // 20 - UWord arg6; // 24 - UWord arg7; // 28 - UWord arg8; // 32 - + Note that sigsetSzB is totally ignored (and irrelevant). */ -/* from vki_arch.h */ +/* from vki-darwin.h, checked at startup by m_vki.c */ #define VKI_SIG_SETMASK 3 - -/* QQQ translate syscall abi conventions */ + .globl ML_(do_syscall_for_client_WRK) ML_(do_syscall_for_client_WRK): - /* save callee-saved regs */ - push %esi - push %edi - push %ebx + /* establish stack frame */ push %ebp - subl $(9*4), %esp /* space for 8 args plus fake ret addr */ -#define FSZ ((9+4+1)*4) /* 4 args + ret addr */ - -1: /* Even though we can't take a signal until the sigprocmask completes, - start the range early. + mov %esp, %ebp + subl $8, %esp /* 16-byte align stack */ + +1: /* Even though we can't take a signal until the + sigprocmask completes, start the range early. If eip is in the range [1,2), the syscall hasn't been started yet */ /* Set the signal mask which should be current during the syscall. */ - movl $__NR_sigprocmask, %eax - movl $VKI_SIG_SETMASK, %ecx - movl %ecx, 4(%esp) - movl 8+FSZ(%esp), %ecx - movl %ecx, 8(%esp) - movl 12+FSZ(%esp), %ecx - movl %ecx, 12(%esp) - int $0x80 - jb 7f /* sigprocmask failed */ - - /* We have already collapsed the stupid FreeBSD/i386 indirect syscalls */ - movl 20+FSZ(%esp), %ebx - movl 0+FSZ(%esp), %eax /* use syscallno argument rather than thread EAX */ - /* copy 8 args */ - movl 4(%ebx), %ecx - movl 8(%ebx), %edx - movl 12(%ebx), %esi - movl 16(%ebx), %edi - movl %ecx, 4(%esp) - movl %edx, 8(%esp) - movl %esi, 12(%esp) - movl %edi, 16(%esp) - movl 20(%ebx), %ecx - movl 24(%ebx), %edx - movl 28(%ebx), %esi - movl 32(%ebx), %edi - movl %ecx, 20(%esp) - movl %edx, 24(%esp) - movl %esi, 28(%esp) - movl %edi, 32(%esp) + pushl 20(%ebp) + pushl 16(%ebp) + pushl $VKI_SIG_SETMASK + pushl $0xcafebabe /* totally fake return address */ + movl $__NR_sigprocmask, %eax + int $0x80 + jc 7f /* sigprocmask failed */ + addl $16,%esp + + /* Copy syscall parameters to the stack - assume no more than 8 + * plus the return address */ + /* do_syscall8 */ + /* stack is currently aligned assuming 8 parameters */ + movl 12(%ebp), %edx + movl OFFSET_x86_ESP(%edx), %edx /* edx = simulated ESP */ + movl 28+4(%edx), %eax + pushl %eax + movl 24+4(%edx), %eax + pushl %eax + movl 20+4(%edx), %eax + pushl %eax + movl 16+4(%edx), %eax + pushl %eax + movl 12+4(%edx), %eax + pushl %eax + movl 8+4(%edx), %eax + pushl %eax + movl 4+4(%edx), %eax + pushl %eax + movl 0+4(%edx), %eax + pushl %eax + /* return address */ + movl 0(%edx), %eax + pushl %eax + + /* Put syscall number in eax */ + movl 8(%ebp), %eax /* If eip==2, then the syscall was either just about to start, or was interrupted and the kernel was restarting it. */ -2: int $0x80 -3: /* In the range [3, 4), the syscall result is in %eax/%edx/eflags, - but hasn't been committed to EAX/EDX. */ - pushf - popl %edi /* copy flags to %edi */ - movl 4+FSZ(%esp), %ebx - movl %eax, OFFSET_x86_EAX(%ebx) /* save back to EAX */ - movl %edx, OFFSET_x86_EDX(%ebx) /* save back to EDX */ - /* QQQ Race here. We aren't really "committed" until we have called - LibVEX_GuestX86_put_eflag_c() to store the carry bit. Unfortunately - we cannot test for %eip in that range. It might be that the syscall - result extraction code needs to be widened from ending at - blksys_complete to blksys_finished instead. Note that on FreeBSD, - %edi is saved across a syscall so we don't have to worry about - it getting trashed by the sigprocmask below. */ +2: int $0x80 /* UNIX (GrP fixme should be sysenter?) */ -4: /* Re-block signals. If eip is in [4,5), then the syscall is complete and - we needn't worry about it. */ - /* QQQ: However, on FreeBSD, the trap handler has to export just carry */ - movl $__NR_sigprocmask, %eax - movl $VKI_SIG_SETMASK, %ecx +3: /* In the range [3, 4), the syscall result is in %eax and %edx and C, + but hasn't been committed to the thread state. */ + setc 0(%esp) /* stash returned carry flag */ + movl 12(%ebp), %ecx + movl %eax, OFFSET_x86_EAX(%ecx) /* save EAX to vex */ + movl %edx, OFFSET_x86_EDX(%ecx) /* save EDX to vex */ + /* save carry flag to vex */ + subl $12, %esp movl %ecx, 4(%esp) - movl 12+FSZ(%esp), %ecx - movl %ecx, 8(%esp) - xorl %ecx, %ecx - movl %ecx, 12(%esp) - int $0x80 - jb 7f /* sigprocmask failed */ + movl $0, 0(%esp) + movb 12(%esp), %al + movb %al, 0(%esp) + call LibVEX_GuestX86_put_eflag_c + addl $12, %esp + +4: /* Re-block signals. If eip is in [4,5), then the syscall is + complete and we needn't worry about it. */ + /* Set up for __pthread_sigmask(SIG_SETMASK, postmask, NULL) */ + pushl $0 + pushl 20(%ebp) + pushl $VKI_SIG_SETMASK + pushl $0xcafef00d /* totally fake return address */ + movl $__NR_sigprocmask, %eax + int $0x80 /* should be sysenter? */ + jc 7f /* sigprocmask failed */ + addl $16,%esp 5: /* now safe from signals */ - - /* Export carry state */ - movl %edi, %eax - andl $1, %eax /* SUCCESS */ - addl $(9*4), %esp /* args + fake return address */ + movl $0, %eax /* SUCCESS */ + movl %ebp, %esp popl %ebp - popl %ebx - popl %edi - popl %esi ret -7: /* failure: return 0x8000 | error code */ - orl $0x8000, %eax - addl $(9*4), %esp /* args + fake return address */ +7: /* failure: return 0x8000 | error code */ + /* Note that we enter here with %esp being 16 too low + (4 extra words on the stack). But because we're nuking + the stack frame now, that doesn't matter. */ + andl $0x7FFF, %eax + orl $0x8000, %eax + movl %ebp, %esp popl %ebp - popl %ebx - popl %edi - popl %esi ret -#undef FSZ - .section .rodata /* export the ranges so that VG_(fixup_guest_state_after_syscall_interrupted) can do the right thing */ - + .globl ML_(blksys_setup) .globl ML_(blksys_restart) .globl ML_(blksys_complete) .globl ML_(blksys_committed) .globl ML_(blksys_finished) -ML_(blksys_setup): .long 1b -ML_(blksys_restart): .long 2b -ML_(blksys_complete): .long 3b -ML_(blksys_committed): .long 4b -ML_(blksys_finished): .long 5b +ML_(blksys_setup): .long 1b +ML_(blksys_restart): .long 2b +ML_(blksys_complete): .long 3b +ML_(blksys_committed): .long 4b +ML_(blksys_finished): .long 5b .previous - -/* Let the linker know we don't need an executable stack */ -.section .note.GNU-stack,"",@progbits - -#endif /* defined(VGP_x86_freebsd) */ - + +#endif // defined(VGP_x86_freebsd) + /*--------------------------------------------------------------------*/ /*--- end ---*/ /*--------------------------------------------------------------------*/ ==== //depot/projects/valgrind/coregrind/m_ume/elf.c#3 (text+ko) ==== @@ -41,6 +41,7 @@ #include "pub_core_libcfile.h" // VG_(open) et al #include "pub_core_machine.h" // VG_ELF_CLASS (XXX: which should be moved) #include "pub_core_mallocfree.h" // VG_(malloc), VG_(free) +#include "pub_core_vkiscnums.h" #include "pub_core_syscall.h" // VG_(strerror) #include "pub_core_ume.h" // self @@ -160,22 +161,38 @@ Int i; SysRes res; ESZ(Addr) elfbrk = 0; + ESZ(Word) mapsize; + ESZ(Addr) base_offset, base_vaddr, base_vlimit, baseaddr; + ESZ(Phdr) *ph0, *phlast; + + if (e->e.e_phnum < 1) { + VG_(printf)("valgrind: m_ume.c: too few sections\n"); + return 1; + } - for (i = 0; i < e->e.e_phnum; i++) { + /* Map the entire address space of the object. */ + ph0 = NULL; + phlast = NULL; + for (i = 1; i < e->e.e_phnum; i++) { ESZ(Phdr) *ph = &e->p[i]; - ESZ(Addr) addr, brkaddr; - ESZ(Word) memsz; - if (ph->p_type != PT_LOAD) continue; - - addr = ph->p_vaddr+base; - memsz = ph->p_memsz; - brkaddr = addr+memsz; - - if (brkaddr > elfbrk) - elfbrk = brkaddr; + if (ph0 == NULL) + ph0 = ph; + if (phlast == NULL || ph->p_vaddr > phlast->p_vaddr) + phlast = &e->p[i]; + } + if (ph0 == NULL || phlast == NULL) { + VG_(printf)("valgrind: m_ume.c: too few loadable sections\n"); + return 1; } + base_offset = VG_PGROUNDDN(ph0->p_offset); + base_vaddr = VG_PGROUNDDN(ph0->p_vaddr); + base_vlimit = VG_PGROUNDUP(phlast->p_vaddr + phlast->p_memsz); + mapsize = base_vlimit - base_vaddr; + baseaddr = VG_PGROUNDDN(ph0->p_vaddr + base); + res = VG_(am_mmap_anon_fixed_client)(baseaddr, mapsize, VKI_PROT_NONE); + check_mmap(res, baseaddr, mapsize); for (i = 0; i < e->e.e_phnum; i++) { ESZ(Phdr) *ph = &e->p[i]; @@ -199,12 +216,9 @@ memsz = ph->p_memsz; brkaddr = addr+memsz; - // Tom says: In the following, do what the Linux kernel does and only - // map the pages that are required instead of rounding everything to - // the specified alignment (ph->p_align). (AMD64 doesn't work if you - // use ph->p_align -- part of stage2's memory gets trashed somehow.) - // - // The condition handles the case of a zero-length segment. + if (brkaddr > elfbrk) + elfbrk = brkaddr; + if (VG_PGROUNDUP(bss)-VG_PGROUNDDN(addr) > 0) { if (0) VG_(debugLog)(0,"ume","mmap_file_fixed_client #1\n"); res = VG_(am_mmap_file_fixed_client)( @@ -222,23 +236,38 @@ if (memsz > filesz) { UInt bytes; - bytes = VG_PGROUNDUP(brkaddr)-VG_PGROUNDUP(bss); + bytes = VG_PGROUNDUP(bss) - bss; if (bytes > 0) { - if (0) VG_(debugLog)(0,"ume","mmap_anon_fixed_client #2\n"); - res = VG_(am_mmap_anon_fixed_client)( - VG_PGROUNDUP(bss), bytes, - prot - ); - if (0) VG_(am_show_nsegments)(0,"after #2"); - check_mmap(res, VG_PGROUNDUP(bss), bytes); + /* Make sure the end of the segment is writable */ + if ((prot & VKI_PROT_WRITE) == 0) { + res = VG_(am_do_mprotect_NO_NOTIFY)((UWord)VG_PGROUNDDN(bss), VKI_PAGE_SIZE, + prot|VKI_PROT_WRITE); + if (sr_isError(res)) { + VG_(printf)("valgrind: m_ume.c: mprotect failed\n"); + return (1); + } + } + VG_(memset)((char *)bss, 0, bytes); + /* Reset the data protection back */ + if ((prot & VKI_PROT_WRITE) == 0) { + res = VG_(am_do_mprotect_NO_NOTIFY)((UWord)VG_PGROUNDDN(bss), VKI_PAGE_SIZE, + prot); + if (sr_isError(res)) { + VG_(printf)("valgrind: m_ume.c: mprotect failed\n"); + return (1); + } + } } - bytes = bss & (VKI_PAGE_SIZE - 1); - - // The 'prot' condition allows for a read-only bss - if ((prot & VKI_PROT_WRITE) && (bytes > 0)) { - bytes = VKI_PAGE_SIZE - bytes; - VG_(memset)((char *)bss, 0, bytes); + /* Overlay the BSS segment onto the proper region. */ + if (VG_PGROUNDUP(brkaddr) > VG_PGROUNDUP(bss)) { + res = VG_(am_do_mprotect_NO_NOTIFY)((UWord)VG_PGROUNDUP(bss), + VG_PGROUNDUP(brkaddr) - VG_PGROUNDUP(bss), prot); + if (sr_isError(res)) { + VG_(printf)("valgrind: m_ume.c: mprotect failed\n"); + return (1); + } + VG_(am_notify_mprotect)((Addr)VG_PGROUNDUP(bss), VG_PGROUNDUP(brkaddr) - VG_PGROUNDUP(bss), prot); } } } ==== //depot/projects/valgrind/coregrind/pub_core_aspacemgr.h#4 (text+ko) ==== @@ -164,6 +164,9 @@ specified address range. */ extern Bool VG_(am_notify_client_shmat)( Addr a, SizeT len, UInt prot ); +extern SysRes VG_(am_do_mprotect_NO_NOTIFY) + ( Addr start, SizeT length, UInt prot); + /* Notifies aspacem that an mprotect was completed successfully. The segment array is updated accordingly. Note, as with VG_(am_notify_munmap), it is not the job of this function to reject @@ -191,7 +194,6 @@ extern SysRes VG_(am_do_mmap_NO_NOTIFY) ( Addr start, SizeT length, UInt prot, UInt flags, Int fd, Off64T offset); - //-------------------------------------------------------------- // Functions pertaining to AIX5-specific notifications.