diff options
author | Stephane Marchesin <marchesin@icps.u-strasbg.fr> | 2009-05-04 19:05:59 +0200 |
---|---|---|
committer | Stephane Marchesin <marchesin@icps.u-strasbg.fr> | 2009-05-04 19:05:59 +0200 |
commit | 6e410b3bb6ff51580897431105aae14591cbf7fb (patch) | |
tree | f8aeba9352710f10cd6b1d5138c8fc3ece91c8c3 /coregrind/m_machine.c |
Diffstat (limited to 'coregrind/m_machine.c')
-rw-r--r-- | coregrind/m_machine.c | 676 |
1 files changed, 676 insertions, 0 deletions
diff --git a/coregrind/m_machine.c b/coregrind/m_machine.c new file mode 100644 index 0000000..8d5901f --- /dev/null +++ b/coregrind/m_machine.c @@ -0,0 +1,676 @@ + +/*--------------------------------------------------------------------*/ +/*--- Machine-related stuff. m_machine.c ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2000-2009 Julian Seward + jseward@acm.org + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. + + The GNU General Public License is contained in the file COPYING. +*/ + +#include "pub_core_basics.h" +#include "pub_core_vki.h" +#include "pub_core_threadstate.h" +#include "pub_core_libcassert.h" +#include "pub_core_libcbase.h" +#include "pub_core_machine.h" +#include "pub_core_cpuid.h" +#include "pub_core_libcsignal.h" // for ppc32 messing with SIGILL and SIGFPE +#include "pub_core_debuglog.h" + + +#define INSTR_PTR(regs) ((regs).vex.VG_INSTR_PTR) +#define STACK_PTR(regs) ((regs).vex.VG_STACK_PTR) +#define FRAME_PTR(regs) ((regs).vex.VG_FRAME_PTR) + +Addr VG_(get_SP) ( ThreadId tid ) +{ + return STACK_PTR( VG_(threads)[tid].arch ); +} + +Addr VG_(get_IP) ( ThreadId tid ) +{ + return INSTR_PTR( VG_(threads)[tid].arch ); +} + +Addr VG_(get_FP) ( ThreadId tid ) +{ + return FRAME_PTR( VG_(threads)[tid].arch ); +} + +Addr VG_(get_LR) ( ThreadId tid ) +{ +# if defined(VGA_ppc32) || defined(VGA_ppc64) + return VG_(threads)[tid].arch.vex.guest_LR; +# elif defined(VGA_x86) || defined(VGA_amd64) + return 0; +# else +# error "Unknown arch" +# endif +} + +void VG_(set_SP) ( ThreadId tid, Addr sp ) +{ + STACK_PTR( VG_(threads)[tid].arch ) = sp; +} + +void VG_(set_IP) ( ThreadId tid, Addr ip ) +{ + INSTR_PTR( VG_(threads)[tid].arch ) = ip; +} + +void VG_(set_syscall_return_shadows) ( ThreadId tid, + /* shadow vals for the result */ + UWord s1res, UWord s2res, + /* shadow vals for the error val */ + UWord s1err, UWord s2err ) +{ +# if defined(VGP_x86_linux) + VG_(threads)[tid].arch.vex_shadow1.guest_EAX = s1res; + VG_(threads)[tid].arch.vex_shadow2.guest_EAX = s2res; +# elif defined(VGP_amd64_linux) + VG_(threads)[tid].arch.vex_shadow1.guest_RAX = s1res; + VG_(threads)[tid].arch.vex_shadow2.guest_RAX = s2res; +# elif defined(VGP_ppc32_linux) || defined(VGP_ppc64_linux) + VG_(threads)[tid].arch.vex_shadow1.guest_GPR3 = s1res; + VG_(threads)[tid].arch.vex_shadow2.guest_GPR3 = s2res; +# elif defined(VGP_ppc32_aix5) || defined(VGP_ppc64_aix5) + VG_(threads)[tid].arch.vex_shadow1.guest_GPR3 = s1res; + VG_(threads)[tid].arch.vex_shadow2.guest_GPR3 = s2res; + VG_(threads)[tid].arch.vex_shadow1.guest_GPR4 = s1err; + VG_(threads)[tid].arch.vex_shadow2.guest_GPR4 = s2err; +# else +# error "Unknown plat" +# endif +} + +void +VG_(get_shadow_regs_area) ( ThreadId tid, + /*DST*/UChar* dst, + /*SRC*/Int shadowNo, PtrdiffT offset, SizeT size ) +{ + void* src; + ThreadState* tst; + vg_assert(shadowNo == 0 || shadowNo == 1 || shadowNo == 2); + vg_assert(VG_(is_valid_tid)(tid)); + // Bounds check + vg_assert(0 <= offset && offset < sizeof(VexGuestArchState)); + vg_assert(offset + size <= sizeof(VexGuestArchState)); + // Copy + tst = & VG_(threads)[tid]; + src = NULL; + switch (shadowNo) { + case 0: src = (void*)(((Addr)&(tst->arch.vex)) + offset); break; + case 1: src = (void*)(((Addr)&(tst->arch.vex_shadow1)) + offset); break; + case 2: src = (void*)(((Addr)&(tst->arch.vex_shadow2)) + offset); break; + } + tl_assert(src != NULL); + VG_(memcpy)( dst, src, size); +} + +void +VG_(set_shadow_regs_area) ( ThreadId tid, + /*DST*/Int shadowNo, PtrdiffT offset, SizeT size, + /*SRC*/const UChar* src ) +{ + void* dst; + ThreadState* tst; + vg_assert(shadowNo == 0 || shadowNo == 1 || shadowNo == 2); + vg_assert(VG_(is_valid_tid)(tid)); + // Bounds check + vg_assert(0 <= offset && offset < sizeof(VexGuestArchState)); + vg_assert(offset + size <= sizeof(VexGuestArchState)); + // Copy + tst = & VG_(threads)[tid]; + dst = NULL; + switch (shadowNo) { + case 0: dst = (void*)(((Addr)&(tst->arch.vex)) + offset); break; + case 1: dst = (void*)(((Addr)&(tst->arch.vex_shadow1)) + offset); break; + case 2: dst = (void*)(((Addr)&(tst->arch.vex_shadow2)) + offset); break; + } + tl_assert(dst != NULL); + VG_(memcpy)( dst, src, size); +} + + +static void apply_to_GPs_of_tid(VexGuestArchState* vex, void (*f)(Addr)) +{ +#if defined(VGA_x86) + (*f)(vex->guest_EAX); + (*f)(vex->guest_ECX); + (*f)(vex->guest_EDX); + (*f)(vex->guest_EBX); + (*f)(vex->guest_ESI); + (*f)(vex->guest_EDI); + (*f)(vex->guest_ESP); + (*f)(vex->guest_EBP); +#elif defined(VGA_amd64) + (*f)(vex->guest_RAX); + (*f)(vex->guest_RCX); + (*f)(vex->guest_RDX); + (*f)(vex->guest_RBX); + (*f)(vex->guest_RSI); + (*f)(vex->guest_RDI); + (*f)(vex->guest_RSP); + (*f)(vex->guest_RBP); + (*f)(vex->guest_R8); + (*f)(vex->guest_R9); + (*f)(vex->guest_R10); + (*f)(vex->guest_R11); + (*f)(vex->guest_R12); + (*f)(vex->guest_R13); + (*f)(vex->guest_R14); + (*f)(vex->guest_R15); +#elif defined(VGA_ppc32) || defined(VGA_ppc64) + /* XXX ask tool about validity? */ + (*f)(vex->guest_GPR0); + (*f)(vex->guest_GPR1); + (*f)(vex->guest_GPR2); + (*f)(vex->guest_GPR3); + (*f)(vex->guest_GPR4); + (*f)(vex->guest_GPR5); + (*f)(vex->guest_GPR6); + (*f)(vex->guest_GPR7); + (*f)(vex->guest_GPR8); + (*f)(vex->guest_GPR9); + (*f)(vex->guest_GPR10); + (*f)(vex->guest_GPR11); + (*f)(vex->guest_GPR12); + (*f)(vex->guest_GPR13); + (*f)(vex->guest_GPR14); + (*f)(vex->guest_GPR15); + (*f)(vex->guest_GPR16); + (*f)(vex->guest_GPR17); + (*f)(vex->guest_GPR18); + (*f)(vex->guest_GPR19); + (*f)(vex->guest_GPR20); + (*f)(vex->guest_GPR21); + (*f)(vex->guest_GPR22); + (*f)(vex->guest_GPR23); + (*f)(vex->guest_GPR24); + (*f)(vex->guest_GPR25); + (*f)(vex->guest_GPR26); + (*f)(vex->guest_GPR27); + (*f)(vex->guest_GPR28); + (*f)(vex->guest_GPR29); + (*f)(vex->guest_GPR30); + (*f)(vex->guest_GPR31); + (*f)(vex->guest_CTR); + (*f)(vex->guest_LR); + +#else +# error Unknown arch +#endif +} + + +void VG_(apply_to_GP_regs)(void (*f)(UWord)) +{ + ThreadId tid; + + for (tid = 1; tid < VG_N_THREADS; tid++) { + if (VG_(is_valid_tid)(tid)) { + ThreadState* tst = VG_(get_ThreadState)(tid); + apply_to_GPs_of_tid(&(tst->arch.vex), f); + } + } +} + +void VG_(thread_stack_reset_iter)(/*OUT*/ThreadId* tid) +{ + *tid = (ThreadId)(-1); +} + +Bool VG_(thread_stack_next)(/*MOD*/ThreadId* tid, + /*OUT*/Addr* stack_min, + /*OUT*/Addr* stack_max) +{ + ThreadId i; + for (i = (*tid)+1; i < VG_N_THREADS; i++) { + if (i == VG_INVALID_THREADID) + continue; + if (VG_(threads)[i].status != VgTs_Empty) { + *tid = i; + *stack_min = VG_(get_SP)(i); + *stack_max = VG_(threads)[i].client_stack_highest_word; + return True; + } + } + return False; +} + +Addr VG_(thread_get_stack_max)(ThreadId tid) +{ + vg_assert(0 <= tid && tid < VG_N_THREADS && tid != VG_INVALID_THREADID); + vg_assert(VG_(threads)[tid].status != VgTs_Empty); + return VG_(threads)[tid].client_stack_highest_word; +} + +SizeT VG_(thread_get_stack_size)(ThreadId tid) +{ + vg_assert(0 <= tid && tid < VG_N_THREADS && tid != VG_INVALID_THREADID); + vg_assert(VG_(threads)[tid].status != VgTs_Empty); + return VG_(threads)[tid].client_stack_szB; +} + +//------------------------------------------------------------- +/* Details about the capabilities of the underlying (host) CPU. These + details are acquired by (1) enquiring with the CPU at startup, or + (2) from the AT_SYSINFO entries the kernel gave us (ppc32 cache + line size). It's a bit nasty in the sense that there's no obvious + way to stop uses of some of this info before it's ready to go. + + Current dependencies are: + + x86: initially: call VG_(machine_get_hwcaps) + + then safe to use VG_(machine_get_VexArchInfo) + and VG_(machine_x86_have_mxcsr) + ------------- + amd64: initially: call VG_(machine_get_hwcaps) + + then safe to use VG_(machine_get_VexArchInfo) + ------------- + ppc32: initially: call VG_(machine_get_hwcaps) + call VG_(machine_ppc32_set_clszB) + + then safe to use VG_(machine_get_VexArchInfo) + and VG_(machine_ppc32_has_FP) + and VG_(machine_ppc32_has_VMX) + ------------- + ppc64: initially: call VG_(machine_get_hwcaps) + call VG_(machine_ppc64_set_clszB) + + then safe to use VG_(machine_get_VexArchInfo) + and VG_(machine_ppc64_has_VMX) + + VG_(machine_get_hwcaps) may use signals (although it attempts to + leave signal state unchanged) and therefore should only be + called before m_main sets up the client's signal state. +*/ + +/* --------- State --------- */ +static Bool hwcaps_done = False; + +/* --- all archs --- */ +static VexArch va; +static VexArchInfo vai; + +#if defined(VGA_x86) +UInt VG_(machine_x86_have_mxcsr) = 0; +#endif +#if defined(VGA_ppc32) +UInt VG_(machine_ppc32_has_FP) = 0; +UInt VG_(machine_ppc32_has_VMX) = 0; +#endif +#if defined(VGA_ppc64) +ULong VG_(machine_ppc64_has_VMX) = 0; +#endif + + +/* Determine what insn set and insn set variant the host has, and + record it. To be called once at system startup. Returns False if + this a CPU incapable of running Valgrind. */ + +#if defined(VGA_ppc32) || defined(VGA_ppc64) +#include <setjmp.h> // For jmp_buf +static jmp_buf env_unsup_insn; +static void handler_unsup_insn ( Int x ) { __builtin_longjmp(env_unsup_insn,1); } +#endif + +Bool VG_(machine_get_hwcaps)( void ) +{ + vg_assert(hwcaps_done == False); + hwcaps_done = True; + + // Whack default settings into vai, so that we only need to fill in + // any interesting bits. + LibVEX_default_VexArchInfo(&vai); + +#if defined(VGA_x86) + { Bool have_sse1, have_sse2; + UInt eax, ebx, ecx, edx; + + if (!VG_(has_cpuid)()) + /* we can't do cpuid at all. Give up. */ + return False; + + VG_(cpuid)(0, &eax, &ebx, &ecx, &edx); + if (eax < 1) + /* we can't ask for cpuid(x) for x > 0. Give up. */ + return False; + + /* get capabilities bits into edx */ + VG_(cpuid)(1, &eax, &ebx, &ecx, &edx); + + have_sse1 = (edx & (1<<25)) != 0; /* True => have sse insns */ + have_sse2 = (edx & (1<<26)) != 0; /* True => have sse2 insns */ + + if (have_sse2 && have_sse1) { + va = VexArchX86; + vai.hwcaps = VEX_HWCAPS_X86_SSE1; + vai.hwcaps |= VEX_HWCAPS_X86_SSE2; + VG_(machine_x86_have_mxcsr) = 1; + return True; + } + + if (have_sse1) { + va = VexArchX86; + vai.hwcaps = VEX_HWCAPS_X86_SSE1; + VG_(machine_x86_have_mxcsr) = 1; + return True; + } + + va = VexArchX86; + vai.hwcaps = 0; /*baseline - no sse at all*/ + VG_(machine_x86_have_mxcsr) = 0; + return True; + } + +#elif defined(VGA_amd64) + vg_assert(VG_(has_cpuid)()); + va = VexArchAMD64; + vai.hwcaps = 0; /*baseline - SSE2 */ + return True; + +#elif defined(VGA_ppc32) + { + /* Find out which subset of the ppc32 instruction set is supported by + verifying whether various ppc32 instructions generate a SIGILL + or a SIGFPE. An alternative approach is to check the AT_HWCAP and + AT_PLATFORM entries in the ELF auxiliary table -- see also + the_iifii.client_auxv in m_main.c. + */ + vki_sigset_t saved_set, tmp_set; + struct vki_sigaction saved_sigill_act, tmp_sigill_act; + struct vki_sigaction saved_sigfpe_act, tmp_sigfpe_act; + + volatile Bool have_F, have_V, have_FX, have_GX; + Int r; + + VG_(sigemptyset)(&tmp_set); + VG_(sigaddset)(&tmp_set, VKI_SIGILL); + VG_(sigaddset)(&tmp_set, VKI_SIGFPE); + + r = VG_(sigprocmask)(VKI_SIG_UNBLOCK, &tmp_set, &saved_set); + vg_assert(r == 0); + + r = VG_(sigaction)(VKI_SIGILL, NULL, &saved_sigill_act); + vg_assert(r == 0); + tmp_sigill_act = saved_sigill_act; + + r = VG_(sigaction)(VKI_SIGFPE, NULL, &saved_sigfpe_act); + vg_assert(r == 0); + tmp_sigfpe_act = saved_sigfpe_act; + + /* NODEFER: signal handler does not return (from the kernel's point of + view), hence if it is to successfully catch a signal more than once, + we need the NODEFER flag. */ + tmp_sigill_act.sa_flags &= ~VKI_SA_RESETHAND; + tmp_sigill_act.sa_flags &= ~VKI_SA_SIGINFO; + tmp_sigill_act.sa_flags |= VKI_SA_NODEFER; + tmp_sigill_act.ksa_handler = handler_unsup_insn; + r = VG_(sigaction)(VKI_SIGILL, &tmp_sigill_act, NULL); + vg_assert(r == 0); + + tmp_sigfpe_act.sa_flags &= ~VKI_SA_RESETHAND; + tmp_sigfpe_act.sa_flags &= ~VKI_SA_SIGINFO; + tmp_sigfpe_act.sa_flags |= VKI_SA_NODEFER; + tmp_sigfpe_act.ksa_handler = handler_unsup_insn; + r = VG_(sigaction)(VKI_SIGFPE, &tmp_sigfpe_act, NULL); + vg_assert(r == 0); + + /* standard FP insns */ + have_F = True; + if (__builtin_setjmp(env_unsup_insn)) { + have_F = False; + } else { + __asm__ __volatile__(".long 0xFC000090"); /*fmr 0,0 */ + } + + /* Altivec insns */ + have_V = True; + if (__builtin_setjmp(env_unsup_insn)) { + have_V = False; + } else { + /* Unfortunately some older assemblers don't speak Altivec (or + choose not to), so to be safe we directly emit the 32-bit + word corresponding to "vor 0,0,0". This fixes a build + problem that happens on Debian 3.1 (ppc32), and probably + various other places. */ + __asm__ __volatile__(".long 0x10000484"); /*vor 0,0,0*/ + } + + /* General-Purpose optional (fsqrt, fsqrts) */ + have_FX = True; + if (__builtin_setjmp(env_unsup_insn)) { + have_FX = False; + } else { + __asm__ __volatile__(".long 0xFC00002C"); /*fsqrt 0,0 */ + } + + /* Graphics optional (stfiwx, fres, frsqrte, fsel) */ + have_GX = True; + if (__builtin_setjmp(env_unsup_insn)) { + have_GX = False; + } else { + __asm__ __volatile__(".long 0xFC000034"); /* frsqrte 0,0 */ + } + + r = VG_(sigaction)(VKI_SIGILL, &saved_sigill_act, NULL); + vg_assert(r == 0); + r = VG_(sigaction)(VKI_SIGFPE, &saved_sigfpe_act, NULL); + vg_assert(r == 0); + r = VG_(sigprocmask)(VKI_SIG_SETMASK, &saved_set, NULL); + vg_assert(r == 0); + VG_(debugLog)(1, "machine", "F %d V %d FX %d GX %d\n", + (Int)have_F, (Int)have_V, (Int)have_FX, (Int)have_GX); + /* Make FP a prerequisite for VMX (bogusly so), and for FX and GX. */ + if (have_V && !have_F) + have_V = False; + if (have_FX && !have_F) + have_FX = False; + if (have_GX && !have_F) + have_GX = False; + + VG_(machine_ppc32_has_FP) = have_F ? 1 : 0; + VG_(machine_ppc32_has_VMX) = have_V ? 1 : 0; + + va = VexArchPPC32; + + vai.hwcaps = 0; + if (have_F) vai.hwcaps |= VEX_HWCAPS_PPC32_F; + if (have_V) vai.hwcaps |= VEX_HWCAPS_PPC32_V; + if (have_FX) vai.hwcaps |= VEX_HWCAPS_PPC32_FX; + if (have_GX) vai.hwcaps |= VEX_HWCAPS_PPC32_GX; + + /* But we're not done yet: VG_(machine_ppc32_set_clszB) must be + called before we're ready to go. */ + return True; + } + +#elif defined(VGA_ppc64) + { + /* Same instruction set detection algorithm as for ppc32. */ + vki_sigset_t saved_set, tmp_set; + struct vki_sigaction saved_sigill_act, tmp_sigill_act; + struct vki_sigaction saved_sigfpe_act, tmp_sigfpe_act; + + volatile Bool have_F, have_V, have_FX, have_GX; + + VG_(sigemptyset)(&tmp_set); + VG_(sigaddset)(&tmp_set, VKI_SIGILL); + VG_(sigaddset)(&tmp_set, VKI_SIGFPE); + + VG_(sigprocmask)(VKI_SIG_UNBLOCK, &tmp_set, &saved_set); + + VG_(sigaction)(VKI_SIGILL, NULL, &saved_sigill_act); + tmp_sigill_act = saved_sigill_act; + + VG_(sigaction)(VKI_SIGFPE, NULL, &saved_sigfpe_act); + tmp_sigfpe_act = saved_sigfpe_act; + + + /* NODEFER: signal handler does not return (from the kernel's point of + view), hence if it is to successfully catch a signal more than once, + we need the NODEFER flag. */ + tmp_sigill_act.sa_flags &= ~VKI_SA_RESETHAND; + tmp_sigill_act.sa_flags &= ~VKI_SA_SIGINFO; + tmp_sigill_act.sa_flags |= VKI_SA_NODEFER; + tmp_sigill_act.ksa_handler = handler_unsup_insn; + VG_(sigaction)(VKI_SIGILL, &tmp_sigill_act, NULL); + + tmp_sigfpe_act.sa_flags &= ~VKI_SA_RESETHAND; + tmp_sigfpe_act.sa_flags &= ~VKI_SA_SIGINFO; + tmp_sigfpe_act.sa_flags |= VKI_SA_NODEFER; + tmp_sigfpe_act.ksa_handler = handler_unsup_insn; + VG_(sigaction)(VKI_SIGFPE, &tmp_sigfpe_act, NULL); + + /* standard FP insns */ + have_F = True; + if (__builtin_setjmp(env_unsup_insn)) { + have_F = False; + } else { + __asm__ __volatile__("fmr 0,0"); + } + + /* Altivec insns */ + have_V = True; + if (__builtin_setjmp(env_unsup_insn)) { + have_V = False; + } else { + __asm__ __volatile__(".long 0x10000484"); /*vor 0,0,0*/ + } + + /* General-Purpose optional (fsqrt, fsqrts) */ + have_FX = True; + if (__builtin_setjmp(env_unsup_insn)) { + have_FX = False; + } else { + __asm__ __volatile__(".long 0xFC00002C"); /*fsqrt 0,0*/ + } + + /* Graphics optional (stfiwx, fres, frsqrte, fsel) */ + have_GX = True; + if (__builtin_setjmp(env_unsup_insn)) { + have_GX = False; + } else { + __asm__ __volatile__(".long 0xFC000034"); /*frsqrte 0,0*/ + } + + VG_(sigaction)(VKI_SIGILL, &saved_sigill_act, NULL); + VG_(sigaction)(VKI_SIGFPE, &saved_sigfpe_act, NULL); + VG_(sigprocmask)(VKI_SIG_SETMASK, &saved_set, NULL); + VG_(debugLog)(1, "machine", "F %d V %d FX %d GX %d\n", + (Int)have_F, (Int)have_V, (Int)have_FX, (Int)have_GX); + /* on ppc64, if we don't even have FP, just give up. */ + if (!have_F) + return False; + + VG_(machine_ppc64_has_VMX) = have_V ? 1 : 0; + + va = VexArchPPC64; + + vai.hwcaps = 0; + if (have_V) vai.hwcaps |= VEX_HWCAPS_PPC64_V; + if (have_FX) vai.hwcaps |= VEX_HWCAPS_PPC64_FX; + if (have_GX) vai.hwcaps |= VEX_HWCAPS_PPC64_GX; + + /* But we're not done yet: VG_(machine_ppc64_set_clszB) must be + called before we're ready to go. */ + return True; + } + +#else +# error "Unknown arch" +#endif +} + +/* Notify host cpu cache line size. */ +#if defined(VGA_ppc32) +void VG_(machine_ppc32_set_clszB)( Int szB ) +{ + vg_assert(hwcaps_done); + + /* Either the value must not have been set yet (zero) or we can + tolerate it being set to the same value multiple times, as the + stack scanning logic in m_main is a bit stupid. */ + vg_assert(vai.ppc_cache_line_szB == 0 + || vai.ppc_cache_line_szB == szB); + + vg_assert(szB == 32 || szB == 64 || szB == 128); + vai.ppc_cache_line_szB = szB; +} +#endif + + +/* Notify host cpu cache line size. */ +#if defined(VGA_ppc64) +void VG_(machine_ppc64_set_clszB)( Int szB ) +{ + vg_assert(hwcaps_done); + + /* Either the value must not have been set yet (zero) or we can + tolerate it being set to the same value multiple times, as the + stack scanning logic in m_main is a bit stupid. */ + vg_assert(vai.ppc_cache_line_szB == 0 + || vai.ppc_cache_line_szB == szB); + + vg_assert(szB == 32 || szB == 64 || szB == 128); + vai.ppc_cache_line_szB = szB; +} +#endif + + +/* Fetch host cpu info, once established. */ +void VG_(machine_get_VexArchInfo)( /*OUT*/VexArch* pVa, + /*OUT*/VexArchInfo* pVai ) +{ + vg_assert(hwcaps_done); + if (pVa) *pVa = va; + if (pVai) *pVai = vai; +} + + +// Given a pointer to a function as obtained by "& functionname" in C, +// produce a pointer to the actual entry point for the function. +void* VG_(fnptr_to_fnentry)( void* f ) +{ +#if defined(VGP_x86_linux) || defined(VGP_amd64_linux) \ + || defined(VGP_ppc32_linux) + return f; +#elif defined(VGP_ppc64_linux) || defined(VGP_ppc32_aix5) \ + || defined(VGP_ppc64_aix5) + /* All other ppc variants use the AIX scheme, in which f is a + pointer to a 3-word function descriptor, of which the first word + is the entry address. */ + UWord* descr = (UWord*)f; + return (void*)(descr[0]); +#else +# error "Unknown platform" +#endif +} + +/*--------------------------------------------------------------------*/ +/*--- end ---*/ +/*--------------------------------------------------------------------*/ |