From: Paul Floyd Date: Mon, 4 Mar 2024 20:09:16 +0000 (+0100) Subject: FreeBSD and macOS: change detection of when carry flag is being set X-Git-Tag: VALGRIND_3_23_0~128 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3b90d5a2a563e4af13ed1cb8a253ff9859ca5780;p=thirdparty%2Fvalgrind.git FreeBSD and macOS: change detection of when carry flag is being set FreeBSD and macOS syscalls both have two return registers and use the carry flag for the status. So syscall for client needs to set the carry flag in the VexGuestArchState. That's a bit much to do all in asm so we call VEX funtions. But that doesn't play well with interrupts. There are labels in ML_(do_syscall_for_client_WRK) so that we can work out what to do if we get interrupted there. But there are no asm labels in the VEX functions. Getting the address of the start of the extern function is easy. There's no way in C to get the length, and getting the address for the static helpers is also messy. I did bodge a solution whereby I put a dummy function in the source file and scientifically crossed my fingers and hoped that the compiler would lay out the object file in the same way. And it did, at least for amd64 FreeBSD amd64 Darwin and x86 FreeBSD (I don't have easy access to Darwin with working x86). Still, it's UB. I recently tried the same thing for arm64 FreeBSD. And there the functions are all over the shop in the object file. So, time to do something a bit cleaner. I've removed all of the hacky dummy functions and put a flag in the guest vex state. For both amd64 and x86 there were spare padding UInts that I've used. Arm64 won't be so lucky when I get there, no spare padding words. --- diff --git a/VEX/auxprogs/genoffsets.c b/VEX/auxprogs/genoffsets.c index 54376dc90f..81cf77e417 100644 --- a/VEX/auxprogs/genoffsets.c +++ b/VEX/auxprogs/genoffsets.c @@ -97,6 +97,7 @@ void foo ( void ) GENOFFSET(X86,x86,FS); GENOFFSET(X86,x86,GS); GENOFFSET(X86,x86,SS); + GENOFFSET(X86,x86,SETC); // amd64 GENOFFSET(AMD64,amd64,RAX); @@ -116,6 +117,7 @@ void foo ( void ) GENOFFSET(AMD64,amd64,R14); GENOFFSET(AMD64,amd64,R15); GENOFFSET(AMD64,amd64,RIP); + GENOFFSET(AMD64,amd64,SETC); // ppc32 GENOFFSET(PPC32,ppc32,GPR0); diff --git a/VEX/priv/guest_amd64_helpers.c b/VEX/priv/guest_amd64_helpers.c index 42ec80e036..adb5c7287e 100644 --- a/VEX/priv/guest_amd64_helpers.c +++ b/VEX/priv/guest_amd64_helpers.c @@ -768,26 +768,6 @@ ULong amd64g_calculate_rflags_all_WRK ( ULong cc_op, } } -#if defined(VGO_freebsd) || defined(VGO_darwin) - -/* This dummy function is just used to have an address just after - amd64g_calculate_rflags_all_WRK */ - -static -void _______VVVVVVVV_amd64g_calculate_rflags_all_WRK_VVVVVVVV_______ (void) -{ -} - -/* Export addresses of amd64g_calculate_rflags_all_WRK and - _______VVVVVVVV_amd64g_calculate_rflags_all_WRK_VVVVVVVV_______ - Used in syswrap-main.c / VG_(post_syscall) in the case where - the above function was interrupted and we need to work out - what needs to be done for the resumption */ - -Addr addr_amd64g_calculate_rflags_all_WRK = (Addr)amd64g_calculate_rflags_all_WRK; -Addr addr________VVVVVVVV_amd64g_calculate_rflags_all_WRK_VVVVVVVV_______ = (Addr)_______VVVVVVVV_amd64g_calculate_rflags_all_WRK_VVVVVVVV_______; -#endif - /* CALLED FROM GENERATED CODE: CLEAN HELPER */ /* Calculate all the 6 flags from the supplied thunk parameters. */ ULong amd64g_calculate_rflags_all ( ULong cc_op, @@ -1013,16 +993,6 @@ LibVEX_GuestAMD64_put_rflag_c ( ULong new_carry_flag, vex_state->guest_CC_NDEP = 0; } -#if defined(VGO_freebsd) || defined(VGO_darwin) -/* Used in syswrap-main.c / VG_(post_syscall) in the case where - the above function was interrupted and we need to work out - what needs to be done for the resumption. These functions - are extern so no need for 'addr' global variables */ -void _______VVVVVVVV_after_GuestAMD64_put_rflag_c_VVVVVVVV_______ (void) -{ -} -#endif - /*---------------------------------------------------------------*/ /*--- %rflags translation-time function specialisers. ---*/ /*--- These help iropt specialise calls the above run-time ---*/ @@ -4816,6 +4786,8 @@ void LibVEX_GuestAMD64_initialise ( /*OUT*/VexGuestAMD64State* vex_state ) vex_state->guest_EMNOTE = EmNote_NONE; + vex_state->guest_SETC = 0; + /* These should not ever be either read or written, but we initialise them anyway. */ vex_state->guest_CMSTART = 0; diff --git a/VEX/priv/guest_x86_helpers.c b/VEX/priv/guest_x86_helpers.c index 0c0c1ad2c8..7743c63a47 100644 --- a/VEX/priv/guest_x86_helpers.c +++ b/VEX/priv/guest_x86_helpers.c @@ -567,21 +567,6 @@ UInt x86g_calculate_eflags_all_WRK ( UInt cc_op, } } -#if defined(VGO_freebsd) || defined(VGO_darwin) - -/* see guest_amd64_helpers.c - Used in syswrap-main.c / VG_(post_syscall) for signal - resumption */ - -static void _______VVVVVVVV_after_x86g_calculate_eflags_all_WRK_VVVVVVVV_______ (void) -{ -} - -Addr addr_x86g_calculate_eflags_all_WRK = (Addr)x86g_calculate_eflags_all_WRK; -Addr addr________VVVVVVVV_x86g_calculate_eflags_all_WRK_VVVVVVVV_______ = (Addr)_______VVVVVVVV_after_x86g_calculate_eflags_all_WRK_VVVVVVVV_______; -#endif - - /* CALLED FROM GENERATED CODE: CLEAN HELPER */ /* Calculate all the 6 flags from the supplied thunk parameters. */ UInt x86g_calculate_eflags_all ( UInt cc_op, @@ -804,16 +789,6 @@ LibVEX_GuestX86_put_eflag_c ( UInt new_carry_flag, vex_state->guest_CC_NDEP = 0; } -#if defined(VGO_freebsd) || defined(VGO_darwin) - -/* Used in syswrap-main.c / VG_(post_syscall) for signal resumption */ - -void _______VVVVVVVV_after_LibVEX_GuestX86_put_eflag_c_VVVVVVVV_______ (void) -{ -} -#endif - - /*---------------------------------------------------------------*/ /*--- %eflags translation-time function specialisers. ---*/ /*--- These help iropt specialise calls the above run-time ---*/ @@ -2943,9 +2918,10 @@ void LibVEX_GuestX86_initialise ( /*OUT*/VexGuestX86State* vex_state ) vex_state->guest_SC_CLASS = 0; vex_state->guest_IP_AT_SYSCALL = 0; + vex_state->guest_SETC = 0; + vex_state->padding1 = 0; vex_state->padding2 = 0; - vex_state->padding3 = 0; } diff --git a/VEX/pub/libvex_guest_amd64.h b/VEX/pub/libvex_guest_amd64.h index 864b54b04e..c0520d2f6d 100644 --- a/VEX/pub/libvex_guest_amd64.h +++ b/VEX/pub/libvex_guest_amd64.h @@ -131,7 +131,10 @@ typedef /* Emulation notes */ UInt guest_EMNOTE; - UInt pad2; + /* Used by Darwin and FreeBSD when setting the carry flag from + * ML_(do_syscall_for_client_WRK). Needed to determine how + * to restart interrupted syscalls. */ + UInt guest_SETC; /* Translation-invalidation area description. Not used on amd64 (there is no invalidate-icache insn), but needed so as to diff --git a/VEX/pub/libvex_guest_x86.h b/VEX/pub/libvex_guest_x86.h index 53f72acb8c..50de8d3798 100644 --- a/VEX/pub/libvex_guest_x86.h +++ b/VEX/pub/libvex_guest_x86.h @@ -219,10 +219,11 @@ typedef been interrupted by a signal. */ UInt guest_IP_AT_SYSCALL; + UInt guest_SETC; + /* Padding to make it have an 16-aligned size */ UInt padding1; UInt padding2; - UInt padding3; } VexGuestX86State; @@ -292,12 +293,6 @@ void LibVEX_GuestX86_put_eflag_c ( UInt new_carry_flag, /*MOD*/VexGuestX86State* vex_state ); -#if defined(VGO_freebsd) || defined(VGO_darwin) -extern void _______VVVVVVVV_after_LibVEX_GuestX86_put_eflag_c_VVVVVVVV_______ (void); -extern Addr addr_x86g_calculate_eflags_all_WRK; -extern Addr addr________VVVVVVVV_x86g_calculate_eflags_all_WRK_VVVVVVVV_______; -#endif - /* Do x87 save from the supplied VexGuestX86State structure and store the result at the given address which represents a buffer of at least 108 bytes. */ diff --git a/coregrind/m_syswrap/syscall-amd64-darwin.S b/coregrind/m_syswrap/syscall-amd64-darwin.S index ed93a851eb..5c68d0c4d0 100644 --- a/coregrind/m_syswrap/syscall-amd64-darwin.S +++ b/coregrind/m_syswrap/syscall-amd64-darwin.S @@ -153,7 +153,10 @@ L_$0_3: /* In the range [3, 4), the syscall result is in %rax, movq %rax, %rdi /* arg1 = new flag */ movq %r11, %rsi /* arg2 = vex state */ addq $$24, %rsp /* remove syscall parameters */ + movl $$1, OFFSET_amd64_SETC(%r11) call _LibVEX_GuestAMD64_put_rflag_c + movq -16(%rbp), %r11 + movl $$0, OFFSET_amd64_SETC(%r11) .else addq $$24, %rsp /* remove syscall parameters*/ .endif diff --git a/coregrind/m_syswrap/syscall-amd64-freebsd.S b/coregrind/m_syswrap/syscall-amd64-freebsd.S index 8f084c3e19..d1516b1065 100644 --- a/coregrind/m_syswrap/syscall-amd64-freebsd.S +++ b/coregrind/m_syswrap/syscall-amd64-freebsd.S @@ -153,7 +153,10 @@ ML_(do_syscall_for_client_WRK): movq %rax, %rdi /* arg1 = new flag */ movq %r11, %rsi /* arg2 = vex state */ addq $24, %rsp /* remove syscall parameters */ + movl $1, OFFSET_amd64_SETC(%r11) call LibVEX_GuestAMD64_put_rflag_c + movq -16(%rbp), %r11 /* r11 = VexGuestAMD64State * */ + movl $0, OFFSET_amd64_SETC(%r11) 4: /* Re-block signals. If eip is in [4,5), then the syscall is complete and we needn't worry about it. */ diff --git a/coregrind/m_syswrap/syscall-x86-darwin.S b/coregrind/m_syswrap/syscall-x86-darwin.S index 9032422685..d92ecf15e0 100644 --- a/coregrind/m_syswrap/syscall-x86-darwin.S +++ b/coregrind/m_syswrap/syscall-x86-darwin.S @@ -156,7 +156,10 @@ L_$0_3: /* In the range [3, 4), the syscall result is in %eax and %edx and C, movl $$0, 0(%esp) movb 12(%esp), %al movb %al, 0(%esp) + movl $$1, OFFSET_x86_SETC(%ecx) call _LibVEX_GuestX86_put_eflag_c + movl 12(%ebp), %ecx + movl $$0, OFFSET_x86_SETC(%ecx) addl $$12, %esp .endif diff --git a/coregrind/m_syswrap/syscall-x86-freebsd.S b/coregrind/m_syswrap/syscall-x86-freebsd.S index 1faa74c4d6..4ddba2d340 100644 --- a/coregrind/m_syswrap/syscall-x86-freebsd.S +++ b/coregrind/m_syswrap/syscall-x86-freebsd.S @@ -143,7 +143,10 @@ ML_(do_syscall_for_client_WRK): movl $0, 0(%esp) movb 12(%esp), %al movb %al, 0(%esp) + movl $1, OFFSET_x86_SETC(%ecx) call LibVEX_GuestX86_put_eflag_c + movl 12(%ebp), %ecx + movl $0, OFFSET_x86_SETC(%ecx) addl $12, %esp 4: /* Re-block signals. If eip is in [4,5), then the syscall is diff --git a/coregrind/m_syswrap/syswrap-main.c b/coregrind/m_syswrap/syswrap-main.c index 91a1f7e53e..20d02c7fa5 100644 --- a/coregrind/m_syswrap/syswrap-main.c +++ b/coregrind/m_syswrap/syswrap-main.c @@ -3120,35 +3120,7 @@ VG_(fixup_guest_state_after_syscall_interrupted)( ThreadId tid, #if defined(VGO_freebsd) || defined(VGO_darwin) if (outside_range) { - /* This is not guaranteed to work since the compiler / link editor - could lay out the binary functions in a different order to - the source file. However, it seems to work. */ - -#if defined (VGA_amd64) - - vg_assert((Addr)_______VVVVVVVV_after_GuestAMD64_put_rflag_c_VVVVVVVV_______ > - (Addr)LibVEX_GuestAMD64_put_rflag_c ); - - vg_assert(addr________VVVVVVVV_amd64g_calculate_rflags_all_WRK_VVVVVVVV_______ > - addr_amd64g_calculate_rflags_all_WRK); - - if ((ip >= (Addr)LibVEX_GuestAMD64_put_rflag_c && - ip < (Addr)_______VVVVVVVV_after_GuestAMD64_put_rflag_c_VVVVVVVV_______) || - (ip >= addr_amd64g_calculate_rflags_all_WRK && - ip < addr________VVVVVVVV_amd64g_calculate_rflags_all_WRK_VVVVVVVV_______)) -#else - - vg_assert((Addr)_______VVVVVVVV_after_LibVEX_GuestX86_put_eflag_c_VVVVVVVV_______ > - (Addr)LibVEX_GuestX86_put_eflag_c); - - vg_assert(addr________VVVVVVVV_x86g_calculate_eflags_all_WRK_VVVVVVVV_______> - addr_x86g_calculate_eflags_all_WRK); - - if ((ip >= (Addr)LibVEX_GuestX86_put_eflag_c && - ip < (Addr)_______VVVVVVVV_after_LibVEX_GuestX86_put_eflag_c_VVVVVVVV_______) || - (ip >= addr_x86g_calculate_eflags_all_WRK && - ip < addr________VVVVVVVV_x86g_calculate_eflags_all_WRK_VVVVVVVV_______)) -#endif + if (th_regs->vex.guest_SETC) { outside_range = False; in_complete_to_committed = True;