From 68bb7c063f71631a4f207adca2235eb0f8d00d33 Mon Sep 17 00:00:00 2001 From: Paul Floyd Date: Sat, 9 Oct 2021 15:01:08 +0200 Subject: [PATCH] FreeBSD support, patch 12 coregrind modified files --- NEWS | 20 +- coregrind/m_aspacemgr/aspacemgr-common.c | 76 +++- coregrind/m_aspacemgr/aspacemgr-linux.c | 195 ++++++++- coregrind/m_aspacemgr/priv_aspacemgr.h | 2 +- coregrind/m_coredump/coredump-elf.c | 79 +++- coregrind/m_debuginfo/d3basics.c | 4 +- coregrind/m_debuginfo/debuginfo.c | 19 +- coregrind/m_debuginfo/priv_readpdb.h | 4 +- coregrind/m_debuginfo/readdwarf.c | 8 +- coregrind/m_debuginfo/readdwarf3.c | 4 +- coregrind/m_debuginfo/readelf.c | 116 +++++- coregrind/m_debuginfo/readpdb.c | 4 +- coregrind/m_debuginfo/storage.c | 7 +- coregrind/m_debuglog.c | 83 ++++ coregrind/m_gdbserver/gdb/signals.h | 3 + coregrind/m_gdbserver/remote-utils.c | 37 +- coregrind/m_gdbserver/signals.c | 8 + coregrind/m_libcassert.c | 6 +- coregrind/m_libcfile.c | 141 ++++++- coregrind/m_libcprint.c | 2 +- coregrind/m_libcproc.c | 108 ++++- coregrind/m_libcsetjmp.c | 22 +- coregrind/m_libcsignal.c | 39 +- coregrind/m_machine.c | 17 +- coregrind/m_main.c | 148 ++++++- coregrind/m_redir.c | 5 + coregrind/m_replacemalloc/vg_replace_malloc.c | 379 ++++++++++++++++-- coregrind/m_scheduler/scheduler.c | 5 +- coregrind/m_scheduler/sema.c | 4 +- coregrind/m_sigframe/sigframe-common.c | 2 +- coregrind/m_signals.c | 99 ++++- coregrind/m_stacktrace.c | 35 +- coregrind/m_syscall.c | 130 ++++++ coregrind/m_syswrap/priv_types_n_macros.h | 84 +++- coregrind/m_syswrap/syswrap-generic.c | 73 +++- coregrind/m_syswrap/syswrap-main.c | 357 ++++++++++++++++- coregrind/m_trampoline.S | 68 ++++ coregrind/m_translate.c | 4 +- coregrind/m_ume/elf.c | 14 +- coregrind/m_ume/main.c | 2 +- coregrind/m_ume/priv_ume.h | 4 +- coregrind/m_vki.c | 4 +- coregrind/m_vkiscnums.c | 11 + coregrind/pub_core_aspacemgr.h | 4 + coregrind/pub_core_debuginfo.h | 2 +- coregrind/pub_core_gdbserver.h | 1 + coregrind/pub_core_initimg.h | 2 +- coregrind/pub_core_libcproc.h | 7 + coregrind/pub_core_machine.h | 4 +- coregrind/pub_core_mallocfree.h | 2 + coregrind/pub_core_sigframe.h | 6 +- coregrind/pub_core_syscall.h | 2 + coregrind/pub_core_syswrap.h | 4 + coregrind/pub_core_trampoline.h | 8 + coregrind/vg_preloaded.c | 6 +- coregrind/vgdb.c | 2 + include/pub_tool_libcproc.h | 2 +- 57 files changed, 2270 insertions(+), 214 deletions(-) diff --git a/NEWS b/NEWS index 68315a77ad..e5414c02b4 100644 --- a/NEWS +++ b/NEWS @@ -4,8 +4,9 @@ Release 3.??.? (?? 2021) This release supports X86/Linux, AMD64/Linux, ARM32/Linux, ARM64/Linux, PPC32/Linux, PPC64BE/Linux, PPC64LE/Linux, S390X/Linux, MIPS32/Linux, MIPS64/Linux, ARM/Android, ARM64/Android, MIPS32/Android, X86/Android, -X86/Solaris, AMD64/Solaris and AMD64/MacOSX 10.12. There is also preliminary -support for X86/macOS 10.13, AMD64/macOS 10.13 and nanoMIPS/Linux. +X86/Solaris, AMD64/Solaris, AMD64/MacOSX 10.12, X86/FreeBSD and +AMD64/FreeBSD. There is also preliminary support for X86/macOS 10.13, +AMD64/macOS 10.13 and nanoMIPS/Linux. * ==================== CORE CHANGES =================== @@ -25,6 +26,8 @@ support for X86/macOS 10.13, AMD64/macOS 10.13 and nanoMIPS/Linux. - ISA 3.0 support for the darn instruction added. - ISA 3.0 support for the vector system call instruction scv added. - ISA 3.0 support for the copy, paste and cpabort instructions added. + +* Support for X86/FreeBSD and AMD64/FreeBSD has been added. * ==================== TOOL CHANGES ==================== @@ -56,6 +59,19 @@ are not entered into bugzilla tend to get forgotten about or ignored. 439590 glibc-2.34 breaks suppressions against obj:*/lib*/libc-2.*so* 440670 unhandled ppc64le-linux syscall: 252 (statfs64) and 253 (fstatfs64) 432387 s390x: z15 instructions support +439046 valgrind is unusably large when linked with lld +433437 FreeBSD support, part 1 +433438 FreeBSD support, part 2 +433439 FreeBSD support, part 3 +433469 FreeBSD support, part 4 +433473 FreeBSD support, part 5 +433477 FreeBSD support, part 6 +433479 FreeBSD support, part 7 +433504 FreeBSD support, part 8 +433506 FreeBSD support, part 9 +433507 FreeBSD support, part 10 +433508 FreeBSD support, part 11 +433510 FreeBSD support, part 12 440906 Fix impossible constraint issue in P10 testcase. 441512 Remove a unneeded / unnecessary prefix check. 441534 Update the expected output for test_isa_3_1_VRT. diff --git a/coregrind/m_aspacemgr/aspacemgr-common.c b/coregrind/m_aspacemgr/aspacemgr-common.c index 214b54a35e..6814410c09 100644 --- a/coregrind/m_aspacemgr/aspacemgr-common.c +++ b/coregrind/m_aspacemgr/aspacemgr-common.c @@ -35,6 +35,7 @@ ************************************************************* */ #include "priv_aspacemgr.h" +#include "pub_core_libcassert.h" #include "config.h" @@ -171,6 +172,16 @@ SysRes VG_(am_do_mmap_NO_NOTIFY)( Addr start, SizeT length, UInt prot, } res = VG_(do_syscall6)(__NR_mmap, (UWord)start, length, prot, flags, (UInt)fd, offset); +# elif defined(VGP_x86_freebsd) + if (flags & VKI_MAP_ANONYMOUS && fd == 0) + fd = -1; + 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; + res = VG_(do_syscall6)(__NR_mmap, (UWord)start, length, + prot, flags, fd, offset); # elif defined(VGP_x86_solaris) /* MAP_ANON with fd==0 is EINVAL. */ if (fd == 0 && (flags & VKI_MAP_ANONYMOUS)) @@ -255,7 +266,7 @@ SysRes ML_(am_open) ( const HChar* pathname, Int flags, Int mode ) /* ARM64 wants to use __NR_openat rather than __NR_open. */ SysRes res = VG_(do_syscall4)(__NR_openat, VKI_AT_FDCWD, (UWord)pathname, flags, mode); -# elif defined(VGO_linux) || defined(VGO_darwin) +# elif defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_freebsd) SysRes res = VG_(do_syscall3)(__NR_open, (UWord)pathname, flags, mode); # elif defined(VGO_solaris) SysRes res = VG_(do_syscall4)(__NR_openat, VKI_AT_FDCWD, (UWord)pathname, @@ -283,7 +294,7 @@ Int ML_(am_readlink)(const HChar* path, HChar* buf, UInt bufsiz) # if defined(VGP_arm64_linux) || defined(VGP_nanomips_linux) res = VG_(do_syscall4)(__NR_readlinkat, VKI_AT_FDCWD, (UWord)path, (UWord)buf, bufsiz); -# elif defined(VGO_linux) || defined(VGO_darwin) +# elif defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_freebsd) res = VG_(do_syscall3)(__NR_readlink, (UWord)path, (UWord)buf, bufsiz); # elif defined(VGO_solaris) res = VG_(do_syscall4)(__NR_readlinkat, VKI_AT_FDCWD, (UWord)path, @@ -296,7 +307,7 @@ Int ML_(am_readlink)(const HChar* path, HChar* buf, UInt bufsiz) Int ML_(am_fcntl) ( Int fd, Int cmd, Addr arg ) { -# if defined(VGO_linux) || defined(VGO_solaris) +# if defined(VGO_linux) || defined(VGO_solaris) || defined(VGO_freebsd) # if defined(VGP_nanomips_linux) SysRes res = VG_(do_syscall3)(__NR_fcntl64, fd, cmd, arg); # else @@ -330,7 +341,8 @@ Bool ML_(am_get_fd_d_i_m)( Int fd, *mode = (UInt)bufx.stx_mode; return True; } -# endif +# endif // VGO_linux only + # if defined(VGO_linux) && defined(__NR_fstat64) /* fstat64 is second candidate as it can cope with minor and major device numbers outside the 0-255 range and it works properly for x86 @@ -343,7 +355,8 @@ Bool ML_(am_get_fd_d_i_m)( Int fd, *mode = (UInt) buf64.st_mode; return True; } -# endif +# endif // VGO_linux and defined __NR_fstat64 + # if defined(__NR_fstat) struct vki_stat buf; res = VG_(do_syscall2)(__NR_fstat, fd, (UWord)&buf); @@ -353,7 +366,7 @@ Bool ML_(am_get_fd_d_i_m)( Int fd, *mode = (UInt) buf.st_mode; return True; } -# endif +# endif // defined __NR_fstat return False; # elif defined(VGO_solaris) # if defined(VGP_x86_solaris) @@ -372,11 +385,30 @@ Bool ML_(am_get_fd_d_i_m)( Int fd, return True; } return False; +# elif defined(VGO_freebsd) + struct vki_freebsd11_stat buf; +#if (FREEBSD_VERS >= FREEBSD_12) + SysRes res = VG_(do_syscall2)(__NR_freebsd11_fstat, fd, (UWord)&buf); +#else + SysRes res = VG_(do_syscall2)(__NR_fstat, fd, (UWord)&buf); +#endif + if (!sr_isError(res)) { + *dev = (ULong)buf.st_dev; + *ino = (ULong)buf.st_ino; + *mode = (UInt) buf.st_mode; + return True; + } + return False; # else # error Unknown OS # endif } +#if defined(VGO_freebsd) +#define M_FILEDESC_BUF 1000000 +static Char filedesc_buf[M_FILEDESC_BUF]; +#endif + Bool ML_(am_resolve_filename) ( Int fd, /*OUT*/HChar* buf, Int nbuf ) { #if defined(VGO_linux) @@ -389,6 +421,38 @@ Bool ML_(am_resolve_filename) ( Int fd, /*OUT*/HChar* buf, Int nbuf ) else return False; +#elif defined(VGO_freebsd) + Int mib[4]; + SysRes sres; + vki_size_t len; + Char *bp, *eb; + struct vki_kinfo_file *kf; + + mib[0] = VKI_CTL_KERN; + mib[1] = VKI_KERN_PROC; + mib[2] = VKI_KERN_PROC_FILEDESC; + mib[3] = sr_Res(VG_(do_syscall0)(__NR_getpid)); + len = sizeof(filedesc_buf); + sres = VG_(do_syscall6)(__NR___sysctl, (UWord)mib, 4, (UWord)filedesc_buf, + (UWord)&len, 0, 0); + if (sr_isError(sres)) { + VG_(debugLog)(0, "sysctl(kern.proc.filedesc)", "%s\n", VG_(strerror)(sr_Err(sres))); + ML_(am_exit)(1); + } + /* Walk though the list. */ + bp = filedesc_buf; + eb = filedesc_buf + len; + while (bp < eb) { + kf = (struct vki_kinfo_file *)bp; + if (kf->kf_fd == fd) + break; + bp += kf->kf_structsize; + } + if (bp >= eb || *kf->kf_path == '\0') + VG_(strncpy)( buf, "[unknown]", nbuf ); + else + VG_(strncpy)( buf, kf->kf_path, nbuf ); + return True; #elif defined(VGO_darwin) HChar tmp[VKI_MAXPATHLEN+1]; if (0 == ML_(am_fcntl)(fd, VKI_F_GETPATH, (UWord)tmp)) { diff --git a/coregrind/m_aspacemgr/aspacemgr-linux.c b/coregrind/m_aspacemgr/aspacemgr-linux.c index 0eb3143161..9a69f3850f 100644 --- a/coregrind/m_aspacemgr/aspacemgr-linux.c +++ b/coregrind/m_aspacemgr/aspacemgr-linux.c @@ -4,7 +4,7 @@ /*--- The address space manager: segment initialisation and ---*/ /*--- tracking, stack operations ---*/ /*--- ---*/ -/*--- Implementation for Linux (and Darwin!) aspacemgr-linux.c ---*/ +/*--- Implementation for Linux, Darwin, Solaris and FreeBSD ---*/ /*--------------------------------------------------------------------*/ /* @@ -30,7 +30,7 @@ The GNU General Public License is contained in the file COPYING. */ -#if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) +#if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) || defined(VGO_freebsd) /* ************************************************************* DO NOT INCLUDE ANY OTHER FILES HERE. @@ -314,6 +314,8 @@ Addr VG_(clo_aspacem_minAddr) # endif #elif defined(VGO_solaris) = (Addr) 0x00100000; // 1MB +#elif defined(VGO_freebsd) + = (Addr) 0x04000000; // 64M #else #endif @@ -367,7 +369,12 @@ static void parse_procselfmaps ( # define ARM_LINUX_FAKE_COMMPAGE_END1 0xFFFF1000 #endif - +#if !defined(VKI_MAP_STACK) +/* this is only defined for FreeBSD + * for readability, define it to 0 + * for other platforms */ +#define VKI_MAP_STACK 0 +#endif /*-----------------------------------------------------------------*/ /*--- ---*/ @@ -871,7 +878,7 @@ static void sync_check_mapping_callback ( Addr addr, SizeT len, UInt prot, cmp_devino = False; #endif -#if defined(VGO_darwin) +#if defined(VGO_darwin) || defined(VGO_freebsd) // GrP fixme kernel info doesn't have dev/inode cmp_devino = False; @@ -1491,7 +1498,13 @@ static void init_nsegment ( /*OUT*/NSegment* seg ) seg->mode = 0; seg->offset = 0; seg->fnIdx = -1; - seg->hasR = seg->hasW = seg->hasX = seg->hasT = seg->isCH = False; + + seg->hasR = seg->hasW = seg->hasX = seg->hasT + = seg->isCH = False; +#if defined(VGO_freebsd) + seg->isFF = False; +#endif + } /* Make an NSegment which holds a reservation. */ @@ -1637,6 +1650,81 @@ Addr VG_(am_startup) ( Addr sp_at_startup ) suggested_clstack_end = -1; // ignored; Mach-O specifies its stack + // --- Freebsd ------------------------------------------ +#elif defined(VGO_freebsd) + + + VG_(debugLog)(2, "aspacem", + " sp_at_startup = 0x%010lx (supplied)\n", + sp_at_startup ); + +# if VG_WORDSIZE == 4 + + aspacem_maxAddr = VG_PGROUNDDN( sp_at_startup ) - 1; +# else + aspacem_maxAddr = (Addr) (Addr)0x800000000UL - 1; // 32G +# ifdef ENABLE_INNER + { Addr cse = VG_PGROUNDDN( sp_at_startup ) - 1; + if (aspacem_maxAddr > cse) + aspacem_maxAddr = cse; + } +# endif // ENABLE_INNER +# endif + + aspacem_cStart = aspacem_minAddr; + aspacem_vStart = VG_PGROUNDUP((aspacem_minAddr + aspacem_maxAddr + 1) / 2); + +# ifdef ENABLE_INNER + aspacem_vStart -= 0x10000000UL; // 512M +# endif // ENABLE_INNER + + // starting with FreeBSD 10.4, the stack is created with a zone + // that is marked MAP_GUARD. This zone is reserved but unmapped, + // and fills the space up to the end of the segment + // see man mmap + + // Version number from + // https://www.freebsd.org/doc/en_US.ISO8859-1/books/porters-handbook/versions-10.html + + // On x86 this is 0x3FE0000 + // And on amd64 it is 0x1FFE0000 (536739840) + // There is less of an issue on amd64 as we just choose some arbitrary address rather then trying + // to squeeze in just below the host stack + + // Some of this is in sys/vm/vm_map.c, for instance vm_map_stack and vm_map_stack_locked + // These refer to the kernel global sgrowsiz, which seems to be the initial size + // of the user stack, 128k on my system + // + // This seems to be in the sysctl kern.sgrowsiz + // Then there is kern.maxssiz which is the total stack size (grow size + guard area) + // In other words guard area = maxssiz - sgrowsiz + +#if (__FreeBSD_version >= 1003516) + +#if 0 + // this block implements what is described above + // this makes no changes to the regression tests + // I'm keeping it for a rainy day. + // note this needs + // #include "pub_core_libcproc.h" + SizeT kern_maxssiz; + SizeT kern_sgrowsiz; + SizeT sysctl_size = sizeof(SizeT); + VG_(sysctlbyname)("kern.maxssiz", &kern_maxssiz, &sysctl_size, NULL, 0); + VG_(sysctlbyname)("kern.sgrowsiz", &kern_sgrowsiz, &sysctl_size, NULL, 0); + + suggested_clstack_end = aspacem_maxAddr - (kern_maxssiz - kern_sgrowsiz) + VKI_PAGE_SIZE; +#endif + + suggested_clstack_end = aspacem_maxAddr - 64*1024*1024UL + + VKI_PAGE_SIZE; + +#else + suggested_clstack_end = aspacem_maxAddr - 16*1024*1024UL + + VKI_PAGE_SIZE; + +#endif + // --- Solaris ------------------------------------------ #elif defined(VGO_solaris) # if VG_WORDSIZE == 4 @@ -1759,7 +1847,7 @@ Addr VG_(am_startup) ( Addr sp_at_startup ) suggested_clstack_end = aspacem_maxAddr - 16*1024*1024ULL + VKI_PAGE_SIZE; -#endif +#endif /* #else of 'defined(VGO_solaris)' */ // --- (end) -------------------------------------------- aspacem_assert(VG_IS_PAGE_ALIGNED(aspacem_minAddr)); @@ -2165,13 +2253,13 @@ VG_(am_notify_client_mmap)( Addr a, SizeT len, UInt prot, UInt flags, needDiscard = any_Ts_in_range( a, len ); init_nsegment( &seg ); - seg.kind = (flags & VKI_MAP_ANONYMOUS) ? SkAnonC : SkFileC; + seg.kind = (flags & (VKI_MAP_ANONYMOUS | VKI_MAP_STACK)) ? SkAnonC : SkFileC; seg.start = a; seg.end = a + len - 1; seg.hasR = toBool(prot & VKI_PROT_READ); seg.hasW = toBool(prot & VKI_PROT_WRITE); seg.hasX = toBool(prot & VKI_PROT_EXEC); - if (!(flags & VKI_MAP_ANONYMOUS)) { + if (!(flags & (VKI_MAP_ANONYMOUS | VKI_MAP_STACK))) { // Nb: We ignore offset requests in anonymous mmaps (see bug #126722) seg.offset = offset; if (ML_(am_get_fd_d_i_m)(fd, &dev, &ino, &mode)) { @@ -2182,6 +2270,9 @@ VG_(am_notify_client_mmap)( Addr a, SizeT len, UInt prot, UInt flags, if (ML_(am_resolve_filename)(fd, buf, VKI_PATH_MAX)) { seg.fnIdx = ML_(am_allocate_segname)( buf ); } +#if defined(VGO_freebsd) + seg.isFF = (flags & VKI_MAP_FIXED); +#endif } add_segment( &seg ); AM_SANITY_CHECK; @@ -2423,6 +2514,9 @@ SysRes VG_(am_mmap_named_file_fixed_client_flags) } else if (ML_(am_resolve_filename)(fd, buf, VKI_PATH_MAX)) { seg.fnIdx = ML_(am_allocate_segname)( buf ); } +#if defined(VGO_freebsd) + seg.isFF = (flags & VKI_MAP_FIXED); +#endif add_segment( &seg ); AM_SANITY_CHECK; @@ -2733,6 +2827,9 @@ static SysRes VG_(am_mmap_file_float_valgrind_flags) ( SizeT length, UInt prot, if (ML_(am_resolve_filename)(fd, buf, VKI_PATH_MAX)) { seg.fnIdx = ML_(am_allocate_segname)( buf ); } +#if defined(VGO_freebsd) + seg.isFF = (flags & VKI_MAP_FIXED); +#endif add_segment( &seg ); AM_SANITY_CHECK; @@ -3796,13 +3893,89 @@ Bool VG_(get_changed_segments)( return !css_overflowed; } -#endif // defined(VGO_darwin) /*------END-procmaps-parser-for-Darwin---------------------------*/ +/*------BEGIN-procmaps-parser-for-Freebsd------------------------*/ +#elif defined(VGO_freebsd) + +/* Size of a smallish table used to read /proc/self/map entries. */ +#define M_PROCMAP_BUF 10485760 /* 10M */ + +/* static ... to keep it out of the stack frame. */ +static char procmap_buf[M_PROCMAP_BUF]; + +static void parse_procselfmaps ( + void (*record_mapping)( Addr addr, SizeT len, UInt prot, + ULong dev, ULong ino, Off64T offset, + const HChar* filename ), + void (*record_gap)( Addr addr, SizeT len ) + ) +{ + Addr start, endPlusOne, gapStart; + char* filename; + char *p; + UInt prot; + ULong foffset, dev, ino; + struct vki_kinfo_vmentry *kve; + vki_size_t len; + Int oid[4]; + SysRes sres; + + foffset = ino = 0; /* keep gcc-4.1.0 happy */ + + oid[0] = VKI_CTL_KERN; + oid[1] = VKI_KERN_PROC; + oid[2] = VKI_KERN_PROC_VMMAP; + oid[3] = sr_Res(VG_(do_syscall0)(__NR_getpid)); + len = sizeof(procmap_buf); + + sres = VG_(do_syscall6)(__NR___sysctl, (UWord)oid, 4, (UWord)procmap_buf, + (UWord)&len, 0, 0); + if (sr_isError(sres)) { + VG_(debugLog)(0, "procselfmaps", "sysctl %lu\n", sr_Err(sres)); + ML_(am_exit)(1); + } + gapStart = Addr_MIN; + p = procmap_buf; + while (p < (char *)procmap_buf + len) { + kve = (struct vki_kinfo_vmentry *)p; + start = (UWord)kve->kve_start; + endPlusOne = (UWord)kve->kve_end; + foffset = kve->kve_offset; + filename = kve->kve_path; + dev = kve->kve_fsid; + ino = kve->kve_fileid; + if (filename[0] != '/') { + filename = NULL; + foffset = 0; + } + + prot = 0; + if (kve->kve_protection & VKI_KVME_PROT_READ) prot |= VKI_PROT_READ; + if (kve->kve_protection & VKI_KVME_PROT_WRITE) prot |= VKI_PROT_WRITE; + if (kve->kve_protection & VKI_KVME_PROT_EXEC) prot |= VKI_PROT_EXEC; + + if (record_gap && gapStart < start) + (*record_gap) ( gapStart, start-gapStart ); + + if (record_mapping && start < endPlusOne) + (*record_mapping) ( start, endPlusOne-start, + prot, dev, ino, + foffset, filename ); + gapStart = endPlusOne; + p += kve->kve_structsize; + } + + if (record_gap && gapStart < Addr_MAX) + (*record_gap) ( gapStart, Addr_MAX - gapStart + 1 ); +} + +/*------END-procmaps-parser-for-Freebsd--------------------------*/ + /*------BEGIN-procmaps-parser-for-Solaris------------------------*/ -#if defined(VGO_solaris) +#elif defined(VGO_solaris) /* Note: /proc/self/xmap contains extended information about already materialized mappings whereas /proc/self/rmap contains information about @@ -4112,7 +4285,7 @@ Bool VG_(am_search_for_new_segment)(Addr *addr, SizeT *size, UInt *prot) /*------END-procmaps-parser-for-Solaris--------------------------*/ -#endif // defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) +#endif // defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) || defined(VGO_freebsd) /*--------------------------------------------------------------------*/ /*--- end ---*/ diff --git a/coregrind/m_aspacemgr/priv_aspacemgr.h b/coregrind/m_aspacemgr/priv_aspacemgr.h index fbc46aca7b..161c5c2954 100644 --- a/coregrind/m_aspacemgr/priv_aspacemgr.h +++ b/coregrind/m_aspacemgr/priv_aspacemgr.h @@ -77,7 +77,7 @@ extern void ML_(am_assert_fail) ( const HChar* expr, const HChar* fn ); #define aspacem_assert(expr) \ - ((void) (LIKELY(expr) ? 0 : \ + ((void) (LIKELY(expr) ? (void)0 : \ (ML_(am_assert_fail)(#expr, \ __FILE__, __LINE__, \ __PRETTY_FUNCTION__)))) diff --git a/coregrind/m_coredump/coredump-elf.c b/coregrind/m_coredump/coredump-elf.c index daf85e6479..d0e8a03c94 100644 --- a/coregrind/m_coredump/coredump-elf.c +++ b/coregrind/m_coredump/coredump-elf.c @@ -26,7 +26,7 @@ The GNU General Public License is contained in the file COPYING. */ -#if defined(VGO_linux) +#if defined(VGO_linux) || defined(VGO_freebsd) #include "pub_core_basics.h" #include "pub_core_vki.h" @@ -90,6 +90,9 @@ static void fill_ehdr(ESZ(Ehdr) *ehdr, Int num_phdrs) ehdr->e_ident[EI_CLASS] = VG_ELF_CLASS; ehdr->e_ident[EI_DATA] = VG_ELF_DATA2XXX; ehdr->e_ident[EI_VERSION] = EV_CURRENT; +#if defined(VGO_freebsd) + ehdr->e_ident[EI_OSABI] = ELFOSABI_FREEBSD; +#endif ehdr->e_type = ET_CORE; ehdr->e_machine = VG_ELF_MACHINE; @@ -193,6 +196,19 @@ static void write_note(Int fd, const struct note *n) VG_(write)(fd, &n->note, note_size(n)); } +#if defined(VGO_freebsd) +static void fill_prpsinfo(const ThreadState *tst, + struct vki_elf_prpsinfo *prpsinfo) +{ + VG_(memset)(prpsinfo, 0, sizeof(*prpsinfo)); + + prpsinfo->pr_version = VKI_PRPSINFO_VERSION; + prpsinfo->pr_psinfosz = sizeof(struct vki_elf_prpsinfo); + VG_(client_fname)(prpsinfo->pr_fname, sizeof(prpsinfo->pr_fname), False); + // why? + VG_(strncpy)(prpsinfo->pr_psargs, prpsinfo->pr_fname, sizeof(prpsinfo->pr_psargs) - 1); +} +#else static void fill_prpsinfo(const ThreadState *tst, struct vki_elf_prpsinfo *prpsinfo) { @@ -223,6 +239,7 @@ static void fill_prpsinfo(const ThreadState *tst, VG_(client_fname)(prpsinfo->pr_fname, sizeof(prpsinfo->pr_fname), False); } +#endif static void fill_prstatus(const ThreadState *tst, /*OUT*/struct vki_elf_prstatus *prs, @@ -238,6 +255,16 @@ static void fill_prstatus(const ThreadState *tst, VG_(memset)(prs, 0, sizeof(*prs)); +#if defined(VGO_freebsd) + prs->pr_version = VKI_PRSTATUS_VERSION; + prs->pr_statussz = sizeof(struct vki_elf_prstatus); + prs->pr_gregsetsz = sizeof(vki_elf_gregset_t); + prs->pr_fpregsetsz = sizeof(vki_elf_fpregset_t); + prs->pr_osreldate = VG_(getosreldate)(); + + prs->pr_cursig = si->si_signo; + prs->pr_pid = tst->os_state.lwpid; +#else prs->pr_info.si_signo = si->si_signo; prs->pr_info.si_code = si->si_code; prs->pr_info.si_errno = 0; @@ -248,6 +275,7 @@ static void fill_prstatus(const ThreadState *tst, prs->pr_ppid = 0; prs->pr_pgrp = VG_(getpgrp)(); prs->pr_sid = VG_(getpgrp)(); +#endif #if defined(VGP_s390x_linux) /* prs->pr_reg has struct type. Need to take address. */ @@ -461,6 +489,45 @@ static void fill_prstatus(const ThreadState *tst, regs[VKI_MIPS32_EF_CP0_STATUS] = arch->vex.guest_CP0_status; regs[VKI_MIPS32_EF_CP0_EPC] = arch->vex.guest_PC; # undef DO +#elif defined(VGP_amd64_freebsd) + regs->rflags = LibVEX_GuestAMD64_get_rflags( &((ThreadArchState*)arch)->vex ); + regs->rsp = arch->vex.guest_RSP; + regs->rip = arch->vex.guest_RIP; + regs->rbx = arch->vex.guest_RBX; + regs->rcx = arch->vex.guest_RCX; + regs->rdx = arch->vex.guest_RDX; + regs->rsi = arch->vex.guest_RSI; + regs->rdi = arch->vex.guest_RDI; + regs->rbp = arch->vex.guest_RBP; + regs->rax = arch->vex.guest_RAX; + regs->r8 = arch->vex.guest_R8; + regs->r9 = arch->vex.guest_R9; + regs->r10 = arch->vex.guest_R10; + regs->r11 = arch->vex.guest_R11; + regs->r12 = arch->vex.guest_R12; + regs->r13 = arch->vex.guest_R13; + regs->r14 = arch->vex.guest_R14; + regs->r15 = arch->vex.guest_R15; +#elif defined(VGP_x86_freebsd) + regs->eflags = LibVEX_GuestX86_get_eflags( &arch->vex ); + regs->esp = arch->vex.guest_ESP; + regs->eip = arch->vex.guest_EIP; + + regs->ebx = arch->vex.guest_EBX; + regs->ecx = arch->vex.guest_ECX; + regs->edx = arch->vex.guest_EDX; + regs->esi = arch->vex.guest_ESI; + regs->edi = arch->vex.guest_EDI; + regs->ebp = arch->vex.guest_EBP; + regs->eax = arch->vex.guest_EAX; + + regs->cs = arch->vex.guest_CS; + regs->ds = arch->vex.guest_DS; + regs->ss = arch->vex.guest_SS; + regs->es = arch->vex.guest_ES; + regs->fs = arch->vex.guest_FS; + regs->gs = arch->vex.guest_GS; + #else # error Unknown ELF platform #endif @@ -587,6 +654,16 @@ static void fill_fpu(const ThreadState *tst, vki_elf_fpregset_t *fpu) # undef DO #elif defined(VGP_nanomips_linux) +#elif defined(VGP_x86_freebsd) + +#elif defined(VGP_amd64_freebsd) + +# define DO(n) VG_(memcpy)(fpu->xmm_space + n * 4, \ + &arch->vex.guest_YMM##n[0], 16) + DO(0); DO(1); DO(2); DO(3); DO(4); DO(5); DO(6); DO(7); + DO(8); DO(9); DO(10); DO(11); DO(12); DO(13); DO(14); DO(15); +# undef DO + #else # error Unknown ELF platform #endif diff --git a/coregrind/m_debuginfo/d3basics.c b/coregrind/m_debuginfo/d3basics.c index 1bc5f8f052..555e1e00d0 100644 --- a/coregrind/m_debuginfo/d3basics.c +++ b/coregrind/m_debuginfo/d3basics.c @@ -498,11 +498,11 @@ static Bool get_Dwarf_Reg( /*OUT*/Addr* a, Word regno, const RegSummary* regs ) { vg_assert(regs); # if defined(VGP_x86_linux) || defined(VGP_x86_darwin) \ - || defined(VGP_x86_solaris) + || defined(VGP_x86_solaris) || defined(VGP_x86_freebsd) if (regno == 5/*EBP*/) { *a = regs->fp; return True; } if (regno == 4/*ESP*/) { *a = regs->sp; return True; } # elif defined(VGP_amd64_linux) || defined(VGP_amd64_darwin) \ - || defined(VGP_amd64_solaris) + || defined(VGP_amd64_solaris) || defined(VGP_amd64_freebsd) if (regno == 6/*RBP*/) { *a = regs->fp; return True; } if (regno == 7/*RSP*/) { *a = regs->sp; return True; } # elif defined(VGP_ppc32_linux) diff --git a/coregrind/m_debuginfo/debuginfo.c b/coregrind/m_debuginfo/debuginfo.c index e2218f2668..2e5b9b0192 100644 --- a/coregrind/m_debuginfo/debuginfo.c +++ b/coregrind/m_debuginfo/debuginfo.c @@ -57,7 +57,7 @@ #include "priv_tytypes.h" #include "priv_storage.h" #include "priv_readdwarf.h" -#if defined(VGO_linux) || defined(VGO_solaris) +#if defined(VGO_linux) || defined(VGO_solaris) || defined(VGO_freebsd) # include "priv_readelf.h" # include "priv_readdwarf3.h" # include "priv_readpdb.h" @@ -814,7 +814,7 @@ void VG_(di_initialise) ( void ) /*--- ---*/ /*--------------------------------------------------------------*/ -#if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) +#if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) || defined(VGO_freebsd) /* Helper (indirect) for di_notify_ACHIEVE_ACCEPT_STATE */ static Bool overlaps_DebugInfoMappings ( const DebugInfoMapping* map1, @@ -965,7 +965,7 @@ static ULong di_notify_ACHIEVE_ACCEPT_STATE ( struct _DebugInfo* di ) truncate_DebugInfoMapping_overlaps( di, di->fsm.maps ); /* And acquire new info. */ -# if defined(VGO_linux) || defined(VGO_solaris) +# if defined(VGO_linux) || defined(VGO_solaris) || defined(VGO_freebsd) ok = ML_(read_elf_debug_info)( di ); # elif defined(VGO_darwin) ok = ML_(read_macho_debug_info)( di ); @@ -1204,6 +1204,13 @@ ULong VG_(di_notify_mmap)( Addr a, Bool allow_SkFileV, Int use_fd ) if (!(is_rx_map || is_rw_map || is_ro_map)) return 0; +#if defined(VGO_freebsd) + /* Ignore non-fixed read-only mappings. The dynamic linker may be + * mapping something for its own transient purposes. */ + if (!seg->isFF && is_ro_map) + return 0; +#endif + /* Peer at the first few bytes of the file, to see if it is an ELF */ /* object file. Ignore the file if we do not have read permission. */ VG_(memset)(buf1k, 0, sizeof(buf1k)); @@ -1247,7 +1254,7 @@ ULong VG_(di_notify_mmap)( Addr a, Bool allow_SkFileV, Int use_fd ) vg_assert(sr_Res(preadres) > 0 && sr_Res(preadres) <= sizeof(buf1k) ); /* We're only interested in mappings of object files. */ -# if defined(VGO_linux) || defined(VGO_solaris) +# if defined(VGO_linux) || defined(VGO_solaris) || defined(VGO_freebsd) if (!ML_(is_elf_object_file)( buf1k, (SizeT)sr_Res(preadres), False )) return 0; # elif defined(VGO_darwin) @@ -1696,7 +1703,7 @@ void VG_(di_notify_pdb_debuginfo)( Int fd_obj, Addr avma_obj, if (pdbname) ML_(dinfo_free)(pdbname); } -#endif /* defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) */ +#endif /* defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) || defined(VGO_freebsd) */ /*------------------------------------------------------------*/ @@ -2290,6 +2297,8 @@ Vg_FnNameKind VG_(get_fnname_kind) ( const HChar* name ) VG_STREQ("generic_start_main", name) || // Yellow Dog doggedness VG_STREQN(19, "generic_start_main.", name) || // gcc optimization VG_STREQ("_start", name) || +# elif defined(VGO_freebsd) + VG_STREQ("_start", name) || // FreeBSD libc # elif defined(VGO_darwin) // See readmacho.c for an explanation of this. VG_STREQ("start_according_to_valgrind", name) || // Darwin, darling diff --git a/coregrind/m_debuginfo/priv_readpdb.h b/coregrind/m_debuginfo/priv_readpdb.h index b8f5958103..b9b8fb3a2c 100644 --- a/coregrind/m_debuginfo/priv_readpdb.h +++ b/coregrind/m_debuginfo/priv_readpdb.h @@ -30,7 +30,7 @@ The GNU General Public License is contained in the file COPYING. */ -#if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) +#if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) || defined(VGO_freebsd) #ifndef __PRIV_READPDB_H #define __PRIV_READPDB_H @@ -57,7 +57,7 @@ HChar* ML_(find_name_of_pdb_file)( const HChar* pename ); #endif /* ndef __PRIV_READPDB_H */ -#endif // defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) +#endif // defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) || defined(VGO_freebsd) /*--------------------------------------------------------------------*/ /*--- end ---*/ diff --git a/coregrind/m_debuginfo/readdwarf.c b/coregrind/m_debuginfo/readdwarf.c index bcacca4cb9..39a2946870 100644 --- a/coregrind/m_debuginfo/readdwarf.c +++ b/coregrind/m_debuginfo/readdwarf.c @@ -27,7 +27,7 @@ The GNU General Public License is contained in the file COPYING. */ -#if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) +#if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) || defined(VGO_freebsd) #include "pub_core_basics.h" #include "pub_core_debuginfo.h" @@ -1961,11 +1961,11 @@ void ML_(read_debuginfo_dwarf1) ( /* --------------- Decls --------------- */ -#if defined(VGP_x86_linux) || defined(VGP_x86_solaris) +#if defined(VGP_x86_linux) || defined(VGP_x86_solaris) || defined(VGP_x86_freebsd) # define FP_REG 5 # define SP_REG 4 # define RA_REG_DEFAULT 8 -#elif defined(VGP_amd64_linux) || defined(VGP_amd64_solaris) +#elif defined(VGP_amd64_linux) || defined(VGP_amd64_solaris) || defined(VGP_amd64_freebsd) # define FP_REG 6 # define SP_REG 7 # define RA_REG_DEFAULT 16 @@ -4522,7 +4522,7 @@ void ML_(read_callframe_info_dwarf3) return; } -#endif // defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) +#endif // defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) || defined(VGO_freebsd) /*--------------------------------------------------------------------*/ /*--- end ---*/ diff --git a/coregrind/m_debuginfo/readdwarf3.c b/coregrind/m_debuginfo/readdwarf3.c index 4ac23a3c4d..18eecea9f3 100644 --- a/coregrind/m_debuginfo/readdwarf3.c +++ b/coregrind/m_debuginfo/readdwarf3.c @@ -33,7 +33,7 @@ without prior written permission. */ -#if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) +#if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) || defined(VGO_freebsd) /* REFERENCE (without which this code will not make much sense): @@ -5879,7 +5879,7 @@ ML_(new_dwarf3_reader) ( TRACE_SYMTAB("\n"); #endif -#endif // defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) +#endif // defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) || defined(VGO_freebsd) /*--------------------------------------------------------------------*/ /*--- end ---*/ diff --git a/coregrind/m_debuginfo/readelf.c b/coregrind/m_debuginfo/readelf.c index e424e3e7e8..c586e3f332 100644 --- a/coregrind/m_debuginfo/readelf.c +++ b/coregrind/m_debuginfo/readelf.c @@ -27,7 +27,7 @@ The GNU General Public License is contained in the file COPYING. */ -#if defined(VGO_linux) || defined(VGO_solaris) +#if defined(VGO_linux) || defined(VGO_solaris) || defined(VGO_freebsd) #include "pub_core_basics.h" #include "pub_core_vki.h" @@ -45,6 +45,7 @@ #include "pub_core_syscall.h" #include "pub_core_tooliface.h" /* VG_(needs) */ #include "pub_core_xarray.h" +#include "pub_core_libcproc.h" #include "priv_misc.h" /* dinfo_zalloc/free/strdup */ #include "priv_image.h" #include "priv_d3basics.h" @@ -1118,6 +1119,80 @@ void read_elf_symtab__ppc64be_linux( VG_(OSetGen_Destroy)( oset ); } +#if defined(VGO_freebsd) + +/** + * read_and_set_osrel + * + * "osrel" is in an Elf note. It has values such as 1201000 for FreeBSD 12.1 + * Some of the behaviour related to SIGSEGV and SIGBUS signals depends on the + * kernel reading this value. + * + * However in the case of Valgrind, the host is strictly statically linked and + * does not contain the NT_FREEBSD_ABI_TAG note. And even if it did, we want to + * override the value with that of the guest. + * + * At some later date we might want to look at the value of "fctl0" (note with the + * NT_FREEBSD_FEATURE_CTL type). This seems to be related to Address Space Layout + * Randomization. No hurry at the moment. + * + * See /usr/src/sys/kern/imgact_elf.c for details on how the kernel reads these + * notes. + */ +static +void read_and_set_osrel(DiImage* img) +{ + if (is_elf_object_file_by_DiImage(img, False)) { + Word i; + + ElfXX_Ehdr ehdr; + ML_(img_get)(&ehdr, img, 0, sizeof(ehdr)); + /* Skip the phdrs when we have to search the shdrs. In separate + .debug files the phdrs might not be valid (they are a copy of + the main ELF file) and might trigger assertions when getting + image notes based on them. */ + for (i = 0; i < ehdr.e_phnum; i++) { + ElfXX_Phdr phdr; + ML_(img_get)(&phdr, img, + ehdr.e_phoff + i * ehdr.e_phentsize, sizeof(phdr)); + + if (phdr.p_type == PT_NOTE) { + ElfXX_Off note_ioff = phdr.p_offset; + + while (note_ioff < phdr.p_offset + phdr.p_filesz) { + ElfXX_Nhdr note[2]; + ML_(img_get)(note, img, (DiOffT)note_ioff, sizeof(note)); + DiOffT name_ioff = note_ioff + sizeof(ElfXX_Nhdr); + //DiOffT desc_ioff = name_ioff + ((note[0].n_namesz + 3) & ~3); + if (ML_(img_strcmp_c)(img, name_ioff, "FreeBSD") == 0 + && note[0].n_type == NT_FREEBSD_ABI_TAG) { + + u_int32_t osrel = note[1].n_type; + int name[4]; + name[0] = CTL_KERN; + name[1] = KERN_PROC; + name[2] = KERN_PROC_OSREL; + name[3] = VG_(getpid)(); + SizeT newlen = sizeof(osrel); + Int error = VG_(sysctl)(name, 4, NULL, NULL, &osrel, newlen); + if (error == -1) { + VG_(message)(Vg_DebugMsg, "Warning: failed to set osrel for current process with value %d\n", osrel); + } else { + if (VG_(clo_verbosity) > 1) { + VG_(message)(Vg_DebugMsg, "Set osrel for current process with value %d\n", osrel); + } + } + } + note_ioff = note_ioff + sizeof(ElfXX_Nhdr) + + ((note[0].n_namesz + 3) & ~3) + + ((note[0].n_descsz + 3) & ~3); + } + } + } + } + +} +#endif /* * Look for a build-id in an ELF image. The build-id specification @@ -1701,7 +1776,7 @@ static HChar* readlink_path (const HChar *path) #if defined(VGP_arm64_linux) || defined(VGP_nanomips_linux) res = VG_(do_syscall4)(__NR_readlinkat, VKI_AT_FDCWD, (UWord)path, (UWord)buf, bufsiz); -#elif defined(VGO_linux) || defined(VGO_darwin) +#elif defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_freebsd) res = VG_(do_syscall3)(__NR_readlink, (UWord)path, (UWord)buf, bufsiz); #elif defined(VGO_solaris) res = VG_(do_syscall4)(__NR_readlinkat, VKI_AT_FDCWD, (UWord)path, @@ -1939,14 +2014,14 @@ Bool ML_(read_elf_debug_info) ( struct _DebugInfo* di ) for (i = 0; i < VG_(sizeXA)(di->fsm.maps); i++) { const DebugInfoMapping* map = VG_(indexXA)(di->fsm.maps, i); if (map->rx) - TRACE_SYMTAB("rx_map: avma %#lx size %lu foff %ld\n", - map->avma, map->size, map->foff); + TRACE_SYMTAB("rx_map: avma %#lx size %lu foff %lld\n", + map->avma, map->size, (Long)map->foff); } for (i = 0; i < VG_(sizeXA)(di->fsm.maps); i++) { const DebugInfoMapping* map = VG_(indexXA)(di->fsm.maps, i); if (map->rw) - TRACE_SYMTAB("rw_map: avma %#lx size %lu foff %ld\n", - map->avma, map->size, map->foff); + TRACE_SYMTAB("rw_map: avma %#lx size %lu foff %lld\n", + map->avma, map->size, (Long)map->foff); } if (phdr_mnent == 0 @@ -2039,6 +2114,11 @@ Bool ML_(read_elf_debug_info) ( struct _DebugInfo* di ) item.svma_limit = a_phdr.p_vaddr + a_phdr.p_memsz; item.bias = map->avma - map->foff + a_phdr.p_offset - a_phdr.p_vaddr; +#if (FREEBSD_VERS >= FREEBSD_12_2) + if ((long long int)item.bias < 0LL) { + item.bias = 0; + } +#endif if (map->rw && (a_phdr.p_flags & (PF_R | PF_W)) == (PF_R | PF_W)) { @@ -2166,8 +2246,8 @@ Bool ML_(read_elf_debug_info) ( struct _DebugInfo* di ) for (i = 0; i < VG_(sizeXA)(di->fsm.maps); i++) { const DebugInfoMapping* map = VG_(indexXA)(di->fsm.maps, i); if (map->rx) - TRACE_SYMTAB("rx: at %#lx are mapped foffsets %ld .. %lu\n", - map->avma, map->foff, map->foff + map->size - 1 ); + TRACE_SYMTAB("rx: at %#lx are mapped foffsets %lld .. %lld\n", + map->avma, (Long)map->foff, (Long)(map->foff + map->size - 1) ); } TRACE_SYMTAB("rx: contains these svma regions:\n"); for (i = 0; i < VG_(sizeXA)(svma_ranges); i++) { @@ -2179,8 +2259,8 @@ Bool ML_(read_elf_debug_info) ( struct _DebugInfo* di ) for (i = 0; i < VG_(sizeXA)(di->fsm.maps); i++) { const DebugInfoMapping* map = VG_(indexXA)(di->fsm.maps, i); if (map->rw) - TRACE_SYMTAB("rw: at %#lx are mapped foffsets %ld .. %lu\n", - map->avma, map->foff, map->foff + map->size - 1 ); + TRACE_SYMTAB("rw: at %#lx are mapped foffsets %lld .. %lld\n", + map->avma, (Long)map->foff, (Long)(map->foff + map->size - 1) ); } TRACE_SYMTAB("rw: contains these svma regions:\n"); for (i = 0; i < VG_(sizeXA)(svma_ranges); i++) { @@ -2222,10 +2302,11 @@ Bool ML_(read_elf_debug_info) ( struct _DebugInfo* di ) } } - TRACE_SYMTAB(" [sec %2ld] %s %s al%4u foff %6ld .. %6lu " + TRACE_SYMTAB(" [sec %2ld] %s %s al%4u foff %6lld .. %6lld " " svma %p name \"%s\"\n", i, inrx ? "rx" : " ", inrw ? "rw" : " ", alyn, - foff, (size == 0) ? foff : foff+size-1, (void *) svma, name); + (Long) foff, (size == 0) ? (Long)foff : (Long)(foff+size-1), + (void *) svma, name); /* Check for sane-sized segments. SHT_NOBITS sections have zero size in the file and their offsets are just conceptual. */ @@ -2540,7 +2621,8 @@ Bool ML_(read_elf_debug_info) ( struct _DebugInfo* di ) || defined(VGP_arm_linux) || defined (VGP_s390x_linux) \ || defined(VGP_mips32_linux) || defined(VGP_mips64_linux) \ || defined(VGP_arm64_linux) || defined(VGP_nanomips_linux) \ - || defined(VGP_x86_solaris) || defined(VGP_amd64_solaris) + || defined(VGP_x86_solaris) || defined(VGP_amd64_solaris) \ + || defined(VGP_x86_freebsd) || defined(VGP_amd64_freebsd) /* Accept .plt where mapped as rx (code) */ if (0 == VG_(strcmp)(name, ".plt")) { if (inrx && !di->plt_present) { @@ -2876,6 +2958,12 @@ Bool ML_(read_elf_debug_info) ( struct _DebugInfo* di ) |dimg| to it. */ vg_assert(dimg == NULL && aimg == NULL); +#if defined(VGO_freebsd) + /* */ + read_and_set_osrel(mimg); + +#endif + /* Look for a build-id */ HChar* buildid = find_buildid(mimg, False, False); @@ -3512,7 +3600,7 @@ Bool ML_(read_elf_debug_info) ( struct _DebugInfo* di ) /* NOTREACHED */ } -#endif // defined(VGO_linux) || defined(VGO_solaris) +#endif // defined(VGO_linux) || defined(VGO_solaris) || defined(VGO_freebsd) /*--------------------------------------------------------------------*/ /*--- end ---*/ diff --git a/coregrind/m_debuginfo/readpdb.c b/coregrind/m_debuginfo/readpdb.c index f9128e30cf..a53cf48c44 100644 --- a/coregrind/m_debuginfo/readpdb.c +++ b/coregrind/m_debuginfo/readpdb.c @@ -33,7 +33,7 @@ The GNU General Public License is contained in the file COPYING. */ -#if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) +#if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) || defined(VGO_freebsd) #include "pub_core_basics.h" #include "pub_core_debuginfo.h" @@ -2604,7 +2604,7 @@ HChar* ML_(find_name_of_pdb_file)( const HChar* pename ) return res; } -#endif // defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) +#endif // defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) || defined(VGO_freebsd) /*--------------------------------------------------------------------*/ /*--- end ---*/ diff --git a/coregrind/m_debuginfo/storage.c b/coregrind/m_debuginfo/storage.c index 48a92b4029..9ba74076c1 100644 --- a/coregrind/m_debuginfo/storage.c +++ b/coregrind/m_debuginfo/storage.c @@ -365,6 +365,11 @@ void ML_(addSym) ( struct _DebugInfo* di, DiSym* sym ) vg_assert(sym->pri_name != NULL); vg_assert(sym->sec_names == NULL); +#if defined(VGO_freebsd) + if (sym->size == 0) + sym->size = 1; +#endif + /* Ignore zero-sized syms. */ if (sym->size == 0) return; @@ -1534,7 +1539,7 @@ Bool preferName ( const DebugInfo* di, vlena = VG_(strlen)(a_name); vlenb = VG_(strlen)(b_name); -# if defined(VGO_linux) || defined(VGO_solaris) +# if defined(VGO_linux) || defined(VGO_solaris) || defined(VGO_freebsd) # define VERSION_CHAR '@' # elif defined(VGO_darwin) # define VERSION_CHAR '$' diff --git a/coregrind/m_debuglog.c b/coregrind/m_debuglog.c index ce4714d1bf..355c3caf5b 100644 --- a/coregrind/m_debuglog.c +++ b/coregrind/m_debuglog.c @@ -435,6 +435,89 @@ static UInt local_sys_getpid ( void ) return (UInt)(__res); } +#elif defined(VGP_x86_freebsd) +static UInt local_sys_write_stderr (const HChar* buf, Int n ) +{ + Int result; + + __asm__ volatile ( + "movl %2, %%eax\n" /* push n */ + "movl %1, %%edx\n" /* push buf */ + "pushl %%eax\n" + "pushl %%edx\n" + "movl $2, %%eax\n" /* push stderr */ + "pushl %%eax\n" + "movl $"VG_STRINGIFY(__NR_write)", %%eax\n" + "pushl %%eax\n" /* push write syscall id */ + "int $0x80\n" /* write(stderr, buf, n) */ + "jnc 1f\n" /* jump if no error */ + "movl $-1, %%eax\n" /* return -1 if error */ + "1: " + "movl %%eax, %0\n" /* __res = eax */ + "addl $16, %%esp\n" /* pop x4 */ + : /*wr*/ "=mr" (result) + : /*rd*/ "g" (buf), "g" (n) + : /*trash*/ "eax", "edx", "cc" + ); + return result >= 0 ? result : -1; +} + +static UInt local_sys_getpid ( void ) +{ + UInt __res; + __asm__ volatile ( + "movl $20, %%eax\n" /* set %eax = __NR_getpid */ + "int $0x80\n" /* getpid() */ + "movl %%eax, %0\n" /* set __res = eax */ + : "=mr" (__res) + : + : "eax" ); + return __res; +} + +#elif defined(VGP_amd64_freebsd) +__attribute__((noinline)) +static UInt local_sys_write_stderr (const HChar* buf, Int n ) +{ + volatile Long block[2]; + block[0] = (Long)buf; + block[1] = n; + __asm__ volatile ( + "subq $256, %%rsp\n" /* don't trash the stack redzone */ + "pushq %%r15\n" /* r15 is callee-save */ + "movq %0, %%r15\n" /* r15 = &block */ + "pushq %%r15\n" /* save &block */ + "movq $"VG_STRINGIFY(__NR_write)", %%rax\n" /* rax = __NR_write */ + "movq $2, %%rdi\n" /* rdi = stderr */ + "movq 0(%%r15), %%rsi\n" /* rsi = buf */ + "movq 8(%%r15), %%rdx\n" /* rdx = n */ + "syscall\n" /* write(stderr, buf, n) */ + "popq %%r15\n" /* reestablish &block */ + "movq %%rax, 0(%%r15)\n" /* block[0] = result */ + "popq %%r15\n" /* restore r15 */ + "addq $256, %%rsp\n" /* restore stack ptr */ + : /*wr*/ + : /*rd*/ "r" (block) + : /*trash*/ "rax", "rdi", "rsi", "rdx", "memory", "cc", "rcx", "r8", "r9", "r11" + ); + if (block[0] < 0) + block[0] = -1; + return (UInt)block[0]; +} + +static UInt local_sys_getpid ( void ) +{ + UInt __res; + __asm__ volatile ( + "movq $20, %%rax\n" /* set %rax = __NR_getpid */ + "syscall\n" /* getpid() */ + "movl %%eax, %0\n" /* set __res = %eax */ + : "=mr" (__res) + : + : "rax", "rcx");//, "r11" ); + return __res; +} + #elif defined(VGP_mips32_linux) || defined(VGP_mips64_linux) static UInt local_sys_write_stderr ( const HChar* buf, Int n ) diff --git a/coregrind/m_gdbserver/gdb/signals.h b/coregrind/m_gdbserver/gdb/signals.h index d04a574771..4857475fa3 100644 --- a/coregrind/m_gdbserver/gdb/signals.h +++ b/coregrind/m_gdbserver/gdb/signals.h @@ -137,6 +137,9 @@ enum target_signal /* Used internally by Solaris threads. See signal(5) on Solaris. */ TARGET_SIGNAL_CANCEL = 76, + /* Similar to the above, but for FreeBSD */ + TARGET_SIGNAL_THR = 77, + /* Yes, this pains me, too. But LynxOS didn't have SIG32, and now GNU/Linux does, and we can't disturb the numbering, since it's part of the remote protocol. Note that in some GDB's diff --git a/coregrind/m_gdbserver/remote-utils.c b/coregrind/m_gdbserver/remote-utils.c index 2d13b79f3d..559d8dd8e9 100644 --- a/coregrind/m_gdbserver/remote-utils.c +++ b/coregrind/m_gdbserver/remote-utils.c @@ -27,6 +27,7 @@ #include "pub_core_libcsignal.h" #include "pub_core_options.h" #include "pub_core_aspacemgr.h" +#include "pub_core_syswrap.h" #include "server.h" @@ -322,7 +323,11 @@ void remote_open (const HChar *name) (Addr) VG_(threads), VG_N_THREADS, sizeof(ThreadState), offsetof(ThreadState, status), offsetof(ThreadState, os_state) + offsetof(ThreadOSstate, lwpid), - 0}; + 0 +#if VEX_HOST_WORDSIZE == 8 + , 0 +#endif + }; user = VG_(getenv)("LOGNAME"); if (user == NULL) user = VG_(getenv)("USER"); @@ -519,12 +524,30 @@ void remote_close (void) from_gdb ? from_gdb : "NULL", to_gdb ? to_gdb : "NULL", shared_mem ? shared_mem : "NULL"); - if (pid == pid_from_to_creator && from_gdb && VG_(unlink) (from_gdb) == -1) - warning ("could not unlink %s\n", from_gdb); - if (pid == pid_from_to_creator && to_gdb && VG_(unlink) (to_gdb) == -1) - warning ("could not unlink %s\n", to_gdb); - if (pid == pid_from_to_creator && shared_mem && VG_(unlink) (shared_mem) == -1) - warning ("could not unlink %s\n", shared_mem); + + // PJF this is not ideal + // if the guest enters capability mode then the unlink calls will fail + // this may well also apply to Linux and seccomp + // I don't have any thoughts on how to fix it, other than forking early on + // having the child run the guest and the parent wait()ing and then + // the parent doing the cleanup + + Bool unlinkPossible = True; +#if defined(VGO_freebsd) + unlinkPossible = (VG_(get_capability_mode)() == False); +#endif + + if (unlinkPossible == True) { + if (pid == pid_from_to_creator && from_gdb && VG_(unlink) (from_gdb) == -1) + warning ("could not unlink %s\n", from_gdb); + if (pid == pid_from_to_creator && to_gdb && VG_(unlink) (to_gdb) == -1) + warning ("could not unlink %s\n", to_gdb); + if (pid == pid_from_to_creator && shared_mem && VG_(unlink) (shared_mem) == -1) + warning ("could not unlink %s\n", shared_mem); + } else { + VG_(debugLog)(1, "remote close", + "cannot unlink gdb pipes\n"); + } free (from_gdb); from_gdb = NULL; free (to_gdb); diff --git a/coregrind/m_gdbserver/signals.c b/coregrind/m_gdbserver/signals.c index 24948a19a4..9aee90fcba 100644 --- a/coregrind/m_gdbserver/signals.c +++ b/coregrind/m_gdbserver/signals.c @@ -404,6 +404,10 @@ enum target_signal target_signal_from_host (int hostsig) if (hostsig == VKI_SIGCANCEL) return TARGET_SIGNAL_CANCEL; #endif +#if defined(VKI_SIGTHR) + if (hostsig == VKI_SIGTHR) + return TARGET_SIGNAL_THR; +#endif #if defined (VKI_SIGLWP) if (hostsig == VKI_SIGLWP) return TARGET_SIGNAL_LWP; @@ -657,6 +661,10 @@ int do_target_signal_to_host (enum target_signal oursig, case TARGET_SIGNAL_CANCEL: return VKI_SIGCANCEL; #endif +#if defined (VKI_SIGTHR) + case TARGET_SIGNAL_THR: + return VKI_SIGTHR; +#endif #if defined (VKI_SIGLWP) case TARGET_SIGNAL_LWP: return VKI_SIGLWP; diff --git a/coregrind/m_libcassert.c b/coregrind/m_libcassert.c index ec63fccefb..35f37f88df 100644 --- a/coregrind/m_libcassert.c +++ b/coregrind/m_libcassert.c @@ -49,7 +49,7 @@ ------------------------------------------------------------------ */ #if defined(VGP_x86_linux) || defined(VGP_x86_darwin) \ - || defined(VGP_x86_solaris) + || defined(VGP_x86_solaris) || defined(VGP_x86_freebsd) # define GET_STARTREGS(srP) \ { UInt eip, esp, ebp; \ __asm__ __volatile__( \ @@ -66,7 +66,7 @@ (srP)->misc.X86.r_ebp = ebp; \ } #elif defined(VGP_amd64_linux) || defined(VGP_amd64_darwin) \ - || defined(VGP_amd64_solaris) + || defined(VGP_amd64_solaris) || defined(VGP_amd64_freebsd) # define GET_STARTREGS(srP) \ { ULong rip, rsp, rbp; \ __asm__ __volatile__( \ @@ -309,7 +309,7 @@ void VG_(exit_now)( Int status ) { #if defined(VGO_linux) (void)VG_(do_syscall1)(__NR_exit_group, status ); -#elif defined(VGO_darwin) || defined(VGO_solaris) +#elif defined(VGO_darwin) || defined(VGO_solaris) || defined(VGO_freebsd) (void)VG_(do_syscall1)(__NR_exit, status ); #else # error Unknown OS diff --git a/coregrind/m_libcfile.c b/coregrind/m_libcfile.c index 3a8fed85d9..598027c6d9 100644 --- a/coregrind/m_libcfile.c +++ b/coregrind/m_libcfile.c @@ -67,6 +67,11 @@ Int VG_(safe_fd)(Int oldfd) return newfd; } +#if defined(VGO_freebsd) +#define M_FILEDESC_BUF 1000000 +static Char filedesc_buf[M_FILEDESC_BUF]; +#endif + /* Given a file descriptor, attempt to deduce its filename. To do this, we use /proc/self/fd/. If this doesn't point to a file, or if it doesn't exist, we return False. @@ -113,6 +118,46 @@ Bool VG_(resolve_filename) ( Int fd, const HChar** result ) *result = NULL; return False; +#elif defined(VGO_freebsd) + Int mib[4]; + SysRes sres; + vki_size_t len; + Char *bp, *eb; + struct vki_kinfo_file *kf; + static HChar *buf = NULL; + static SizeT bufsiz = 0; + + if (buf == NULL) { // first time + bufsiz = 500; + buf = VG_(malloc)("resolve_filename", bufsiz); + } + + mib[0] = VKI_CTL_KERN; + mib[1] = VKI_KERN_PROC; + mib[2] = VKI_KERN_PROC_FILEDESC; + mib[3] = sr_Res(VG_(do_syscall0)(__NR_getpid)); + len = sizeof(filedesc_buf); + sres = VG_(do_syscall6)(__NR___sysctl, (UWord)mib, 4, (UWord)filedesc_buf, + (UWord)&len, 0, 0); + if (sr_isError(sres)) { + VG_(debugLog)(0, "sysctl(kern.proc.filedesc)", "%s\n", VG_(strerror)(sr_Err(sres))); + return False; + } + /* Walk though the list. */ + bp = filedesc_buf; + eb = filedesc_buf + len; + while (bp < eb) { + kf = (struct vki_kinfo_file *)bp; + if (kf->kf_fd == fd) + break; + bp += kf->kf_structsize; + } + if (bp >= eb || *kf->kf_path == '\0') + VG_(strncpy)( buf, "[unknown]", bufsiz ); + else + VG_(strncpy)( buf, kf->kf_path, bufsiz ); + *result = buf; + return True; # elif defined(VGO_darwin) HChar tmp[VKI_MAXPATHLEN+1]; if (0 == VG_(fcntl)(fd, VKI_F_GETPATH, (UWord)tmp)) { @@ -143,6 +188,9 @@ SysRes VG_(mknod) ( const HChar* pathname, Int mode, UWord dev ) # elif defined(VGO_linux) || defined(VGO_darwin) SysRes res = VG_(do_syscall3)(__NR_mknod, (UWord)pathname, mode, dev); +# elif defined(VGO_freebsd) + SysRes res = VG_(do_syscall3)(__NR_freebsd11_mknod, + (UWord)pathname, mode, dev); # elif defined(VGO_solaris) SysRes res = VG_(do_syscall4)(__NR_mknodat, VKI_AT_FDCWD, (UWord)pathname, mode, dev); @@ -158,7 +206,7 @@ SysRes VG_(open) ( const HChar* pathname, Int flags, Int mode ) /* ARM64 wants to use __NR_openat rather than __NR_open. */ SysRes res = VG_(do_syscall4)(__NR_openat, VKI_AT_FDCWD, (UWord)pathname, flags, mode); -# elif defined(VGO_linux) +# elif defined(VGO_linux) || defined(VGO_freebsd) SysRes res = VG_(do_syscall3)(__NR_open, (UWord)pathname, flags, mode); # elif defined(VGO_darwin) @@ -186,7 +234,7 @@ Int VG_(fd_open) (const HChar* pathname, Int flags, Int mode) void VG_(close) ( Int fd ) { /* Hmm. Return value is not checked. That's uncool. */ -# if defined(VGO_linux) || defined(VGO_solaris) +# if defined(VGO_linux) || defined(VGO_solaris) || defined(VGO_freebsd) (void)VG_(do_syscall1)(__NR_close, fd); # elif defined(VGO_darwin) (void)VG_(do_syscall1)(__NR_close_nocancel, fd); @@ -198,7 +246,7 @@ void VG_(close) ( Int fd ) Int VG_(read) ( Int fd, void* buf, Int count) { Int ret; -# if defined(VGO_linux) || defined(VGO_solaris) +# if defined(VGO_linux) || defined(VGO_solaris) || defined(VGO_freebsd) SysRes res = VG_(do_syscall3)(__NR_read, fd, (UWord)buf, count); # elif defined(VGO_darwin) SysRes res = VG_(do_syscall3)(__NR_read_nocancel, fd, (UWord)buf, count); @@ -218,7 +266,7 @@ Int VG_(read) ( Int fd, void* buf, Int count) Int VG_(write) ( Int fd, const void* buf, Int count) { Int ret; -# if defined(VGO_linux) || defined(VGO_solaris) +# if defined(VGO_linux) || defined(VGO_solaris) || defined(VGO_freebsd) SysRes res = VG_(do_syscall3)(__NR_write, fd, (UWord)buf, count); # elif defined(VGO_darwin) SysRes res = VG_(do_syscall3)(__NR_write_nocancel, fd, (UWord)buf, count); @@ -254,6 +302,13 @@ Int VG_(pipe) ( Int fd[2] ) # elif defined(VGO_linux) SysRes res = VG_(do_syscall1)(__NR_pipe, (UWord)fd); return sr_isError(res) ? -1 : 0; +# elif defined(VGO_freebsd) + SysRes res = VG_(do_syscall0)(__NR_freebsd10_pipe); + if (!sr_isError(res)) { + fd[0] = sr_Res(res); + fd[1] = sr_ResHI(res); + } + return sr_isError(res) ? -1 : 0; # elif defined(VGO_darwin) /* __NR_pipe is UX64, so produces a double-word result */ SysRes res = VG_(do_syscall0)(__NR_pipe); @@ -281,7 +336,7 @@ Int VG_(pipe) ( Int fd[2] ) Off64T VG_(lseek) ( Int fd, Off64T offset, Int whence ) { -# if defined(VGO_linux) || defined(VGP_amd64_darwin) +# if defined(VGO_linux) || defined(VGP_amd64_darwin) || defined(VGP_amd64_freebsd) # if defined(__NR__llseek) Off64T result; SysRes res = VG_(do_syscall5)(__NR__llseek, fd, @@ -293,7 +348,7 @@ Off64T VG_(lseek) ( Int fd, Off64T offset, Int whence ) vg_assert(sizeof(Off64T) == sizeof(sr_Res(res))); return sr_isError(res) ? (-1) : sr_Res(res); # endif -# elif defined(VGP_x86_darwin) +# elif defined(VGP_x86_darwin) || defined(VGP_x86_freebsd) SysRes res = VG_(do_syscall4)(__NR_lseek, fd, offset & 0xffffffff, offset >> 32, whence); return sr_isError(res) ? (-1) : sr_Res(res); @@ -424,6 +479,18 @@ SysRes VG_(stat) ( const HChar* file_name, struct vg_stat* vgbuf ) TRANSLATE_TO_vg_stat(vgbuf, &buf64); return res; } +# elif defined(VGO_freebsd) + { + struct vki_freebsd11_stat buf; +#if (FREEBSD_VERS >= FREEBSD_12) + res = VG_(do_syscall2)(__NR_freebsd11_stat, (UWord)file_name, (UWord)&buf); +#else + res = VG_(do_syscall2)(__NR_stat, (UWord)file_name, (UWord)&buf); +#endif + if (!sr_isError(res)) + TRANSLATE_TO_vg_stat(vgbuf, &buf); + return res; + } # else # error Unknown OS # endif @@ -487,6 +554,19 @@ Int VG_(fstat) ( Int fd, struct vg_stat* vgbuf ) TRANSLATE_TO_vg_stat(vgbuf, &buf64); return sr_isError(res) ? (-1) : 0; } +# elif defined(VGO_freebsd) + { + struct vki_freebsd11_stat buf; +#if (FREEBSD_VERS >= FREEBSD_12) + res = VG_(do_syscall2)(__NR_freebsd11_fstat, (RegWord)fd, (RegWord)(Addr)&buf); +#else + res = VG_(do_syscall2)(__NR_fstat, (RegWord)fd, (RegWord)(Addr)&buf); +#endif + if (!sr_isError(res)) { + TRANSLATE_TO_vg_stat(vgbuf, &buf); + } + return sr_isError(res) ? (-1) : 0; + } # else # error Unknown OS # endif @@ -524,7 +604,7 @@ Bool VG_(is_dir) ( const HChar* f ) SysRes VG_(dup) ( Int oldfd ) { -# if defined(VGO_linux) || defined(VGO_darwin) +# if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_freebsd) return VG_(do_syscall1)(__NR_dup, oldfd); # elif defined(VGO_solaris) return VG_(do_syscall3)(__NR_fcntl, oldfd, F_DUPFD, 0); @@ -546,7 +626,7 @@ SysRes VG_(dup2) ( Int oldfd, Int newfd ) return VG_(mk_SysRes_Success)(newfd); } return VG_(do_syscall3)(__NR_dup3, oldfd, newfd, 0); -# elif defined(VGO_linux) || defined(VGO_darwin) +# elif defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_freebsd) return VG_(do_syscall2)(__NR_dup2, oldfd, newfd); # elif defined(VGO_solaris) return VG_(do_syscall3)(__NR_fcntl, oldfd, F_DUP2FD, newfd); @@ -558,7 +638,7 @@ SysRes VG_(dup2) ( Int oldfd, Int newfd ) /* Returns -1 on error. */ Int VG_(fcntl) ( Int fd, Int cmd, Addr arg ) { -# if defined(VGO_linux) || defined(VGO_solaris) +# if defined(VGO_linux) || defined(VGO_solaris) || defined(VGO_freebsd) # if defined(VGP_nanomips_linux) SysRes res = VG_(do_syscall3)(__NR_fcntl64, fd, cmd, arg); # else @@ -581,7 +661,7 @@ Int VG_(rename) ( const HChar* old_name, const HChar* new_name ) SysRes res = VG_(do_syscall5)(__NR_renameat2, VKI_AT_FDCWD, (UWord)old_name, VKI_AT_FDCWD, (UWord)new_name, 0); -# elif defined(VGO_linux) || defined(VGO_darwin) +# elif defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_freebsd) SysRes res = VG_(do_syscall2)(__NR_rename, (UWord)old_name, (UWord)new_name); # else # error "Unknown OS" @@ -594,7 +674,7 @@ Int VG_(unlink) ( const HChar* file_name ) # if defined(VGP_arm64_linux) || defined(VGP_nanomips_linux) SysRes res = VG_(do_syscall2)(__NR_unlinkat, VKI_AT_FDCWD, (UWord)file_name); -# elif defined(VGO_linux) || defined(VGO_darwin) +# elif defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_freebsd) SysRes res = VG_(do_syscall1)(__NR_unlink, (UWord)file_name); # elif defined(VGO_solaris) SysRes res = VG_(do_syscall3)(__NR_unlinkat, VKI_AT_FDCWD, @@ -616,7 +696,7 @@ static HChar *startup_wd; changes. */ void VG_(record_startup_wd) ( void ) { -# if defined(VGO_linux) || defined(VGO_solaris) +# if defined(VGO_linux) || defined(VGO_solaris) || defined(VGO_freebsd) /* Simple: just ask the kernel */ SysRes res; SizeT szB = 0; @@ -624,7 +704,11 @@ void VG_(record_startup_wd) ( void ) szB += 500; startup_wd = VG_(realloc)("startup_wd", startup_wd, szB); VG_(memset)(startup_wd, 0, szB); +# if defined(VGO_linux) || defined(VGO_solaris) res = VG_(do_syscall2)(__NR_getcwd, (UWord)startup_wd, szB-1); +# elif defined(VGO_freebsd) + res = VG_(do_syscall2)(__NR___getcwd, (UWord)startup_wd, szB-1); +# endif } while (sr_isError(res) && sr_Err(res) == VKI_ERANGE); if (sr_isError(res)) { @@ -679,6 +763,8 @@ SysRes VG_(poll) (struct vki_pollfd *fds, Int nfds, Int timeout) (UWord)NULL); # elif defined(VGO_linux) res = VG_(do_syscall3)(__NR_poll, (UWord)fds, nfds, timeout); +# elif defined(VGO_freebsd) + res = VG_(do_syscall3)(__NR_poll, (UWord)fds, nfds, timeout); # elif defined(VGO_darwin) res = VG_(do_syscall3)(__NR_poll_nocancel, (UWord)fds, nfds, timeout); # elif defined(VGO_solaris) @@ -712,7 +798,7 @@ SSizeT VG_(readlink) (const HChar* path, HChar* buf, SizeT bufsiz) # if defined(VGP_arm64_linux) || defined(VGP_nanomips_linux) res = VG_(do_syscall4)(__NR_readlinkat, VKI_AT_FDCWD, (UWord)path, (UWord)buf, bufsiz); -# elif defined(VGO_linux) || defined(VGO_darwin) +# elif defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_freebsd) res = VG_(do_syscall3)(__NR_readlink, (UWord)path, (UWord)buf, bufsiz); # elif defined(VGO_solaris) res = VG_(do_syscall4)(__NR_readlinkat, VKI_AT_FDCWD, (UWord)path, @@ -790,7 +876,7 @@ Int VG_(access) ( const HChar* path, Bool irusr, Bool iwusr, Bool ixusr ) | (ixusr ? VKI_X_OK : 0); # if defined(VGP_arm64_linux) || defined(VGP_nanomips_linux) SysRes res = VG_(do_syscall3)(__NR_faccessat, VKI_AT_FDCWD, (UWord)path, w); -# elif defined(VGO_linux) || defined(VGO_darwin) +# elif defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_freebsd) SysRes res = VG_(do_syscall2)(__NR_access, (UWord)path, w); # elif defined(VGO_solaris) SysRes res = VG_(do_syscall4)(__NR_faccessat, VKI_AT_FDCWD, (UWord)path, @@ -937,6 +1023,15 @@ SysRes VG_(pread) ( Int fd, void* buf, Int count, OffT offset ) || defined(VGP_mips64_linux) || defined(VGP_arm64_linux) res = VG_(do_syscall4)(__NR_pread64, fd, (UWord)buf, count, offset); return res; +# elif defined(VGP_amd64_freebsd) + vg_assert(sizeof(OffT) == 8); + res = VG_(do_syscall4)(__NR_pread, fd, (UWord)buf, count, offset); + return res; +# elif defined(VGP_x86_freebsd) + vg_assert(sizeof(OffT) == 8); + res = VG_(do_syscall5)(__NR_pread, fd, (UWord)buf, count, + offset & 0xffffffff, offset >> 32); + return res; # elif defined(VGP_amd64_darwin) vg_assert(sizeof(OffT) == 8); res = VG_(do_syscall4)(__NR_pread_nocancel, fd, (UWord)buf, count, offset); @@ -1088,7 +1183,7 @@ UShort VG_(ntohs) ( UShort x ) */ Int VG_(connect_via_socket)( const HChar* str ) { -# if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) +# if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) || defined(VGO_freebsd) Int sd, res; struct vki_sockaddr_in servAddr; UInt ip = 0; @@ -1189,7 +1284,7 @@ Int VG_(socket) ( Int domain, Int type, Int protocol ) # elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \ || defined(VGP_mips32_linux) || defined(VGP_mips64_linux) \ - || defined(VGP_arm64_linux) || defined(VGP_nanomips_linux) + || defined(VGP_arm64_linux) || defined(VGP_nanomips_linux) || defined(VGO_freebsd) SysRes res; res = VG_(do_syscall3)(__NR_socket, domain, type, protocol ); return sr_isError(res) ? -1 : sr_Res(res); @@ -1244,7 +1339,7 @@ Int my_connect ( Int sockfd, struct vki_sockaddr_in* serv_addr, Int addrlen ) # elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \ || defined(VGP_mips32_linux) || defined(VGP_mips64_linux) \ - || defined(VGP_arm64_linux) || defined(VGP_nanomips_linux) + || defined(VGP_arm64_linux) || defined(VGP_nanomips_linux) || defined(VGO_freebsd) SysRes res; res = VG_(do_syscall3)(__NR_connect, sockfd, (UWord)serv_addr, addrlen); return sr_isError(res) ? -1 : sr_Res(res); @@ -1291,7 +1386,7 @@ Int VG_(write_socket)( Int sd, const void *msg, Int count ) # elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \ || defined(VGP_mips32_linux) || defined(VGP_mips64_linux) \ - || defined(VGP_arm64_linux) || defined(VGP_nanomips_linux) + || defined(VGP_arm64_linux) || defined(VGP_nanomips_linux) || defined(VGO_freebsd) SysRes res; res = VG_(do_syscall6)(__NR_sendto, sd, (UWord)msg, count, VKI_MSG_NOSIGNAL, 0,0); @@ -1328,7 +1423,8 @@ Int VG_(getsockname) ( Int sd, struct vki_sockaddr *name, Int *namelen) # elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \ || defined(VGP_mips64_linux) || defined(VGP_arm64_linux) \ - || defined(VGP_nanomips_linux) + || defined(VGP_nanomips_linux) || defined(VGO_freebsd) \ + || defined(VGP_mips64_linux) || defined(VGP_arm64_linux) SysRes res; res = VG_(do_syscall3)( __NR_getsockname, (UWord)sd, (UWord)name, (UWord)namelen ); @@ -1367,7 +1463,7 @@ Int VG_(getpeername) ( Int sd, struct vki_sockaddr *name, Int *namelen) # elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \ || defined(VGP_mips64_linux) || defined(VGP_arm64_linux) \ - || defined(VGP_nanomips_linux) + || defined(VGP_nanomips_linux) || defined(VGO_freebsd) SysRes res; res = VG_(do_syscall3)( __NR_getpeername, (UWord)sd, (UWord)name, (UWord)namelen ); @@ -1408,7 +1504,8 @@ Int VG_(getsockopt) ( Int sd, Int level, Int optname, void *optval, # elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \ || defined(VGP_mips32_linux) || defined(VGP_mips64_linux) \ - || defined(VGP_arm64_linux) || defined(VGP_nanomips_linux) + || defined(VGP_arm64_linux) || defined(VGP_nanomips_linux) \ + || defined(VGO_freebsd) SysRes res; res = VG_(do_syscall5)( __NR_getsockopt, (UWord)sd, (UWord)level, (UWord)optname, @@ -1459,7 +1556,7 @@ Int VG_(setsockopt) ( Int sd, Int level, Int optname, void *optval, (UWord)optval, (UWord)optlen ); return sr_isError(res) ? -1 : sr_Res(res); -# elif defined(VGO_darwin) +# elif defined(VGO_darwin) || defined(VGO_freebsd) SysRes res; res = VG_(do_syscall5)( __NR_setsockopt, (UWord)sd, (UWord)level, (UWord)optname, diff --git a/coregrind/m_libcprint.c b/coregrind/m_libcprint.c index 022209a12b..1680082885 100644 --- a/coregrind/m_libcprint.c +++ b/coregrind/m_libcprint.c @@ -1184,7 +1184,7 @@ void VG_(err_config_error) ( const HChar* format, ... ) VG_(sr_as_string)() ------------------------------------------------------------------ */ -#if defined(VGO_linux) +#if defined(VGO_linux) || defined(VGO_freebsd) // FIXME: Does this function need to be adjusted for MIPS's _valEx ? const HChar *VG_(sr_as_string) ( SysRes sr ) { diff --git a/coregrind/m_libcproc.c b/coregrind/m_libcproc.c index ae3804f990..7425c9c887 100644 --- a/coregrind/m_libcproc.c +++ b/coregrind/m_libcproc.c @@ -41,6 +41,7 @@ #include "pub_core_syscall.h" #include "pub_core_xarray.h" #include "pub_core_clientstate.h" +#include "pub_core_debuglog.h" // VG_(debugLog) #if defined(VGO_darwin) /* --- !!! --- EXTERNAL HEADERS start --- !!! --- */ @@ -65,7 +66,7 @@ HChar** VG_(client_envp) = NULL; const HChar *VG_(libdir) = VG_LIBDIR; const HChar *VG_(LD_PRELOAD_var_name) = -#if defined(VGO_linux) || defined(VGO_solaris) +#if defined(VGO_linux) || defined(VGO_solaris) || defined(VGO_freebsd) "LD_PRELOAD"; #elif defined(VGO_darwin) "DYLD_INSERT_LIBRARIES"; @@ -346,7 +347,7 @@ void VG_(client_cmd_and_args)(HChar *buffer, SizeT buf_size) Int VG_(waitpid)(Int pid, Int *status, Int options) { -# if defined(VGO_linux) +# if defined(VGO_linux) || defined(VGO_freebsd) SysRes res = VG_(do_syscall4)(__NR_wait4, pid, (UWord)status, options, 0); return sr_isError(res) ? -1 : sr_Res(res); @@ -581,10 +582,10 @@ Int VG_(system) ( const HChar* cmd ) return zzz == -1 ? -1 : 0; } -Int VG_(sysctl)(Int *name, UInt namelen, void *oldp, SizeT *oldlenp, void *newp, SizeT newlen) +Int VG_(sysctl)(Int *name, UInt namelen, void *oldp, SizeT *oldlenp, const void *newp, SizeT newlen) { SysRes res; -# if defined(VGO_darwin) +# if defined(VGO_darwin) || defined(VGO_freebsd) res = VG_(do_syscall6)(__NR___sysctl, (UWord)name, namelen, (UWord)oldp, (UWord)oldlenp, (UWord)newp, newlen); # else @@ -718,6 +719,15 @@ Int VG_(gettid)(void) return sr_Res(res); +# elif defined(VGO_freebsd) + SysRes res; + long tid; + + res = VG_(do_syscall1)(__NR_thr_self, (UWord)&tid); + if (sr_isError(res)) + tid = sr_Res(VG_(do_syscall0)(__NR_getpid)); + return tid; + # elif defined(VGO_darwin) // Darwin's gettid syscall is something else. // Use Mach thread ports for lwpid instead. @@ -744,7 +754,7 @@ Int VG_(getpgrp) ( void ) /* ASSUMES SYSCALL ALWAYS SUCCEEDS */ # if defined(VGP_arm64_linux) || defined(VGP_nanomips_linux) return sr_Res( VG_(do_syscall1)(__NR_getpgid, 0) ); -# elif defined(VGO_linux) || defined(VGO_darwin) +# elif defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_freebsd) return sr_Res( VG_(do_syscall0)(__NR_getpgrp) ); # elif defined(VGO_solaris) /* Uses the shared pgrpsys syscall, 0 for the getpgrp variant. */ @@ -757,7 +767,7 @@ Int VG_(getpgrp) ( void ) Int VG_(getppid) ( void ) { /* ASSUMES SYSCALL ALWAYS SUCCEEDS */ -# if defined(VGO_linux) || defined(VGO_darwin) +# if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_freebsd) return sr_Res( VG_(do_syscall0)(__NR_getppid) ); # elif defined(VGO_solaris) /* Uses the shared getpid/getppid syscall, val2 contains a parent pid. */ @@ -770,7 +780,7 @@ Int VG_(getppid) ( void ) Int VG_(geteuid) ( void ) { /* ASSUMES SYSCALL ALWAYS SUCCEEDS */ -# if defined(VGO_linux) || defined(VGO_darwin) +# if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_freebsd) { # if defined(__NR_geteuid32) // We use the 32-bit version if it's supported. Otherwise, IDs greater @@ -791,7 +801,7 @@ Int VG_(geteuid) ( void ) Int VG_(getegid) ( void ) { -# if defined(VGO_linux) || defined(VGO_darwin) +# if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_freebsd) /* ASSUMES SYSCALL ALWAYS SUCCEEDS */ # if defined(__NR_getegid32) // We use the 32-bit version if it's supported. Otherwise, IDs greater @@ -838,7 +848,8 @@ Int VG_(getgroups)( Int size, UInt* list ) || defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux) \ || defined(VGO_darwin) || defined(VGP_s390x_linux) \ || defined(VGP_mips32_linux) || defined(VGP_arm64_linux) \ - || defined(VGO_solaris) || defined(VGP_nanomips_linux) + || defined(VGO_solaris) || defined(VGP_nanomips_linux) \ + || defined(VGO_freebsd) SysRes sres; sres = VG_(do_syscall2)(__NR_getgroups, size, (Addr)list); if (sr_isError(sres)) @@ -857,7 +868,7 @@ Int VG_(getgroups)( Int size, UInt* list ) Int VG_(ptrace) ( Int request, Int pid, void *addr, void *data ) { SysRes res; -# if defined(VGO_linux) || defined(VGO_darwin) +# if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_freebsd) res = VG_(do_syscall4)(__NR_ptrace, request, pid, (UWord)addr, (UWord)data); # elif defined(VGO_solaris) /* There is no ptrace syscall on Solaris. Such requests has to be @@ -887,7 +898,7 @@ Int VG_(fork) ( void ) return -1; return sr_Res(res); -# elif defined(VGO_linux) +# elif defined(VGO_linux) || defined(VGO_freebsd) SysRes res; res = VG_(do_syscall0)(__NR_fork); if (sr_isError(res)) @@ -955,6 +966,13 @@ UInt VG_(read_millisecond_timer) ( void ) } } +# elif defined(VGO_freebsd) + { SysRes res; + struct vki_timeval tv_now; + res = VG_(do_syscall2)(__NR_gettimeofday, (UWord)&tv_now, (UWord)NULL); + vg_assert(! sr_isError(res)); + now = tv_now.tv_sec * 1000000ULL + tv_now.tv_usec; + } # elif defined(VGO_darwin) // Weird: it seems that gettimeofday() doesn't fill in the timeval, but // rather returns the tv_sec as the low 32 bits of the result and the @@ -978,7 +996,7 @@ UInt VG_(read_millisecond_timer) ( void ) return (now - base) / 1000; } -# if defined(VGO_linux) || defined(VGO_solaris) +# if defined(VGO_linux) || defined(VGO_solaris) || defined(VGO_freebsd) void VG_(clock_gettime) ( struct vki_timespec *ts, vki_clockid_t clk_id ) { SysRes res; @@ -1030,6 +1048,16 @@ UInt VG_(get_user_milliseconds)(void) } } +# elif defined(VGO_freebsd) + { + struct vki_rusage ru; + VG_(memset)(&ru, 0, sizeof(ru)); + SysRes sr = VG_(do_syscall2)(__NR_getrusage, VKI_RUSAGE_SELF, (UWord)&ru); + if (!sr_isError(sr)) { + res = ru.ru_utime.tv_sec * 1000 + ru.ru_utime.tv_usec / 1000; + } + } + # elif defined(VGO_darwin) res = 0; @@ -1105,6 +1133,62 @@ void VG_(do_atfork_child)(ThreadId tid) (*atforks[i].child)(tid); } +/* --------------------------------------------------------------------- + FreeBSD sysctlbyname(), modfind(), etc + ------------------------------------------------------------------ */ + +#if defined(VGO_freebsd) +Int VG_(sysctlbyname)(const HChar *name, void *oldp, SizeT *oldlenp, const void *newp, SizeT newlen) +{ + Int oid[2]; + Int real_oid[10]; + SizeT oidlen; + int error; + + oid[0] = 0; /* magic */ + oid[1] = 3; /* undocumented */ + oidlen = sizeof(real_oid); + error = VG_(sysctl)(oid, 2, real_oid, &oidlen, name, VG_(strlen)(name)); + if (error < 0) + return error; + oidlen /= sizeof(int); + error = VG_(sysctl)(real_oid, oidlen, oldp, oldlenp, newp, newlen); + return error; +} + +Int VG_(getosreldate)(void) +{ + static Int osreldate = 0; + SizeT osreldatel; + + if (osreldate == 0) { + osreldatel = sizeof(osreldate); + VG_(sysctlbyname)("kern.osreldate", &osreldate, &osreldatel, 0, 0); + } + return (osreldate); +} + +Bool VG_(is32on64)(void) +{ +#if defined(VGP_amd64_freebsd) + return False; +#elif defined(VGP_x86_freebsd) + SysRes res; + struct vg_stat stat_buf; + res = VG_(stat)("/libexec/ld-elf32.so.1", &stat_buf); + if (!sr_isError(res)) { + // file exists, we're running on amd64 + VG_(debugLog)(1, "check-os-bitness", "i386 executable on amd64 kernel\n"); + return True; + } else { + VG_(debugLog)(1, "check-os-bitness", "i386 executable on i386 kernel\n"); + return False; + } +#else +# error Unknown platform +#endif +} +#endif /* --------------------------------------------------------------------- icache invalidation diff --git a/coregrind/m_libcsetjmp.c b/coregrind/m_libcsetjmp.c index abb8f23e72..4f1ecb1502 100644 --- a/coregrind/m_libcsetjmp.c +++ b/coregrind/m_libcsetjmp.c @@ -37,7 +37,7 @@ /* See include/pub_tool_libcsetjmp.h for background and rationale. */ /* The alternative implementations are for ppc{32,64}-linux and - {amd64,x86}-{linux,darwin,solaris}. See #259977. That leaves only + {amd64,x86}-{linux,darwin,solaris,freebsd}. See #259977. That leaves only {arm,s390x}-linux using the gcc builtins now. */ @@ -377,16 +377,16 @@ __asm__( #endif /* VGP_ppc64be_linux */ -/* -------- amd64-{linux,darwin,solaris} -------- */ +/* -------- amd64-{linux,darwin,solaris,freebsd} -------- */ #if defined(VGP_amd64_linux) || defined(VGP_amd64_darwin) || \ - defined(VGP_amd64_solaris) + defined(VGP_amd64_solaris) || defined(VGP_amd64_freebsd) __asm__( ".text" "\n" "" "\n" -#if defined(VGP_amd64_linux) || defined(VGP_amd64_solaris) +#if defined(VGP_amd64_linux) || defined(VGP_amd64_solaris) || defined(VGP_amd64_freebsd) ".global VG_MINIMAL_SETJMP" "\n" // rdi = jmp_buf "VG_MINIMAL_SETJMP:" "\n" @@ -423,7 +423,7 @@ __asm__( "" "\n" -#if defined(VGP_amd64_linux) || defined(VGP_amd64_solaris) +#if defined(VGP_amd64_linux) || defined(VGP_amd64_solaris) || defined(VGP_amd64_freebsd) ".global VG_MINIMAL_LONGJMP" "\n" "VG_MINIMAL_LONGJMP:" "\n" // rdi = jmp_buf @@ -471,19 +471,19 @@ __asm__( #endif ); -#endif /* VGP_amd64_linux || VGP_amd64_darwin || VGP_amd64_solaris */ +#endif /* VGP_amd64_linux || VGP_amd64_darwin || VGP_amd64_solaris || VGP_amd64_freebsd */ -/* -------- x86-{linux,darwin,solaris} -------- */ +/* -------- x86-{linux,darwin,solaris,freebsd} -------- */ #if defined(VGP_x86_linux) || defined(VGP_x86_darwin) || \ - defined(VGP_x86_solaris) + defined(VGP_x86_solaris) || defined(VGP_x86_freebsd) __asm__( ".text" "\n" "" "\n" -#if defined(VGP_x86_linux) || defined(VGP_x86_solaris) +#if defined(VGP_x86_linux) || defined(VGP_x86_solaris) || defined(VGP_x86_freebsd) ".global VG_MINIMAL_SETJMP" "\n" // eax = jmp_buf "VG_MINIMAL_SETJMP:" "\n" @@ -514,7 +514,7 @@ __asm__( "" "\n" -#if defined(VGP_x86_linux) || defined(VGP_x86_solaris) +#if defined(VGP_x86_linux) || defined(VGP_x86_solaris) || defined(VGP_x86_freebsd) ".global VG_MINIMAL_LONGJMP" "\n" "VG_MINIMAL_LONGJMP:" "\n" // eax = jmp_buf @@ -548,7 +548,7 @@ __asm__( #endif ); -#endif /* VGP_x86_linux || VGP_x86_darwin || VGP_x86_solaris */ +#endif /* VGP_x86_linux || VGP_x86_darwin || VGP_x86_solaris || VGP_x86_freebsd */ #if defined(VGP_mips32_linux) diff --git a/coregrind/m_libcsignal.c b/coregrind/m_libcsignal.c index 35d1247f72..a32b53a2f4 100644 --- a/coregrind/m_libcsignal.c +++ b/coregrind/m_libcsignal.c @@ -34,6 +34,7 @@ #include "pub_core_libcassert.h" #include "pub_core_syscall.h" #include "pub_core_libcsignal.h" /* self */ +#include "pub_core_libcproc.h" #if !defined(VGO_solaris) # define _VKI_MAXSIG (_VKI_NSIG - 1) @@ -214,7 +215,7 @@ void VG_(sigcomplementset)( vki_sigset_t* dst, const vki_sigset_t* src ) */ Int VG_(sigprocmask)( Int how, const vki_sigset_t* set, vki_sigset_t* oldset) { -# if defined(VGO_linux) || defined(VGO_solaris) +# if defined(VGO_linux) || defined(VGO_solaris) || defined(VGO_freebsd) # if defined(__NR_rt_sigprocmask) SysRes res = VG_(do_syscall4)(__NR_rt_sigprocmask, how, (UWord)set, (UWord)oldset, @@ -317,6 +318,18 @@ Int VG_(sigaction) ( Int signum, SysRes res = VG_(do_syscall3)(__NR_sigaction, signum, (UWord)act, (UWord)oldact); return sr_isError(res) ? -1 : 0; + +# elif defined(VGO_freebsd) + SysRes res = VG_(do_syscall3)(__NR_sigaction, + signum, (UWord)act, (UWord)oldact); + return sr_isError(res) ? -1 : 0; + + +# elif defined(VGO_freebsd) + SysRes res = VG_(do_syscall3)(__NR_sigaction, + signum, (UWord)act, (UWord)oldact); + return sr_isError(res) ? -1 : 0; + # else # error "Unsupported OS" @@ -329,7 +342,7 @@ void VG_(convert_sigaction_fromK_to_toK)( const vki_sigaction_fromK_t* fromK, /*OUT*/vki_sigaction_toK_t* toK ) { -# if defined(VGO_linux) || defined(VGO_solaris) +# if defined(VGO_linux) || defined(VGO_solaris) || defined(VGO_freebsd) *toK = *fromK; # elif defined(VGO_darwin) toK->ksa_handler = fromK->ksa_handler; @@ -346,7 +359,7 @@ Int VG_(kill)( Int pid, Int signo ) { # if defined(VGO_linux) || defined(VGO_solaris) SysRes res = VG_(do_syscall2)(__NR_kill, pid, signo); -# elif defined(VGO_darwin) +# elif defined(VGO_darwin) || defined(VGO_freebsd) SysRes res = VG_(do_syscall3)(__NR_kill, pid, signo, 1/*posix-compliant*/); # else @@ -385,6 +398,11 @@ Int VG_(tkill)( Int lwpid, Int signo ) # endif return sr_isError(res) ? -1 : 0; +# elif defined(VGO_freebsd) + SysRes res; + res = VG_(do_syscall2)(__NR_thr_kill, lwpid, signo); + return sr_isError(res) ? -1 : 0; + # else # error "Unsupported plat" # endif @@ -411,7 +429,7 @@ Int VG_(tkill)( Int lwpid, Int signo ) /* ---------- sigtimedwait_zero: Linux ----------- */ #if defined(VGO_linux) -Int VG_(sigtimedwait_zero)( const vki_sigset_t *set, +Int VG_(sigtimedwait_zero)( const vki_sigset_t *set, vki_siginfo_t *info ) { static const struct vki_timespec zero = { 0, 0 }; @@ -548,6 +566,19 @@ Int VG_(sigtimedwait_zero)( const vki_sigset_t *set, vki_siginfo_t *info ) return sr_isError(res) ? -1 : sr_Res(res); } +#elif defined(VGO_freebsd) + + +Int VG_(sigtimedwait_zero)( const vki_sigset_t *set, + vki_siginfo_t *info ) +{ + static const struct vki_timespec zero = { 0, 0 }; + + SysRes res = VG_(do_syscall3)(__NR_sigtimedwait, (UWord)set, (UWord)info, + (UWord)&zero); + return sr_isError(res) ? -1 : sr_Res(res); +} + #else # error "Unknown OS" #endif diff --git a/coregrind/m_machine.c b/coregrind/m_machine.c index ab436aec6e..0b60ecc0fd 100644 --- a/coregrind/m_machine.c +++ b/coregrind/m_machine.c @@ -30,6 +30,7 @@ #include "pub_core_threadstate.h" #include "pub_core_libcassert.h" #include "pub_core_libcbase.h" +#include "pub_core_libcprint.h" #include "pub_core_libcfile.h" #include "pub_core_libcprint.h" #include "pub_core_libcproc.h" @@ -906,6 +907,20 @@ Bool VG_(machine_get_hwcaps)( void ) if (!have_cx8) return False; +#if defined(VGP_x86_freebsd) + if (have_sse1 || have_sse2) { + Int sc, error; + SizeT scl; + /* Regardless of whether cpuid says, the OS has to enable SSE first! */ + scl = sizeof(sc); + error = VG_(sysctlbyname)("hw.instruction_sse", &sc, &scl, 0, 0); + if (error == -1 || sc != 1) { + have_sse1 = 0; + have_sse2 = 0; + VG_(message)(Vg_UserMsg, "Warning: cpu has SSE, but the OS has not enabled it. Disabling in valgrind!"); + } + } +#endif /* Figure out if this is an AMD that can do MMXEXT. */ have_mmxext = False; if (0 == VG_(strcmp)(vstr, "AuthenticAMD") @@ -2353,7 +2368,7 @@ Int VG_(machine_get_size_of_largest_guest_register) ( void ) void* VG_(fnptr_to_fnentry)( void* f ) { # if defined(VGP_x86_linux) || defined(VGP_amd64_linux) \ - || defined(VGP_arm_linux) || defined(VGO_darwin) \ + || defined(VGP_arm_linux) || defined(VGO_darwin) || defined(VGO_freebsd) \ || defined(VGP_ppc32_linux) || defined(VGP_ppc64le_linux) \ || defined(VGP_s390x_linux) || defined(VGP_mips32_linux) \ || defined(VGP_mips64_linux) || defined(VGP_arm64_linux) \ diff --git a/coregrind/m_main.c b/coregrind/m_main.c index 68edc4d499..56f9c6cbf0 100644 --- a/coregrind/m_main.c +++ b/coregrind/m_main.c @@ -1120,7 +1120,11 @@ void main_process_cmd_line_options( void ) /* Number of file descriptors that Valgrind tries to reserve for its own use - just a small constant. */ +#if defined(VGO_freebsd) +#define N_RESERVED_FDS (20) +#else #define N_RESERVED_FDS (12) +#endif static void setup_file_descriptors(void) { @@ -1344,6 +1348,27 @@ Int valgrind_main ( Int argc, HChar **argv, HChar **envp ) VG_(exit)(1); } + //-------------------------------------------------------------- + // FreeBSD check security.bsd.unprivileged_proc_debug sysctl + // This needs to be done before aspacemgr starts, otherwise that + // will fail with mysterious error codes + //-------------------------------------------------------------- +#if defined(VGO_freebsd) + Int val; + SizeT len = sizeof(val); + Int error = VG_(sysctlbyname)("security.bsd.unprivileged_proc_debug", &val, &len, 0, 0); + if (error != -1 && val != 1) { + VG_(debugLog)(0, "main", "Valgrind: FATAL:\n"); + VG_(debugLog)(0, "main", "security.bsd.unprivileged_proc_debug sysctl is 0.\n"); + VG_(debugLog)(0, "main", " Set this sysctl with\n"); + VG_(debugLog)(0, "main", " 'sysctl security.bsd.unprivileged_proc_debug=1'.\n"); + VG_(debugLog)(0, "main", " Cannot continue.\n"); + + VG_(exit)(1); + } +#endif + + //-------------------------------------------------------------- // Start up the address space manager, and determine the // approximate location of the client's stack @@ -1550,7 +1575,7 @@ Int valgrind_main ( Int argc, HChar **argv, HChar **envp ) if (!need_help) { VG_(debugLog)(1, "main", "Create initial image\n"); -# if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) +# if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) || defined(VGO_freebsd) the_iicii.argv = argv; the_iicii.envp = envp; the_iicii.toolname = VG_(clo_toolname); @@ -1802,7 +1827,7 @@ Int valgrind_main ( Int argc, HChar **argv, HChar **envp ) addr2dihandle = VG_(newXA)( VG_(malloc), "main.vm.2", VG_(free), sizeof(Addr_n_ULong) ); -# if defined(VGO_linux) || defined(VGO_solaris) +# if defined(VGO_linux) || defined(VGO_solaris) || defined(VGO_freebsd) { Addr* seg_starts; Int n_seg_starts; Addr_n_ULong anu; @@ -2326,7 +2351,7 @@ void shutdown_actions_NORETURN( ThreadId tid, */ static void final_tidyup(ThreadId tid) { -#if defined(VGO_linux) || defined(VGO_solaris) +#if defined(VGO_linux) || defined(VGO_solaris) || defined(VGO_freebsd) Addr freeres_wrapper = VG_(client_freeres_wrapper); vg_assert(VG_(is_running_thread)(tid)); @@ -2474,6 +2499,7 @@ static void final_tidyup(ThreadId tid) VG_(set_default_handler)(VKI_SIGBUS); VG_(set_default_handler)(VKI_SIGILL); VG_(set_default_handler)(VKI_SIGFPE); + VG_(set_default_handler)(VKI_SIGSYS); // We were exiting, so assert that... vg_assert(VG_(is_exiting)(tid)); @@ -2988,7 +3014,7 @@ asm( ".previous \n\t" ); #else -# error "Unknown linux platform" +# error "Unknown platform" #endif /* --- !!! --- EXTERNAL HEADERS start --- !!! --- */ @@ -3256,6 +3282,113 @@ void _start_in_C_solaris ( UWord* pArgc ) VG_(exit)(r); } +/*====================================================================*/ +/*=== Getting to main() alive: FreeBSD ===*/ +/*====================================================================*/ +#elif defined(VGO_freebsd) + +#if defined(VGP_x86_freebsd) +asm("\n" + ".text\n" + "\t.globl _start\n" + "\t.type _start,@function\n" + "_start:\n" + /* set up the new stack in %eax */ + "\tmovl $vgPlain_interim_stack, %eax\n" + "\taddl $"VG_STRINGIFY(VG_STACK_GUARD_SZB)", %eax\n" + "\taddl $"VG_STRINGIFY(VG_DEFAULT_STACK_ACTIVE_SZB)", %eax\n" + /* allocate at least 16 bytes on the new stack, and aligned */ + "\tsubl $16, %eax\n" + "\tandl $~15, %eax\n" + /* install it, and collect the original one */ + "\txchgl %eax, %esp\n" + "\tsubl $12, %esp\n" /* Keep stack 16-byte aligned. */ + /* call _start_in_C_freebsd, passing it the startup %esp */ + "\tpushl %eax\n" + "\tcall _start_in_C_freebsd\n" + "\thlt\n" + ".previous\n" +); +#elif defined(VGP_amd64_freebsd) + +// @todo PJF I don't really understand why this is done this way +// other amd64 platforms just put the new stack address in rdi +// then do an exchange so that the stack pointer points to the +// new stack and rdi (which is the 1st argument in the amd64 sysv abi) +// contains the old stack + +// instead for amd64 the same thing is done for rsi, the second +// function argument and rdi is unchanged +// +// In gdb I see the initial rdp is 8+rsp +// e.g. +// rdi 0x7fffffffe3b0 +// rsp 0x7fffffffe3a8 +// +// Maybe on FreeBSD the pointer to argc is 16byte aligned and can be 8 bytes above the +// start of the stack? + +asm("\n" + ".text\n" + "\t.globl _start\n" + "\t.type _start,@function\n" + "_start:\n" + /* set up the new stack in %rsi */ + "\tmovq $vgPlain_interim_stack, %rsi\n" + "\taddq $"VG_STRINGIFY(VG_STACK_GUARD_SZB)", %rsi\n" + "\taddq $"VG_STRINGIFY(VG_DEFAULT_STACK_ACTIVE_SZB)", %rsi\n" + "\tandq $~15, %rsi\n" + /* install it, and collect the original one */ + "\txchgq %rsi, %rsp\n" + /* call _start_in_C_freebsd, passing it the startup %rsp */ + "\tcall _start_in_C_freebsd\n" + "\thlt\n" + ".previous\n" +); +#endif + +void *memcpy(void *dest, const void *src, size_t n); +void *memcpy(void *dest, const void *src, size_t n) { + return VG_(memcpy)(dest, src, n); +} +void* memmove(void *dest, const void *src, SizeT n); +void* memmove(void *dest, const void *src, SizeT n) { + return VG_(memmove)(dest,src,n); +} +void* memset(void *s, int c, SizeT n); +void* memset(void *s, int c, SizeT n) { + return VG_(memset)(s,c,n); +} + +__attribute__ ((used)) +void _start_in_C_freebsd ( UWord* pArgc, UWord *initial_sp ); +__attribute__ ((used)) +void _start_in_C_freebsd ( UWord* pArgc, UWord *initial_sp ) +{ + Int r; + Word argc = pArgc[0]; + HChar** argv = (HChar**)&pArgc[1]; + HChar** envp = (HChar**)&pArgc[1+argc+1]; + + INNER_REQUEST + ((void) VALGRIND_STACK_REGISTER + (&VG_(interim_stack).bytes[0], + &VG_(interim_stack).bytes[0] + sizeof(VG_(interim_stack)))); + + VG_(memset)( &the_iicii, 0, sizeof(the_iicii) ); + VG_(memset)( &the_iifii, 0, sizeof(the_iifii) ); + +#if defined(VGP_amd64_freebsd) + the_iicii.sp_at_startup = (Addr)initial_sp; +#else + the_iicii.sp_at_startup = (Addr)pArgc; +#endif + + r = valgrind_main( (Int)argc, argv, envp ); + /* NOTREACHED */ + VG_(exit)(r); +} + #else # error "Unknown OS" #endif @@ -3710,6 +3843,13 @@ UWord voucher_mach_msg_set ( UWord arg1 ) #endif +Word VG_(get_usrstack)(void) +{ + return VG_PGROUNDDN(the_iicii.clstack_end - the_iifii.clstack_max_size); +} + + + /*--------------------------------------------------------------------*/ /*--- end ---*/ /*--------------------------------------------------------------------*/ diff --git a/coregrind/m_redir.c b/coregrind/m_redir.c index 1a1117e47e..66a3c0c4f9 100644 --- a/coregrind/m_redir.c +++ b/coregrind/m_redir.c @@ -1212,6 +1212,9 @@ Bool VG_(is_soname_ld_so) (const HChar *soname) if (VG_STREQ(soname, VG_U_LD_LINUX_AARCH64_SO_1)) return True; if (VG_STREQ(soname, VG_U_LD_LINUX_ARMHF_SO_3)) return True; if (VG_STREQ(soname, VG_U_LD_LINUX_MIPSN8_S0_1)) return True; +# elif defined(VGO_freebsd) + if (VG_STREQ(soname, VG_U_LD_ELF_SO_1)) return True; + if (VG_STREQ(soname, VG_U_LD_ELF32_SO_1)) return True; # elif defined(VGO_darwin) if (VG_STREQ(soname, VG_U_DYLD)) return True; # elif defined(VGO_solaris) @@ -1527,6 +1530,8 @@ void VG_(redir_initialise) ( void ) # endif } +# elif defined(VGP_x86_freebsd) || defined(VGP_amd64_freebsd) +/* XXX do something real if needed */ # elif defined(VGP_x86_darwin) /* If we're using memcheck, use these intercepts right from the start, otherwise dyld makes a lot of noise. */ diff --git a/coregrind/m_replacemalloc/vg_replace_malloc.c b/coregrind/m_replacemalloc/vg_replace_malloc.c index 7e0229ca17..9711b6573a 100644 --- a/coregrind/m_replacemalloc/vg_replace_malloc.c +++ b/coregrind/m_replacemalloc/vg_replace_malloc.c @@ -87,18 +87,19 @@ 10140 MALLOPT 10150 MALLOC_TRIM 10160 POSIX_MEMALIGN - 10170 MALLOC_USABLE_SIZE - 10180 PANIC - 10190 MALLOC_STATS - 10200 MALLINFO - 10210 DEFAULT_ZONE - 10220 CREATE_ZONE - 10230 ZONE_FROM_PTR - 10240 ZONE_CHECK - 10250 ZONE_REGISTER - 10260 ZONE_UNREGISTER - 10270 ZONE_SET_NAME - 10280 ZONE_GET_NAME + 10170 ALIGNED_ALL0C + 10180 MALLOC_USABLE_SIZE + 10190 PANIC + 10200 MALLOC_STATS + 10210 MALLINFO + 10220 DEFAULT_ZONE + 10230 CREATE_ZONE + 10240 ZONE_FROM_PTR + 10250 ZONE_CHECK + 10260 ZONE_REGISTER + 10270 ZONE_UNREGISTER + 10280 ZONE_SET_NAME + 10290 ZONE_GET_NAME */ /* 2 Apr 05: the Portland Group compiler, which uses cfront/ARM style @@ -379,6 +380,10 @@ extern int *__errno_location (void) __attribute__((weak)); ALLOC_or_NULL(VG_Z_LIBC_SONAME, malloc, malloc); ALLOC_or_NULL(SO_SYN_MALLOC, malloc, malloc); +#elif defined(VGO_freebsd) + ALLOC_or_NULL(VG_Z_LIBC_SONAME, malloc, malloc); + ALLOC_or_NULL(SO_SYN_MALLOC, malloc, malloc); + #elif defined(VGO_darwin) ALLOC_or_NULL(VG_Z_LIBC_SONAME, malloc, malloc); ALLOC_or_NULL(SO_SYN_MALLOC, malloc, malloc); @@ -417,6 +422,20 @@ extern int *__errno_location (void) __attribute__((weak)); ALLOC_or_BOMB(SO_SYN_MALLOC, _Znwm, __builtin_new); #endif +#elif defined(VGO_freebsd) + // operator new(unsigned int), GNU mangling + #if VG_WORDSIZE == 4 + ALLOC_or_BOMB(VG_Z_LIBSTDCXX_SONAME, _Znwj, __builtin_new); + ALLOC_or_BOMB(VG_Z_LIBCXX_SONAME, _Znwj, __builtin_new); + ALLOC_or_BOMB(SO_SYN_MALLOC, _Znwj, __builtin_new); + #endif + // operator new(unsigned long), GNU mangling + #if VG_WORDSIZE == 8 + ALLOC_or_BOMB(VG_Z_LIBSTDCXX_SONAME, _Znwm, __builtin_new); + ALLOC_or_BOMB(VG_Z_LIBCXX_SONAME, _Znwm, __builtin_new); + ALLOC_or_BOMB(SO_SYN_MALLOC, _Znwm, __builtin_new); + #endif + #elif defined(VGO_darwin) // operator new(unsigned int), GNU mangling #if VG_WORDSIZE == 4 @@ -461,6 +480,20 @@ extern int *__errno_location (void) __attribute__((weak)); ALLOC_or_BOMB_ALIGNED(SO_SYN_MALLOC, _ZnwmSt11align_val_t, __builtin_new_aligned); #endif +#elif defined(VGO_freebsd) + // operator new(unsigned int), GNU mangling + #if VG_WORDSIZE == 4 + ALLOC_or_BOMB_ALIGNED(VG_Z_LIBSTDCXX_SONAME, _ZnwjSt11align_val_t, __builtin_new_aligned); + ALLOC_or_BOMB_ALIGNED(VG_Z_LIBCXX_SONAME, _ZnwjSt11align_val_t, __builtin_new_aligned); + ALLOC_or_BOMB_ALIGNED(SO_SYN_MALLOC, _ZnwjSt11align_val_t, __builtin_new_aligned); + #endif + // operator new(unsigned long), GNU mangling + #if VG_WORDSIZE == 8 + ALLOC_or_BOMB_ALIGNED(VG_Z_LIBSTDCXX_SONAME, _ZnwmSt11align_val_t, __builtin_new_aligned); + ALLOC_or_BOMB_ALIGNED(VG_Z_LIBCXX_SONAME, _ZnwmSt11align_val_t, __builtin_new_aligned); + ALLOC_or_BOMB_ALIGNED(SO_SYN_MALLOC, _ZnwmSt11align_val_t, __builtin_new_aligned); + #endif + #elif defined(VGO_darwin) #elif defined(VGO_solaris) @@ -497,6 +530,20 @@ extern int *__errno_location (void) __attribute__((weak)); ALLOC_or_NULL(SO_SYN_MALLOC, _ZnwmRKSt9nothrow_t, __builtin_new); #endif +#elif defined(VGO_freebsd) + // operator new(unsigned, std::nothrow_t const&), GNU mangling + #if VG_WORDSIZE == 4 + ALLOC_or_NULL(VG_Z_LIBSTDCXX_SONAME, _ZnwjRKSt9nothrow_t, __builtin_new); + ALLOC_or_BOMB(VG_Z_LIBCXX_SONAME, _ZnwjRKSt9nothrow_t, __builtin_new); + ALLOC_or_NULL(SO_SYN_MALLOC, _ZnwjRKSt9nothrow_t, __builtin_new); + #endif + // operator new(unsigned long, std::nothrow_t const&), GNU mangling + #if VG_WORDSIZE == 8 + ALLOC_or_NULL(VG_Z_LIBSTDCXX_SONAME, _ZnwmRKSt9nothrow_t, __builtin_new); + ALLOC_or_NULL(VG_Z_LIBCXX_SONAME, _ZnwmRKSt9nothrow_t, __builtin_new); + ALLOC_or_NULL(SO_SYN_MALLOC, _ZnwjRKSt9nothrow_t, __builtin_new); + #endif + #elif defined(VGO_darwin) // operator new(unsigned, std::nothrow_t const&), GNU mangling #if VG_WORDSIZE == 4 @@ -541,6 +588,20 @@ extern int *__errno_location (void) __attribute__((weak)); ALLOC_or_NULL_ALIGNED(SO_SYN_MALLOC, _ZnwmSt11align_val_tRKSt9nothrow_t, __builtin_new_aligned); #endif +#elif defined(VGO_freebsd) + // operator new(unsigned int, std::align_val_t, std::nothrow_t const&), GNU mangling + #if VG_WORDSIZE == 4 + ALLOC_or_NULL_ALIGNED(VG_Z_LIBSTDCXX_SONAME, _ZnwjSt11align_val_tRKSt9nothrow_t, __builtin_new_aligned); + ALLOC_or_NULL_ALIGNED(VG_Z_LIBCXX_SONAME, _ZnwjSt11align_val_tRKSt9nothrow_t, __builtin_new_aligned); + ALLOC_or_NULL_ALIGNED(SO_SYN_MALLOC, _ZnwjSt11align_val_tRKSt9nothrow_t, __builtin_new_aligned); + #endif + // operator new(unsigned long, std::align_val_t, std::nothrow_t const&), GNU mangling + #if VG_WORDSIZE == 8 + ALLOC_or_NULL_ALIGNED(VG_Z_LIBSTDCXX_SONAME, _ZnwmSt11align_val_tRKSt9nothrow_t, __builtin_new_aligned); + ALLOC_or_NULL_ALIGNED(VG_Z_LIBCXX_SONAME, _ZnwmSt11align_val_tRKSt9nothrow_t, __builtin_new_aligned); + ALLOC_or_NULL_ALIGNED(SO_SYN_MALLOC, _ZnwmSt11align_val_tRKSt9nothrow_t, __builtin_new_aligned); + #endif + #elif defined(VGO_darwin) #elif defined(VGO_solaris) @@ -579,6 +640,20 @@ extern int *__errno_location (void) __attribute__((weak)); ALLOC_or_BOMB(SO_SYN_MALLOC, _Znam, __builtin_vec_new ); #endif +#elif defined(VGO_freebsd) + // operator new[](unsigned int), GNU mangling + #if VG_WORDSIZE == 4 + ALLOC_or_BOMB(VG_Z_LIBSTDCXX_SONAME, _Znaj, __builtin_vec_new ); + ALLOC_or_BOMB(VG_Z_LIBCXX_SONAME, _Znaj, __builtin_vec_new ); + ALLOC_or_BOMB(SO_SYN_MALLOC, _Znaj, __builtin_vec_new ); + #endif + // operator new[](unsigned long), GNU mangling + #if VG_WORDSIZE == 8 + ALLOC_or_BOMB(VG_Z_LIBSTDCXX_SONAME, _Znam, __builtin_vec_new ); + ALLOC_or_BOMB(VG_Z_LIBCXX_SONAME, _Znam, __builtin_vec_new ); + ALLOC_or_BOMB(SO_SYN_MALLOC, _Znaj, __builtin_vec_new ); + #endif + #elif defined(VGO_darwin) // operator new[](unsigned int), GNU mangling #if VG_WORDSIZE == 4 @@ -623,6 +698,20 @@ extern int *__errno_location (void) __attribute__((weak)); ALLOC_or_BOMB_ALIGNED(SO_SYN_MALLOC, _ZnamSt11align_val_t, __builtin_vec_new_aligned ); #endif +#elif defined(VGO_freebsd) + // operator new[](unsigned int, std::align_val_t), GNU mangling + #if VG_WORDSIZE == 4 + ALLOC_or_BOMB_ALIGNED(VG_Z_LIBSTDCXX_SONAME, _ZnajSt11align_val_t, __builtin_vec_new_aligned ); + ALLOC_or_BOMB_ALIGNED(VG_Z_LIBCXX_SONAME, _ZnajSt11align_val_t, __builtin_vec_new_aligned ); + ALLOC_or_BOMB_ALIGNED(SO_SYN_MALLOC, _ZnajSt11align_val_t, __builtin_vec_new_aligned ); + #endif + // operator new[](unsigned long, std::align_val_t), GNU mangling + #if VG_WORDSIZE == 8 + ALLOC_or_BOMB_ALIGNED(VG_Z_LIBSTDCXX_SONAME, _ZnamSt11align_val_t, __builtin_vec_new_aligned ); + ALLOC_or_BOMB_ALIGNED(VG_Z_LIBCXX_SONAME, _ZnamSt11align_val_t, __builtin_vec_new_aligned ); + ALLOC_or_BOMB_ALIGNED(SO_SYN_MALLOC, _ZnamSt11align_val_t, __builtin_vec_new_aligned ); + #endif + #elif defined(VGO_darwin) #elif defined(VGO_solaris) @@ -658,6 +747,20 @@ extern int *__errno_location (void) __attribute__((weak)); ALLOC_or_NULL(SO_SYN_MALLOC, _ZnamRKSt9nothrow_t, __builtin_vec_new ); #endif +#elif defined(VGO_freebsd) + // operator new[](unsigned, std::nothrow_t const&), GNU mangling + #if VG_WORDSIZE == 4 + ALLOC_or_NULL(VG_Z_LIBSTDCXX_SONAME, _ZnajRKSt9nothrow_t, __builtin_vec_new ); + ALLOC_or_NULL(VG_Z_LIBCXX_SONAME, _ZnajRKSt9nothrow_t, __builtin_vec_new ); + ALLOC_or_NULL(SO_SYN_MALLOC, _ZnajRKSt9nothrow_t, __builtin_vec_new ); + #endif + // operator new[](unsigned long, std::nothrow_t const&), GNU mangling + #if VG_WORDSIZE == 8 + ALLOC_or_NULL(VG_Z_LIBSTDCXX_SONAME, _ZnamRKSt9nothrow_t, __builtin_vec_new ); + ALLOC_or_NULL(VG_Z_LIBCXX_SONAME, _ZnamRKSt9nothrow_t, __builtin_vec_new ); + ALLOC_or_NULL(SO_SYN_MALLOC, _ZnajRKSt9nothrow_t, __builtin_vec_new ); + #endif + #elif defined(VGO_darwin) // operator new[](unsigned, std::nothrow_t const&), GNU mangling #if VG_WORDSIZE == 4 @@ -702,6 +805,20 @@ extern int *__errno_location (void) __attribute__((weak)); ALLOC_or_NULL_ALIGNED(SO_SYN_MALLOC, _ZnamSt11align_val_tRKSt9nothrow_t, __builtin_vec_new_aligned ); #endif +#elif defined(VGO_freebsd) + // operator new[](unsigned int, std::align_val_t, std::nothrow_t const&), GNU mangling + #if VG_WORDSIZE == 4 + ALLOC_or_NULL_ALIGNED(VG_Z_LIBSTDCXX_SONAME, _ZnajSt11align_val_tRKSt9nothrow_t, __builtin_vec_new_aligned ); + ALLOC_or_NULL_ALIGNED(VG_Z_LIBCXX_SONAME, _ZnajSt11align_val_tRKSt9nothrow_t, __builtin_vec_new_aligned ); + ALLOC_or_NULL_ALIGNED(SO_SYN_MALLOC, _ZnajSt11align_val_tRKSt9nothrow_t, __builtin_vec_new_aligned ); + #endif + // operator new[](unsigned long, std::align_val_t, std::nothrow_t const&), GNU mangling + #if VG_WORDSIZE == 8 + ALLOC_or_NULL_ALIGNED(VG_Z_LIBSTDCXX_SONAME, _ZnamSt11align_val_tRKSt9nothrow_t, __builtin_vec_new_aligned ); + ALLOC_or_NULL_ALIGNED(VG_Z_LIBCXX_SONAME, _ZnamSt11align_val_tRKSt9nothrow_t, __builtin_vec_new_aligned ); + ALLOC_or_NULL_ALIGNED(SO_SYN_MALLOC, _ZnamSt11align_val_tRKSt9nothrow_t, __builtin_vec_new_aligned ); + #endif + #elif defined(VGO_darwin) #elif defined(VGO_solaris) @@ -754,6 +871,10 @@ extern int *__errno_location (void) __attribute__((weak)); FREE(VG_Z_LIBC_SONAME, free, free ); FREE(SO_SYN_MALLOC, free, free ); +#elif defined(VGO_freebsd) + FREE(VG_Z_LIBC_SONAME, free, free ); + FREE(SO_SYN_MALLOC, free, free ); + #elif defined(VGO_darwin) FREE(VG_Z_LIBC_SONAME, free, free ); FREE(SO_SYN_MALLOC, free, free ); @@ -815,6 +936,21 @@ extern int *__errno_location (void) __attribute__((weak)); #endif +#elif defined(VGO_freebsd) + FREE(VG_Z_LIBSTDCXX_SONAME, _ZdlPv, __builtin_delete ); + FREE(VG_Z_LIBCXX_SONAME, _ZdlPv, __builtin_delete ); + FREE(SO_SYN_MALLOC, _ZdlPv, __builtin_delete ); + // operator delete(void*, unsigned long), C++14, GNU mangling +#if __SIZEOF_SIZE_T__ == 4 + FREE(VG_Z_LIBSTDCXX_SONAME, _ZdlPvj, __builtin_delete ); + FREE(VG_Z_LIBCXX_SONAME, _ZdlPvj, __builtin_delete ); + FREE(SO_SYN_MALLOC, _ZdlPvj, __builtin_delete ); +#elif __SIZEOF_SIZE_T__ == 8 + FREE(VG_Z_LIBSTDCXX_SONAME, _ZdlPvm, __builtin_delete ); + FREE(VG_Z_LIBCXX_SONAME, _ZdlPvm, __builtin_delete ); + FREE(SO_SYN_MALLOC, _ZdlPvm, __builtin_delete ); +#endif + #elif defined(VGO_darwin) // operator delete(void*), GNU mangling //FREE(VG_Z_LIBSTDCXX_SONAME, _ZdlPv, __builtin_delete ); @@ -860,6 +996,23 @@ extern int *__errno_location (void) __attribute__((weak)); FREE(SO_SYN_MALLOC, _ZdlPvmSt11align_val_t, __builtin_delete_aligned ); #endif +#elif defined(VGO_freebsd) + // operator delete(void*, std::align_val_t), GNU mangling + FREE(VG_Z_LIBSTDCXX_SONAME, _ZdlPvSt11align_val_t, __builtin_delete_aligned ); + FREE(VG_Z_LIBCXX_SONAME, _ZdlPvSt11align_val_t, __builtin_delete_aligned ); + FREE(SO_SYN_MALLOC, _ZdlPvSt11align_val_t, __builtin_delete_aligned ); + + // operator delete(void*, unsigned int, std::align_val_t), GNU mangling +#if __SIZEOF_SIZE_T__ == 4 + FREE(VG_Z_LIBSTDCXX_SONAME, _ZdlPvjSt11align_val_t, __builtin_delete_aligned ); + FREE(VG_Z_LIBCXX_SONAME, _ZdlPvjSt11align_val_t, __builtin_delete_aligned ); + FREE(SO_SYN_MALLOC, _ZdlPvjSt11align_val_t, __builtin_delete_aligned ); + // operator delete(void*, unsigned long, std::align_val_t), GNU mangling +#elif __SIZEOF_SIZE_T__ == 8 + FREE(VG_Z_LIBSTDCXX_SONAME, _ZdlPvmSt11align_val_t, __builtin_delete_aligned ); + FREE(VG_Z_LIBCXX_SONAME, _ZdlPvmSt11align_val_t, __builtin_delete_aligned ); + FREE(SO_SYN_MALLOC, _ZdlPvmSt11align_val_t, __builtin_delete_aligned ); +#endif #elif defined(VGO_darwin) @@ -890,6 +1043,12 @@ extern int *__errno_location (void) __attribute__((weak)); FREE(VG_Z_LIBC_SONAME, _ZdlPvRKSt9nothrow_t, __builtin_delete ); FREE(SO_SYN_MALLOC, _ZdlPvRKSt9nothrow_t, __builtin_delete ); +#elif defined(VGO_freebsd) + // operator delete(void*, std::nothrow_t const&), GNU mangling + FREE(VG_Z_LIBSTDCXX_SONAME, _ZdlPvRKSt9nothrow_t, __builtin_delete ); + FREE(VG_Z_LIBCXX_SONAME, _ZdlPvRKSt9nothrow_t, __builtin_delete ); + FREE(SO_SYN_MALLOC, _ZdlPvRKSt9nothrow_t, __builtin_delete ); + #elif defined(VGO_darwin) // operator delete(void*, std::nothrow_t const&), GNU mangling //FREE(VG_Z_LIBSTDCXX_SONAME, _ZdlPvRKSt9nothrow_t, __builtin_delete ); @@ -913,6 +1072,12 @@ extern int *__errno_location (void) __attribute__((weak)); // no sized version of this operator +#elif defined(VGO_freebsd) + // operator delete(void*, std::align_val_t, std::nothrow_t const&), GNU mangling + FREE(VG_Z_LIBSTDCXX_SONAME, _ZdlPvSt11align_val_tRKSt9nothrow_t, __builtin_delete_aligned ); + FREE(VG_Z_LIBCXX_SONAME, _ZdlPvSt11align_val_tRKSt9nothrow_t, __builtin_delete_aligned ); + FREE(SO_SYN_MALLOC, _ZdlPvSt11align_val_tRKSt9nothrow_t, __builtin_delete_aligned ); + #elif defined(VGO_darwin) #elif defined(VGO_solaris) @@ -951,6 +1116,22 @@ extern int *__errno_location (void) __attribute__((weak)); FREE(SO_SYN_MALLOC, _ZdaPvm, __builtin_vec_delete ); #endif +#elif defined(VGO_freebsd) + // operator delete[](void*), GNU mangling + FREE(VG_Z_LIBSTDCXX_SONAME, _ZdaPv, __builtin_vec_delete ); + FREE(VG_Z_LIBCXX_SONAME, _ZdaPv, __builtin_vec_delete ); + FREE(SO_SYN_MALLOC, _ZdaPv, __builtin_vec_delete ); + // operator delete[](void*, unsigned long), C++14, GNU mangling + #if __SIZEOF_SIZE_T__ == 4 + FREE(VG_Z_LIBSTDCXX_SONAME, _ZdaPvj, __builtin_vec_delete ); + FREE(VG_Z_LIBCXX_SONAME, _ZdaPvj, __builtin_vec_delete ); + FREE(SO_SYN_MALLOC, _ZdaPvj, __builtin_vec_delete ); + #elif __SIZEOF_SIZE_T__ == 8 + FREE(VG_Z_LIBSTDCXX_SONAME, _ZdaPvm, __builtin_vec_delete ); + FREE(VG_Z_LIBCXX_SONAME, _ZdaPvm, __builtin_vec_delete ); + FREE(SO_SYN_MALLOC, _ZdaPvm, __builtin_vec_delete ); + #endif + #elif defined(VGO_darwin) // operator delete[](void*), not mangled (for gcc 2.96) //FREE(VG_Z_LIBSTDCXX_SONAME, __builtin_vec_delete, __builtin_vec_delete ); @@ -999,6 +1180,24 @@ extern int *__errno_location (void) __attribute__((weak)); FREE(SO_SYN_MALLOC, _ZdaPvmSt11align_val_t, __builtin_vec_delete_aligned ); #endif +#elif defined(VGO_freebsd) + // operator delete[](void*, std::align_val_t), GNU mangling + FREE(VG_Z_LIBSTDCXX_SONAME, _ZdaPvSt11align_val_t, __builtin_vec_delete_aligned ); + FREE(VG_Z_LIBCXX_SONAME, _ZdaPvSt11align_val_t, __builtin_vec_delete_aligned ); + FREE(SO_SYN_MALLOC, _ZdaPvSt11align_val_t, __builtin_vec_delete_aligned ); + + // operator delete[](void*, unsigned int, std::align_val_t), GNU mangling + #if __SIZEOF_SIZE_T__ == 4 + FREE(VG_Z_LIBSTDCXX_SONAME, _ZdaPvjSt11align_val_t, __builtin_vec_delete_aligned ); + FREE(VG_Z_LIBCXX_SONAME, _ZdaPvjSt11align_val_t, __builtin_vec_delete_aligned ); + FREE(SO_SYN_MALLOC, _ZdaPvjSt11align_val_t, __builtin_vec_delete_aligned ); + // operator delete[](void*, unsigned long, std::align_val_t), GNU mangling + #elif __SIZEOF_SIZE_T__ == 8 + FREE(VG_Z_LIBSTDCXX_SONAME, _ZdaPvmSt11align_val_t, __builtin_vec_delete_aligned ); + FREE(VG_Z_LIBCXX_SONAME, _ZdaPvmSt11align_val_t, __builtin_vec_delete_aligned ); + FREE(SO_SYN_MALLOC, _ZdaPvmSt11align_val_t, __builtin_vec_delete_aligned ); +#endif + #elif defined(VGO_darwin) #elif defined(VGO_solaris) @@ -1027,6 +1226,12 @@ extern int *__errno_location (void) __attribute__((weak)); FREE(VG_Z_LIBC_SONAME, _ZdaPvRKSt9nothrow_t, __builtin_vec_delete ); FREE(SO_SYN_MALLOC, _ZdaPvRKSt9nothrow_t, __builtin_vec_delete ); +#elif defined(VGO_freebsd) + // operator delete[](void*, std::nothrow_t const&), GNU mangling + FREE(VG_Z_LIBSTDCXX_SONAME, _ZdaPvRKSt9nothrow_t, __builtin_vec_delete ); + FREE(VG_Z_LIBCXX_SONAME, _ZdaPvRKSt9nothrow_t, __builtin_vec_delete ); + FREE(SO_SYN_MALLOC, _ZdaPvRKSt9nothrow_t, __builtin_vec_delete ); + #elif defined(VGO_darwin) // operator delete[](void*, std::nothrow_t const&), GNU mangling //FREE(VG_Z_LIBSTDCXX_SONAME, _ZdaPvRKSt9nothrow_t, __builtin_vec_delete ); @@ -1050,6 +1255,12 @@ extern int *__errno_location (void) __attribute__((weak)); // no sized version of this operator +#elif defined(VGO_freebsd) + // operator delete[](void*, std::align_val_t, std::nothrow_t const&), GNU mangling + FREE(VG_Z_LIBSTDCXX_SONAME, _ZdaPvSt11align_val_tRKSt9nothrow_t, __builtin_vec_delete_aligned ); + FREE(VG_Z_LIBCXX_SONAME, _ZdaPvSt11align_val_tRKSt9nothrow_t, __builtin_vec_delete_aligned ); + FREE(SO_SYN_MALLOC, _ZdaPvSt11align_val_tRKSt9nothrow_t, __builtin_vec_delete_aligned ); + #elif defined(VGO_darwin) #elif defined(VGO_solaris) @@ -1116,6 +1327,10 @@ extern int *__errno_location (void) __attribute__((weak)); CALLOC(VG_Z_LIBC_SONAME, calloc); CALLOC(SO_SYN_MALLOC, calloc); +#elif defined(VGO_freebsd) + CALLOC(VG_Z_LIBC_SONAME, calloc); + CALLOC(SO_SYN_MALLOC, calloc); + #elif defined(VGO_darwin) CALLOC(VG_Z_LIBC_SONAME, calloc); CALLOC(SO_SYN_MALLOC, calloc); @@ -1187,10 +1402,46 @@ extern int *__errno_location (void) __attribute__((weak)); return v; \ } +#define REALLOCF(soname, fnname) \ + \ + void* VG_REPLACE_FUNCTION_EZU(10091,soname,fnname) \ + ( void* ptrV, SizeT new_size );\ + void* VG_REPLACE_FUNCTION_EZU(10091,soname,fnname) \ + ( void* ptrV, SizeT new_size ) \ + { \ + void* v; \ + \ + if (!init_done) init(); \ + MALLOC_TRACE("reallocf(%p,%llu)", ptrV, (ULong)new_size ); \ + \ + if (ptrV == NULL) \ + /* We need to call a malloc-like function; so let's use \ + one which we know exists. */ \ + return VG_REPLACE_FUNCTION_EZU(10010,VG_Z_LIBC_SONAME,malloc) \ + (new_size); \ + if (new_size <= 0) { \ + VG_REPLACE_FUNCTION_EZU(10050,VG_Z_LIBC_SONAME,free)(ptrV); \ + MALLOC_TRACE(" = 0\n"); \ + return NULL; \ + } \ + v = (void*)VALGRIND_NON_SIMD_CALL2( info.tl_realloc, ptrV, new_size ); \ + MALLOC_TRACE(" = %p\n", v ); \ + if (v == NULL) \ + VG_REPLACE_FUNCTION_EZU(10050,VG_Z_LIBC_SONAME,free)(ptrV); \ + MALLOC_TRACE(" = %p\n", v ); \ + return v; \ + } + #if defined(VGO_linux) REALLOC(VG_Z_LIBC_SONAME, realloc); REALLOC(SO_SYN_MALLOC, realloc); +#elif defined(VGO_freebsd) + REALLOC(VG_Z_LIBC_SONAME, realloc); + REALLOC(SO_SYN_MALLOC, realloc); + REALLOCF(VG_Z_LIBC_SONAME, reallocf); + REALLOCF(SO_SYN_MALLOC, reallocf); + #elif defined(VGO_darwin) REALLOC(VG_Z_LIBC_SONAME, realloc); REALLOC(SO_SYN_MALLOC, realloc); @@ -1265,6 +1516,10 @@ extern int *__errno_location (void) __attribute__((weak)); MEMALIGN(VG_Z_LIBC_SONAME, memalign); MEMALIGN(SO_SYN_MALLOC, memalign); +#elif defined(VGO_freebsd) + MEMALIGN(VG_Z_LIBC_SONAME, memalign); + MEMALIGN(SO_SYN_MALLOC, memalign); + #elif defined(VGO_darwin) MEMALIGN(VG_Z_LIBC_SONAME, memalign); MEMALIGN(SO_SYN_MALLOC, memalign); @@ -1312,6 +1567,10 @@ extern int *__errno_location (void) __attribute__((weak)); VALLOC(VG_Z_LIBC_SONAME, valloc); VALLOC(SO_SYN_MALLOC, valloc); +#elif defined(VGO_freebsd) + VALLOC(VG_Z_LIBC_SONAME, valloc); + VALLOC(SO_SYN_MALLOC, valloc); + #elif defined(VGO_darwin) VALLOC(VG_Z_LIBC_SONAME, valloc); VALLOC(SO_SYN_MALLOC, valloc); @@ -1429,6 +1688,10 @@ extern int *__errno_location (void) __attribute__((weak)); POSIX_MEMALIGN(VG_Z_LIBC_SONAME, posix_memalign); POSIX_MEMALIGN(SO_SYN_MALLOC, posix_memalign); +#elif defined(VGO_freebsd) + POSIX_MEMALIGN(VG_Z_LIBC_SONAME, posix_memalign); + POSIX_MEMALIGN(SO_SYN_MALLOC, posix_memalign); + #elif defined(VGO_darwin) //POSIX_MEMALIGN(VG_Z_LIBC_SONAME, posix_memalign); @@ -1438,13 +1701,53 @@ extern int *__errno_location (void) __attribute__((weak)); #endif + /*---------------------- aligned_alloc ----------------------*/ + + #define ALIGNED_ALLOC(soname, fnname) \ + \ + void* VG_REPLACE_FUNCTION_EZU(10170,soname,fnname) \ + ( SizeT alignment, SizeT size ); \ + void* VG_REPLACE_FUNCTION_EZU(10170,soname,fnname) \ + ( SizeT alignment, SizeT size ) \ + { \ + void *mem; \ + \ + /* Test whether the alignment argument is valid. It must be \ + a power of two multiple of sizeof (void *). */ \ + if (alignment == 0 \ + || alignment % sizeof (void *) != 0 \ + || (alignment & (alignment - 1)) != 0) \ + return 0; \ + \ + mem = VG_REPLACE_FUNCTION_EZU(10110,VG_Z_LIBC_SONAME,memalign) \ + (alignment, size); \ + \ + return mem; \ + } + + #if defined(VGO_linux) + ALIGNED_ALLOC(VG_Z_LIBC_SONAME, aligned_alloc); + ALIGNED_ALLOC(SO_SYN_MALLOC, aligned_alloc); + +#elif defined(VGO_freebsd) + ALIGNED_ALLOC(G_Z_LIBC_SONAME, aligned_alloc); + ALIGNED_ALLOC(SO_SYN_MALLOC, aligned_alloc); + + #elif defined(VGO_darwin) + //ALIGNED_ALLOC(VG_Z_LIBC_SONAME, aligned_alloc); + + #elif defined(VGO_solaris) + ALIGNED_ALLOC(VG_Z_LIBC_SONAME, aligned_alloc); + ALIGNED_ALLOC(SO_SYN_MALLOC, aligned_alloc); + + #endif /*---------------------- malloc_usable_size ----------------------*/ #define MALLOC_USABLE_SIZE(soname, fnname) \ \ - SizeT VG_REPLACE_FUNCTION_EZU(10170,soname,fnname) ( void* p ); \ - SizeT VG_REPLACE_FUNCTION_EZU(10170,soname,fnname) ( void* p ) \ + SizeT VG_REPLACE_FUNCTION_EZU(10180,soname,fnname) ( void* p ); \ + SizeT VG_REPLACE_FUNCTION_EZU(10180,soname,fnname) ( void* p ) \ { \ SizeT pszB; \ \ @@ -1470,6 +1773,10 @@ extern int *__errno_location (void) __attribute__((weak)); MALLOC_USABLE_SIZE(SO_SYN_MALLOC, dlmalloc_usable_size); # endif +#elif defined(VGO_freebsd) + MALLOC_USABLE_SIZE(VG_Z_LIBC_SONAME, malloc_usable_size); + MALLOC_USABLE_SIZE(SO_SYN_MALLOC, malloc_usable_size); + #elif defined(VGO_darwin) //MALLOC_USABLE_SIZE(VG_Z_LIBC_SONAME, malloc_usable_size); MALLOC_USABLE_SIZE(VG_Z_LIBC_SONAME, malloc_size); @@ -1491,8 +1798,8 @@ static void panic(const char *str) #define PANIC(soname, fnname) \ \ - void VG_REPLACE_FUNCTION_EZU(10180,soname,fnname) ( void ); \ - void VG_REPLACE_FUNCTION_EZU(10180,soname,fnname) ( void ) \ + void VG_REPLACE_FUNCTION_EZU(10190,soname,fnname) ( void ); \ + void VG_REPLACE_FUNCTION_EZU(10190,soname,fnname) ( void ) \ { \ panic(#fnname); \ } @@ -1512,8 +1819,8 @@ static void panic(const char *str) #define MALLOC_STATS(soname, fnname) \ \ - void VG_REPLACE_FUNCTION_EZU(10190,soname,fnname) ( void ); \ - void VG_REPLACE_FUNCTION_EZU(10190,soname,fnname) ( void ) \ + void VG_REPLACE_FUNCTION_EZU(10200,soname,fnname) ( void ); \ + void VG_REPLACE_FUNCTION_EZU(10200,soname,fnname) ( void ) \ { \ /* Valgrind's malloc_stats implementation does nothing. */ \ } @@ -1535,8 +1842,8 @@ static void panic(const char *str) // doesn't know that the call to mallinfo fills in mi. #define MALLINFO(soname, fnname) \ \ - struct vg_mallinfo VG_REPLACE_FUNCTION_EZU(10200,soname,fnname) ( void ); \ - struct vg_mallinfo VG_REPLACE_FUNCTION_EZU(10200,soname,fnname) ( void ) \ + struct vg_mallinfo VG_REPLACE_FUNCTION_EZU(10210,soname,fnname) ( void ); \ + struct vg_mallinfo VG_REPLACE_FUNCTION_EZU(10210,soname,fnname) ( void ) \ { \ static struct vg_mallinfo mi; \ DO_INIT; \ @@ -1597,8 +1904,8 @@ static vki_malloc_zone_t vg_default_zone = { #define DEFAULT_ZONE(soname, fnname) \ \ - void *VG_REPLACE_FUNCTION_EZU(10210,soname,fnname) ( void ); \ - void *VG_REPLACE_FUNCTION_EZU(10210,soname,fnname) ( void ) \ + void *VG_REPLACE_FUNCTION_EZU(10220,soname,fnname) ( void ); \ + void *VG_REPLACE_FUNCTION_EZU(10220,soname,fnname) ( void ) \ { \ return &vg_default_zone; \ } @@ -1611,8 +1918,8 @@ DEFAULT_ZONE(SO_SYN_MALLOC, malloc_default_purgeable_zone); #define CREATE_ZONE(soname, fnname) \ \ - void *VG_REPLACE_FUNCTION_EZU(10220,soname,fnname)(size_t sz, unsigned fl); \ - void *VG_REPLACE_FUNCTION_EZU(10220,soname,fnname)(size_t sz, unsigned fl) \ + void *VG_REPLACE_FUNCTION_EZU(10230,soname,fnname)(size_t sz, unsigned fl); \ + void *VG_REPLACE_FUNCTION_EZU(10230,soname,fnname)(size_t sz, unsigned fl) \ { \ return &vg_default_zone; \ } @@ -1621,8 +1928,8 @@ CREATE_ZONE(VG_Z_LIBC_SONAME, malloc_create_zone); #define ZONE_FROM_PTR(soname, fnname) \ \ - void *VG_REPLACE_FUNCTION_EZU(10230,soname,fnname) ( void* ptr ); \ - void *VG_REPLACE_FUNCTION_EZU(10230,soname,fnname) ( void* ptr ) \ + void *VG_REPLACE_FUNCTION_EZU(10240,soname,fnname) ( void* ptr ); \ + void *VG_REPLACE_FUNCTION_EZU(10240,soname,fnname) ( void* ptr ) \ { \ return &vg_default_zone; \ } @@ -1634,8 +1941,8 @@ ZONE_FROM_PTR(SO_SYN_MALLOC, malloc_zone_from_ptr); // GrP fixme bypass libc's use of zone->introspect->check #define ZONE_CHECK(soname, fnname) \ \ - int VG_REPLACE_FUNCTION_EZU(10240,soname,fnname)(void* zone); \ - int VG_REPLACE_FUNCTION_EZU(10240,soname,fnname)(void* zone) \ + int VG_REPLACE_FUNCTION_EZU(10250,soname,fnname)(void* zone); \ + int VG_REPLACE_FUNCTION_EZU(10250,soname,fnname)(void* zone) \ { \ TRIGGER_MEMCHECK_ERROR_IF_UNDEFINED(zone); \ panic(#fnname); \ @@ -1648,8 +1955,8 @@ ZONE_CHECK(SO_SYN_MALLOC, malloc_zone_check); #define ZONE_REGISTER(soname, fnname) \ \ - void VG_REPLACE_FUNCTION_EZU(10250,soname,fnname)(void* zone); \ - void VG_REPLACE_FUNCTION_EZU(10250,soname,fnname)(void* zone) \ + void VG_REPLACE_FUNCTION_EZU(10260,soname,fnname)(void* zone); \ + void VG_REPLACE_FUNCTION_EZU(10260,soname,fnname)(void* zone) \ { \ TRIGGER_MEMCHECK_ERROR_IF_UNDEFINED(zone); \ } @@ -1660,8 +1967,8 @@ ZONE_REGISTER(SO_SYN_MALLOC, malloc_zone_register); #define ZONE_UNREGISTER(soname, fnname) \ \ - void VG_REPLACE_FUNCTION_EZU(10260,soname,fnname)(void* zone); \ - void VG_REPLACE_FUNCTION_EZU(10260,soname,fnname)(void* zone) \ + void VG_REPLACE_FUNCTION_EZU(10270,soname,fnname)(void* zone); \ + void VG_REPLACE_FUNCTION_EZU(10270,soname,fnname)(void* zone) \ { \ TRIGGER_MEMCHECK_ERROR_IF_UNDEFINED(zone); \ } @@ -1672,8 +1979,8 @@ ZONE_UNREGISTER(SO_SYN_MALLOC, malloc_zone_unregister); #define ZONE_SET_NAME(soname, fnname) \ \ - void VG_REPLACE_FUNCTION_EZU(10270,soname,fnname)(void* zone, char* nm); \ - void VG_REPLACE_FUNCTION_EZU(10270,soname,fnname)(void* zone, char* nm) \ + void VG_REPLACE_FUNCTION_EZU(10280,soname,fnname)(void* zone, char* nm); \ + void VG_REPLACE_FUNCTION_EZU(10280,soname,fnname)(void* zone, char* nm) \ { \ TRIGGER_MEMCHECK_ERROR_IF_UNDEFINED(zone); \ } @@ -1684,8 +1991,8 @@ ZONE_SET_NAME(SO_SYN_MALLOC, malloc_set_zone_name); #define ZONE_GET_NAME(soname, fnname) \ \ - const char* VG_REPLACE_FUNCTION_EZU(10280,soname,fnname)(void* zone); \ - const char* VG_REPLACE_FUNCTION_EZU(10280,soname,fnname)(void* zone) \ + const char* VG_REPLACE_FUNCTION_EZU(10290,soname,fnname)(void* zone); \ + const char* VG_REPLACE_FUNCTION_EZU(10290,soname,fnname)(void* zone) \ { \ TRIGGER_MEMCHECK_ERROR_IF_UNDEFINED(zone); \ return vg_default_zone.zone_name; \ diff --git a/coregrind/m_scheduler/scheduler.c b/coregrind/m_scheduler/scheduler.c index 4420a22d71..ea36cd4f56 100644 --- a/coregrind/m_scheduler/scheduler.c +++ b/coregrind/m_scheduler/scheduler.c @@ -519,7 +519,7 @@ void VG_(vg_yield)(void) /* Tell the kernel we're yielding. */ -# if defined(VGO_linux) || defined(VGO_darwin) +# if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_freebsd) VG_(do_syscall0)(__NR_sched_yield); # elif defined(VGO_solaris) VG_(do_syscall0)(__NR_yield); @@ -545,6 +545,7 @@ static void block_signals(void) VG_(sigdelset)(&mask, VKI_SIGFPE); VG_(sigdelset)(&mask, VKI_SIGILL); VG_(sigdelset)(&mask, VKI_SIGTRAP); + VG_(sigdelset)(&mask, VKI_SIGSYS); /* Can't block these anyway */ VG_(sigdelset)(&mask, VKI_SIGSTOP); @@ -560,6 +561,8 @@ static void os_state_clear(ThreadState *tst) tst->os_state.stk_id = NULL_STK_ID; # if defined(VGO_linux) /* no other fields to clear */ +# elif defined(VGO_freebsd) + /* no other fields to clear */ # elif defined(VGO_darwin) tst->os_state.post_mach_trap_fn = NULL; tst->os_state.pthread = 0; diff --git a/coregrind/m_scheduler/sema.c b/coregrind/m_scheduler/sema.c index 61e10dcf0b..5954cdf8f3 100644 --- a/coregrind/m_scheduler/sema.c +++ b/coregrind/m_scheduler/sema.c @@ -108,8 +108,8 @@ void ML_(sema_down)( vg_sema_t *sema, Bool as_LL ) INNER_REQUEST(ANNOTATE_RWLOCK_ACQUIRED(sema, /*is_w*/1)); if (ret != 1) - VG_(debugLog)(0, "scheduler", - "VG_(sema_down): read returned %d\n", ret); + VG_(debugLog)(1, "scheduler", + "ML_(sema_down): read returned %d\n", ret); if (ret == -VKI_EINTR) goto again; diff --git a/coregrind/m_sigframe/sigframe-common.c b/coregrind/m_sigframe/sigframe-common.c index fd33367bf5..3812c22f83 100644 --- a/coregrind/m_sigframe/sigframe-common.c +++ b/coregrind/m_sigframe/sigframe-common.c @@ -47,7 +47,7 @@ static void track_frame_memory ( Addr addr, SizeT size, ThreadId tid ) VG_TRACK( new_mem_stack_signal, addr - VG_STACK_REDZONE_SZB, size, tid ); } -#if defined(VGO_linux) || defined(VGO_solaris) +#if defined(VGO_linux) || defined(VGO_solaris) || defined(VGO_freebsd) /* Extend the stack segment downwards if needed so as to ensure the new signal frames are mapped to something. Return a Bool diff --git a/coregrind/m_signals.c b/coregrind/m_signals.c index b45afe5992..9210db8e5e 100644 --- a/coregrind/m_signals.c +++ b/coregrind/m_signals.c @@ -514,6 +514,38 @@ typedef struct SigQueue { srP->misc.AMD64.r_rbp = (ULong)(ss->__rbp); } +#elif defined(VGP_x86_freebsd) +# define VG_UCONTEXT_INSTR_PTR(uc) ((UWord)(uc)->uc_mcontext.eip) +# define VG_UCONTEXT_STACK_PTR(uc) ((UWord)(uc)->uc_mcontext.esp) +# define VG_UCONTEXT_FRAME_PTR(uc) ((UWord)(uc)->uc_mcontext.ebp) +# define VG_UCONTEXT_SYSCALL_NUM(uc) ((UWord)(uc)->uc_mcontext.eax) +# define VG_UCONTEXT_SYSCALL_SYSRES(uc) \ + /* Convert the value in uc_mcontext.eax into a SysRes. */ \ + VG_(mk_SysRes_x86_freebsd)( (uc)->uc_mcontext.eax, \ + (uc)->uc_mcontext.edx, ((uc)->uc_mcontext.eflags & 1) != 0 ? True : False) +# define VG_UCONTEXT_LINK_REG(uc) 0 /* What is an LR for anyway? */ +# define VG_UCONTEXT_TO_UnwindStartRegs(srP, uc) \ + { (srP)->r_pc = (ULong)((uc)->uc_mcontext.eip); \ + (srP)->r_sp = (ULong)((uc)->uc_mcontext.esp); \ + (srP)->misc.X86.r_ebp = (uc)->uc_mcontext.ebp; \ + } + +#elif defined(VGP_amd64_freebsd) +# define VG_UCONTEXT_INSTR_PTR(uc) ((uc)->uc_mcontext.rip) +# define VG_UCONTEXT_STACK_PTR(uc) ((uc)->uc_mcontext.rsp) +# define VG_UCONTEXT_FRAME_PTR(uc) ((uc)->uc_mcontext.rbp) +# define VG_UCONTEXT_SYSCALL_NUM(uc) ((uc)->uc_mcontext.rax) +# define VG_UCONTEXT_SYSCALL_SYSRES(uc) \ + /* Convert the value in uc_mcontext.rax into a SysRes. */ \ + VG_(mk_SysRes_amd64_freebsd)( (uc)->uc_mcontext.rax, \ + (uc)->uc_mcontext.rdx, ((uc)->uc_mcontext.rflags & 1) != 0 ? True : False ) +# define VG_UCONTEXT_LINK_REG(uc) 0 /* No LR on amd64 either */ +# define VG_UCONTEXT_TO_UnwindStartRegs(srP, uc) \ + { (srP)->r_pc = (uc)->uc_mcontext.rip; \ + (srP)->r_sp = (uc)->uc_mcontext.rsp; \ + (srP)->misc.AMD64.r_rbp = (uc)->uc_mcontext.rbp; \ + } + #elif defined(VGP_s390x_linux) # define VG_UCONTEXT_INSTR_PTR(uc) ((uc)->uc_mcontext.regs.psw.addr) @@ -631,7 +663,7 @@ typedef struct SigQueue { #if defined(VGO_linux) # define VKI_SIGINFO_si_addr _sifields._sigfault._addr # define VKI_SIGINFO_si_pid _sifields._kill._pid -#elif defined(VGO_darwin) || defined(VGO_solaris) +#elif defined(VGO_darwin) || defined(VGO_solaris) || defined(VGO_freebsd) # define VKI_SIGINFO_si_addr si_addr # define VKI_SIGINFO_si_pid si_pid #else @@ -790,6 +822,9 @@ void calculate_SKSS_from_SCSS ( SKSS* dst ) case VKI_SIGFPE: case VKI_SIGILL: case VKI_SIGTRAP: +#if defined(VGO_freebsd) + case VKI_SIGSYS: +#endif /* For these, we always want to catch them and report, even if the client code doesn't. */ skss_handler = sync_signalhandler; @@ -857,7 +892,8 @@ void calculate_SKSS_from_SCSS ( SKSS* dst ) /* We don't set a signal stack, so ignore */ /* always ask for SA_SIGINFO */ - skss_flags |= VKI_SA_SIGINFO; + if (skss_handler != VKI_SIG_IGN && skss_handler != VKI_SIG_DFL) + skss_flags |= VKI_SA_SIGINFO; /* use our own restorer */ skss_flags |= VKI_SA_RESTORER; @@ -1020,7 +1056,14 @@ extern void my_sigreturn(void); "my_sigreturn:\n" \ "ud2\n" \ ".previous\n" - +#elif defined(VGP_x86_freebsd) || defined(VGP_amd64_freebsd) +/* Not used on FreeBSD */ +# define _MY_SIGRETURN(name) \ + ".text\n" \ + ".globl my_sigreturn\n" \ + "my_sigreturn:\n" \ + "ud2\n" \ + ".previous\n" #else # error Unknown platform #endif @@ -1064,7 +1107,7 @@ static void handle_SCSS_change ( Bool force_update ) ksa.sa_flags = skss.skss_per_sig[sig].skss_flags; # if !defined(VGP_ppc32_linux) && \ !defined(VGP_x86_darwin) && !defined(VGP_amd64_darwin) && \ - !defined(VGP_mips32_linux) && !defined(VGO_solaris) + !defined(VGP_mips32_linux) && !defined(VGO_solaris) && !defined(VGO_freebsd) ksa.sa_restorer = my_sigreturn; # endif /* Re above ifdef (also the assertion below), PaulM says: @@ -1111,7 +1154,8 @@ static void handle_SCSS_change ( Bool force_update ) # if !defined(VGP_ppc32_linux) && \ !defined(VGP_x86_darwin) && !defined(VGP_amd64_darwin) && \ !defined(VGP_mips32_linux) && !defined(VGP_mips64_linux) && \ - !defined(VGP_nanomips_linux) && !defined(VGO_solaris) + !defined(VGP_nanomips_linux) && !defined(VGO_solaris) && \ + !defined(VGO_freebsd) vg_assert(ksa_old.sa_restorer == my_sigreturn); # endif VG_(sigaddset)( &ksa_old.sa_mask, VKI_SIGKILL ); @@ -1231,7 +1275,7 @@ SysRes VG_(do_sys_sigaction) ( Int signo, old_act->ksa_handler = scss.scss_per_sig[signo].scss_handler; old_act->sa_flags = scss.scss_per_sig[signo].scss_flags; old_act->sa_mask = scss.scss_per_sig[signo].scss_mask; -# if !defined(VGP_x86_darwin) && !defined(VGP_amd64_darwin) && \ +# if !defined(VGO_darwin) && !defined(VGO_freebsd) && \ !defined(VGO_solaris) old_act->sa_restorer = scss.scss_per_sig[signo].scss_restorer; # endif @@ -1244,7 +1288,7 @@ SysRes VG_(do_sys_sigaction) ( Int signo, scss.scss_per_sig[signo].scss_mask = new_act->sa_mask; scss.scss_per_sig[signo].scss_restorer = NULL; -# if !defined(VGP_x86_darwin) && !defined(VGP_amd64_darwin) && \ +# if !defined(VGO_darwin) && !defined(VGO_freebsd) && \ !defined(VGO_solaris) scss.scss_per_sig[signo].scss_restorer = new_act->sa_restorer; # endif @@ -1546,6 +1590,9 @@ const HChar *VG_(signame)(Int sigNo) # if defined(VKI_SIGUNUSED) && (VKI_SIGUNUSED != VKI_SIGSYS) case VKI_SIGUNUSED: return "SIGUNUSED"; # endif +# if defined(VKI_SIGINFO) + case VKI_SIGINFO: return "SIGINFO"; +# endif /* Solaris-specific signals. */ # if defined(VKI_SIGEMT) @@ -1601,7 +1648,7 @@ void VG_(kill_self)(Int sigNo) sa.ksa_handler = VKI_SIG_DFL; sa.sa_flags = 0; -# if !defined(VGP_x86_darwin) && !defined(VGP_amd64_darwin) && \ +# if !defined(VGO_darwin) && !defined(VGO_freebsd) && \ !defined(VGO_solaris) sa.sa_restorer = 0; # endif @@ -1638,7 +1685,21 @@ static Bool is_signal_from_kernel(ThreadId tid, int signum, int si_code) // macros but we don't use them here because other platforms don't have // them. return ( si_code > VKI_SI_USER ? True : False ); +#elif defined(VGO_freebsd) + + // The comment below seems a bit out of date. From the siginfo manpage + // Full support for POSIX signal information first appeared in FreeBSD 7.0. + // The codes SI_USER and SI_KERNEL can be generated as of FreeBSD 8.1. The + // code SI_LWP can be generated as of FreeBSD 9.0. + if (si_code == VKI_SI_USER || si_code == VKI_SI_LWP) + return False; + + // It looks like there's no reliable way to say where the signal came from + if (VG_(threads)[tid].status == VgTs_WaitSys) { + return False; + } else + return True; # elif defined(VGO_darwin) // On Darwin 9.6.0, the si_code is completely unreliable. It should be the // case that 0 means "user", and >0 means "kernel". But: @@ -1857,6 +1918,14 @@ static void default_action(const vki_siginfo_t *info, ThreadId tid) case VKI_BUS_ADRALN: event = "Invalid address alignment"; break; case VKI_BUS_ADRERR: event = "Non-existent physical address"; break; case VKI_BUS_OBJERR: event = "Hardware error"; break; +#if defined(VGO_freebsd) + // This si_code can be generated for both SIGBUS and SIGSEGV on FreeBSD + // This is undocumented + case VKI_SEGV_PAGE_FAULT: + // It should get replaced with this non-standard value, which is documented. + case VKI_BUS_OOMERR: + event = "Access not within mapped region"; +#endif } break; } /* switch (sigNo) */ @@ -2322,7 +2391,7 @@ static int sanitize_si_code(int si_code) mask them off) sign extends them when exporting to user space so we do the same thing here. */ return (Short)si_code; -#elif defined(VGO_darwin) || defined(VGO_solaris) +#elif defined(VGO_darwin) || defined(VGO_solaris) || defined(VGO_freebsd) return si_code; #else # error Unknown OS @@ -2459,9 +2528,9 @@ void async_signalhandler ( Int sigNo, info->si_code = sanitize_si_code(info->si_code); if (VG_(clo_trace_signals)) - VG_(dmsg)("async signal handler: signal=%d, tid=%u, si_code=%d, " + VG_(dmsg)("async signal handler: signal=%d, vgtid=%d, tid=%u, si_code=%d, " "exitreason %s\n", - sigNo, tid, info->si_code, + sigNo, VG_(gettid)(), tid, info->si_code, VG_(name_of_VgSchedReturnCode)(tst->exitreason)); /* See similar logic in VG_(poll_signals). */ @@ -2947,7 +3016,7 @@ void pp_ksigaction ( vki_sigaction_toK_t* sa ) VG_(printf)("pp_ksigaction: handler %p, flags 0x%x, restorer %p\n", sa->ksa_handler, (UInt)sa->sa_flags, -# if !defined(VGP_x86_darwin) && !defined(VGP_amd64_darwin) && \ +# if !defined(VGO_darwin) && !defined(VGO_freebsd) && \ !defined(VGO_solaris) sa->sa_restorer # else @@ -2970,7 +3039,7 @@ void VG_(set_default_handler)(Int signo) sa.ksa_handler = VKI_SIG_DFL; sa.sa_flags = 0; -# if !defined(VGP_x86_darwin) && !defined(VGP_amd64_darwin) && \ +# if !defined(VGO_darwin) && !defined(VGO_freebsd) && \ !defined(VGO_solaris) sa.sa_restorer = 0; # endif @@ -3092,7 +3161,7 @@ void VG_(sigstartup_actions) ( void ) tsa.ksa_handler = (void *)sync_signalhandler; tsa.sa_flags = VKI_SA_SIGINFO; -# if !defined(VGP_x86_darwin) && !defined(VGP_amd64_darwin) && \ +# if !defined(VGO_darwin) && !defined(VGO_freebsd) && \ !defined(VGO_solaris) tsa.sa_restorer = 0; # endif @@ -3120,7 +3189,7 @@ void VG_(sigstartup_actions) ( void ) scss.scss_per_sig[i].scss_mask = sa.sa_mask; scss.scss_per_sig[i].scss_restorer = NULL; -# if !defined(VGP_x86_darwin) && !defined(VGP_amd64_darwin) && \ +# if !defined(VGO_darwin) && !defined(VGO_freebsd) && \ !defined(VGO_solaris) scss.scss_per_sig[i].scss_restorer = sa.sa_restorer; # endif diff --git a/coregrind/m_stacktrace.c b/coregrind/m_stacktrace.c index d26280cc90..9467f3caf6 100644 --- a/coregrind/m_stacktrace.c +++ b/coregrind/m_stacktrace.c @@ -42,6 +42,7 @@ #include "pub_core_xarray.h" #include "pub_core_clientstate.h" // VG_(client__dl_sysinfo_int80) #include "pub_core_trampoline.h" +#include "config.h" /*------------------------------------------------------------*/ @@ -92,7 +93,7 @@ do { \ /* ------------------------ x86 ------------------------- */ #if defined(VGP_x86_linux) || defined(VGP_x86_darwin) \ - || defined(VGP_x86_solaris) + || defined(VGP_x86_solaris) || defined(VGP_x86_freebsd) #define N_FP_CF_VERIF 1021 // prime number so that size of fp_CF_verif is just below 4K or 8K @@ -238,14 +239,14 @@ UInt VG_(get_StackTrace_wrk) ( ThreadId tid_if_known, if (fp_min + 512 >= fp_max) { /* If the stack limits look bogus, don't poke around ... but don't bomb out either. */ -# elif defined(VGO_solaris) +# elif defined(VGO_solaris) || defined(VGO_freebsd) if (fp_max == 0) { /* VG_(get_StackTrace)() can be called by tools very early when various tracing options are enabled. Don't proceed further if the stack limits look bogus. */ # endif -# if defined(VGO_linux) || defined(VGO_solaris) +# if defined(VGO_linux) || defined(VGO_solaris) || defined(VGO_freebsd) if (sps) sps[0] = uregs.xsp; if (fps) fps[0] = uregs.xbp; ips[0] = uregs.xip; @@ -281,6 +282,26 @@ UInt VG_(get_StackTrace_wrk) ( ThreadId tid_if_known, i = 1; if (do_stats) stats.nr++; + // Does this apply to macOS 10.14 and earlier? +# if defined(VGO_freebsd) && (FREEBSD_VERS < FREEBSD_13) + if (VG_(is_valid_tid)(tid_if_known) && + VG_(is_in_syscall)(tid_if_known) && + i < max_n_ips) { + /* On FreeBSD, all the system call stubs have no function + * prolog. So instead of top of the stack being a new + * frame comprising a saved BP and a return address, we + * just have the return address in the caller's frame. + * Adjust for this by recording the return address. + */ + if (debug) + VG_(printf)(" in syscall, use XSP-1\n"); + ips[i] = *(Addr *)uregs.xsp - 1; + if (sps) sps[i] = uregs.xsp; + if (fps) fps[i] = uregs.xbp; + i++; + } +# endif + while (True) { if (i >= max_n_ips) @@ -498,7 +519,7 @@ UInt VG_(get_StackTrace_wrk) ( ThreadId tid_if_known, /* ----------------------- amd64 ------------------------ */ #if defined(VGP_amd64_linux) || defined(VGP_amd64_darwin) \ - || defined(VGP_amd64_solaris) + || defined(VGP_amd64_solaris) || defined(VGP_amd64_freebsd) UInt VG_(get_StackTrace_wrk) ( ThreadId tid_if_known, /*OUT*/Addr* ips, UInt max_n_ips, @@ -573,16 +594,18 @@ UInt VG_(get_StackTrace_wrk) ( ThreadId tid_if_known, VG_(printf)(" ipsS[%d]=%#08lx rbp %#08lx rsp %#08lx\n", i-1, ips[i-1], uregs.xbp, uregs.xsp); -# if defined(VGO_darwin) +# if defined(VGO_darwin) || (defined(VGO_freebsd) && (FREEBSD_VERS < FREEBSD_13)) if (VG_(is_valid_tid)(tid_if_known) && VG_(is_in_syscall)(tid_if_known) && i < max_n_ips) { - /* On Darwin, all the system call stubs have no function + /* On Darwin and FreeBSD, all the system call stubs have no function * prolog. So instead of top of the stack being a new * frame comprising a saved BP and a return address, we * just have the return address in the caller's frame. * Adjust for this by recording the return address. */ + if (debug) + VG_(printf)(" in syscall, use XSP-1\n"); ips[i] = *(Addr *)uregs.xsp - 1; if (sps) sps[i] = uregs.xsp; if (fps) fps[i] = uregs.xbp; diff --git a/coregrind/m_syscall.c b/coregrind/m_syscall.c index c12632d366..ad3d71602e 100644 --- a/coregrind/m_syscall.c +++ b/coregrind/m_syscall.c @@ -364,6 +364,42 @@ SysRes VG_(mk_SysRes_amd64_solaris) ( Bool isErr, ULong val, ULong val2 ) return res; } + +#elif defined(VGO_freebsd) + +SysRes VG_(mk_SysRes_x86_freebsd) ( UInt val, UInt val2, Bool err ) { + SysRes r; + r._isError = err; + r._val = val; + r._val2 = val2; + return r; +} + +SysRes VG_(mk_SysRes_amd64_freebsd) ( ULong val, ULong val2, Bool err ) { + SysRes r; + r._isError = err; + r._val = val; + r._val2 = val2; + return r; +} + +/* Generic constructors. */ +SysRes VG_(mk_SysRes_Error) ( UWord err ) { + SysRes r; + r._val = err; + r._val2 = 0; + r._isError = True; + return r; +} + +SysRes VG_(mk_SysRes_Success) ( UWord res ) { + SysRes r; + r._val = res; + r._val2 = 0; + r._isError = False; + return r; +} + #else # error "Unknown OS" #endif @@ -671,6 +707,82 @@ asm( ".previous\n" ); +#elif defined(VGP_x86_freebsd) +/* Incoming args (syscall number + up to 8 args) are on the stack. + FreeBSD has a syscall called 'syscall' that takes all args (including + the syscall number) off the stack. Since we're called, the return + address is on the stack as expected, so we can just call syscall(2) + and it Just Works. Error is when carry is set. +*/ +extern ULong do_syscall_WRK ( + UWord syscall_no, + UWord a1, UWord a2, UWord a3, + UWord a4, UWord a5, UWord a6, + UWord a7, UWord a8, UInt *flags + ); +asm( +".text\n" +"do_syscall_WRK:\n" +" movl $0,%eax\n" /* syscall number = "syscall" (0) to avoid stack frobbing +*/ +" int $0x80\n" +" jb 1f\n" +" ret\n" +"1: movl 40(%esp),%ecx\n" /* store carry in *flags */ +" movl $1,(%ecx)\n" +" ret\n" +".previous\n" +); + +#elif defined(VGP_amd64_freebsd) +extern UWord do_syscall_WRK ( + UWord syscall_no, /* %rdi */ + UWord a1, /* %rsi */ + UWord a2, /* %rdx */ + UWord a3, /* %rcx */ + UWord a4, /* %r8 */ + UWord a5, /* %r9 */ + UWord a6, /* 8(%rsp) */ + UWord a7, /* 16(%rsp) */ + UWord a8, /* 24(%rsp) */ + UInt *flags, /* 32(%rsp) */ + UWord *rv2 /* 40(%rsp) */ + ); +asm( +".text\n" +"do_syscall_WRK:\n" + /* Convert function calling convention --> syscall calling + convention */ +" pushq %rbp\n" +" movq %rsp, %rbp\n" +" movq %rdi, %rax\n" /* syscall_no */ +" movq %rsi, %rdi\n" /* a1 */ +" movq %rdx, %rsi\n" /* a2 */ +" movq %rcx, %rdx\n" /* a3 */ +" movq %r8, %r10\n" /* a4 */ +" movq %r9, %r8\n" /* a5 */ +" movq 16(%rbp), %r9\n" /* a6 last arg from stack, account for %rbp */ +" movq 24(%rbp), %r11\n" /* a7 from stack */ +" pushq %r11\n" +" movq 32(%rbp), %r11\n" /* a8 from stack */ +" pushq %r11\n" +" subq $8,%rsp\n" /* fake return addr */ +" syscall\n" +" jb 1f\n" +" movq 48(%rbp),%rsi\n" +" movq %rdx, (%rsi)\n" +" movq %rbp, %rsp\n" +" popq %rbp\n" +" ret\n" +"1:\n" +" movq 40(%rbp), %rsi\n" +" movl $1,(%rsi)\n" +" movq %rbp, %rsp\n" +" popq %rbp\n" +" ret\n" +".previous\n" +); + #elif defined(VGP_x86_darwin) /* Incoming args (syscall number + up to 8 args) come in on the stack @@ -1027,6 +1139,21 @@ SysRes VG_(do_syscall) ( UWord sysno, RegWord a1, RegWord a2, RegWord a3, UWord val = do_syscall_WRK(sysno,a1,a2,a3,a4,a5,a6); return VG_(mk_SysRes_amd64_linux)( val ); +# elif defined(VGP_x86_freebsd) + ULong val; + UInt err = 0; + val = do_syscall_WRK(sysno, a1, a2, a3, a4, a5, + a6, a7, a8, &err); + return VG_(mk_SysRes_x86_freebsd)( (UInt)val, (UInt)(val>>32), (err & 1) != 0 ? True : False); + +# elif defined(VGP_amd64_freebsd) + UWord val; + UWord val2 = 0; + UInt err = 0; + val = do_syscall_WRK(sysno, a1, a2, a3, a4, a5, + a6, a7, a8, &err, &val2); + return VG_(mk_SysRes_amd64_freebsd)( val, val2, (err & 1) != 0 ? True : False); + # elif defined(VGP_ppc32_linux) ULong ret = do_syscall_WRK(sysno,a1,a2,a3,a4,a5,a6); UInt val = (UInt)(ret>>32); @@ -1257,6 +1384,9 @@ const HChar* VG_(strerror) ( UWord errnum ) case VKI_EOVERFLOW: return "Value too large for defined data type"; # if defined(VKI_ERESTARTSYS) case VKI_ERESTARTSYS: return "ERESTARTSYS"; +# endif +# if defined(VKI_ERESTART) + case VKI_ERESTART: return "ERESTART"; # endif default: return "VG_(strerror): unknown error"; } diff --git a/coregrind/m_syswrap/priv_types_n_macros.h b/coregrind/m_syswrap/priv_types_n_macros.h index 7a9fd3260f..3966cfa604 100644 --- a/coregrind/m_syswrap/priv_types_n_macros.h +++ b/coregrind/m_syswrap/priv_types_n_macros.h @@ -50,6 +50,9 @@ /* Arguments for a syscall. */ typedef struct SyscallArgs { +#if defined(VGO_freebsd) + Word klass; +#endif Word sysno; RegWord arg1; RegWord arg2; @@ -109,6 +112,31 @@ typedef Int o_arg6; Int o_arg7; Int uu_arg8; +# elif defined(VGP_x86_freebsd) + Int s_arg1; + Int s_arg2; + Int s_arg3; + Int s_arg4; + Int s_arg5; + Int s_arg6; + Int s_arg7; + Int s_arg8; +# elif defined(VGP_amd64_freebsd) + Int o_arg1; + Int o_arg2; + Int o_arg3; + Int o_arg4; + Int o_arg5; + // arg6 can either be a register or a stack + // depending on whether the syscall is 'syscall/__syscall' + // or any other syscall + union { + Int o_arg6; + Int s_arg6; + }; + Int s_arg7; + Int s_arg8; + Bool arg6_is_reg; # elif defined(VGP_mips32_linux) Int o_arg1; Int o_arg2; @@ -213,6 +241,10 @@ extern const UInt ML_(syscall_table_size); extern SyscallTableEntry* ML_(get_solaris_syscall_entry)( UInt sysno ); +#elif defined(VGO_freebsd) +extern +const SyscallTableEntry* ML_(get_freebsd_syscall_entry)( UInt sysno ); + #else # error Unknown OS #endif @@ -241,9 +273,9 @@ SyscallTableEntry* ML_(get_solaris_syscall_entry)( UInt sysno ); void vgSysWrap_##auxstr##_##name##_before \ ( ThreadId tid, \ SyscallArgLayout* layout, \ - /*MOD*/SyscallArgs* arrghs, \ - /*OUT*/SyscallStatus* status, \ - /*OUT*/UWord* flags \ + /*MOD*/ SyscallArgs* arrghs, \ + /*OUT*/ SyscallStatus* status, \ + /*OUT*/ UWord* flags \ ) #define DEFN_POST_TEMPLATE(auxstr, name) \ @@ -291,7 +323,7 @@ SyscallTableEntry* ML_(get_solaris_syscall_entry)( UInt sysno ); vgSysWrap_##auxstr##_##name##_after /* Add a generic wrapper to a syscall table. */ -#if defined(VGO_linux) || defined(VGO_solaris) +#if defined(VGO_linux) || defined(VGO_solaris) || defined(VGO_freebsd) # define GENX_(sysno, name) WRAPPER_ENTRY_X_(generic, sysno, name) # define GENXY(sysno, name) WRAPPER_ENTRY_XY(generic, sysno, name) #elif defined(VGO_darwin) @@ -306,6 +338,11 @@ SyscallTableEntry* ML_(get_solaris_syscall_entry)( UInt sysno ); #define LINX_(sysno, name) WRAPPER_ENTRY_X_(linux, sysno, name) #define LINXY(sysno, name) WRAPPER_ENTRY_XY(linux, sysno, name) +/* Add a FreeBSD-specific, arch-independent wrapper to a syscall + table. */ +#define BSDX_(sysno, name) WRAPPER_ENTRY_X_(freebsd, sysno, name) +#define BSDXY(sysno, name) WRAPPER_ENTRY_XY(freebsd, sysno, name) + /* --------------------------------------------------------------------- Macros useful for writing wrappers concisely. These refer to the @@ -325,6 +362,7 @@ SyscallTableEntry* ML_(get_solaris_syscall_entry)( UInt sysno ); #define ARG6 (arrghs->arg6) #define ARG7 (arrghs->arg7) #define ARG8 (arrghs->arg8) +#define RETVAL2 (arrghs->retval2) /* Provide signed versions of the argument values */ #define SARG1 ((Word)ARG1) @@ -351,7 +389,7 @@ static inline UWord getRES ( SyscallStatus* st ) { return sr_Res(st->sres); } -#if defined(VGO_darwin) || defined(VGO_solaris) +#if defined(VGO_darwin) || defined(VGO_solaris) || defined(VGO_freebsd) static inline UWord getRESHI ( SyscallStatus* st ) { vg_assert(st->what == SsComplete); vg_assert(!sr_isError(st->sres)); @@ -372,6 +410,13 @@ static inline UWord getERR ( SyscallStatus* st ) { status->sres = VG_(mk_SysRes_Success)(zzz); \ } while (0) +#ifdef VGO_freebsd +#define SET_STATUS_Success2(zzz, zzz2) \ + do { status->what = SsComplete; \ + status->sres = VG_(mk_SysRes_amd64_freebsd)(zzz, zzz2, False); \ + } while (0) +#endif + #define SET_STATUS_Failure(zzz) \ do { Word wzz = (Word)(zzz); \ /* Catch out wildly bogus error values. */ \ @@ -424,6 +469,35 @@ static inline UWord getERR ( SyscallStatus* st ) { # define PRA5(s,t,a) PRRAn(5,s,t,a) # define PRA6(s,t,a) PRRAn(6,s,t,a) +#elif defined(VGP_x86_freebsd) + /* Up to 8 parameters, all on the stack. */ +# define PRA1(s,t,a) PSRAn(1,s,t,a) +# define PRA2(s,t,a) PSRAn(2,s,t,a) +# define PRA3(s,t,a) PSRAn(3,s,t,a) +# define PRA4(s,t,a) PSRAn(4,s,t,a) +# define PRA5(s,t,a) PSRAn(5,s,t,a) +# define PRA6(s,t,a) PSRAn(6,s,t,a) +# define PRA7(s,t,a) PSRAn(7,s,t,a) +# define PRA8(s,t,a) PSRAn(8,s,t,a) + +#elif defined(VGP_amd64_freebsd) + /* Up to 8 parameters, 6 in registers, 2 on the stack. */ + /* or 7 in registers and 3 on the stack */ +# define PRA1(s,t,a) PRRAn(1,s,t,a) +# define PRA2(s,t,a) PRRAn(2,s,t,a) +# define PRA3(s,t,a) PRRAn(3,s,t,a) +# define PRA4(s,t,a) PRRAn(4,s,t,a) +# define PRA5(s,t,a) PRRAn(5,s,t,a) +# define PRA6(s,t,a) \ + do { \ + if (layout->arg6_is_reg) \ + PRRAn(6,s,t,a); \ + else \ + PSRAn(6,s,t,a); \ + } while (0) +# define PRA7(s,t,a) PSRAn(7,s,t,a) +# define PRA8(s,t,a) PSRAn(8,s,t,a) + #elif defined(VGP_x86_darwin) || defined(VGP_x86_solaris) /* Up to 8 parameters, all on the stack. */ # define PRA1(s,t,a) PSRAn(1,s,t,a) diff --git a/coregrind/m_syswrap/syswrap-generic.c b/coregrind/m_syswrap/syswrap-generic.c index 0739ccc9af..b1b982cc4a 100644 --- a/coregrind/m_syswrap/syswrap-generic.c +++ b/coregrind/m_syswrap/syswrap-generic.c @@ -28,7 +28,7 @@ The GNU General Public License is contained in the file COPYING. */ -#if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) +#if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) || defined(VGO_freebsd) #include "pub_core_basics.h" #include "pub_core_vki.h" @@ -938,7 +938,7 @@ void VG_(init_preopened_fds)(void) out: VG_(close)(sr_Res(f)); -#elif defined(VGO_darwin) +#elif defined(VGO_darwin) || defined(VGO_freebsd) init_preopened_fds_without_proc_self_fd(); #elif defined(VGO_solaris) @@ -1142,6 +1142,10 @@ void pre_mem_read_sockaddr ( ThreadId tid, VG_(sprintf) ( outmsg, description, "sa_family" ); PRE_MEM_READ( outmsg, (Addr) &sa->sa_family, sizeof(vki_sa_family_t)); +#if defined(VGO_freebsd) + VG_(sprintf) ( outmsg, description, "sa_len" ); + PRE_MEM_READ( outmsg, (Addr) &sa->sa_len, sizeof(char)); +#endif /* Don't do any extra checking if we cannot determine the sa_family. */ if (! ML_(safe_to_deref) (&sa->sa_family, sizeof(vki_sa_family_t))) @@ -1819,7 +1823,15 @@ UInt get_sem_count( Int semid ) return 0; return buf.sem_nsems; +# elif defined(__NR___semctl) /* FreeBSD */ + struct vki_semid_ds buf; + arg.buf = &buf; + res = VG_(do_syscall4)(__NR___semctl, semid, 0, VKI_IPC_STAT, *(UWord *)&arg); + + if (sr_isError(res)) + return 0; + return buf.sem_nsems; # elif defined(__NR_semsys) /* Solaris */ struct vki_semid_ds buf; arg.buf = &buf; @@ -1854,10 +1866,17 @@ ML_(generic_PRE_sys_semctl) ( ThreadId tid, #if defined(VKI_IPC_INFO) case VKI_IPC_INFO: case VKI_SEM_INFO: +#if defined(VKI_IPC_64) case VKI_IPC_INFO|VKI_IPC_64: case VKI_SEM_INFO|VKI_IPC_64: +#endif +#if defined(VGO_freebsd) + PRE_MEM_WRITE( "semctl(IPC_INFO, arg.buf)", + (Addr)arg.buf, sizeof(struct vki_semid_ds) ); +#else PRE_MEM_WRITE( "semctl(IPC_INFO, arg.buf)", (Addr)arg.buf, sizeof(struct vki_seminfo) ); +#endif break; #endif @@ -1933,9 +1952,15 @@ ML_(generic_POST_sys_semctl) ( ThreadId tid, #if defined(VKI_IPC_INFO) case VKI_IPC_INFO: case VKI_SEM_INFO: +#if defined(VKI_IPC_64) case VKI_IPC_INFO|VKI_IPC_64: case VKI_SEM_INFO|VKI_IPC_64: +#endif +#if defined(VGO_freebsd) + POST_MEM_WRITE( (Addr)arg.buf, sizeof(struct vki_semid_ds) ); +#else POST_MEM_WRITE( (Addr)arg.buf, sizeof(struct vki_seminfo) ); +#endif break; #endif @@ -2132,8 +2157,13 @@ ML_(generic_PRE_sys_shmctl) ( ThreadId tid, switch (arg1 /* cmd */) { #if defined(VKI_IPC_INFO) case VKI_IPC_INFO: +# if defined(VGO_freebsd) + PRE_MEM_WRITE( "shmctl(IPC_INFO, buf)", + arg2, sizeof(struct vki_shmid_ds) ); +# else PRE_MEM_WRITE( "shmctl(IPC_INFO, buf)", arg2, sizeof(struct vki_shminfo) ); +# endif break; #if defined(VKI_IPC_64) case VKI_IPC_INFO|VKI_IPC_64: @@ -2191,12 +2221,18 @@ ML_(generic_POST_sys_shmctl) ( ThreadId tid, switch (arg1 /* cmd */) { #if defined(VKI_IPC_INFO) case VKI_IPC_INFO: +# if defined(VGO_freebsd) + POST_MEM_WRITE( arg2, sizeof(struct vki_shmid_ds) ); +# else POST_MEM_WRITE( arg2, sizeof(struct vki_shminfo) ); +# endif break; +#if defined(VKI_IPC_64) case VKI_IPC_INFO|VKI_IPC_64: POST_MEM_WRITE( arg2, sizeof(struct vki_shminfo64) ); break; #endif +#endif #if defined(VKI_SHM_INFO) case VKI_SHM_INFO: @@ -2735,6 +2771,7 @@ PRE(sys_getpriority) PRE_REG_READ2(long, "getpriority", int, which, int, who); } +#if !defined(VGO_freebsd) PRE(sys_pwrite64) { *flags |= SfMayBlock; @@ -2755,6 +2792,7 @@ PRE(sys_pwrite64) #endif PRE_MEM_READ( "pwrite64(buf)", ARG2, ARG3 ); } +#endif PRE(sys_sync) { @@ -2799,6 +2837,7 @@ PRE(sys_getsid) PRE_REG_READ1(long, "getsid", vki_pid_t, pid); } +#if !defined(VGO_freebsd) PRE(sys_pread64) { *flags |= SfMayBlock; @@ -2826,6 +2865,7 @@ POST(sys_pread64) POST_MEM_WRITE( ARG2, RES ); } } +#endif PRE(sys_mknod) { @@ -3363,7 +3403,7 @@ PRE(sys_fchmod) PRE_REG_READ2(long, "fchmod", unsigned int, fildes, vki_mode_t, mode); } -#if !defined(VGP_nanomips_linux) +#if !defined(VGP_nanomips_linux) && !defined (VGO_freebsd) PRE(sys_newfstat) { FUSE_COMPATIBLE_MAY_BLOCK(); @@ -3404,7 +3444,7 @@ PRE(sys_fork) if (!SUCCESS) return; -#if defined(VGO_linux) +#if defined(VGO_linux) || defined(VGO_freebsd) // RES is 0 for child, non-0 (the child's PID) for parent. is_child = ( RES == 0 ? True : False ); child_pid = ( is_child ? -1 : RES ); @@ -3748,7 +3788,7 @@ void ML_(PRE_unknown_ioctl)(ThreadId tid, UWord request, UWord arg) unknown_ioctl[i] = request; moans--; VG_(umsg)("Warning: noted but unhandled ioctl 0x%lx" - " with no size/direction hints.\n", request); + " with no size/direction hints.\n", request); VG_(umsg)(" This could cause spurious value errors to appear.\n"); VG_(umsg)(" See README_MISSING_SYSCALL_OR_IOCTL for " "guidance on writing a proper wrapper.\n" ); @@ -3884,7 +3924,7 @@ PRE(sys_link) PRE_MEM_RASCIIZ( "link(newpath)", ARG2); } -#if !defined(VGP_nanomips_linux) +#if !defined(VGP_nanomips_linux) && !defined(VGO_freebsd) PRE(sys_newlstat) { PRINT("sys_newlstat ( %#" FMT_REGWORD "x(%s), %#" FMT_REGWORD "x )", ARG1, @@ -3934,7 +3974,11 @@ void handle_sys_mprotect(ThreadId tid, SyscallStatus* status, Addr *addr, SizeT *len, Int *prot) { if (!ML_(valid_client_addr)(*addr, *len, tid, "mprotect")) { +#if defined(VGO_freebsd) + SET_STATUS_Failure( VKI_EINVAL ); +#else SET_STATUS_Failure( VKI_ENOMEM ); +#endif } #if defined(VKI_PROT_GROWSDOWN) else @@ -4195,7 +4239,7 @@ PRE(sys_read) PRINT("sys_read ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %" FMT_REGWORD "u )", ARG1, ARG2, ARG3); PRE_REG_READ3(ssize_t, "read", - unsigned int, fd, char *, buf, vki_size_t, count); + int, fd, char *, buf, vki_size_t, count); if (!ML_(fd_allowed)(ARG1, "read", tid, False)) SET_STATUS_Failure( VKI_EBADF ); @@ -4284,7 +4328,8 @@ PRE(sys_poll) POST(sys_poll) { - if (RES >= 0) { + // RES is UWord so always >= 0 + if (SUCCESS && RES >= 0) { UInt i; struct vki_pollfd* ufds = (struct vki_pollfd *)(Addr)ARG1; for (i = 0; i < ARG2; i++) @@ -4483,7 +4528,11 @@ PRE(sys_setrlimit) } else if (((struct vki_rlimit *)(Addr)ARG2)->rlim_cur > ((struct vki_rlimit *)(Addr)ARG2)->rlim_max) { +#if defined(VGO_freebsd) + SET_STATUS_Failure( VKI_EPERM ); +#else SET_STATUS_Failure( VKI_EINVAL ); +#endif } else if (arg1 == VKI_RLIMIT_NOFILE) { if (((struct vki_rlimit *)(Addr)ARG2)->rlim_cur > VG_(fd_hard_limit) || @@ -4536,7 +4585,7 @@ PRE(sys_setuid) PRE_REG_READ1(long, "setuid", vki_uid_t, uid); } -#if !defined(VGP_nanomips_linux) +#if !defined(VGP_nanomips_linux) && !defined(VGO_freebsd) PRE(sys_newstat) { FUSE_COMPATIBLE_MAY_BLOCK(); @@ -4551,7 +4600,9 @@ POST(sys_newstat) { POST_MEM_WRITE( ARG2, sizeof(struct vki_stat) ); } +#endif +#if !defined(VGP_nanomips_linux) PRE(sys_statfs) { FUSE_COMPATIBLE_MAY_BLOCK(); @@ -4638,6 +4689,7 @@ PRE(sys_unlink) PRE_MEM_RASCIIZ( "unlink(pathname)", ARG1 ); } +#if !defined(VGO_freebsd) PRE(sys_newuname) { PRINT("sys_newuname ( %#" FMT_REGWORD "x )", ARG1); @@ -4651,6 +4703,7 @@ POST(sys_newuname) POST_MEM_WRITE( ARG1, sizeof(struct vki_new_utsname) ); } } +#endif PRE(sys_waitpid) { @@ -4793,7 +4846,7 @@ PRE(sys_sethostname) #undef PRE #undef POST -#endif // defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) +#endif // defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) || defined(VGO_freebsd) /*--------------------------------------------------------------------*/ /*--- end ---*/ diff --git a/coregrind/m_syswrap/syswrap-main.c b/coregrind/m_syswrap/syswrap-main.c index 1a475422b1..2982e27669 100644 --- a/coregrind/m_syswrap/syswrap-main.c +++ b/coregrind/m_syswrap/syswrap-main.c @@ -71,6 +71,10 @@ mips64 v0 a0 a1 a2 a3 a4 a5 a6 a7 v0 (== NUM) arm64 x8 x0 x1 x2 x3 x4 x5 n/a n/a x0 ?? (== ARG1??) + FreeBSD: + x86 eax +4 +8 +12 +16 +20 +24 +28 +32 edx:eax, eflags.c + amd64 rax rdi rsi rdx rcx r8 r9 +8 +16 rdx:rax, rflags.c + On s390x the svc instruction is used for system calls. The system call number is encoded in the instruction (8 bit immediate field). Since Linux 2.6 it is also allowed to use svc 0 with the system call number in r1. @@ -84,8 +88,8 @@ x86 eax +4 +8 +12 +16 +20 +24 +28 +32 edx:eax, eflags.c amd64 rax rdi rsi rdx rcx r8 r9 +8 +16 rdx:rax, rflags.c - For x86-darwin, "+N" denotes "in memory at N(%esp)"; ditto - amd64-darwin. Apparently 0(%esp) is some kind of return address + For x86-darwin and x86-freebsd, "+N" denotes "in memory at N(%esp)"; + ditto amd64-darwin/amd64-freebsd. Apparently 0(%esp) is some kind of return address (perhaps for syscalls done with "sysenter"?) I don't think it is relevant for syscalls done with "int $0x80/1/2". @@ -172,6 +176,12 @@ ppc32: Success(N) ==> r3 = N, CR0.SO = 0 Fail(N) ==> r3 = N, CR0.SO = 1 + FreeBSD: + x86: Success(N) ==> edx:eax = N, cc = 0 + Fail(N) ==> edx:eax = N, cc = 1 + + ditto amd64 + Darwin: x86: Success(N) ==> edx:eax = N, cc = 0 Fail(N) ==> edx:eax = N, cc = 1 @@ -285,6 +295,13 @@ */ #if defined(VGO_linux) extern +UWord ML_(do_syscall_for_client_WRK)( Word syscallno, + void* guest_state, + const vki_sigset_t *syscall_mask, + const vki_sigset_t *restore_mask, + Word sigsetSzB ); +#elif defined(VGO_freebsd) +extern UWord ML_(do_syscall_for_client_WRK)( Word syscallno, void* guest_state, const vki_sigset_t *syscall_mask, @@ -333,11 +350,25 @@ void do_syscall_for_client ( Int syscallno, { vki_sigset_t saved; UWord err; +# if defined(VGO_freebsd) + Int real_syscallno; +# endif # if defined(VGO_linux) err = ML_(do_syscall_for_client_WRK)( syscallno, &tst->arch.vex, syscall_mask, &saved, sizeof(vki_sigset_t) ); +# elif defined(VGO_freebsd) + if (tst->arch.vex.guest_SC_CLASS == VG_FREEBSD_SYSCALL0) + real_syscallno = __NR_syscall; + else if (tst->arch.vex.guest_SC_CLASS == VG_FREEBSD_SYSCALL198) + real_syscallno = __NR___syscall; + else + real_syscallno = syscallno; + err = ML_(do_syscall_for_client_WRK)( + real_syscallno, &tst->arch.vex, + syscall_mask, &saved, sizeof(vki_sigset_t) + ); # elif defined(VGO_darwin) switch (VG_DARWIN_SYSNO_CLASS(syscallno)) { case VG_DARWIN_SYSCALL_CLASS_UNIX: @@ -518,6 +549,80 @@ void getSyscallArgsFromGuestState ( /*OUT*/SyscallArgs* canonical, vg_assert(gst->guest_syscall_flag == SC_FLAG); #endif +#elif defined(VGP_x86_freebsd) + VexGuestX86State* gst = (VexGuestX86State*)gst_vanilla; + UWord *stack = (UWord *)gst->guest_ESP; + + // FreeBSD supports different calling conventions + switch (gst->guest_EAX) { + case __NR_syscall: + canonical->klass = VG_FREEBSD_SYSCALL0; + canonical->sysno = stack[1]; + stack += 1; + break; + case __NR___syscall: + canonical->klass = VG_FREEBSD_SYSCALL198; + canonical->sysno = stack[1]; + stack += 2; + break; + default: + canonical->klass = 0; + canonical->sysno = gst->guest_EAX; + break; + } + // stack[0] is a (fake) return address + canonical->arg1 = stack[1]; + canonical->arg2 = stack[2]; + canonical->arg3 = stack[3]; + canonical->arg4 = stack[4]; + canonical->arg5 = stack[5]; + canonical->arg6 = stack[6]; + canonical->arg7 = stack[7]; + canonical->arg8 = stack[8]; + +#elif defined(VGP_amd64_freebsd) + VexGuestAMD64State* gst = (VexGuestAMD64State*)gst_vanilla; + UWord *stack = (UWord *)gst->guest_RSP; + + // FreeBSD supports different calling conventions + switch (gst->guest_RAX) { + case __NR_syscall: + canonical->klass = VG_FREEBSD_SYSCALL0; + canonical->sysno = gst->guest_RDI; + break; + case __NR___syscall: + canonical->klass = VG_FREEBSD_SYSCALL198; + canonical->sysno = gst->guest_RDI; + break; + default: + canonical->klass = 0; + canonical->sysno = gst->guest_RAX; + break; + } + + // stack[0] is a (fake) return address + if (canonical->klass == VG_FREEBSD_SYSCALL0 || canonical->klass == VG_FREEBSD_SYSCALL198) { + // stack[0] is return address + canonical->arg1 = gst->guest_RSI; + canonical->arg2 = gst->guest_RDX; + canonical->arg3 = gst->guest_R10; + canonical->arg4 = gst->guest_R8; + canonical->arg5 = gst->guest_R9; + canonical->arg6 = stack[1]; + canonical->arg7 = stack[2]; + canonical->arg8 = stack[3]; + } else { + // stack[0] is return address + canonical->arg1 = gst->guest_RDI; + canonical->arg2 = gst->guest_RSI; + canonical->arg3 = gst->guest_RDX; + canonical->arg4 = gst->guest_R10; + canonical->arg5 = gst->guest_R8; + canonical->arg6 = gst->guest_R9; + canonical->arg7 = stack[1]; + canonical->arg8 = stack[2]; + } + #elif defined(VGP_arm_linux) VexGuestARMState* gst = (VexGuestARMState*)gst_vanilla; canonical->sysno = gst->guest_R7; @@ -709,7 +814,7 @@ void getSyscallArgsFromGuestState ( /*OUT*/SyscallArgs* canonical, canonical->arg6 = stack[1]; canonical->arg7 = stack[2]; canonical->arg8 = stack[3]; - + PRINT("SYSCALL[%d,?](0) syscall(%s, ...); please stand by...\n", VG_(getpid)(), /*tid,*/ VG_SYSNUM_STRING(canonical->sysno)); @@ -842,6 +947,74 @@ void putSyscallArgsIntoGuestState ( /*IN*/ SyscallArgs* canonical, gst->guest_GPR8 = canonical->arg6; gst->guest_GPR9 = canonical->arg7; +#elif defined(VGP_x86_freebsd) + VexGuestX86State* gst = (VexGuestX86State*)gst_vanilla; + UWord *stack = (UWord *)gst->guest_ESP; + + // stack[0] is a (fake) return address + switch (canonical->klass) { + case VG_FREEBSD_SYSCALL0: + gst->guest_EAX = __NR_syscall; + stack[1] = canonical->sysno; + stack++; + break; + case VG_FREEBSD_SYSCALL198: + gst->guest_EAX = __NR___syscall; + stack[1] = canonical->sysno; + stack += 2; + break; + default: + gst->guest_EAX = canonical->sysno; + break; + } + + stack[1] = canonical->arg1; + stack[2] = canonical->arg2; + stack[3] = canonical->arg3; + stack[4] = canonical->arg4; + stack[5] = canonical->arg5; + stack[6] = canonical->arg6; + stack[7] = canonical->arg7; + stack[8] = canonical->arg8; + +#elif defined(VGP_amd64_freebsd) + VexGuestAMD64State* gst = (VexGuestAMD64State*)gst_vanilla; + UWord *stack = (UWord *)gst->guest_RSP; + + // stack[0] is a (fake) return address + switch (canonical->klass) { + case VG_FREEBSD_SYSCALL0: + gst->guest_RAX = __NR_syscall; + break; + case VG_FREEBSD_SYSCALL198: + gst->guest_RAX = __NR___syscall; + break; + default: + gst->guest_RAX = canonical->sysno; + break; + } + + if (canonical->klass == VG_FREEBSD_SYSCALL0 || canonical->klass == VG_FREEBSD_SYSCALL198) { + gst->guest_RDI = canonical->sysno; + gst->guest_RSI = canonical->arg1; + gst->guest_RDX = canonical->arg2; + gst->guest_R10 = canonical->arg3; + gst->guest_R8 = canonical->arg4; + gst->guest_R9 = canonical->arg5; + stack[1] = canonical->arg6; + stack[2] = canonical->arg7; + stack[3] = canonical->arg8; + } else { + gst->guest_RDI = canonical->arg1; + gst->guest_RSI = canonical->arg2; + gst->guest_RDX = canonical->arg3; + gst->guest_R10 = canonical->arg4; + gst->guest_R8 = canonical->arg5; + gst->guest_R9 = canonical->arg6; + stack[1] = canonical->arg7; + stack[2] = canonical->arg8; + } + #elif defined(VGP_arm_linux) VexGuestARMState* gst = (VexGuestARMState*)gst_vanilla; gst->guest_R7 = canonical->sysno; @@ -1027,6 +1200,15 @@ void getSyscallStatusFromGuestState ( /*OUT*/SyscallStatus* canonical, canonical->sres = VG_(mk_SysRes_ppc64_linux)( gst->guest_GPR3, cr0so, flag ); canonical->what = SsComplete; +# elif defined(VGP_x86_freebsd) + /* duplicates logic in m_signals.VG_UCONTEXT_SYSCALL_SYSRES */ + VexGuestX86State* gst = (VexGuestX86State*)gst_vanilla; + UInt flags = LibVEX_GuestX86_get_eflags(gst); + + canonical->sres = VG_(mk_SysRes_x86_freebsd)(gst->guest_EAX, gst->guest_EDX, + (flags & 1) != 0 ? True : False); + canonical->what = SsComplete; + # elif defined(VGP_arm_linux) VexGuestARMState* gst = (VexGuestARMState*)gst_vanilla; canonical->sres = VG_(mk_SysRes_arm_linux)( gst->guest_R0 ); @@ -1058,6 +1240,13 @@ void getSyscallStatusFromGuestState ( /*OUT*/SyscallStatus* canonical, RegWord a0 = gst->guest_r4; // a0 canonical->sres = VG_(mk_SysRes_nanomips_linux)(a0); canonical->what = SsComplete; +# elif defined(VGP_amd64_freebsd) + /* duplicates logic in m_signals.VG_UCONTEXT_SYSCALL_SYSRES */ + VexGuestAMD64State* gst = (VexGuestAMD64State*)gst_vanilla; + ULong flags = LibVEX_GuestAMD64_get_rflags(gst); + canonical->sres = VG_(mk_SysRes_amd64_freebsd)(gst->guest_RAX, gst->guest_RDX, + (flags & 1) != 0 ? True : False); + canonical->what = SsComplete; # elif defined(VGP_x86_darwin) /* duplicates logic in m_signals.VG_UCONTEXT_SYSCALL_SYSRES */ @@ -1262,6 +1451,43 @@ void putSyscallStatusIntoGuestState ( /*IN*/ ThreadId tid, VG_TRACK( post_reg_write, Vg_CoreSysCall, tid, OFFSET_arm64_X0, sizeof(UWord) ); +#elif defined(VGP_x86_freebsd) + VexGuestX86State* gst = (VexGuestX86State*)gst_vanilla; + vg_assert(canonical->what == SsComplete); + if (sr_isError(canonical->sres)) { + gst->guest_EAX = sr_Err(canonical->sres); + LibVEX_GuestX86_put_eflag_c(1, gst); + } else { + gst->guest_EAX = sr_Res(canonical->sres); + gst->guest_EDX = sr_ResHI(canonical->sres); + LibVEX_GuestX86_put_eflag_c(0, gst); + } + VG_TRACK( post_reg_write, Vg_CoreSysCall, tid, + OFFSET_x86_EAX, sizeof(UInt) ); + VG_TRACK( post_reg_write, Vg_CoreSysCall, tid, + OFFSET_x86_EDX, sizeof(UInt) ); + // GrP fixme sets defined for entire eflags, not just bit c + VG_TRACK( post_reg_write, Vg_CoreSysCall, tid, + offsetof(VexGuestX86State, guest_CC_DEP1), sizeof(UInt) ); + +#elif defined(VGP_amd64_freebsd) + VexGuestAMD64State* gst = (VexGuestAMD64State*)gst_vanilla; + vg_assert(canonical->what == SsComplete); + if (sr_isError(canonical->sres)) { + gst->guest_RAX = sr_Err(canonical->sres); + LibVEX_GuestAMD64_put_rflag_c(1, gst); + } else { + gst->guest_RAX = sr_Res(canonical->sres); + gst->guest_RDX = sr_ResHI(canonical->sres); + LibVEX_GuestAMD64_put_rflag_c(0, gst); + } + VG_TRACK( post_reg_write, Vg_CoreSysCall, tid, + OFFSET_amd64_RAX, sizeof(ULong) ); + VG_TRACK( post_reg_write, Vg_CoreSysCall, tid, + OFFSET_amd64_RDX, sizeof(ULong) ); + // GrP fixme sets defined for entire eflags, not just bit c + VG_TRACK( post_reg_write, Vg_CoreSysCall, tid, + offsetof(VexGuestAMD64State, guest_CC_DEP1), sizeof(ULong) ); #elif defined(VGP_x86_darwin) VexGuestX86State* gst = (VexGuestX86State*)gst_vanilla; SysRes sres = canonical->sres; @@ -1493,6 +1719,30 @@ void getSyscallArgLayout ( /*OUT*/SyscallArgLayout* layout ) layout->o_arg7 = OFFSET_ppc64_GPR9; layout->uu_arg8 = -1; /* impossible value */ +#elif defined(VGP_x86_freebsd) + layout->o_sysno = OFFSET_x86_EAX; + // syscall parameters are on stack in C convention + layout->s_arg1 = sizeof(UWord) * 1; + layout->s_arg2 = sizeof(UWord) * 2; + layout->s_arg3 = sizeof(UWord) * 3; + layout->s_arg4 = sizeof(UWord) * 4; + layout->s_arg5 = sizeof(UWord) * 5; + layout->s_arg6 = sizeof(UWord) * 6; + layout->s_arg7 = sizeof(UWord) * 7; + layout->s_arg8 = sizeof(UWord) * 8; + +#elif defined(VGP_amd64_freebsd) + layout->o_sysno = OFFSET_amd64_RAX; + layout->o_arg1 = OFFSET_amd64_RDI; + layout->o_arg2 = OFFSET_amd64_RSI; + layout->o_arg3 = OFFSET_amd64_RDX; + layout->o_arg4 = OFFSET_amd64_R10; + layout->o_arg5 = OFFSET_amd64_R8; + layout->o_arg6 = OFFSET_amd64_R9; + layout->s_arg7 = sizeof(UWord) * 1; + layout->s_arg8 = sizeof(UWord) * 2; + layout->arg6_is_reg = True; + #elif defined(VGP_arm_linux) layout->o_sysno = OFFSET_arm_R7; layout->o_arg1 = OFFSET_arm_R0; @@ -1610,6 +1860,24 @@ void getSyscallArgLayout ( /*OUT*/SyscallArgLayout* layout ) #endif } +#if defined(VGP_amd64_freebsd) +static +void getSyscallArgLayout_0_198 ( /*OUT*/SyscallArgLayout* layout ) +{ + VG_(bzero_inline)(layout, sizeof(*layout)); + layout->o_sysno = OFFSET_amd64_RDI; + layout->o_arg1 = OFFSET_amd64_RSI; + layout->o_arg2 = OFFSET_amd64_RDX; + layout->o_arg3 = OFFSET_amd64_R10; + layout->o_arg4 = OFFSET_amd64_R8; + layout->o_arg5 = OFFSET_amd64_R9; + layout->s_arg6 = sizeof(UWord) * 1; + layout->s_arg7 = sizeof(UWord) * 2; + layout->s_arg8 = sizeof(UWord) * 3; + layout->arg6_is_reg = False; +} +#endif + /* --------------------------------------------------------------------- The main driver logic @@ -1652,6 +1920,9 @@ static const SyscallTableEntry* get_syscall_entry ( Int syscallno ) # if defined(VGO_linux) sys = ML_(get_linux_syscall_entry)( syscallno ); +# elif defined(VGO_freebsd) + sys = ML_(get_freebsd_syscall_entry)( syscallno ); + # elif defined(VGO_darwin) Int idx = VG_DARWIN_SYSNO_INDEX(syscallno); @@ -1868,6 +2139,9 @@ void VG_(client_syscall) ( ThreadId tid, UInt trc ) is interrupted by a signal. */ sysno = sci->orig_args.sysno; +# if defined(VGO_freebsd) + tst->arch.vex.guest_SC_CLASS = sci->orig_args.klass; +# endif /* It's sometimes useful, as a crude debugging hack, to get a stack trace at each (or selected) syscalls. */ if (0 && sysno == __NR_ioctl) { @@ -1907,8 +2181,23 @@ void VG_(client_syscall) ( ThreadId tid, UInt trc ) action. This info is needed so that the scalar syscall argument checks (PRE_REG_READ calls) know which bits of the guest state they need to inspect. */ +#if defined(VGP_amd64_freebsd) + // PJF - somewhat unfortunate uglificaton of the code, but the current code handles two + // types of syscall with different register use. Mixing them up is not good. + // I've avoided modifying the existing function (I could have added + // a FreeBSD amd64-only flag to it for this purpose). + if (sci->orig_args.klass == VG_FREEBSD_SYSCALL0 || sci->orig_args.klass == VG_FREEBSD_SYSCALL198) { + getSyscallArgLayout_0_198( &layout ); + } else { +#endif + getSyscallArgLayout( &layout ); +#if defined(VGP_amd64_freebsd) + } +#endif + + /* Make sure the tmp signal mask matches the real signal mask; sigsuspend may change this. */ vg_assert(VG_(iseqsigset)(&tst->sig_mask, &tst->tmp_sig_mask)); @@ -2269,7 +2558,7 @@ void VG_(post_syscall) (ThreadId tid) /* These are addresses within ML_(do_syscall_for_client_WRK). See syscall-$PLAT.S for details. */ -#if defined(VGO_linux) +#if defined(VGO_linux) || defined(VGO_freebsd) extern const Addr ML_(blksys_setup); extern const Addr ML_(blksys_restart); extern const Addr ML_(blksys_complete); @@ -2450,6 +2739,46 @@ void ML_(fixup_guest_state_to_restart_syscall) ( ThreadArchState* arch ) vg_assert(p[0] == 0x01 && p[1] == 0x00 && p[2] == 0x00 && p[3] == 0xD4); } +#elif defined(VGP_x86_freebsd) + /* XXX: we support different syscall methods. */ + arch->vex.guest_EIP -= 2; // sizeof(int $0x80) + + /* Make sure our caller is actually sane, and we're really backing + back over a syscall. + + int $0x80 == CD 80 + */ + { + UChar *p = (UChar *)arch->vex.guest_EIP; + + if (p[0] != 0xcd || p[1] != 0x80) + VG_(message)(Vg_DebugMsg, + "?! restarting over syscall at %#x %02x %02x\n", + arch->vex.guest_EIP, p[0], p[1]); + + vg_assert(p[0] == 0xcd && p[1] == 0x80); + } + +#elif defined(VGP_amd64_freebsd) + /* XXX: we support different syscall methods. */ + arch->vex.guest_RIP -= 2; // sizeof(syscall) + + /* Make sure our caller is actually sane, and we're really backing + back over a syscall. + + syscall == 0F 05 + */ + { + UChar *p = (UChar *)arch->vex.guest_RIP; + + if (p[0] != 0x0F || p[1] != 0x05) + VG_(message)(Vg_DebugMsg, + "?! restarting over syscall at %#llx %02x %02x\n", + arch->vex.guest_RIP, p[0], p[1]); + + vg_assert(p[0] == 0x0F && p[1] == 0x05); + } + #elif defined(VGP_x86_darwin) arch->vex.guest_EIP = arch->vex.guest_IP_AT_SYSCALL; @@ -2700,7 +3029,7 @@ VG_(fixup_guest_state_after_syscall_interrupted)( ThreadId tid, th_regs = &tst->arch; sci = & syscallInfo[tid]; -# if defined(VGO_linux) +# if defined(VGO_linux) || defined(VGO_freebsd) outside_range = ip < ML_(blksys_setup) || ip >= ML_(blksys_finished); in_setup_to_restart @@ -2868,6 +3197,24 @@ VG_(fixup_guest_state_after_syscall_interrupted)( ThreadId tid, /* Result committed, but the signal mask has not been restored; we expect our caller (the signal handler) will have fixed this up. */ +/* XXX: needed? */ +#if defined(VGP_x86_freebsd) + /* On FreeBSD, the success/fail status is returned to the caller + and still has to be fixed up here. */ + if (!(sci->flags & SfNoWriteResult)) { + if (sr_isError(sres)) + LibVEX_GuestX86_put_eflag_c(1, &th_regs->vex); + else + LibVEX_GuestX86_put_eflag_c(0, &th_regs->vex); + } +#elif defined(VGP_amd64_freebsd) + if (!(sci->flags & SfNoWriteResult)) { + if (sr_isError(sres)) + LibVEX_GuestAMD64_put_rflag_c(1, &th_regs->vex); + else + LibVEX_GuestAMD64_put_rflag_c(0, &th_regs->vex); + } +#endif if (VG_(clo_trace_signals)) VG_(message)( Vg_DebugMsg, " completed and committed: nothing to do\n"); diff --git a/coregrind/m_trampoline.S b/coregrind/m_trampoline.S index c2d642992a..ad1db3cb9f 100644 --- a/coregrind/m_trampoline.S +++ b/coregrind/m_trampoline.S @@ -851,6 +851,72 @@ VG_(trampoline_stuff_end): # undef UD2_1024 # undef UD2_PAGE +/*---------------- x86-freebsd ----------------*/ +#else +#if defined(VGP_x86_freebsd) + +.global VG_(trampoline_stuff_start) +VG_(trampoline_stuff_start): + +.global VG_(x86_freebsd_SUBST_FOR_sigreturn) +VG_(x86_freebsd_SUBST_FOR_sigreturn): + /* + * PJF this magic number is fairly flakey + * If ever it is wrong sys_fake_sigreturn will fail + * the sigreturn will be to some bogus EIP address and + * the client will likely terminate with a SIGILL + * In this case adding some printfs to sigframe_create + * and sys_fake_sigreturn should help debugging to + * find the right offset + */ + lea 0x1c(%esp), %eax /* args to sigreturn(ucontext_t *) */ + pushl %eax + pushl %eax /* fake return addr */ +/* movl 0x44(%eax), %gs ; restore %gs, not done by sigreturn */ + movl $__NR_fake_sigreturn, %eax + int $0x80 + ud2 + +.global VG_(trampoline_stuff_end) +VG_(trampoline_stuff_end): + +#else +#if defined(VGP_amd64_freebsd) + +# define UD2_16 ud2 ; ud2 ; ud2 ; ud2 ;ud2 ; ud2 ; ud2 ; ud2 +# define UD2_64 UD2_16 ; UD2_16 ; UD2_16 ; UD2_16 +# define UD2_256 UD2_64 ; UD2_64 ; UD2_64 ; UD2_64 +# define UD2_1024 UD2_256 ; UD2_256 ; UD2_256 ; UD2_256 +# define UD2_PAGE UD2_1024 ; UD2_1024 ; UD2_1024 ; UD2_1024 + + /* a leading page of unexecutable code */ + UD2_PAGE + +.global VG_(trampoline_stuff_start) +VG_(trampoline_stuff_start): + +.global VG_(amd64_freebsd_SUBST_FOR_sigreturn) +VG_(amd64_freebsd_SUBST_FOR_sigreturn): + /* This is a very specific sequence which GDB uses to + recognize signal handler frames. */ + movq $__NR_fake_sigreturn, %rax + movq %rsp, %rdi + addq $8,%rdi + syscall + ud2 + +.global VG_(trampoline_stuff_end) +VG_(trampoline_stuff_end): + + /* and a trailing page of unexecutable code */ + UD2_PAGE + +# undef UD2_16 +# undef UD2_64 +# undef UD2_256 +# undef UD2_1024 +# undef UD2_PAGE + /*---------------- x86-darwin ----------------*/ #else #if defined(VGP_x86_darwin) @@ -1629,6 +1695,8 @@ VG_(trampoline_stuff_end): #endif #endif #endif +#endif +#endif /* Let the linker know we don't need an executable stack */ MARK_STACK_NO_EXEC diff --git a/coregrind/m_translate.c b/coregrind/m_translate.c index 332202a915..c3f84a9d5b 100644 --- a/coregrind/m_translate.c +++ b/coregrind/m_translate.c @@ -1688,7 +1688,9 @@ Bool VG_(translate) ( ThreadId tid, vex_abiinfo.guest_amd64_assume_fs_is_const = True; vex_abiinfo.guest_amd64_assume_gs_is_const = True; # endif - +# if defined(VGP_amd64_freebsd) + vex_abiinfo.guest_amd64_assume_fs_is_const = True; +# endif # if defined(VGP_amd64_darwin) vex_abiinfo.guest_amd64_assume_gs_is_const = True; # endif diff --git a/coregrind/m_ume/elf.c b/coregrind/m_ume/elf.c index b9ded7ad9d..694c71d5bc 100644 --- a/coregrind/m_ume/elf.c +++ b/coregrind/m_ume/elf.c @@ -26,7 +26,7 @@ The GNU General Public License is contained in the file COPYING. */ -#if defined(VGO_linux) || defined(VGO_solaris) +#if defined(VGO_linux) || defined(VGO_solaris) || defined(VGO_freebsd) #include "pub_core_basics.h" #include "pub_core_vki.h" @@ -39,6 +39,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 @@ -642,6 +643,15 @@ Int VG_(load_ELF)(Int fd, const HChar* name, /*MOD*/ExeInfo* info) VG_(pread)(fd, buf, ph->p_filesz, ph->p_offset); buf[ph->p_filesz] = '\0'; +#if defined(VGP_x86_freebsd) + sres._isError = True; + /* Hack. FreeBSD's kernel overloads the interpreter name. */ + if (VG_(strcmp)(buf, "/libexec/ld-elf.so.1") == 0 || + VG_(strcmp)(buf, "/usr/libexec/ld-elf.so.1") == 0) { + sres = VG_(open)("/libexec/ld-elf32.so.1", VKI_O_RDONLY, 0); + } + if (sr_isError(sres)) +#endif sres = VG_(open)(buf, VKI_O_RDONLY, 0); if (sr_isError(sres)) { VG_(printf)("valgrind: m_ume.c: can't open interpreter\n"); @@ -868,7 +878,7 @@ Int VG_(load_ELF)(Int fd, const HChar* name, /*MOD*/ExeInfo* info) return 0; } -#endif // defined(VGO_linux) || defined(VGO_solaris) +#endif // defined(VGO_linux) || defined(VGO_solaris) || defined(VGO_freebsd) /*--------------------------------------------------------------------*/ /*--- end ---*/ diff --git a/coregrind/m_ume/main.c b/coregrind/m_ume/main.c index d917fb5968..49e48d242b 100644 --- a/coregrind/m_ume/main.c +++ b/coregrind/m_ume/main.c @@ -49,7 +49,7 @@ typedef struct { } ExeHandler; static ExeHandler exe_handlers[] = { -# if defined(VGO_linux) || defined(VGO_solaris) +# if defined(VGO_linux) || defined(VGO_solaris) || defined(VGO_freebsd) { VG_(match_ELF), VG_(load_ELF) }, # elif defined(VGO_darwin) { VG_(match_macho), VG_(load_macho) }, diff --git a/coregrind/m_ume/priv_ume.h b/coregrind/m_ume/priv_ume.h index c9094ed8dc..489fc75229 100644 --- a/coregrind/m_ume/priv_ume.h +++ b/coregrind/m_ume/priv_ume.h @@ -25,7 +25,7 @@ The GNU General Public License is contained in the file COPYING. */ -#if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) +#if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) || defined(VGO_freebsd) #ifndef __PRIV_UME_H #define __PRIV_UME_H @@ -34,7 +34,7 @@ extern Int VG_(do_exec_inner)(const HChar *exe, ExeInfo *info); -#if defined(VGO_linux) || defined(VGO_solaris) +#if defined(VGO_linux) || defined(VGO_solaris) || defined(VGO_freebsd) extern Bool VG_(match_ELF) ( const void *hdr, SizeT len ); extern Int VG_(load_ELF) ( Int fd, const HChar *name, ExeInfo *info ); #elif defined(VGO_darwin) diff --git a/coregrind/m_vki.c b/coregrind/m_vki.c index 278b12fdec..0cc1882a1d 100644 --- a/coregrind/m_vki.c +++ b/coregrind/m_vki.c @@ -76,7 +76,7 @@ void VG_(vki_do_initial_consistency_checks) ( void ) /* --- Platform-specific checks on signal sets --- */ -# if defined(VGO_linux) || defined(VGO_solaris) +# if defined(VGO_linux) || defined(VGO_solaris) || defined(VGO_freebsd) /* nothing to check */ # elif defined(VGP_x86_darwin) || defined(VGP_amd64_darwin) vg_assert(_VKI_NSIG == NSIG); @@ -90,7 +90,7 @@ void VG_(vki_do_initial_consistency_checks) ( void ) /* --- Platform-specific checks on sigactions --- */ -# if defined(VGO_linux) +# if defined(VGO_linux) || defined(VGO_freebsd) /* the toK- and fromK- forms are identical */ vg_assert( sizeof(vki_sigaction_toK_t) == sizeof(vki_sigaction_fromK_t) ); diff --git a/coregrind/m_vkiscnums.c b/coregrind/m_vkiscnums.c index a7ffbf7b51..76ae104afd 100644 --- a/coregrind/m_vkiscnums.c +++ b/coregrind/m_vkiscnums.c @@ -67,6 +67,17 @@ STATIC_ASSERT(__NR_pipe2 == 5287); #endif //--------------------------------------------------------------------------- +#elif defined(VGO_freebsd) +//--------------------------------------------------------------------------- + +const HChar* VG_(sysnum_string)(Word sysnum) +{ + static HChar buf[20+1]; // large enough + + VG_(snprintf)(buf, sizeof(buf), "%3ld", sysnum); + return buf; +} + #elif defined(VGO_darwin) //--------------------------------------------------------------------------- diff --git a/coregrind/pub_core_aspacemgr.h b/coregrind/pub_core_aspacemgr.h index 0f34782d3f..aac2a0a321 100644 --- a/coregrind/pub_core_aspacemgr.h +++ b/coregrind/pub_core_aspacemgr.h @@ -384,6 +384,10 @@ extern Bool VG_(am_search_for_new_segment)(Addr *start, SizeT *size, UInt *prot); #endif +/* For kern.usrstack syscall on FreeBSD */ +extern Word VG_(get_usrstack)(void); + + #endif // __PUB_CORE_ASPACEMGR_H /*--------------------------------------------------------------------*/ diff --git a/coregrind/pub_core_debuginfo.h b/coregrind/pub_core_debuginfo.h index 8f05208ac7..938ed00cc1 100644 --- a/coregrind/pub_core_debuginfo.h +++ b/coregrind/pub_core_debuginfo.h @@ -60,7 +60,7 @@ extern void VG_(di_initialise) ( void ); released by simply re-opening and closing the same file (even via different fd!). */ -#if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) +#if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) || defined(VGO_freebsd) extern ULong VG_(di_notify_mmap)( Addr a, Bool allow_SkFileV, Int use_fd ); extern void VG_(di_notify_munmap)( Addr a, SizeT len ); diff --git a/coregrind/pub_core_gdbserver.h b/coregrind/pub_core_gdbserver.h index 9ecf642484..844337f9d9 100644 --- a/coregrind/pub_core_gdbserver.h +++ b/coregrind/pub_core_gdbserver.h @@ -225,6 +225,7 @@ typedef int offset_lwpid; int vgdb_pid; + int padding; } VgdbShared64; // The below typedef makes the life of valgrind easier. diff --git a/coregrind/pub_core_initimg.h b/coregrind/pub_core_initimg.h index beef7d4c93..cfbd41f8b8 100644 --- a/coregrind/pub_core_initimg.h +++ b/coregrind/pub_core_initimg.h @@ -66,7 +66,7 @@ void VG_(ii_finalise_image)( IIFinaliseImageInfo ); /* ------------------------- Linux ------------------------- */ -#if defined(VGO_linux) +#if defined(VGO_linux) || defined(VGO_freebsd) struct _IICreateImageInfo { /* ------ Mandatory fields ------ */ diff --git a/coregrind/pub_core_libcproc.h b/coregrind/pub_core_libcproc.h index 8bf068d5ca..29cc2a4494 100644 --- a/coregrind/pub_core_libcproc.h +++ b/coregrind/pub_core_libcproc.h @@ -85,6 +85,13 @@ extern void VG_(do_atfork_pre) ( ThreadId tid ); extern void VG_(do_atfork_parent) ( ThreadId tid ); extern void VG_(do_atfork_child) ( ThreadId tid ); +#if defined(VGO_freebsd) +// sysctl, modfind +extern Int VG_(sysctlbyname)(const HChar *name, void *oldp, SizeT *oldlenp, const void *newp, SizeT newlen); +extern Int VG_(getosreldate)(void); +extern Bool VG_(is32on64)(void); +#endif + // icache invalidation extern void VG_(invalidate_icache) ( void *ptr, SizeT nbytes ); diff --git a/coregrind/pub_core_machine.h b/coregrind/pub_core_machine.h index aa1f13de06..38c9ce99c4 100644 --- a/coregrind/pub_core_machine.h +++ b/coregrind/pub_core_machine.h @@ -39,12 +39,12 @@ #include "pub_core_basics.h" // UnwindStartRegs // XXX: this is *really* the wrong spot for these things -#if defined(VGP_x86_linux) || defined(VGP_x86_solaris) +#if defined(VGP_x86_linux) || defined(VGP_x86_solaris) || defined(VGP_x86_freebsd) # define VG_ELF_DATA2XXX ELFDATA2LSB # define VG_ELF_MACHINE EM_386 # define VG_ELF_CLASS ELFCLASS32 # undef VG_PLAT_USES_PPCTOC -#elif defined(VGP_amd64_linux) || defined(VGP_amd64_solaris) +#elif defined(VGP_amd64_linux) || defined(VGP_amd64_solaris) || defined(VGP_amd64_freebsd) # define VG_ELF_DATA2XXX ELFDATA2LSB # define VG_ELF_MACHINE EM_X86_64 # define VG_ELF_CLASS ELFCLASS64 diff --git a/coregrind/pub_core_mallocfree.h b/coregrind/pub_core_mallocfree.h index 3fd22cdad8..b5922ca501 100644 --- a/coregrind/pub_core_mallocfree.h +++ b/coregrind/pub_core_mallocfree.h @@ -78,6 +78,8 @@ typedef Int ArenaId; defined(VGP_ppc64le_linux) || \ defined(VGP_s390x_linux) || \ (defined(VGP_mips64_linux) && !defined(VGABI_N32)) || \ + defined(VGP_x86_freebsd) || \ + defined(VGP_amd64_freebsd) || \ defined(VGP_x86_darwin) || \ defined(VGP_amd64_darwin) || \ defined(VGP_arm64_linux) || \ diff --git a/coregrind/pub_core_sigframe.h b/coregrind/pub_core_sigframe.h index 82bb4779ac..1b8caeb69b 100644 --- a/coregrind/pub_core_sigframe.h +++ b/coregrind/pub_core_sigframe.h @@ -58,9 +58,13 @@ void VG_(sigframe_create) ( ThreadId tid, /* Remove a signal frame from thread 'tid's stack, and restore the CPU state from it. */ +#ifdef VGO_freebsd +extern +void VG_(sigframe_destroy)( ThreadId tid ); +#else extern void VG_(sigframe_destroy)( ThreadId tid, Bool isRT ); - +#endif #if defined(VGO_solaris) extern void VG_(sigframe_return)(ThreadId tid, const vki_ucontext_t *uc); diff --git a/coregrind/pub_core_syscall.h b/coregrind/pub_core_syscall.h index ddcca3809f..6c4f825918 100644 --- a/coregrind/pub_core_syscall.h +++ b/coregrind/pub_core_syscall.h @@ -91,6 +91,8 @@ extern SysRes VG_(mk_SysRes_x86_linux) ( Int val ); extern SysRes VG_(mk_SysRes_amd64_linux) ( Long val ); extern SysRes VG_(mk_SysRes_ppc32_linux) ( UInt val, UInt cr0so ); extern SysRes VG_(mk_SysRes_ppc64_linux) ( ULong val, ULong cr0so, UInt flag ); +extern SysRes VG_(mk_SysRes_x86_freebsd) ( UInt val, UInt val2, Bool err); +extern SysRes VG_(mk_SysRes_amd64_freebsd)( ULong val, ULong val2, Bool err ); extern SysRes VG_(mk_SysRes_arm_linux) ( Int val ); extern SysRes VG_(mk_SysRes_arm64_linux) ( Long val ); extern SysRes VG_(mk_SysRes_x86_darwin) ( UChar scclass, Bool isErr, diff --git a/coregrind/pub_core_syswrap.h b/coregrind/pub_core_syswrap.h index 9dfa97bbfd..a17620afc2 100644 --- a/coregrind/pub_core_syswrap.h +++ b/coregrind/pub_core_syswrap.h @@ -99,6 +99,10 @@ extern Bool VG_(setup_client_dataseg)(void); extern void VG_(track_client_dataseg)(ThreadId tid); #endif +#if defined(VGO_freebsd) +extern Bool VG_(get_capability_mode)(void); +#endif + #endif // __PUB_CORE_SYSWRAP_H /*--------------------------------------------------------------------*/ diff --git a/coregrind/pub_core_trampoline.h b/coregrind/pub_core_trampoline.h index 931a4bcc19..54c575a723 100644 --- a/coregrind/pub_core_trampoline.h +++ b/coregrind/pub_core_trampoline.h @@ -56,6 +56,14 @@ extern Addr VG_(trampoline_stuff_start); extern Addr VG_(trampoline_stuff_end); +#if defined(VGP_x86_freebsd) +extern void VG_(x86_freebsd_SUBST_FOR_sigreturn); +#endif + +#if defined(VGP_amd64_freebsd) +extern void VG_(amd64_freebsd_SUBST_FOR_sigreturn); +#endif + #if defined(VGP_x86_linux) extern Addr VG_(x86_linux_SUBST_FOR_sigreturn); extern Addr VG_(x86_linux_SUBST_FOR_rt_sigreturn); diff --git a/coregrind/vg_preloaded.c b/coregrind/vg_preloaded.c index 39d82c7c23..5e20983908 100644 --- a/coregrind/vg_preloaded.c +++ b/coregrind/vg_preloaded.c @@ -45,7 +45,7 @@ #include "pub_core_debuginfo.h" // Needed for pub_core_redir.h #include "pub_core_redir.h" // For VG_NOTIFY_ON_LOAD -#if defined(VGO_linux) || defined(VGO_solaris) +#if defined(VGO_linux) || defined(VGO_solaris) || defined(VGO_freebsd) /* --------------------------------------------------------------------- Hook for running __gnu_cxx::__freeres() and __libc_freeres() once @@ -207,6 +207,10 @@ void VG_REPLACE_FUNCTION_ZU(libSystemZdZaZddylib, arc4random_addrandom)(unsigned // but don't care if it's initialized } +#elif defined(VGO_freebsd) + +// nothing specific currently + #elif defined(VGO_solaris) /* Declare the errno and environ symbols weakly in case the client is not diff --git a/coregrind/vgdb.c b/coregrind/vgdb.c index 745fe32bc7..01a88ae18b 100644 --- a/coregrind/vgdb.c +++ b/coregrind/vgdb.c @@ -827,8 +827,10 @@ void close_connection(int to_pid, int from_pid) (join, "vgdb error pthread_join invoke_gdbserver_in_valgrind_thread\n"); } +#if !defined(VGO_freebsd) if (close(from_pid) != 0) ERROR(errno, "close from_pid\n"); +#endif } /* Relay data between gdb and Valgrind gdbserver, till EOF or an diff --git a/include/pub_tool_libcproc.h b/include/pub_tool_libcproc.h index f5d48eae74..5f11693cd9 100644 --- a/include/pub_tool_libcproc.h +++ b/include/pub_tool_libcproc.h @@ -70,7 +70,7 @@ extern Int VG_(system) ( const HChar* cmd ); extern Int VG_(spawn) ( const HChar *filename, const HChar **argv ); extern Int VG_(fork) ( void); extern void VG_(execv) ( const HChar* filename, const HChar** argv ); -extern Int VG_(sysctl) ( Int *name, UInt namelen, void *oldp, SizeT *oldlenp, void *newp, SizeT newlen ); +extern Int VG_(sysctl) ( Int *name, UInt namelen, void *oldp, SizeT *oldlenp, const void *newp, SizeT newlen ); /* --------------------------------------------------------------------- Resource limits and capabilities -- 2.47.2