/* Load the client whose name is VG_(argv_the_exename). */
-static void load_client ( /*OUT*/ExeInfo* info,
+static void load_client ( /*MOD*/ExeInfo* info,
/*OUT*/Addr* client_ip,
/*OUT*/Addr* client_toc)
{
VG_(exit)(127); // 127 is Posix NOTFOUND
}
- VG_(memset)(info, 0, sizeof(*info));
ret = VG_(do_exec)(exe_name, info);
if (ret < 0) {
VG_(printf)("valgrind: could not execute '%s'\n", exe_name);
ExeInfo info;
HChar** env = NULL;
- IIFinaliseImageInfo iifii;
- VG_(memset)( &iifii, 0, sizeof(iifii) );
+ IIFinaliseImageInfo iifii = {
+ .clstack_max_size = 0,
+ .initial_client_SP = 0,
+ .initial_client_IP = 0,
+ .initial_client_TOC = 0,
+ .client_auxv = NULL,
+ .arch_elf_state = VKI_INIT_ARCH_ELF_STATE,
+ };
//--------------------------------------------------------------
// Load client executable, finding in $PATH if necessary
if (VG_(args_the_exename) == NULL)
VG_(err_missing_prog)();
+ VG_(memset)(&info, 0, sizeof(info));
+ info.arch_elf_state = &iifii.arch_elf_state;
+
load_client(&info, &iifii.initial_client_IP, &iifii.initial_client_TOC);
//--------------------------------------------------------------
arch->vex.guest_PC = iifii.initial_client_IP;
arch->vex.guest_r31 = iifii.initial_client_SP;
+ if (iifii.arch_elf_state.overall_fp_mode == VKI_FP_FR1) {
+ arch->vex.guest_CP0_status |= MIPS_CP0_STATUS_FR;
+ }
+
# elif defined(VGP_mips64_linux)
vg_assert(0 == sizeof(VexGuestMIPS64State) % LibVEX_GUEST_STATE_ALIGN);
/* Zero out the initial state, and set up the simulated FPU in a
}
}
- /* Check if CPU has FPU and 32 dbl. prec. FP registers */
- int FIR = 0;
- __asm__ __volatile__(
- "cfc1 %0, $0" "\n\t"
- : "=r" (FIR)
- );
- if (FIR & (1 << FP64)) {
- vai.hwcaps |= VEX_MIPS_CPU_32FPR;
- }
-
VG_(convert_sigaction_fromK_to_toK)(&saved_sigill_act, &tmp_sigill_act);
VG_(sigaction)(VKI_SIGILL, &tmp_sigill_act, NULL);
VG_(sigprocmask)(VKI_SIG_SETMASK, &saved_set, NULL);
+# if defined(VGP_mips32_linux)
+ Int fpmode = VG_(prctl)(VKI_PR_GET_FP_MODE);
+# else
+ Int fpmode = -1;
+# endif
+
+ if (fpmode < 0) {
+ /* prctl(PR_GET_FP_MODE) is not supported by Kernel,
+ we are using alternative way to determine FP mode */
+ ULong result = 0;
+ __asm__ volatile (
+ ".set push\n\t"
+ ".set noreorder\n\t"
+ ".set oddspreg\n\t"
+ "lui $t0, 0x3FF0\n\t"
+ "ldc1 $f0, %0\n\t"
+ "mtc1 $t0, $f1\n\t"
+ "sdc1 $f0, %0\n\t"
+ ".set pop\n\t"
+ : "+m"(result)
+ :
+ : "t0", "$f0", "$f1", "memory");
+
+ fpmode = (result != 0x3FF0000000000000ull);
+ }
+
+ if (fpmode != 0)
+ vai.hwcaps |= VEX_MIPS_HOST_FR;
+
VG_(debugLog)(1, "machine", "hwcaps = 0x%x\n", vai.hwcaps);
VG_(machine_get_cache_info)(&vai);
vai.endness = VexEndness_INVALID;
# endif
+ vai.hwcaps |= VEX_MIPS_HOST_FR;
+
VG_(machine_get_cache_info)(&vai);
return True;
DECL_TEMPLATE (mips_linux, sys_cacheflush);
DECL_TEMPLATE (mips_linux, sys_set_thread_area);
DECL_TEMPLATE (mips_linux, sys_pipe);
+DECL_TEMPLATE (mips_linux, sys_prctl);
PRE(sys_mmap2)
{
}
}
+PRE (sys_prctl)
+{
+ switch (ARG1) {
+ case VKI_PR_SET_FP_MODE:
+ {
+ VexArchInfo vai;
+ VG_(machine_get_VexArchInfo)(NULL, &vai);
+ /* Reject unsupported modes */
+ if ((ARG2 & ~VKI_PR_FP_MODE_FR) ||
+ ((ARG2 & VKI_PR_FP_MODE_FR) &&
+ !VEX_MIPS_HOST_FP_MODE(vai.hwcaps))) {
+ SET_STATUS_Failure(VKI_EOPNOTSUPP);
+ } else {
+ if (!(VG_(threads)[tid].arch.vex.guest_CP0_status &
+ MIPS_CP0_STATUS_FR) != !(ARG2 & VKI_PR_FP_MODE_FR)) {
+ ThreadId t;
+ for (t = 1; t < VG_N_THREADS; t++) {
+ if (VG_(threads)[t].status != VgTs_Empty) {
+ if (ARG2 & VKI_PR_FP_MODE_FR) {
+ VG_(threads)[t].arch.vex.guest_CP0_status |=
+ MIPS_CP0_STATUS_FR;
+ } else {
+ VG_(threads)[t].arch.vex.guest_CP0_status &=
+ ~MIPS_CP0_STATUS_FR;
+ }
+ }
+ }
+ /* Discard all translations */
+ VG_(discard_translations)(0, 0xfffffffful, "prctl(PR_SET_FP_MODE)");
+ }
+ SET_STATUS_Success(0);
+ }
+ break;
+ }
+ case VKI_PR_GET_FP_MODE:
+ if (VG_(threads)[tid].arch.vex.guest_CP0_status & MIPS_CP0_STATUS_FR)
+ SET_STATUS_Success(VKI_PR_FP_MODE_FR);
+ else
+ SET_STATUS_Success(0);
+ break;
+ default:
+ WRAPPER_PRE_NAME(linux, sys_prctl)(tid, layout, arrghs, status, flags);
+ break;
+ }
+}
+
#undef PRE
#undef POST
//..
LINX_ (__NR_setresgid, sys_setresgid), // 190
LINXY (__NR_getresgid, sys_getresgid), // 191
- LINXY (__NR_prctl, sys_prctl), // 192
+ PLAX_ (__NR_prctl, sys_prctl), // 192
PLAX_ (__NR_rt_sigreturn, sys_rt_sigreturn), // 193
LINXY (__NR_rt_sigaction, sys_rt_sigaction), // 194
LINXY (__NR_rt_sigprocmask, sys_rt_sigprocmask), // 195
# if defined(VGP_amd64_solaris)
vex_abiinfo.guest_amd64_assume_fs_is_const = True;
# endif
+# if defined(VGP_mips32_linux) || defined(VGP_mips64_linux)
+ ThreadArchState* arch = &VG_(threads)[tid].arch;
+ vex_abiinfo.guest_mips_fp_mode64 =
+ !!(arch->vex.guest_CP0_status & MIPS_CP0_STATUS_FR);
+# endif
/* Set up closure args. */
closure.tid = tid;
Int fd;
};
+#if defined(VGO_linux)
+
+/*
+ arch_elf_pt_proc() - check a PT_LOPROC..PT_HIPROC ELF program header
+ @ehdr: The main ELF header
+ @phdr: The program header to check
+ @fd: The ELF file filedescriptor
+ @is_interpreter: True if the phdr is from the interpreter of the ELF
+ being loaded, else false.
+ @state: Architecture-specific state preserved throughout the process
+ of loading the ELF.
+
+ Inspects the program header phdr to validate its correctness and/or
+ suitability for the system. Called once per ELF program header in the
+ range PT_LOPROC to PT_HIPROC, for both the ELF being loaded and its
+ interpreter.
+
+ Return: Zero to proceed with the ELF load, non-zero to fail the ELF load
+ with that return code.
+
+ arch_check_elf()
+ @ehdr: The main ELF header
+ @has_interpreter: True if the ELF has an interpreter, else false.
+ @state: Architecture-specific state preserved throughout the process
+ of loading the ELF.
+
+ Provides a final opportunity for architecture code to reject the loading
+ of the ELF. This is called after all program headers to be checked by
+ arch_elf_pt_proc have been.
+
+ Return: Zero to proceed with the ELF load, non-zero to fail the ELF load
+ with that return code.
+
+ Ref: linux/fs/binfmt_elf.c
+ */
+
+# if defined(VGP_mips32_linux)
+
+/* Ref: linux/arch/mips/kernel/elf.c */
+static inline Int arch_elf_pt_proc(ESZ(Ehdr) *ehdr,
+ ESZ(Phdr) *phdr,
+ Int fd, Bool is_interpreter,
+ struct vki_arch_elf_state *state)
+{
+ struct vki_mips_elf_abiflags_v0 abiflags;
+ SysRes sres;
+
+ if ( (ehdr->e_ident[EI_CLASS] == ELFCLASS32) &&
+ (ehdr->e_flags & VKI_EF_MIPS_FP64) ) {
+ /*
+ * Set MIPS_ABI_FP_OLD_64 for EF_MIPS_FP64. We will override it
+ * later if needed
+ */
+ if (is_interpreter)
+ state->interp_fp_abi = VKI_MIPS_ABI_FP_OLD_64;
+ else
+ state->fp_abi = VKI_MIPS_ABI_FP_OLD_64;
+ }
+
+ if (phdr->p_type != VKI_PT_MIPS_ABIFLAGS)
+ return 0;
+
+ if (phdr->p_filesz < sizeof(abiflags))
+ return VKI_EINVAL;
+
+ sres = VG_(pread)(fd, &abiflags, sizeof(abiflags), phdr->p_offset);
+
+ if (sr_isError(sres))
+ return sr_Err(sres);
+
+ if (sr_Res(sres) != sizeof(abiflags))
+ return VKI_EIO;
+
+ /* Record the required FP ABIs for use by arch_check_elf */
+ if (is_interpreter)
+ state->interp_fp_abi = abiflags.fp_abi;
+ else
+ state->fp_abi = abiflags.fp_abi;
+
+ return 0;
+}
+
+/* Ref: linux/arch/mips/kernel/elf.c */
+static inline Int arch_check_elf(ESZ(Ehdr) *ehdr,
+ Bool has_interpreter,
+ struct vki_arch_elf_state *state)
+{
+ struct mode_req {
+ Bool single;
+ Bool soft;
+ Bool fr1;
+ Bool frdefault;
+ Bool fre;
+ };
+
+ struct mode_req fpu_reqs[] = {
+ [VKI_MIPS_ABI_FP_ANY] = { True, True, True, True, True },
+ [VKI_MIPS_ABI_FP_DOUBLE] = { False, False, False, True, True },
+ [VKI_MIPS_ABI_FP_SINGLE] = { True, False, False, False, False },
+ [VKI_MIPS_ABI_FP_SOFT] = { False, True, False, False, False },
+ [VKI_MIPS_ABI_FP_OLD_64] = { False, False, False, False, False },
+ [VKI_MIPS_ABI_FP_XX] = { False, False, True, True, True },
+ [VKI_MIPS_ABI_FP_64] = { False, False, True, False, False },
+ [VKI_MIPS_ABI_FP_64A] = { False, False, True, False, True }
+ };
+
+ /* Mode requirements when .MIPS.abiflags is not present in the ELF.
+ Not present means that everything is acceptable except FR1. */
+ struct mode_req none_req = { True, True, False, True, True };
+
+ struct mode_req prog_req, interp_req;
+ Int fp_abi, interp_fp_abi, abi0, abi1, max_abi;
+ Bool is_mips64;
+
+ VexArchInfo vai;
+ VG_(machine_get_VexArchInfo)(NULL, &vai);
+
+ fp_abi = state->fp_abi;
+
+ if (has_interpreter) {
+ interp_fp_abi = state->interp_fp_abi;
+
+ abi0 = VG_MIN(fp_abi, interp_fp_abi);
+ abi1 = VG_MAX(fp_abi, interp_fp_abi);
+ } else {
+ abi0 = abi1 = fp_abi;
+ }
+
+ is_mips64 = (ehdr->e_ident[EI_CLASS] == ELFCLASS64) ||
+ (ehdr->e_flags & EF_MIPS_ABI2);
+
+ if (is_mips64) {
+ /* MIPS64 code always uses FR=1, thus the default is easy */
+ state->overall_fp_mode = VKI_FP_FR1;
+
+ /* Disallow access to the various FPXX & FP64 ABIs */
+ max_abi = VKI_MIPS_ABI_FP_SOFT;
+ } else {
+ /* Default to a mode capable of running code expecting FR=0 */
+
+ /* TODO: Should be changed during implementation of MIPS-R6 support.
+ state->overall_fp_mode = cpu_has_mips_r6 ? VKI_FP_FRE : VKI_FP_FR0; */
+ state->overall_fp_mode = VKI_FP_FR0;
+
+ /* Allow all ABIs we know about */
+ max_abi = VKI_MIPS_ABI_FP_64A;
+ }
+
+ if ((abi0 > max_abi && abi0 != VKI_MIPS_ABI_FP_UNKNOWN) ||
+ (abi1 > max_abi && abi1 != VKI_MIPS_ABI_FP_UNKNOWN))
+ return VKI_ELIBBAD;
+
+ /* It's time to determine the FPU mode requirements */
+ prog_req = (abi0 == VKI_MIPS_ABI_FP_UNKNOWN) ? none_req : fpu_reqs[abi0];
+ interp_req = (abi1 == VKI_MIPS_ABI_FP_UNKNOWN) ? none_req : fpu_reqs[abi1];
+
+ /* Check whether the program's and interp's ABIs have a matching FPU
+ mode requirement. */
+ prog_req.single = interp_req.single && prog_req.single;
+ prog_req.soft = interp_req.soft && prog_req.soft;
+ prog_req.fr1 = interp_req.fr1 && prog_req.fr1;
+ prog_req.frdefault = interp_req.frdefault && prog_req.frdefault;
+ prog_req.fre = interp_req.fre && prog_req.fre;
+
+ /* Determine the desired FPU mode
+
+ Decision making:
+
+ - We want FR_FRE if FRE=1 and both FR=1 and FR=0 are false. This
+ means that we have a combination of program and interpreter
+ that inherently require the hybrid FP mode.
+ - If FR1 and FRDEFAULT is true, that means we hit the any-abi or
+ fpxx case. This is because, in any-ABI (or no-ABI) we have no FPU
+ instructions so we don't care about the mode. We will simply use
+ the one preferred by the hardware. In fpxx case, that ABI can
+ handle both FR=1 and FR=0, so, again, we simply choose the one
+ preferred by the hardware. Next, if we only use single-precision
+ FPU instructions, and the default ABI FPU mode is not good
+ (ie single + any ABI combination), we set again the FPU mode to the
+ one is preferred by the hardware. Next, if we know that the code
+ will only use single-precision instructions, shown by single being
+ true but frdefault being false, then we again set the FPU mode to
+ the one that is preferred by the hardware.
+ - We want FP_FR1 if that's the only matching mode and the default one
+ is not good.
+ - Return with ELIBADD if we can't find a matching FPU mode. */
+ if (prog_req.fre && !prog_req.frdefault && !prog_req.fr1)
+ state->overall_fp_mode = VKI_FP_FRE;
+ else if ((prog_req.fr1 && prog_req.frdefault) ||
+ (prog_req.single && !prog_req.frdefault))
+ state->overall_fp_mode = VEX_MIPS_HOST_FP_MODE(vai.hwcaps) ?
+ VKI_FP_FR1 : VKI_FP_FR0;
+ else if (prog_req.fr1)
+ state->overall_fp_mode = VKI_FP_FR1;
+ else if (!prog_req.fre && !prog_req.frdefault &&
+ !prog_req.fr1 && !prog_req.single && !prog_req.soft)
+ return VKI_ELIBBAD;
+
+ /* TODO: Currently, Valgrind doesn't support FRE and doesn't support FR1
+ emulation on FR0 system, so in those cases we are forced to
+ reject the ELF. */
+ if ((state->overall_fp_mode == VKI_FP_FRE) ||
+ ((state->overall_fp_mode == VKI_FP_FR1) &&
+ !VEX_MIPS_HOST_FP_MODE(vai.hwcaps)))
+ return VKI_ELIBBAD;
+
+ return 0;
+}
+
+# else
+
+static inline Int arch_elf_pt_proc(ESZ(Ehdr) *ehdr,
+ ESZ(Phdr) *phdr,
+ Int fd, Bool is_interpreter,
+ struct vki_arch_elf_state *state)
+{
+ /* Dummy implementation, always proceed */
+ return 0;
+}
+
+static inline Int arch_check_elf(ESZ(Ehdr) *ehdr,
+ Bool has_interpreter,
+ struct vki_arch_elf_state *state)
+{
+ /* Dummy implementation, always proceed */
+ return 0;
+}
+
+# endif
+#endif
+
static void check_mmap(SysRes res, Addr base, SizeT len)
{
if (sr_isError(res)) {
ESZ(Addr) thrptr_addr = 0;
# endif
+# if defined(VGO_linux)
+ Int retval;
+# endif
+
# if defined(HAVE_PIE)
ebase = info->exe_base;
# endif
}
# endif
+# if defined(VGO_linux)
+ if ((iph->p_type >= PT_LOPROC) && (iph->p_type <= PT_HIPROC)) {
+ retval = arch_elf_pt_proc(&interp->e, iph, intfd, True,
+ info->arch_elf_state);
+ if (retval)
+ return retval;
+ }
+# endif
+
if (iph->p_type != PT_LOAD || iph->p_memsz == 0)
continue;
break;
# endif
+# if defined(VGO_linux)
+ case PT_LOPROC ... PT_HIPROC:
+ retval = arch_elf_pt_proc(&e->e, ph, fd, False, info->arch_elf_state);
+ if (retval)
+ return retval;
+ break;
+# endif
+
default:
// do nothing
break;
}
}
+# if defined(VGO_linux)
+ retval = arch_check_elf(&e->e,
+ interp != NULL,
+ info->arch_elf_state);
+ if (retval)
+ return retval;
+# endif
+
if (info->phdr == 0)
info->phdr = minaddr + ebase + e->e.e_phoff;
Addr initial_client_IP;
Addr initial_client_TOC;
UInt* client_auxv;
+ /* ------ Arch-specific ELF loading state ------ */
+ struct vki_arch_elf_state arch_elf_state;
};
/* ------------------------- Darwin ------------------------- */
Bool ldsoexec; // OUT: the program is the runtime linker itself
#endif
+#if defined(VGO_linux)
+ // INOUT: architecture-specific ELF loading state
+ struct vki_arch_elf_state *arch_elf_state;
+#endif
+
Addr entry; // OUT: entrypoint in main executable
Addr init_ip; // OUT: address of first instruction to execute
Addr brkbase; // OUT: base address of brk segment
#define STATIC_ASSERT(x) extern int VG_(VG_(VG_(unused)))[(x) ? 1 : -1] \
__attribute__((unused))
+#define VG_MAX(a,b) ((a) > (b) ? a : b)
+#define VG_MIN(a,b) ((a) < (b) ? a : b)
+
#endif /* __PUB_TOOL_BASICS_H */
/*--------------------------------------------------------------------*/
unsigned long iomap_base; /* cookie passed into ioremap */
};
+//----------------------------------------------------------------------
+// From linux-3.19.0/fs/binfmt_elf.c
+//----------------------------------------------------------------------
+
+#if !defined(VKI_INIT_ARCH_ELF_STATE)
+ /* This structure is used to preserve architecture specific data during
+ the loading of an ELF file, throughout the checking of architecture
+ specific ELF headers & through to the point where the ELF load is
+ known to be proceeding. This implementation is a dummy for
+ architectures which require no specific state. */
+ struct vki_arch_elf_state {
+ };
+
+# define VKI_INIT_ARCH_ELF_STATE { }
+
+#endif
+
+//----------------------------------------------------------------------
+// From linux-4.0/include/uapi/linux/prctl.h
+//----------------------------------------------------------------------
+
+#define VKI_PR_SET_FP_MODE 45
+#define VKI_PR_GET_FP_MODE 46
+# define VKI_PR_FP_MODE_FR (1 << 0) /* 64b FP registers */
+# define VKI_PR_FP_MODE_FRE (1 << 1) /* 32b compatibility */
+
#endif // __VKI_LINUX_H
/*--------------------------------------------------------------------*/
};
#define ARCH_HAS_SOCKET_TYPES 1
+//----------------------------------------------------------------------
+// From linux-3.7.0/arch/mips/include/uapi/asm/errno.h
+//----------------------------------------------------------------------
+
+#define VKI_ELIBBAD 84 /* Accessing a corrupted shared library */
+#define VKI_EOPNOTSUPP 122 /* Operation not supported on transport
+ endpoint */
+
//----------------------------------------------------------------------
// From linux-3.13.0/include/asm/errno.h
//----------------------------------------------------------------------
#define VKI_ENOSYS 89 /* Function not implemented */
#define VKI_EOVERFLOW 79 /* Value too large for defined data type */
+//----------------------------------------------------------------------
+// From linux-3.14.0/arch/mips/include/asm/elf.h
+//----------------------------------------------------------------------
+
+#define VKI_EF_MIPS_FP64 0x00000200
+
+//----------------------------------------------------------------------
+// From linux-4.1.0/arch/mips/include/asm/elf.h
+//----------------------------------------------------------------------
+
+#define VKI_MIPS_ABI_FP_UNKNOWN (-1)
+#define VKI_MIPS_ABI_FP_ANY 0 /* FP ABI doesn't matter */
+#define VKI_MIPS_ABI_FP_DOUBLE 1 /* -mdouble-float */
+#define VKI_MIPS_ABI_FP_SINGLE 2 /* -msingle-float */
+#define VKI_MIPS_ABI_FP_SOFT 3 /* -msoft-float */
+#define VKI_MIPS_ABI_FP_OLD_64 4 /* -mips32r2 -mfp64 */
+#define VKI_MIPS_ABI_FP_XX 5 /* -mfpxx */
+#define VKI_MIPS_ABI_FP_64 6 /* -mips32r2 -mfp64 */
+#define VKI_MIPS_ABI_FP_64A 7 /* -mips32r2 -mfp64 -mno-odd-spreg */
+
+struct vki_arch_elf_state {
+ int fp_abi;
+ int interp_fp_abi;
+ int overall_fp_mode;
+};
+
+#define VKI_INIT_ARCH_ELF_STATE { \
+ .fp_abi = VKI_MIPS_ABI_FP_UNKNOWN, \
+ .interp_fp_abi = VKI_MIPS_ABI_FP_UNKNOWN, \
+ .overall_fp_mode = -1, \
+}
+
+struct vki_mips_elf_abiflags_v0 {
+ vki_u16 version; /* Version of flags structure */
+ vki_u8 isa_level; /* The level of the ISA: 1-5, 32, 64 */
+ vki_u8 isa_rev; /* The revision of ISA: 0 for MIPS V and below,
+ 1-n otherwise */
+ vki_u8 gpr_size; /* The size of general purpose registers */
+ vki_u8 cpr1_size; /* The size of co-processor 1 registers */
+ vki_u8 cpr2_size; /* The size of co-processor 2 registers */
+ vki_u8 fp_abi; /* The floating-point ABI */
+ vki_u32 isa_ext; /* Mask of processor-specific extensions */
+ vki_u32 ases; /* Mask of ASEs used */
+ vki_u32 flags1; /* Mask of general flags */
+ vki_u32 flags2;
+};
+
+#define VKI_PT_MIPS_ABIFLAGS 0x70000003
+
+//----------------------------------------------------------------------
+// From linux-4.1.0/arch/mips/kernel/elf.c
+//----------------------------------------------------------------------
+
+enum {
+ VKI_FP_FRE,
+ VKI_FP_FR0,
+ VKI_FP_FR1,
+};
+
#endif // __VKI_MIPS32_LINUX_H
/*--------------------------------------------------------------------*/