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 ===================
- 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 ====================
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.
************************************************************* */
#include "priv_aspacemgr.h"
+#include "pub_core_libcassert.h"
#include "config.h"
}
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))
/* 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,
# 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,
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
*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
*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);
*mode = (UInt) buf.st_mode;
return True;
}
-# endif
+# endif // defined __NR_fstat
return False;
# elif defined(VGO_solaris)
# if defined(VGP_x86_solaris)
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)
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)) {
/*--- 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 ---*/
/*--------------------------------------------------------------------*/
/*
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.
# endif
#elif defined(VGO_solaris)
= (Addr) 0x00100000; // 1MB
+#elif defined(VGO_freebsd)
+ = (Addr) 0x04000000; // 64M
#else
#endif
# 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
/*-----------------------------------------------------------------*/
/*--- ---*/
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;
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. */
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
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));
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)) {
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;
} 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;
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;
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
/*------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 ---*/
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__))))
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"
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;
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)
{
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,
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;
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. */
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
# 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
{
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)
#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"
/*--- ---*/
/*--------------------------------------------------------------*/
-#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,
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 );
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));
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)
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) */
/*------------------------------------------------------------*/
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
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
#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 ---*/
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"
/* --------------- 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
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 ---*/
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):
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 ---*/
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"
#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"
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
#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,
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
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)) {
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++) {
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++) {
}
}
- 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. */
|| 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) {
|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);
/* NOTREACHED */
}
-#endif // defined(VGO_linux) || defined(VGO_solaris)
+#endif // defined(VGO_linux) || defined(VGO_solaris) || defined(VGO_freebsd)
/*--------------------------------------------------------------------*/
/*--- end ---*/
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"
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 ---*/
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;
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 '$'
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 )
/* 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
#include "pub_core_libcsignal.h"
#include "pub_core_options.h"
#include "pub_core_aspacemgr.h"
+#include "pub_core_syswrap.h"
#include "server.h"
(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");
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);
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;
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;
------------------------------------------------------------------ */
#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__( \
(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__( \
{
#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
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/<FD>. If this doesn't point to a file,
or if it doesn't exist, we return False.
*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)) {
# 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);
/* 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)
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);
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);
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);
# 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);
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,
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);
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
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
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);
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);
/* 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
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"
# 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,
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;
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)) {
(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)
# 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,
| (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,
|| 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);
*/
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;
# 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);
# 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);
# 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);
# 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 );
# 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 );
# 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,
(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,
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 )
{
#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 --- !!! --- */
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";
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);
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
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.
/* 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. */
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. */
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
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
|| 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))
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
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))
}
}
+# 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
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;
}
}
+# 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;
(*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
/* 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.
*/
#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"
"" "\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
#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"
"" "\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
#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)
#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)
*/
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,
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"
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;
{
# 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
# 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
/* ---------- 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 };
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
#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"
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")
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) \
/* 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)
{
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
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);
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;
*/
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));
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));
".previous \n\t"
);
#else
-# error "Unknown linux platform"
+# error "Unknown platform"
#endif
/* --- !!! --- EXTERNAL HEADERS start --- !!! --- */
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
#endif
+Word VG_(get_usrstack)(void)
+{
+ return VG_PGROUNDDN(the_iicii.clstack_end - the_iifii.clstack_max_size);
+}
+
+
+
/*--------------------------------------------------------------------*/
/*--- end ---*/
/*--------------------------------------------------------------------*/
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)
# 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. */
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
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);
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
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)
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
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)
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
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)
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
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)
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 );
#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 );
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)
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 );
// 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)
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 );
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)
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 );
// 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)
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);
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);
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);
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);
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);
#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; \
\
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);
#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); \
}
#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. */ \
}
// 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; \
#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; \
}
#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; \
}
#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; \
}
// 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); \
#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); \
}
#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); \
}
#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); \
}
#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; \
/*
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);
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);
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;
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;
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
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)
#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
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;
/* 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;
"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
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:
# 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 );
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
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
# 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)
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
// 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:
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) */
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
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). */
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
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
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
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
#include "pub_core_xarray.h"
#include "pub_core_clientstate.h" // VG_(client__dl_sysinfo_int80)
#include "pub_core_trampoline.h"
+#include "config.h"
/*------------------------------------------------------------*/
/* ------------------------ 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
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;
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)
/* ----------------------- 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,
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;
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
".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
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);
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";
}
/* Arguments for a syscall. */
typedef
struct SyscallArgs {
+#if defined(VGO_freebsd)
+ Word klass;
+#endif
Word sysno;
RegWord arg1;
RegWord arg2;
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;
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
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) \
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)
#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
#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)
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));
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. */ \
# 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)
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"
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)
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)))
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;
#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
#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
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:
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:
PRE_REG_READ2(long, "getpriority", int, which, int, who);
}
+#if !defined(VGO_freebsd)
PRE(sys_pwrite64)
{
*flags |= SfMayBlock;
#endif
PRE_MEM_READ( "pwrite64(buf)", ARG2, ARG3 );
}
+#endif
PRE(sys_sync)
{
PRE_REG_READ1(long, "getsid", vki_pid_t, pid);
}
+#if !defined(VGO_freebsd)
PRE(sys_pread64)
{
*flags |= SfMayBlock;
POST_MEM_WRITE( ARG2, RES );
}
}
+#endif
PRE(sys_mknod)
{
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();
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 );
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" );
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,
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
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 );
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++)
}
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) ||
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();
{
POST_MEM_WRITE( ARG2, sizeof(struct vki_stat) );
}
+#endif
+#if !defined(VGP_nanomips_linux)
PRE(sys_statfs)
{
FUSE_COMPATIBLE_MAY_BLOCK();
PRE_MEM_RASCIIZ( "unlink(pathname)", ARG1 );
}
+#if !defined(VGO_freebsd)
PRE(sys_newuname)
{
PRINT("sys_newuname ( %#" FMT_REGWORD "x )", ARG1);
POST_MEM_WRITE( ARG1, sizeof(struct vki_new_utsname) );
}
}
+#endif
PRE(sys_waitpid)
{
#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 ---*/
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.
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".
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
*/
#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,
{
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:
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;
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));
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;
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 );
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 */
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;
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;
#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
# 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);
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) {
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));
/* 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);
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;
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
/* 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");
# 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)
#endif
#endif
#endif
+#endif
+#endif
/* Let the linker know we don't need an executable stack */
MARK_STACK_NO_EXEC
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
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"
#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
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");
return 0;
}
-#endif // defined(VGO_linux) || defined(VGO_solaris)
+#endif // defined(VGO_linux) || defined(VGO_solaris) || defined(VGO_freebsd)
/*--------------------------------------------------------------------*/
/*--- end ---*/
} 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) },
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
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)
/* --- 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);
/* --- 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) );
#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)
//---------------------------------------------------------------------------
UInt *prot);
#endif
+/* For kern.usrstack syscall on FreeBSD */
+extern Word VG_(get_usrstack)(void);
+
+
#endif // __PUB_CORE_ASPACEMGR_H
/*--------------------------------------------------------------------*/
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 );
int offset_lwpid;
int vgdb_pid;
+ int padding;
} VgdbShared64;
// The below typedef makes the life of valgrind easier.
/* ------------------------- Linux ------------------------- */
-#if defined(VGO_linux)
+#if defined(VGO_linux) || defined(VGO_freebsd)
struct _IICreateImageInfo {
/* ------ Mandatory fields ------ */
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 );
#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
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) || \
/* 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);
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,
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
/*--------------------------------------------------------------------*/
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);
#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
// 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
(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
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