From: Julian Seward Date: Sun, 22 Aug 2010 12:21:14 +0000 (+0000) Subject: Merge from branches/THUMB: m_machine changes needed for Thumb support: X-Git-Tag: svn/VALGRIND_3_6_0~174 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ad584ebb648706608ed0bfc5b403544cacce79a3;p=thirdparty%2Fvalgrind.git Merge from branches/THUMB: m_machine changes needed for Thumb support: * track guest_R15 -> guest_R15T renaming * change min instruction size to 2 * tidy up VG_(get_IP) etc functions a bit * add hwcaps detection code for ARM git-svn-id: svn://svn.valgrind.org/valgrind/trunk@11283 --- diff --git a/coregrind/m_machine.c b/coregrind/m_machine.c index 911c32eddd..250a21c7ed 100644 --- a/coregrind/m_machine.c +++ b/coregrind/m_machine.c @@ -43,45 +43,23 @@ #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 ) -{ +Addr VG_(get_IP) ( ThreadId tid ) { return INSTR_PTR( VG_(threads)[tid].arch ); } - -Addr VG_(get_FP) ( ThreadId tid ) -{ +Addr VG_(get_SP) ( ThreadId tid ) { + return STACK_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; -# elif defined(VGA_arm) - return VG_(threads)[tid].arch.vex.guest_R14; -# else -# error "Unknown arch" -# endif +void VG_(set_IP) ( ThreadId tid, Addr ip ) { + INSTR_PTR( VG_(threads)[tid].arch ) = ip; } - -void VG_(set_SP) ( ThreadId tid, Addr sp ) -{ +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_(get_UnwindStartRegs) ( /*OUT*/UnwindStartRegs* regs, ThreadId tid ) { @@ -106,7 +84,7 @@ void VG_(get_UnwindStartRegs) ( /*OUT*/UnwindStartRegs* regs, regs->misc.PPC64.r_lr = VG_(threads)[tid].arch.vex.guest_LR; # elif defined(VGA_arm) - regs->r_pc = (ULong)VG_(threads)[tid].arch.vex.guest_R15; + regs->r_pc = (ULong)VG_(threads)[tid].arch.vex.guest_R15T; regs->r_sp = (ULong)VG_(threads)[tid].arch.vex.guest_R13; regs->misc.ARM.r14 = VG_(threads)[tid].arch.vex.guest_R14; @@ -385,13 +363,16 @@ UInt VG_(machine_ppc32_has_VMX) = 0; #if defined(VGA_ppc64) ULong VG_(machine_ppc64_has_VMX) = 0; #endif +#if defined(VGA_arm) +Int VG_(machine_arm_archlevel) = 4; +#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) +#if defined(VGA_ppc32) || defined(VGA_ppc64) || defined(VGA_arm) #include // For jmp_buf static jmp_buf env_unsup_insn; static void handler_unsup_insn ( Int x ) { __builtin_longjmp(env_unsup_insn,1); } @@ -764,8 +745,110 @@ Bool VG_(machine_get_hwcaps)( void ) #elif defined(VGA_arm) { + /* Same instruction set detection algorithm as for ppc32. */ + vki_sigset_t saved_set, tmp_set; + vki_sigaction_fromK_t saved_sigill_act, saved_sigfpe_act; + vki_sigaction_toK_t tmp_sigill_act, tmp_sigfpe_act; + + volatile Bool have_VFP, have_VFP2, have_VFP3, have_NEON; + volatile Int archlevel; + Int r; + + /* This is a kludge. Really we ought to back-convert saved_act + into a toK_t using VG_(convert_sigaction_fromK_to_toK), but + since that's a no-op on all ppc64 platforms so far supported, + it's not worth the typing effort. At least include most basic + sanity check: */ + vg_assert(sizeof(vki_sigaction_fromK_t) == sizeof(vki_sigaction_toK_t)); + + 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; + + 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); + + /* VFP insns */ + have_VFP = True; + if (__builtin_setjmp(env_unsup_insn)) { + have_VFP = False; + } else { + __asm__ __volatile__(".word 0xEEB02B42"); /* VMOV.F64 d2, d2 */ + } + /* There are several generation of VFP extension but they differs very + little so for now we will not distinguish them. */ + have_VFP2 = have_VFP; + have_VFP3 = have_VFP; + + /* NEON insns */ + have_NEON = True; + if (__builtin_setjmp(env_unsup_insn)) { + have_NEON = False; + } else { + __asm__ __volatile__(".word 0xF2244154"); /* VMOV q2, q2 */ + } + + /* ARM architecture level */ + archlevel = 5; /* v5 will be base level */ + if (archlevel < 7) { + archlevel = 7; + if (__builtin_setjmp(env_unsup_insn)) { + archlevel = 5; + } else { + __asm__ __volatile__(".word 0xF45FF000"); /* PLI [PC,#-0] */ + } + } + if (archlevel < 6) { + archlevel = 6; + if (__builtin_setjmp(env_unsup_insn)) { + archlevel = 5; + } else { + __asm__ __volatile__(".word 0xE6822012"); /* PKHBT r2, r2, r2 */ + } + } + + VG_(convert_sigaction_fromK_to_toK)(&saved_sigill_act, &tmp_sigill_act); + VG_(convert_sigaction_fromK_to_toK)(&saved_sigfpe_act, &tmp_sigfpe_act); + VG_(sigaction)(VKI_SIGILL, &tmp_sigill_act, NULL); + VG_(sigaction)(VKI_SIGFPE, &tmp_sigfpe_act, NULL); + VG_(sigprocmask)(VKI_SIG_SETMASK, &saved_set, NULL); + + VG_(debugLog)(1, "machine", "ARMv%d VFP %d VFP2 %d VFP3 %d NEON %d\n", + archlevel, (Int)have_VFP, (Int)have_VFP2, (Int)have_VFP3, + (Int)have_NEON); + + VG_(machine_arm_archlevel) = archlevel; + va = VexArchARM; - vai.hwcaps = 0; + + vai.hwcaps = VEX_ARM_ARCHLEVEL(archlevel); + if (have_VFP3) vai.hwcaps |= VEX_HWCAPS_ARM_VFP3; + if (have_VFP2) vai.hwcaps |= VEX_HWCAPS_ARM_VFP2; + if (have_VFP) vai.hwcaps |= VEX_HWCAPS_ARM_VFP; + if (have_NEON) vai.hwcaps |= VEX_HWCAPS_ARM_NEON; + return True; } diff --git a/coregrind/pub_core_machine.h b/coregrind/pub_core_machine.h index bd90fd4e6e..91d048aabb 100644 --- a/coregrind/pub_core_machine.h +++ b/coregrind/pub_core_machine.h @@ -96,7 +96,7 @@ # define VG_STACK_PTR guest_GPR1 # define VG_FRAME_PTR guest_GPR1 // No frame ptr for PPC #elif defined(VGA_arm) -# define VG_INSTR_PTR guest_R15 +# define VG_INSTR_PTR guest_R15T # define VG_STACK_PTR guest_R13 # define VG_FRAME_PTR guest_R11 #else @@ -109,6 +109,18 @@ #define VG_O_INSTR_PTR (offsetof(VexGuestArchState, VG_INSTR_PTR)) +//------------------------------------------------------------- +// Guest state accessors that are not visible to tools. The only +// ones that are visible are get_IP and get_SP. + +//Addr VG_(get_IP) ( ThreadId tid ); // in pub_tool_machine.h +//Addr VG_(get_SP) ( ThreadId tid ); // in pub_tool_machine.h +Addr VG_(get_FP) ( ThreadId tid ); + +void VG_(set_IP) ( ThreadId tid, Addr encip ); +void VG_(set_SP) ( ThreadId tid, Addr sp ); + + //------------------------------------------------------------- // Get hold of the values needed for a stack unwind, for the specified // (client) thread. @@ -198,6 +210,10 @@ extern UInt VG_(machine_ppc32_has_VMX); extern ULong VG_(machine_ppc64_has_VMX); #endif +#if defined(VGA_arm) +extern Int VG_(machine_arm_archlevel); +#endif + #endif // __PUB_CORE_MACHINE_H /*--------------------------------------------------------------------*/ diff --git a/include/pub_tool_machine.h b/include/pub_tool_machine.h index daa7d87412..c9d77dd726 100644 --- a/include/pub_tool_machine.h +++ b/include/pub_tool_machine.h @@ -59,7 +59,7 @@ // Supplement 1.7 #elif defined(VGP_arm_linux) -# define VG_MIN_INSTR_SZB 4 +# define VG_MIN_INSTR_SZB 2 # define VG_MAX_INSTR_SZB 4 # define VG_CLREQ_SZB 28 # define VG_STACK_REDZONE_SZB 0 @@ -99,13 +99,11 @@ #endif // Guest state accessors -extern Addr VG_(get_SP) ( ThreadId tid ); -extern Addr VG_(get_IP) ( ThreadId tid ); -extern Addr VG_(get_FP) ( ThreadId tid ); -extern Addr VG_(get_LR) ( ThreadId tid ); +// Are mostly in the core_ header. +// Only these two are available to tools. +Addr VG_(get_IP) ( ThreadId tid ); +Addr VG_(get_SP) ( ThreadId tid ); -extern void VG_(set_SP) ( ThreadId tid, Addr sp ); -extern void VG_(set_IP) ( ThreadId tid, Addr ip ); // For get/set, 'area' is where the asked-for guest state will be copied // into/from. If shadowNo == 0, the real (non-shadow) guest state is