From: Nicholas Nethercote Date: Fri, 3 Sep 2004 13:45:29 +0000 (+0000) Subject: Arch-abstraction: X-Git-Tag: svn/VALGRIND_3_0_0~1627 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=18355ff96b9cd916a7064b3a79acfe5d4303cb8a;p=thirdparty%2Fvalgrind.git Arch-abstraction: - Added include/x86/: contains tool_arch.h, Makefile.am, .cvsignore. - Added coregrind/x86/state.c. Contains some arch-specific code for dealing with x86 registers -- eg. setting up the baseBlock, loading/saving the whole register state. It is compiled into coregrind/x86/libarch.a and linked via ${VG_ARCH} with the core. Relatedly, also added coregrind/x86/{core_arch.h,core_arch_asm.h}. - Correspondingly abstracted the register state out of ThreadState. This affected every place that touches registers, and there are a lot of them. (Eventually all the register touching should be abstracted out in an arch-neutral way, but not yet; one step at a time.) - Added some declarations about register loading/saving functions to core.h; all architectures will have to provide these functions. - Rejigged the build system so that the arch-specific stuff is all done via ${VG_ARCH}, rather than naming e.g. x86/ directly. Appropriate -I arguments are used so that all the headers are found, etc. git-svn-id: svn://svn.valgrind.org/valgrind/trunk@2656 --- diff --git a/Makefile.core-AM_CPPFLAGS.am b/Makefile.core-AM_CPPFLAGS.am index 4a68b1ad09..ff660077e6 100644 --- a/Makefile.core-AM_CPPFLAGS.am +++ b/Makefile.core-AM_CPPFLAGS.am @@ -1,5 +1,7 @@ add_includes = -I$(top_builddir)/coregrind -I$(top_srcdir)/coregrind \ - -I$(top_builddir)/include -I$(top_srcdir)/include + -I$(top_srcdir)/coregrind/$(VG_ARCH) \ + -I$(top_builddir)/include -I$(top_srcdir)/include \ + -I$(top_srcdir)/include/$(VG_ARCH) AM_CPPFLAGS = $(add_includes) diff --git a/Makefile.tool.am b/Makefile.tool.am index cdde4b8d3b..321f53a551 100644 --- a/Makefile.tool.am +++ b/Makefile.tool.am @@ -5,7 +5,8 @@ SUBDIRS = . tests docs ## Need $(top_builddir)/include because tool.h is built from tool.h.base; ## otherwise it will not work if builddir != srcdir. -add_includes = -I$(top_builddir)/include -I$(top_srcdir)/include +add_includes = -I$(top_builddir)/include -I$(top_srcdir)/include \ + -I$(top_srcdir)/include/$(VG_ARCH) AM_CPPFLAGS = $(add_includes) AM_CFLAGS = $(WERROR) -Winline -Wall -Wshadow -O -fomit-frame-pointer \ diff --git a/configure.in b/configure.in index 50af03769e..8867f0749d 100644 --- a/configure.in +++ b/configure.in @@ -391,6 +391,7 @@ AC_OUTPUT( tests/vg_regtest tests/unused/Makefile include/Makefile + include/x86/Makefile auxprogs/Makefile coregrind/Makefile coregrind/demangle/Makefile diff --git a/coregrind/Makefile.am b/coregrind/Makefile.am index 1ef20f2529..cd9705481f 100644 --- a/coregrind/Makefile.am +++ b/coregrind/Makefile.am @@ -1,10 +1,9 @@ include $(top_srcdir)/Makefile.all.am include $(top_srcdir)/Makefile.core-AM_CPPFLAGS.am -SUBDIRS = x86 demangle . docs +SUBDIRS = $(VG_ARCH) demangle . docs AM_CPPFLAGS += -DVG_LIBDIR="\"$(valdir)"\" -I$(srcdir)/demangle \ - -I$(srcdir)/x86 \ -DKICKSTART_BASE=$(KICKSTART_BASE) AM_CFLAGS = $(WERROR) -Winline -Wall -Wshadow -O -fno-omit-frame-pointer \ @PREFERRED_STACK_BOUNDARY@ -g -DELFSZ=32 @@ -92,6 +91,7 @@ stage2_LDADD= \ demangle/cplus-dem.o \ demangle/dyn-string.o \ demangle/safe-ctype.o \ + ${VG_ARCH}/libarch.a \ -ldl vg_intercept.c: $(srcdir)/gen_intercepts.pl $(srcdir)/vg_intercept.c.base diff --git a/coregrind/core.h b/coregrind/core.h index 2811a55218..0eaabf4e04 100644 --- a/coregrind/core.h +++ b/coregrind/core.h @@ -85,6 +85,7 @@ #include "core_asm.h" // asm stuff #include "tool.h" // tool stuff +#include "core_arch.h" // arch-specific stuff; eg. x86/arch.h #include "valgrind.h" @@ -573,26 +574,6 @@ struct vg_mallocfunc_info { Bool clo_trace_malloc; }; -/* --------------------------------------------------------------------- - Constants pertaining to the simulated CPU state, VG_(baseBlock), - which need to go here to avoid ugly circularities. - ------------------------------------------------------------------ */ - -/* How big is the saved SSE/SSE2 state? Note that this subsumes the - FPU state. On machines without SSE, we just save/restore the FPU - state into the first part of this area. */ -/* A general comment about SSE save/restore: It appears that the 7th - word (which is the MXCSR) has to be &ed with 0x0000FFBF in order - that restoring from it later does not cause a GP fault (which is - delivered as a segfault). I guess this will have to be done - any time we do fxsave :-( 7th word means word offset 6 or byte - offset 24 from the start address of the save area. - */ -#define VG_SIZE_OF_SSESTATE 512 -/* ... and in words ... */ -#define VG_SIZE_OF_SSESTATE_W ((VG_SIZE_OF_SSESTATE+3)/4) - - /* --------------------------------------------------------------------- Exports of vg_defaults.c ------------------------------------------------------------------ */ @@ -600,37 +581,6 @@ struct vg_mallocfunc_info { extern Bool VG_(sk_malloc_called_by_scheduler); -/* --------------------------------------------------------------------- - Exports of vg_ldt.c - ------------------------------------------------------------------ */ - -/* This is the hardware-format for a segment descriptor, ie what the - x86 actually deals with. It is 8 bytes long. It's ugly. */ - -typedef struct _LDT_ENTRY { - union { - struct { - UShort LimitLow; - UShort BaseLow; - unsigned BaseMid : 8; - unsigned Type : 5; - unsigned Dpl : 2; - unsigned Pres : 1; - unsigned LimitHi : 4; - unsigned Sys : 1; - unsigned Reserved_0 : 1; - unsigned Default_Big : 1; - unsigned Granularity : 1; - unsigned BaseHi : 8; - } Bits; - struct { - UInt word1; - UInt word2; - } Words; - } - LdtEnt; -} VgLdtEntry; - /* Maximum number of LDT entries supported (by the x86). */ #define VG_M_LDT_ENTRIES 8192 /* The size of each LDT entry == sizeof(VgLdtEntry) */ @@ -893,57 +843,8 @@ typedef /* Alternate signal stack */ vki_kstack_t altstack; - /* Pointer to this thread's Local (Segment) Descriptor Table. - Starts out as NULL, indicating there is no table, and we hope to - keep it that way. If the thread does __NR_modify_ldt to create - entries, we allocate a 8192-entry table at that point. This is - a straight copy of the Linux kernel's scheme. Don't forget to - deallocate this at thread exit. */ - VgLdtEntry* ldt; - - /* TLS table. This consists of a small number (currently 3) of - entries from the Global Descriptor Table. */ - VgLdtEntry tls[VKI_GDT_TLS_ENTRIES]; - - /* Saved machine context. Note the FPU state, %EIP and segment - registers are not shadowed. - - Although the segment registers are 16 bits long, storage - management here and in VG_(baseBlock) is - simplified if we pretend they are 32 bits. */ - UInt m_cs; - UInt m_ss; - UInt m_ds; - UInt m_es; - UInt m_fs; - UInt m_gs; - - UInt m_eax; - UInt m_ebx; - UInt m_ecx; - UInt m_edx; - UInt m_esi; - UInt m_edi; - UInt m_ebp; - UInt m_esp; - UInt m_eflags; - UInt m_eip; - - /* The SSE/FPU state. This array does not (necessarily) have the - required 16-byte alignment required to get stuff in/out by - fxsave/fxrestore. So we have to do it "by hand". - */ - UInt m_sse[VG_SIZE_OF_SSESTATE_W]; - - UInt sh_eax; - UInt sh_ebx; - UInt sh_ecx; - UInt sh_edx; - UInt sh_esi; - UInt sh_edi; - UInt sh_ebp; - UInt sh_esp; - UInt sh_eflags; + /* Architecture-specific thread state */ + arch_thread_t arch; } ThreadState; @@ -1007,7 +908,7 @@ extern void VG_(scheduler_handle_fatal_signal)( Int sigNo ); /* Write a value to a client's thread register, and shadow (if necessary) */ #define SET_THREAD_REG( zztid, zzval, zzreg, zzREG, zzevent, zzargs... ) \ - do { VG_(threads)[zztid].m_##zzreg = (zzval); \ + do { VG_(threads)[zztid].arch.m_##zzreg = (zzval); \ VG_TRACK( zzevent, zztid, R_##zzREG, ##zzargs ); \ } while (0) @@ -1668,7 +1569,12 @@ extern Int VGOFF_(tls_ptr); extern Int VGOFF_(helper_undefined_instruction); -#endif /* ndef __CORE_H */ +// --------------------------------------------------------------------- +// Architecture-specific things defined in eg. x86/*.c +// --------------------------------------------------------------------- + +extern void VGA_(load_state) ( arch_thread_t*, ThreadId tid ); +extern void VGA_(save_state) ( arch_thread_t*, ThreadId tid ); /* --------------------------------------------------------------------- @@ -1677,6 +1583,8 @@ extern Int VGOFF_(helper_undefined_instruction); #include "config.h" +#endif /* ndef __CORE_H */ + /*--------------------------------------------------------------------*/ /*--- end ---*/ /*--------------------------------------------------------------------*/ diff --git a/coregrind/core_asm.h b/coregrind/core_asm.h index 9d470d4636..25b62418eb 100644 --- a/coregrind/core_asm.h +++ b/coregrind/core_asm.h @@ -31,7 +31,8 @@ #ifndef __CORE_ASM_H #define __CORE_ASM_H -#include "tool_asm.h" +#include "tool_asm.h" // tool asm stuff +#include "core_arch_asm.h" // arch-specific asm stuff /* This file is included in all Valgrind source files, including assembly ones. */ @@ -53,12 +54,6 @@ #define VG_TRC_INNER_COUNTERZERO 29 /* TRC only; means bb ctr == 0 */ #define VG_TRC_UNRESUMABLE_SIGNAL 37 /* TRC only; got sigsegv/sigbus */ -/* size of call instruction put into generated code at jump sites */ -#define VG_PATCHME_CALLSZ 5 - -/* size of jmp instruction which overwrites the call */ -#define VG_PATCHME_JMPSZ 5 - /* maximum number of normal jumps which can appear in a basic block */ #define VG_MAX_JUMPS 2 diff --git a/coregrind/valgrind.vs b/coregrind/valgrind.vs index 0d4652f21d..a246684b12 100644 --- a/coregrind/valgrind.vs +++ b/coregrind/valgrind.vs @@ -4,6 +4,7 @@ VALGRIND_2.1 { vgSkin_*; vgProf_*; vgOff_*; + vgArch_*; local: *; # default to hidden diff --git a/coregrind/vg_execontext.c b/coregrind/vg_execontext.c index d4e87a82eb..4e077c4d1f 100644 --- a/coregrind/vg_execontext.c +++ b/coregrind/vg_execontext.c @@ -314,9 +314,9 @@ void get_needed_regs(ThreadId tid, Addr* eip, Addr* ebp, Addr* esp, } else { /* thread in thread table */ ThreadState* tst = & VG_(threads)[ tid ]; - *eip = tst->m_eip; - *ebp = tst->m_ebp; - *esp = tst->m_esp; + *eip = tst->arch.m_eip; + *ebp = tst->arch.m_ebp; + *esp = tst->arch.m_esp; *stack_highest_word = tst->stack_highest_word; } @@ -370,7 +370,7 @@ Addr VG_(get_EIP) ( ThreadId tid ) if (VG_(is_running_thread)(tid)) ret = VG_(baseBlock)[VGOFF_(m_eip)]; else - ret = VG_(threads)[ tid ].m_eip; + ret = VG_(threads)[ tid ].arch.m_eip; return ret; } diff --git a/coregrind/vg_from_ucode.c b/coregrind/vg_from_ucode.c index 1391423da0..5f1fcc7601 100644 --- a/coregrind/vg_from_ucode.c +++ b/coregrind/vg_from_ucode.c @@ -3427,14 +3427,14 @@ UInt VG_(get_thread_archreg) ( ThreadId tid, UInt arch ) tst = & VG_(threads)[tid]; switch (arch) { - case R_EAX: return tst->m_eax; - case R_ECX: return tst->m_ecx; - case R_EDX: return tst->m_edx; - case R_EBX: return tst->m_ebx; - case R_ESP: return tst->m_esp; - case R_EBP: return tst->m_ebp; - case R_ESI: return tst->m_esi; - case R_EDI: return tst->m_edi; + case R_EAX: return tst->arch.m_eax; + case R_ECX: return tst->arch.m_ecx; + case R_EDX: return tst->arch.m_edx; + case R_EBX: return tst->arch.m_ebx; + case R_ESP: return tst->arch.m_esp; + case R_EBP: return tst->arch.m_ebp; + case R_ESI: return tst->arch.m_esi; + case R_EDI: return tst->arch.m_edi; default: VG_(core_panic)( "get_thread_archreg"); } } @@ -3491,14 +3491,14 @@ UInt VG_(get_thread_shadow_archreg) ( ThreadId tid, UInt archreg ) tst = & VG_(threads)[tid]; switch (archreg) { - case R_EAX: return tst->sh_eax; - case R_ECX: return tst->sh_ecx; - case R_EDX: return tst->sh_edx; - case R_EBX: return tst->sh_ebx; - case R_ESP: return tst->sh_esp; - case R_EBP: return tst->sh_ebp; - case R_ESI: return tst->sh_esi; - case R_EDI: return tst->sh_edi; + case R_EAX: return tst->arch.sh_eax; + case R_ECX: return tst->arch.sh_ecx; + case R_EDX: return tst->arch.sh_edx; + case R_EBX: return tst->arch.sh_ebx; + case R_ESP: return tst->arch.sh_esp; + case R_EBP: return tst->arch.sh_ebp; + case R_ESI: return tst->arch.sh_esi; + case R_EDI: return tst->arch.sh_edi; default: VG_(core_panic)( "get_thread_shadow_archreg"); } } @@ -3511,14 +3511,14 @@ void VG_(set_thread_shadow_archreg) ( ThreadId tid, UInt archreg, UInt val ) tst = & VG_(threads)[tid]; switch (archreg) { - case R_EAX: tst->sh_eax = val; break; - case R_ECX: tst->sh_ecx = val; break; - case R_EDX: tst->sh_edx = val; break; - case R_EBX: tst->sh_ebx = val; break; - case R_ESP: tst->sh_esp = val; break; - case R_EBP: tst->sh_ebp = val; break; - case R_ESI: tst->sh_esi = val; break; - case R_EDI: tst->sh_edi = val; break; + case R_EAX: tst->arch.sh_eax = val; break; + case R_ECX: tst->arch.sh_ecx = val; break; + case R_EDX: tst->arch.sh_edx = val; break; + case R_EBX: tst->arch.sh_ebx = val; break; + case R_ESP: tst->arch.sh_esp = val; break; + case R_EBP: tst->arch.sh_ebp = val; break; + case R_ESI: tst->arch.sh_esi = val; break; + case R_EDI: tst->arch.sh_edi = val; break; default: VG_(core_panic)( "set_thread_shadow_archreg"); } } diff --git a/coregrind/vg_ldt.c b/coregrind/vg_ldt.c index 45b4c4c388..cce9fefcb5 100644 --- a/coregrind/vg_ldt.c +++ b/coregrind/vg_ldt.c @@ -320,7 +320,7 @@ Int read_ldt ( ThreadId tid, UChar* ptr, UInt bytecount ) VG_(printf)("read_ldt: tid = %d, ptr = %p, bytecount = %d\n", tid, ptr, bytecount ); - ldt = (Char*)(VG_(threads)[tid].ldt); + ldt = (Char*)(VG_(threads)[tid].arch.ldt); err = 0; if (ldt == NULL) /* LDT not allocated, meaning all entries are null */ @@ -351,7 +351,7 @@ Int write_ldt ( ThreadId tid, void* ptr, UInt bytecount, Int oldmode ) "bytecount = %d, oldmode = %d\n", tid, ptr, bytecount, oldmode ); - ldt = VG_(threads)[tid].ldt; + ldt = VG_(threads)[tid].arch.ldt; ldt_info = (struct vki_modify_ldt_ldt_s*)ptr; error = -VKI_EINVAL; @@ -372,7 +372,7 @@ Int write_ldt ( ThreadId tid, void* ptr, UInt bytecount, Int oldmode ) now. */ if (ldt == NULL) { ldt = VG_(allocate_LDT_for_thread)( NULL ); - VG_(threads)[tid].ldt = ldt; + VG_(threads)[tid].arch.ldt = ldt; } /* Install the new entry ... */ @@ -417,7 +417,7 @@ Int VG_(sys_set_thread_area) ( ThreadId tid, if (idx == -1) { for (idx = 0; idx < VKI_GDT_TLS_ENTRIES; idx++) { - VgLdtEntry* tls = VG_(threads)[tid].tls + idx; + VgLdtEntry* tls = VG_(threads)[tid].arch.tls + idx; if (tls->LdtEnt.Words.word1 == 0 && tls->LdtEnt.Words.word2 == 0) break; @@ -431,7 +431,7 @@ Int VG_(sys_set_thread_area) ( ThreadId tid, idx = info->entry_number - VKI_GDT_TLS_MIN; } - translate_to_hw_format(info, VG_(threads)[tid].tls + idx, 0); + translate_to_hw_format(info, VG_(threads)[tid].arch.tls + idx, 0); VG_TRACK( pre_mem_write, Vg_CoreSysCall, tid, "set_thread_area(info->entry)", @@ -453,7 +453,7 @@ Int VG_(sys_get_thread_area) ( ThreadId tid, if (idx < VKI_GDT_TLS_MIN || idx > VKI_GDT_TLS_MAX) return -VKI_EINVAL; - tls = VG_(threads)[tid].tls + idx - VKI_GDT_TLS_MIN; + tls = VG_(threads)[tid].arch.tls + idx - VKI_GDT_TLS_MIN; info->base_addr = ( tls->LdtEnt.Bits.BaseHi << 24 ) | ( tls->LdtEnt.Bits.BaseMid << 16 ) | diff --git a/coregrind/vg_main.c b/coregrind/vg_main.c index c7b81549bf..3dc0de3e80 100644 --- a/coregrind/vg_main.c +++ b/coregrind/vg_main.c @@ -266,22 +266,22 @@ void VG_(start_debugger) ( Int tid ) } else { ThreadState* tst = & VG_(threads)[ tid ]; - regs.cs = tst->m_cs; - regs.ss = tst->m_ss; - regs.ds = tst->m_ds; - regs.es = tst->m_es; - regs.fs = tst->m_fs; - regs.gs = tst->m_gs; - regs.eax = tst->m_eax; - regs.ebx = tst->m_ebx; - regs.ecx = tst->m_ecx; - regs.edx = tst->m_edx; - regs.esi = tst->m_esi; - regs.edi = tst->m_edi; - regs.ebp = tst->m_ebp; - regs.esp = tst->m_esp; - regs.eflags = tst->m_eflags; - regs.eip = tst->m_eip; + regs.cs = tst->arch.m_cs; + regs.ss = tst->arch.m_ss; + regs.ds = tst->arch.m_ds; + regs.es = tst->arch.m_es; + regs.fs = tst->arch.m_fs; + regs.gs = tst->arch.m_gs; + regs.eax = tst->arch.m_eax; + regs.ebx = tst->arch.m_ebx; + regs.ecx = tst->arch.m_ecx; + regs.edx = tst->arch.m_edx; + regs.esi = tst->arch.m_esi; + regs.edi = tst->arch.m_edi; + regs.ebp = tst->arch.m_ebp; + regs.esp = tst->arch.m_esp; + regs.eflags = tst->arch.m_eflags; + regs.eip = tst->arch.m_eip; } if ((res = VG_(waitpid)(pid, &status, 0)) == pid && diff --git a/coregrind/vg_proxylwp.c b/coregrind/vg_proxylwp.c index 57625e94ed..90fe9e73d5 100644 --- a/coregrind/vg_proxylwp.c +++ b/coregrind/vg_proxylwp.c @@ -151,13 +151,13 @@ static void thread_syscall(Int syscallno, ThreadState *tst, enum PXState *state , enum PXState poststate) { do_thread_syscall(syscallno, /* syscall no. */ - tst->m_ebx, /* arg 1 */ - tst->m_ecx, /* arg 2 */ - tst->m_edx, /* arg 3 */ - tst->m_esi, /* arg 4 */ - tst->m_edi, /* arg 5 */ - tst->m_ebp, /* arg 6 */ - &tst->m_eax, /* result */ + tst->arch.m_ebx, /* arg 1 */ + tst->arch.m_ecx, /* arg 2 */ + tst->arch.m_edx, /* arg 3 */ + tst->arch.m_esi, /* arg 4 */ + tst->arch.m_edi, /* arg 5 */ + tst->arch.m_ebp, /* arg 6 */ + &tst->arch.m_eax, /* result */ state, /* state to update */ poststate); /* state when syscall has finished */ } @@ -430,7 +430,7 @@ void VG_(proxy_handlesig)(const vki_ksiginfo_t *siginfo, anywhere else, except that we can make some assertions about the proxy and machine state here. */ vg_assert(px->state == PXS_RunSyscall); - vg_assert(px->tst->m_eax == -VKI_ERESTARTSYS); + vg_assert(px->tst->arch.m_eax == -VKI_ERESTARTSYS); } else if (sys_after <= eip && eip <= sys_done) { /* We're after the syscall. Either it was interrupted by the signal, or the syscall completed normally. In either case @@ -439,7 +439,7 @@ void VG_(proxy_handlesig)(const vki_ksiginfo_t *siginfo, vg_assert(px->state == PXS_RunSyscall || px->state == PXS_SysDone); px->state = PXS_SysDone; - px->tst->m_eax = eax; + px->tst->arch.m_eax = eax; } px_printf(" signalled in state %s\n", pxs_name(px->state)); @@ -556,7 +556,7 @@ static Int proxylwp(void *v) */ reply.u.syscallno = tst->syscallno; - tst->m_eax = -VKI_ERESTARTSYS; + tst->arch.m_eax = -VKI_ERESTARTSYS; px->state = PXS_IntReply; break; @@ -726,14 +726,14 @@ static Int proxylwp(void *v) */ px_printf("RunSyscall in SigACK: rejecting syscall %d with ERESTARTSYS\n", reply.u.syscallno); - tst->m_eax = -VKI_ERESTARTSYS; + tst->arch.m_eax = -VKI_ERESTARTSYS; } else { Int syscallno = tst->syscallno; px->state = PXS_RunSyscall; /* If we're interrupted before we get to the syscall itself, we want the syscall restarted. */ - tst->m_eax = -VKI_ERESTARTSYS; + tst->arch.m_eax = -VKI_ERESTARTSYS; /* set our process group ID to match parent */ if (VG_(getpgrp)() != VG_(main_pgrp)) @@ -1142,7 +1142,7 @@ static void sys_wait_results(Bool block, ThreadId tid, enum RequestType reqtype, case PX_RunSyscall: if (VG_(clo_trace_syscalls)) VG_(message)(Vg_DebugMsg, "sys_wait_results: got PX_RunSyscall for TID %d: syscall %d result %d", - res.tid, tst->syscallno, tst->m_eax); + res.tid, tst->syscallno, tst->arch.m_eax); if (tst->status != VgTs_WaitSys) VG_(printf)("tid %d in status %d\n", @@ -1301,8 +1301,8 @@ Int VG_(sys_issue)(int tid) req.request = PX_RunSyscall; - tst->syscallno = tst->m_eax; - tst->m_eax = -VKI_ERESTARTSYS; + tst->syscallno = tst->arch.m_eax; + tst->arch.m_eax = -VKI_ERESTARTSYS; res = VG_(write)(proxy->topx, &req, sizeof(req)); diff --git a/coregrind/vg_scheduler.c b/coregrind/vg_scheduler.c index c27ce36473..65c7bf55b8 100644 --- a/coregrind/vg_scheduler.c +++ b/coregrind/vg_scheduler.c @@ -162,7 +162,7 @@ ThreadId VG_(first_matching_thread_stack) for (tid = 1; tid < VG_N_THREADS; tid++) { if (VG_(threads)[tid].status == VgTs_Empty) continue; if (tid == tid_to_skip) continue; - if ( p ( VG_(threads)[tid].m_esp, + if ( p ( VG_(threads)[tid].arch.m_esp, VG_(threads)[tid].stack_highest_word, d ) ) return tid; } @@ -194,8 +194,8 @@ void VG_(pp_sched_status) ( void ) VG_(threads)[i].associated_mx, VG_(threads)[i].associated_cv ); VG_(pp_ExeContext)( - VG_(get_ExeContext2)( VG_(threads)[i].m_eip, VG_(threads)[i].m_ebp, - VG_(threads)[i].m_esp, + VG_(get_ExeContext2)( VG_(threads)[i].arch.m_eip, VG_(threads)[i].arch.m_ebp, + VG_(threads)[i].arch.m_esp, VG_(threads)[i].stack_highest_word) ); } @@ -272,80 +272,13 @@ ThreadId VG_(get_current_or_recent_tid) ( void ) return vg_tid_last_in_baseBlock; } -static UInt insertDflag(UInt eflags, Int d) -{ - vg_assert(d == 1 || d == -1); - eflags &= ~EFlagD; - if (d < 0) eflags |= EFlagD; - return eflags; -} - -static Int extractDflag(UInt eflags) -{ - return ( eflags & EFlagD ? -1 : 1 ); -} - -/* Junk to fill up a thread's shadow regs with when shadow regs aren't - being used. */ -#define VG_UNUSED_SHADOW_REG_VALUE 0x27182818 - /* Copy the saved state of a thread into VG_(baseBlock), ready for it to be run. */ static void load_thread_state ( ThreadId tid ) { - Int i; vg_assert(vg_tid_currently_in_baseBlock == VG_INVALID_THREADID); - VG_(baseBlock)[VGOFF_(ldt)] = (UInt)VG_(threads)[tid].ldt; - VG_(baseBlock)[VGOFF_(tls_ptr)] = (UInt)VG_(threads)[tid].tls; - VG_(baseBlock)[VGOFF_(m_cs)] = VG_(threads)[tid].m_cs; - VG_(baseBlock)[VGOFF_(m_ss)] = VG_(threads)[tid].m_ss; - VG_(baseBlock)[VGOFF_(m_ds)] = VG_(threads)[tid].m_ds; - VG_(baseBlock)[VGOFF_(m_es)] = VG_(threads)[tid].m_es; - VG_(baseBlock)[VGOFF_(m_fs)] = VG_(threads)[tid].m_fs; - VG_(baseBlock)[VGOFF_(m_gs)] = VG_(threads)[tid].m_gs; - - VG_(baseBlock)[VGOFF_(m_eax)] = VG_(threads)[tid].m_eax; - VG_(baseBlock)[VGOFF_(m_ebx)] = VG_(threads)[tid].m_ebx; - VG_(baseBlock)[VGOFF_(m_ecx)] = VG_(threads)[tid].m_ecx; - VG_(baseBlock)[VGOFF_(m_edx)] = VG_(threads)[tid].m_edx; - VG_(baseBlock)[VGOFF_(m_esi)] = VG_(threads)[tid].m_esi; - VG_(baseBlock)[VGOFF_(m_edi)] = VG_(threads)[tid].m_edi; - VG_(baseBlock)[VGOFF_(m_ebp)] = VG_(threads)[tid].m_ebp; - VG_(baseBlock)[VGOFF_(m_esp)] = VG_(threads)[tid].m_esp; - VG_(baseBlock)[VGOFF_(m_eflags)] - = VG_(threads)[tid].m_eflags & ~EFlagD; - VG_(baseBlock)[VGOFF_(m_dflag)] - = extractDflag(VG_(threads)[tid].m_eflags); - VG_(baseBlock)[VGOFF_(m_eip)] = VG_(threads)[tid].m_eip; - - for (i = 0; i < VG_SIZE_OF_SSESTATE_W; i++) - VG_(baseBlock)[VGOFF_(m_ssestate) + i] - = VG_(threads)[tid].m_sse[i]; - - if (VG_(needs).shadow_regs) { - VG_(baseBlock)[VGOFF_(sh_eax)] = VG_(threads)[tid].sh_eax; - VG_(baseBlock)[VGOFF_(sh_ebx)] = VG_(threads)[tid].sh_ebx; - VG_(baseBlock)[VGOFF_(sh_ecx)] = VG_(threads)[tid].sh_ecx; - VG_(baseBlock)[VGOFF_(sh_edx)] = VG_(threads)[tid].sh_edx; - VG_(baseBlock)[VGOFF_(sh_esi)] = VG_(threads)[tid].sh_esi; - VG_(baseBlock)[VGOFF_(sh_edi)] = VG_(threads)[tid].sh_edi; - VG_(baseBlock)[VGOFF_(sh_ebp)] = VG_(threads)[tid].sh_ebp; - VG_(baseBlock)[VGOFF_(sh_esp)] = VG_(threads)[tid].sh_esp; - VG_(baseBlock)[VGOFF_(sh_eflags)] = VG_(threads)[tid].sh_eflags; - } else { - /* Fields shouldn't be used -- check their values haven't changed. */ - vg_assert( - VG_UNUSED_SHADOW_REG_VALUE == VG_(threads)[tid].sh_eax && - VG_UNUSED_SHADOW_REG_VALUE == VG_(threads)[tid].sh_ebx && - VG_UNUSED_SHADOW_REG_VALUE == VG_(threads)[tid].sh_ecx && - VG_UNUSED_SHADOW_REG_VALUE == VG_(threads)[tid].sh_edx && - VG_UNUSED_SHADOW_REG_VALUE == VG_(threads)[tid].sh_esi && - VG_UNUSED_SHADOW_REG_VALUE == VG_(threads)[tid].sh_edi && - VG_UNUSED_SHADOW_REG_VALUE == VG_(threads)[tid].sh_ebp && - VG_UNUSED_SHADOW_REG_VALUE == VG_(threads)[tid].sh_esp && - VG_UNUSED_SHADOW_REG_VALUE == VG_(threads)[tid].sh_eflags); - } + VGA_(load_state)(&VG_(threads)[tid].arch, tid); vg_tid_currently_in_baseBlock = tid; vg_tid_last_in_baseBlock = tid; @@ -360,108 +293,9 @@ static void load_thread_state ( ThreadId tid ) */ static void save_thread_state ( ThreadId tid ) { - Int i; - const UInt junk = 0xDEADBEEF; - vg_assert(vg_tid_currently_in_baseBlock != VG_INVALID_THREADID); - - /* We don't copy out the LDT entry, because it can never be changed - by the normal actions of the thread, only by the modify_ldt - syscall, in which case we will correctly be updating - VG_(threads)[tid].ldt. This printf happens iff the following - assertion fails. */ - if ((void*)VG_(threads)[tid].ldt != (void*)VG_(baseBlock)[VGOFF_(ldt)]) - VG_(printf)("VG_(threads)[%d].ldt=%p VG_(baseBlock)[VGOFF_(ldt)]=%p\n", - tid, (void*)VG_(threads)[tid].ldt, - (void*)VG_(baseBlock)[VGOFF_(ldt)]); - - vg_assert((void*)VG_(threads)[tid].ldt - == (void*)VG_(baseBlock)[VGOFF_(ldt)]); - - /* We don't copy out the TLS entry, because it can never be changed - by the normal actions of the thread, only by the set_thread_area - syscall, in which case we will correctly be updating - VG_(threads)[tid].tls. This printf happens iff the following - assertion fails. */ - if ((void*)VG_(threads)[tid].tls != (void*)VG_(baseBlock)[VGOFF_(tls_ptr)]) - VG_(printf)("VG_(threads)[%d].tls=%p VG_(baseBlock)[VGOFF_(tls_ptr)]=%p\n", - tid, (void*)VG_(threads)[tid].tls, - (void*)VG_(baseBlock)[VGOFF_(tls_ptr)]); - - vg_assert((void*)VG_(threads)[tid].tls - == (void*)VG_(baseBlock)[VGOFF_(tls_ptr)]); - - VG_(threads)[tid].m_cs = VG_(baseBlock)[VGOFF_(m_cs)]; - VG_(threads)[tid].m_ss = VG_(baseBlock)[VGOFF_(m_ss)]; - VG_(threads)[tid].m_ds = VG_(baseBlock)[VGOFF_(m_ds)]; - VG_(threads)[tid].m_es = VG_(baseBlock)[VGOFF_(m_es)]; - VG_(threads)[tid].m_fs = VG_(baseBlock)[VGOFF_(m_fs)]; - VG_(threads)[tid].m_gs = VG_(baseBlock)[VGOFF_(m_gs)]; - - VG_(threads)[tid].m_eax = VG_(baseBlock)[VGOFF_(m_eax)]; - VG_(threads)[tid].m_ebx = VG_(baseBlock)[VGOFF_(m_ebx)]; - VG_(threads)[tid].m_ecx = VG_(baseBlock)[VGOFF_(m_ecx)]; - VG_(threads)[tid].m_edx = VG_(baseBlock)[VGOFF_(m_edx)]; - VG_(threads)[tid].m_esi = VG_(baseBlock)[VGOFF_(m_esi)]; - VG_(threads)[tid].m_edi = VG_(baseBlock)[VGOFF_(m_edi)]; - VG_(threads)[tid].m_ebp = VG_(baseBlock)[VGOFF_(m_ebp)]; - VG_(threads)[tid].m_esp = VG_(baseBlock)[VGOFF_(m_esp)]; - VG_(threads)[tid].m_eflags - = insertDflag(VG_(baseBlock)[VGOFF_(m_eflags)], - VG_(baseBlock)[VGOFF_(m_dflag)]); - VG_(threads)[tid].m_eip = VG_(baseBlock)[VGOFF_(m_eip)]; - - for (i = 0; i < VG_SIZE_OF_SSESTATE_W; i++) - VG_(threads)[tid].m_sse[i] - = VG_(baseBlock)[VGOFF_(m_ssestate) + i]; - - if (VG_(needs).shadow_regs) { - VG_(threads)[tid].sh_eax = VG_(baseBlock)[VGOFF_(sh_eax)]; - VG_(threads)[tid].sh_ebx = VG_(baseBlock)[VGOFF_(sh_ebx)]; - VG_(threads)[tid].sh_ecx = VG_(baseBlock)[VGOFF_(sh_ecx)]; - VG_(threads)[tid].sh_edx = VG_(baseBlock)[VGOFF_(sh_edx)]; - VG_(threads)[tid].sh_esi = VG_(baseBlock)[VGOFF_(sh_esi)]; - VG_(threads)[tid].sh_edi = VG_(baseBlock)[VGOFF_(sh_edi)]; - VG_(threads)[tid].sh_ebp = VG_(baseBlock)[VGOFF_(sh_ebp)]; - VG_(threads)[tid].sh_esp = VG_(baseBlock)[VGOFF_(sh_esp)]; - VG_(threads)[tid].sh_eflags = VG_(baseBlock)[VGOFF_(sh_eflags)]; - } else { - /* Fill with recognisable junk */ - VG_(threads)[tid].sh_eax = - VG_(threads)[tid].sh_ebx = - VG_(threads)[tid].sh_ecx = - VG_(threads)[tid].sh_edx = - VG_(threads)[tid].sh_esi = - VG_(threads)[tid].sh_edi = - VG_(threads)[tid].sh_ebp = - VG_(threads)[tid].sh_esp = - VG_(threads)[tid].sh_eflags = VG_UNUSED_SHADOW_REG_VALUE; - } - - /* Fill it up with junk. */ - VG_(baseBlock)[VGOFF_(ldt)] = junk; - VG_(baseBlock)[VGOFF_(tls_ptr)] = junk; - VG_(baseBlock)[VGOFF_(m_cs)] = junk; - VG_(baseBlock)[VGOFF_(m_ss)] = junk; - VG_(baseBlock)[VGOFF_(m_ds)] = junk; - VG_(baseBlock)[VGOFF_(m_es)] = junk; - VG_(baseBlock)[VGOFF_(m_fs)] = junk; - VG_(baseBlock)[VGOFF_(m_gs)] = junk; - - VG_(baseBlock)[VGOFF_(m_eax)] = junk; - VG_(baseBlock)[VGOFF_(m_ebx)] = junk; - VG_(baseBlock)[VGOFF_(m_ecx)] = junk; - VG_(baseBlock)[VGOFF_(m_edx)] = junk; - VG_(baseBlock)[VGOFF_(m_esi)] = junk; - VG_(baseBlock)[VGOFF_(m_edi)] = junk; - VG_(baseBlock)[VGOFF_(m_ebp)] = junk; - VG_(baseBlock)[VGOFF_(m_esp)] = junk; - VG_(baseBlock)[VGOFF_(m_eflags)] = junk; - VG_(baseBlock)[VGOFF_(m_eip)] = junk; - - for (i = 0; i < VG_SIZE_OF_SSESTATE_W; i++) - VG_(baseBlock)[VGOFF_(m_ssestate) + i] = junk; + VGA_(save_state)(&VG_(threads)[tid].arch, tid); vg_tid_currently_in_baseBlock = VG_INVALID_THREADID; } @@ -521,8 +355,8 @@ static void mostly_clear_thread_record ( ThreadId tid ) { vg_assert(tid >= 0 && tid < VG_N_THREADS); - VG_(threads)[tid].ldt = NULL; - VG_(clear_TLS_for_thread)(VG_(threads)[tid].tls); + VG_(threads)[tid].arch.ldt = NULL; + VG_(clear_TLS_for_thread)(VG_(threads)[tid].arch.tls); VG_(threads)[tid].tid = tid; VG_(threads)[tid].status = VgTs_Empty; VG_(threads)[tid].associated_mx = NULL; @@ -587,7 +421,7 @@ void VG_(scheduler_init) ( void ) /* Copy VG_(baseBlock) state to tid_main's slot. */ vg_tid_currently_in_baseBlock = tid_main; vg_tid_last_in_baseBlock = tid_main; - VG_(baseBlock)[VGOFF_(tls_ptr)] = (UInt)VG_(threads)[tid_main].tls; + VG_(baseBlock)[VGOFF_(tls_ptr)] = (UInt)VG_(threads)[tid_main].arch.tls; save_thread_state ( tid_main ); VG_(threads)[tid_main].stack_highest_word @@ -632,12 +466,12 @@ void handle_signal_return ( ThreadId tid ) return; if (VG_(threads)[tid].status == VgTs_Sleeping - && VG_(threads)[tid].m_eax == __NR_nanosleep) { + && VG_(threads)[tid].arch.m_eax == __NR_nanosleep) { /* We interrupted a nanosleep(). The right thing to do is to write the unused time to nanosleep's second param, but that's too much effort ... we just say that 1 nanosecond was not used, and return EINTR. */ - rem = (struct vki_timespec *)VG_(threads)[tid].m_ecx; /* arg2 */ + rem = (struct vki_timespec *)VG_(threads)[tid].arch.m_ecx; /* arg2 */ if (rem != NULL) { rem->tv_sec = 0; rem->tv_nsec = 1; @@ -691,7 +525,7 @@ void sched_do_syscall ( ThreadId tid ) vg_assert(VG_(is_valid_tid)(tid)); vg_assert(VG_(threads)[tid].status == VgTs_Runnable); - syscall_no = VG_(threads)[tid].m_eax; /* syscall number */ + syscall_no = VG_(threads)[tid].arch.m_eax; /* syscall number */ /* Special-case nanosleep because we can. But should we? @@ -701,7 +535,7 @@ void sched_do_syscall ( ThreadId tid ) if (0 && syscall_no == __NR_nanosleep) { UInt t_now, t_awaken; struct vki_timespec* req; - req = (struct vki_timespec*)VG_(threads)[tid].m_ebx; /* arg1 */ + req = (struct vki_timespec*)VG_(threads)[tid].arch.m_ebx; /* arg1 */ if (req->tv_sec < 0 || req->tv_nsec < 0 || req->tv_nsec >= 1000000000) { SET_SYSCALL_RETVAL(tid, -VKI_EINVAL); @@ -1002,18 +836,18 @@ VgSchedReturnCode do_scheduler ( Int* exitcode, ThreadId* last_run_tid ) # if 0 if (VG_(bbs_done) > 31700000 + 0) { dispatch_ctr_SAVED = VG_(dispatch_ctr) = 2; - VG_(translate)(&VG_(threads)[tid], VG_(threads)[tid].m_eip, + VG_(translate)(&VG_(threads)[tid], VG_(threads)[tid].arch.m_eip, /*debugging*/True); } - vg_assert(VG_(threads)[tid].m_eip != 0); + vg_assert(VG_(threads)[tid].arch.m_eip != 0); # endif trc = run_thread_for_a_while ( tid ); # if 0 - if (0 == VG_(threads)[tid].m_eip) { + if (0 == VG_(threads)[tid].arch.m_eip) { VG_(printf)("tid = %d, dc = %llu\n", tid, VG_(bbs_done)); - vg_assert(0 != VG_(threads)[tid].m_eip); + vg_assert(0 != VG_(threads)[tid].arch.m_eip); } # endif @@ -1025,11 +859,11 @@ VgSchedReturnCode do_scheduler ( Int* exitcode, ThreadId* last_run_tid ) /* Trivial event. Miss in the fast-cache. Do a full lookup for it. */ - trans_addr = VG_(search_transtab) ( VG_(threads)[tid].m_eip ); + trans_addr = VG_(search_transtab) ( VG_(threads)[tid].arch.m_eip ); if (trans_addr == (Addr)0) { /* Not found; we need to request a translation. */ - VG_(translate)( tid, VG_(threads)[tid].m_eip, /*debug*/False ); - trans_addr = VG_(search_transtab) ( VG_(threads)[tid].m_eip ); + VG_(translate)( tid, VG_(threads)[tid].arch.m_eip, /*debug*/False ); + trans_addr = VG_(search_transtab) ( VG_(threads)[tid].arch.m_eip ); if (trans_addr == (Addr)0) VG_(core_panic)("VG_TRC_INNER_FASTMISS: missing tt_fast entry"); } @@ -1037,7 +871,7 @@ VgSchedReturnCode do_scheduler ( Int* exitcode, ThreadId* last_run_tid ) } if (trc == VG_TRC_EBP_JMP_CLIENTREQ) { - UInt reqno = *(UInt*)(VG_(threads)[tid].m_eax); + UInt reqno = *(UInt*)(VG_(threads)[tid].arch.m_eax); /* VG_(printf)("request 0x%x\n", reqno); */ /* Are we really absolutely totally quitting? */ @@ -1067,7 +901,7 @@ VgSchedReturnCode do_scheduler ( Int* exitcode, ThreadId* last_run_tid ) to exit. */ # if 0 { UInt* esp; Int i; - esp=(UInt*)VG_(threads)[tid].m_esp; + esp=(UInt*)VG_(threads)[tid].arch.m_esp; VG_(printf)("\nBEFORE\n"); for (i = 10; i >= -10; i--) VG_(printf)("%2d %p = 0x%x\n", i, &esp[i], esp[i]); @@ -1085,12 +919,12 @@ VgSchedReturnCode do_scheduler ( Int* exitcode, ThreadId* last_run_tid ) __libc_freeres does some invalid frees which crash the unprotected malloc/free system. */ - if (VG_(threads)[tid].m_eax == __NR_exit - || VG_(threads)[tid].m_eax == __NR_exit_group + if (VG_(threads)[tid].arch.m_eax == __NR_exit + || VG_(threads)[tid].arch.m_eax == __NR_exit_group ) { /* If __NR_exit, remember the supplied argument. */ - *exitcode = VG_(threads)[tid].m_ebx; /* syscall arg1 */ + *exitcode = VG_(threads)[tid].arch.m_ebx; /* syscall arg1 */ /* Only run __libc_freeres if the tool says it's ok and it hasn't been overridden with --run-libc-freeres=no @@ -1105,7 +939,7 @@ VgSchedReturnCode do_scheduler ( Int* exitcode, ThreadId* last_run_tid ) "Caught __NR_exit; running __libc_freeres()"); } VG_(nuke_all_threads_except) ( tid ); - VG_(threads)[tid].m_eip = (UInt)__libc_freeres_wrapper; + VG_(threads)[tid].arch.m_eip = (UInt)__libc_freeres_wrapper; vg_assert(VG_(threads)[tid].status == VgTs_Runnable); goto stage1; /* party on, dudes (but not for much longer :) */ @@ -1122,13 +956,13 @@ VgSchedReturnCode do_scheduler ( Int* exitcode, ThreadId* last_run_tid ) } /* We've dealt with __NR_exit at this point. */ - vg_assert(VG_(threads)[tid].m_eax != __NR_exit && - VG_(threads)[tid].m_eax != __NR_exit_group); + vg_assert(VG_(threads)[tid].arch.m_eax != __NR_exit && + VG_(threads)[tid].arch.m_eax != __NR_exit_group); /* Trap syscalls to __NR_sched_yield and just have this thread yield instead. Not essential, just an optimisation. */ - if (VG_(threads)[tid].m_eax == __NR_sched_yield) { + if (VG_(threads)[tid].arch.m_eax == __NR_sched_yield) { SET_SYSCALL_RETVAL(tid, 0); /* syscall returns with success */ goto stage1; /* find a new thread to run */ } @@ -1137,7 +971,7 @@ VgSchedReturnCode do_scheduler ( Int* exitcode, ThreadId* last_run_tid ) # if 0 { UInt* esp; Int i; - esp=(UInt*)VG_(threads)[tid].m_esp; + esp=(UInt*)VG_(threads)[tid].arch.m_esp; VG_(printf)("AFTER\n"); for (i = 10; i >= -10; i--) VG_(printf)("%2d %p = 0x%x\n", i, &esp[i], esp[i]); @@ -1319,19 +1153,19 @@ void make_thread_jump_to_cancelhdlr ( ThreadId tid ) vg_assert(VG_(threads)[tid].cancel_pend != NULL); /* Push a suitable arg, and mark it as readable. */ - SET_PTHREQ_ESP(tid, VG_(threads)[tid].m_esp - 4); - * (UInt*)(VG_(threads)[tid].m_esp) = (UInt)PTHREAD_CANCELED; - VG_TRACK( post_mem_write, VG_(threads)[tid].m_esp, sizeof(void*) ); + SET_PTHREQ_ESP(tid, VG_(threads)[tid].arch.m_esp - 4); + * (UInt*)(VG_(threads)[tid].arch.m_esp) = (UInt)PTHREAD_CANCELED; + VG_TRACK( post_mem_write, VG_(threads)[tid].arch.m_esp, sizeof(void*) ); /* Push a bogus return address. It will not return, but we still need to have it so that the arg is at the correct stack offset. Don't mark as readable; any attempt to read this is and internal valgrind bug since thread_exit_wrapper should not return. */ - SET_PTHREQ_ESP(tid, VG_(threads)[tid].m_esp - 4); - * (UInt*)(VG_(threads)[tid].m_esp) = 0xBEADDEEF; + SET_PTHREQ_ESP(tid, VG_(threads)[tid].arch.m_esp - 4); + * (UInt*)(VG_(threads)[tid].arch.m_esp) = 0xBEADDEEF; /* .cancel_pend will hold &thread_exit_wrapper */ - VG_(threads)[tid].m_eip = (UInt)VG_(threads)[tid].cancel_pend; + VG_(threads)[tid].arch.m_eip = (UInt)VG_(threads)[tid].cancel_pend; VG_(proxy_abort_syscall)(tid); @@ -1413,11 +1247,11 @@ void cleanup_after_thread_exited ( ThreadId tid, Bool forcekill ) VG_(threads)[tid].stack_size ); /* Deallocate its LDT, if it ever had one. */ - VG_(deallocate_LDT_for_thread)( VG_(threads)[tid].ldt ); - VG_(threads)[tid].ldt = NULL; + VG_(deallocate_LDT_for_thread)( VG_(threads)[tid].arch.ldt ); + VG_(threads)[tid].arch.ldt = NULL; /* Clear its TLS array. */ - VG_(clear_TLS_for_thread)( VG_(threads)[tid].tls ); + VG_(clear_TLS_for_thread)( VG_(threads)[tid].arch.tls ); /* Not interested in the timeout anymore */ VG_(threads)[tid].awaken_at = 0xFFFFFFFF; @@ -1919,19 +1753,19 @@ void do__apply_in_new_thread ( ThreadId parent_tid, load_thread_state(parent_tid); /* We inherit our parent's LDT. */ - if (VG_(threads)[parent_tid].ldt == NULL) { + if (VG_(threads)[parent_tid].arch.ldt == NULL) { /* We hope this is the common case. */ VG_(baseBlock)[VGOFF_(ldt)] = 0; } else { /* No luck .. we have to take a copy of the parent's. */ - VG_(threads)[tid].ldt - = VG_(allocate_LDT_for_thread)( VG_(threads)[parent_tid].ldt ); - VG_(baseBlock)[VGOFF_(ldt)] = (UInt)VG_(threads)[tid].ldt; + VG_(threads)[tid].arch.ldt + = VG_(allocate_LDT_for_thread)( VG_(threads)[parent_tid].arch.ldt ); + VG_(baseBlock)[VGOFF_(ldt)] = (UInt)VG_(threads)[tid].arch.ldt; } /* Initialise the thread's TLS array */ - VG_(clear_TLS_for_thread)( VG_(threads)[tid].tls ); - VG_(baseBlock)[VGOFF_(tls_ptr)] = (UInt)VG_(threads)[tid].tls; + VG_(clear_TLS_for_thread)( VG_(threads)[tid].arch.tls ); + VG_(baseBlock)[VGOFF_(tls_ptr)] = (UInt)VG_(threads)[tid].arch.tls; save_thread_state(tid); vg_tid_last_in_baseBlock = tid; @@ -1980,25 +1814,25 @@ void do__apply_in_new_thread ( ThreadId parent_tid, VG_TRACK ( die_mem_stack, VG_(threads)[tid].stack_base, VG_(threads)[tid].stack_size - VG_AR_CLIENT_STACKBASE_REDZONE_SZB); - VG_TRACK ( ban_mem_stack, VG_(threads)[tid].m_esp, + VG_TRACK ( ban_mem_stack, VG_(threads)[tid].arch.m_esp, VG_AR_CLIENT_STACKBASE_REDZONE_SZB ); /* push two args */ - SET_PTHREQ_ESP(tid, VG_(threads)[tid].m_esp - 8); + SET_PTHREQ_ESP(tid, VG_(threads)[tid].arch.m_esp - 8); - VG_TRACK ( new_mem_stack, (Addr)VG_(threads)[tid].m_esp, 2 * 4 ); + VG_TRACK ( new_mem_stack, (Addr)VG_(threads)[tid].arch.m_esp, 2 * 4 ); VG_TRACK ( pre_mem_write, Vg_CorePThread, tid, "new thread: stack", - (Addr)VG_(threads)[tid].m_esp, 2 * 4 ); + (Addr)VG_(threads)[tid].arch.m_esp, 2 * 4 ); /* push arg and (bogus) return address */ - * (UInt*)(VG_(threads)[tid].m_esp+4) = (UInt)arg; - * (UInt*)(VG_(threads)[tid].m_esp) + * (UInt*)(VG_(threads)[tid].arch.m_esp+4) = (UInt)arg; + * (UInt*)(VG_(threads)[tid].arch.m_esp) = (UInt)&do__apply_in_new_thread_bogusRA; - VG_TRACK ( post_mem_write, VG_(threads)[tid].m_esp, 2 * 4 ); + VG_TRACK ( post_mem_write, VG_(threads)[tid].arch.m_esp, 2 * 4 ); /* this is where we start */ - VG_(threads)[tid].m_eip = (UInt)fn; + VG_(threads)[tid].arch.m_eip = (UInt)fn; if (VG_(clo_trace_sched)) { VG_(sprintf)(msg_buf, "new thread, created by %d", parent_tid ); @@ -3001,7 +2835,7 @@ void VG_(intercept_libc_freeres_wrapper)(Addr addr) static void do_client_request ( ThreadId tid ) { - UInt* arg = (UInt*)(VG_(threads)[tid].m_eax); + UInt* arg = (UInt*)(VG_(threads)[tid].arch.m_eax); UInt req_no = arg[0]; if (0) @@ -3430,7 +3264,7 @@ void scheduler_sanity ( void ) if (VG_(threads)[i].status != VgTs_Empty) { Int stack_used = (Addr)VG_(threads)[i].stack_highest_word - - (Addr)VG_(threads)[i].m_esp; + - (Addr)VG_(threads)[i].arch.m_esp; Int stack_avail = VG_(threads)[i].stack_size - VG_AR_CLIENT_STACKBASE_REDZONE_SZB diff --git a/coregrind/vg_signals.c b/coregrind/vg_signals.c index 1fb60eaf73..d47cfdd76b 100644 --- a/coregrind/vg_signals.c +++ b/coregrind/vg_signals.c @@ -489,9 +489,9 @@ void VG_(do__NR_sigaltstack) ( ThreadId tid ) Addr m_esp; vg_assert(VG_(is_valid_tid)(tid)); - ss = (vki_kstack_t*)(VG_(threads)[tid].m_ebx); - oss = (vki_kstack_t*)(VG_(threads)[tid].m_ecx); - m_esp = VG_(threads)[tid].m_esp; + ss = (vki_kstack_t*)(VG_(threads)[tid].arch.m_ebx); + oss = (vki_kstack_t*)(VG_(threads)[tid].arch.m_ecx); + m_esp = VG_(threads)[tid].arch.m_esp; if (VG_(clo_trace_signals)) VG_(message)(Vg_DebugExtraMsg, @@ -506,7 +506,7 @@ void VG_(do__NR_sigaltstack) ( ThreadId tid ) } if (ss != NULL) { - if (on_sig_stack(tid, VG_(threads)[tid].m_esp)) { + if (on_sig_stack(tid, VG_(threads)[tid].arch.m_esp)) { SET_SYSCALL_RETVAL(tid, -VKI_EPERM); return; } @@ -542,9 +542,9 @@ void VG_(do__NR_sigaction) ( ThreadId tid ) vg_assert(is_correct_sigmask()); vg_assert(VG_(is_valid_tid)(tid)); - signo = VG_(threads)[tid].m_ebx; /* int sigNo */ - new_act = (vki_ksigaction*)(VG_(threads)[tid].m_ecx); - old_act = (vki_ksigaction*)(VG_(threads)[tid].m_edx); + signo = VG_(threads)[tid].arch.m_ebx; /* int sigNo */ + new_act = (vki_ksigaction*)(VG_(threads)[tid].arch.m_ecx); + old_act = (vki_ksigaction*)(VG_(threads)[tid].arch.m_edx); if (VG_(clo_trace_signals)) VG_(message)(Vg_DebugExtraMsg, @@ -921,7 +921,7 @@ static void synth_ucontext(ThreadId tid, const vki_ksiginfo_t *si, uc->uc_sigmask = *set; uc->uc_stack = tst->altstack; -#define SC(reg) sc->reg = tst->m_##reg +#define SC(reg) sc->reg = tst->arch.m_##reg SC(gs); SC(fs); SC(es); @@ -973,7 +973,7 @@ void vg_push_signal_frame ( ThreadId tid, const vki_ksiginfo_t *siginfo ) && /* there is a defined and enabled alt stack, which we're not already using. Logic from get_sigframe in arch/i386/kernel/signal.c. */ - sas_ss_flags(tid, tst->m_esp) == 0 + sas_ss_flags(tid, tst->arch.m_esp) == 0 ) { esp_top_of_frame = (Addr)(tst->altstack.ss_sp) + tst->altstack.ss_size; @@ -986,7 +986,7 @@ void vg_push_signal_frame ( ThreadId tid, const vki_ksiginfo_t *siginfo ) VG_TRACK( pre_deliver_signal, tid, sigNo, /*alt_stack*/True ); } else { - esp_top_of_frame = tst->m_esp; + esp_top_of_frame = tst->arch.m_esp; /* Signal delivery to tools */ VG_TRACK( pre_deliver_signal, tid, sigNo, /*alt_stack*/False ); @@ -1025,7 +1025,7 @@ void vg_push_signal_frame ( ThreadId tid, const vki_ksiginfo_t *siginfo ) (Addr)&frame->sigInfo, sizeof(frame->sigInfo) ); VG_(memcpy)(&frame->sigInfo, siginfo, sizeof(vki_ksiginfo_t)); if (sigNo == VKI_SIGFPE) { - frame->sigInfo._sifields._sigfault._addr = (void *)tst->m_eip; + frame->sigInfo._sifields._sigfault._addr = (void *)tst->arch.m_eip; } VG_TRACK( post_mem_write, (Addr)&frame->sigInfo, sizeof(frame->sigInfo) ); @@ -1053,29 +1053,29 @@ void vg_push_signal_frame ( ThreadId tid, const vki_ksiginfo_t *siginfo ) frame->magicPI = 0x31415927; for (i = 0; i < VG_SIZE_OF_SSESTATE_W; i++) - frame->m_sse[i] = tst->m_sse[i]; - - frame->m_eax = tst->m_eax; - frame->m_ecx = tst->m_ecx; - frame->m_edx = tst->m_edx; - frame->m_ebx = tst->m_ebx; - frame->m_ebp = tst->m_ebp; - frame->m_esp = tst->m_esp; - frame->m_esi = tst->m_esi; - frame->m_edi = tst->m_edi; - frame->m_eflags = tst->m_eflags; - frame->m_eip = tst->m_eip; + frame->m_sse[i] = tst->arch.m_sse[i]; + + frame->m_eax = tst->arch.m_eax; + frame->m_ecx = tst->arch.m_ecx; + frame->m_edx = tst->arch.m_edx; + frame->m_ebx = tst->arch.m_ebx; + frame->m_ebp = tst->arch.m_ebp; + frame->m_esp = tst->arch.m_esp; + frame->m_esi = tst->arch.m_esi; + frame->m_edi = tst->arch.m_edi; + frame->m_eflags = tst->arch.m_eflags; + frame->m_eip = tst->arch.m_eip; if (VG_(needs).shadow_regs) { - frame->sh_eax = tst->sh_eax; - frame->sh_ecx = tst->sh_ecx; - frame->sh_edx = tst->sh_edx; - frame->sh_ebx = tst->sh_ebx; - frame->sh_ebp = tst->sh_ebp; - frame->sh_esp = tst->sh_esp; - frame->sh_esi = tst->sh_esi; - frame->sh_edi = tst->sh_edi; - frame->sh_eflags = tst->sh_eflags; + frame->sh_eax = tst->arch.sh_eax; + frame->sh_ecx = tst->arch.sh_ecx; + frame->sh_edx = tst->arch.sh_edx; + frame->sh_ebx = tst->arch.sh_ebx; + frame->sh_ebp = tst->arch.sh_ebp; + frame->sh_esp = tst->arch.sh_esp; + frame->sh_esi = tst->arch.sh_esi; + frame->sh_edi = tst->arch.sh_edi; + frame->sh_eflags = tst->arch.sh_eflags; } frame->mask = tst->sig_mask; @@ -1092,16 +1092,16 @@ void vg_push_signal_frame ( ThreadId tid, const vki_ksiginfo_t *siginfo ) /* Ensure 'tid' and 'tst' correspond */ vg_assert(& VG_(threads)[tid] == tst); /* Set the thread so it will next run the handler. */ - /* tst->m_esp = esp; */ + /* tst->arch.m_esp = esp; */ SET_SIGNAL_ESP(tid, esp); - tst->m_eip = (Addr)vg_scss.scss_per_sig[sigNo].scss_handler; + tst->arch.m_eip = (Addr)vg_scss.scss_per_sig[sigNo].scss_handler; /* This thread needs to be marked runnable, but we leave that the caller to do. */ if (0) VG_(printf)("pushed signal frame; %%ESP now = %p, next %%EBP = %p, status=%d\n", - esp, tst->m_eip, tst->status); + esp, tst->arch.m_eip, tst->status); } /* Clear the signal frame created by vg_push_signal_frame, restore the @@ -1119,7 +1119,7 @@ Int vg_pop_signal_frame ( ThreadId tid ) tst = & VG_(threads)[tid]; /* Correctly reestablish the frame base address. */ - esp = tst->m_esp; + esp = tst->arch.m_esp; frame = (VgSigFrame*) (esp -4 /* because the handler's RET pops the RA */ +20 /* because signalreturn_bogusRA pushes 5 words */); @@ -1135,29 +1135,29 @@ Int vg_pop_signal_frame ( ThreadId tid ) /* restore machine state */ for (i = 0; i < VG_SIZE_OF_SSESTATE_W; i++) - tst->m_sse[i] = frame->m_sse[i]; - - tst->m_eax = frame->m_eax; - tst->m_ecx = frame->m_ecx; - tst->m_edx = frame->m_edx; - tst->m_ebx = frame->m_ebx; - tst->m_ebp = frame->m_ebp; - tst->m_esp = frame->m_esp; - tst->m_esi = frame->m_esi; - tst->m_edi = frame->m_edi; - tst->m_eflags = frame->m_eflags; - tst->m_eip = frame->m_eip; + tst->arch.m_sse[i] = frame->m_sse[i]; + + tst->arch.m_eax = frame->m_eax; + tst->arch.m_ecx = frame->m_ecx; + tst->arch.m_edx = frame->m_edx; + tst->arch.m_ebx = frame->m_ebx; + tst->arch.m_ebp = frame->m_ebp; + tst->arch.m_esp = frame->m_esp; + tst->arch.m_esi = frame->m_esi; + tst->arch.m_edi = frame->m_edi; + tst->arch.m_eflags = frame->m_eflags; + tst->arch.m_eip = frame->m_eip; if (VG_(needs).shadow_regs) { - tst->sh_eax = frame->sh_eax; - tst->sh_ecx = frame->sh_ecx; - tst->sh_edx = frame->sh_edx; - tst->sh_ebx = frame->sh_ebx; - tst->sh_ebp = frame->sh_ebp; - tst->sh_esp = frame->sh_esp; - tst->sh_esi = frame->sh_esi; - tst->sh_edi = frame->sh_edi; - tst->sh_eflags = frame->sh_eflags; + tst->arch.sh_eax = frame->sh_eax; + tst->arch.sh_ecx = frame->sh_ecx; + tst->arch.sh_edx = frame->sh_edx; + tst->arch.sh_ebx = frame->sh_ebx; + tst->arch.sh_ebp = frame->sh_ebp; + tst->arch.sh_esp = frame->sh_esp; + tst->arch.sh_esi = frame->sh_esi; + tst->arch.sh_edi = frame->sh_edi; + tst->arch.sh_eflags = frame->sh_eflags; } /* don't use the copy exposed to the handler; it might have changed @@ -1473,24 +1473,24 @@ static void fill_prstatus(const ThreadState *tst, struct elf_prstatus *prs, cons regs->fs = VG_(baseBlock)[VGOFF_(m_fs)]; regs->gs = VG_(baseBlock)[VGOFF_(m_gs)]; } else { - regs->eflags = tst->m_eflags; - regs->esp = tst->m_esp; - regs->eip = tst->m_eip; - - regs->ebx = tst->m_ebx; - regs->ecx = tst->m_ecx; - regs->edx = tst->m_edx; - regs->esi = tst->m_esi; - regs->edi = tst->m_edi; - regs->ebp = tst->m_ebp; - regs->eax = tst->m_eax; - - regs->cs = tst->m_cs; - regs->ds = tst->m_ds; - regs->ss = tst->m_ss; - regs->es = tst->m_es; - regs->fs = tst->m_fs; - regs->gs = tst->m_gs; + regs->eflags = tst->arch.m_eflags; + regs->esp = tst->arch.m_esp; + regs->eip = tst->arch.m_eip; + + regs->ebx = tst->arch.m_ebx; + regs->ecx = tst->arch.m_ecx; + regs->edx = tst->arch.m_edx; + regs->esi = tst->arch.m_esi; + regs->edi = tst->arch.m_edi; + regs->ebp = tst->arch.m_ebp; + regs->eax = tst->arch.m_eax; + + regs->cs = tst->arch.m_cs; + regs->ds = tst->arch.m_ds; + regs->ss = tst->arch.m_ss; + regs->es = tst->arch.m_es; + regs->fs = tst->arch.m_fs; + regs->gs = tst->arch.m_gs; } } @@ -1501,7 +1501,7 @@ static void fill_fpu(const ThreadState *tst, elf_fpregset_t *fpu) if (VG_(is_running_thread)(tst->tid)) { from = (const Char *)&VG_(baseBlock)[VGOFF_(m_ssestate)]; } else { - from = (const Char *)&tst->m_sse; + from = (const Char *)&tst->arch.m_sse; } if (VG_(have_ssestate)) { @@ -1527,7 +1527,7 @@ static void fill_xfpu(const ThreadState *tst, elf_fpxregset_t *xfpu) if (VG_(is_running_thread)(tst->tid)) from = (UShort *)&VG_(baseBlock)[VGOFF_(m_ssestate)]; else - from = (UShort *)tst->m_sse; + from = (UShort *)tst->arch.m_sse; VG_(memcpy)(xfpu, from, sizeof(*xfpu)); } @@ -1867,8 +1867,8 @@ void VG_(deliver_signal) ( ThreadId tid, const vki_ksiginfo_t *info, Bool async if (tst->status == VgTs_WaitSys) { /* blocked in a syscall; we assume it should be interrupted */ - if (tst->m_eax == -VKI_ERESTARTSYS) - tst->m_eax = -VKI_EINTR; + if (tst->arch.m_eax == -VKI_ERESTARTSYS) + tst->arch.m_eax = -VKI_EINTR; } VG_(proxy_sigack)(tid, &tst->sig_mask); @@ -2076,7 +2076,7 @@ void vg_sync_signalhandler ( Int sigNo, vki_ksiginfo_t *info, struct vki_ucontex ThreadId tid = VG_(get_current_or_recent_tid)(); Addr fault = (Addr)info->_sifields._sigfault._addr; Addr esp = VG_(is_running_thread)(tid) ? - VG_(baseBlock)[VGOFF_(m_esp)] : VG_(threads)[tid].m_esp; + VG_(baseBlock)[VGOFF_(m_esp)] : VG_(threads)[tid].arch.m_esp; Segment *seg; seg = VG_(find_segment)(fault); diff --git a/coregrind/vg_symtab2.c b/coregrind/vg_symtab2.c index 2759f991a2..a250d4abba 100644 --- a/coregrind/vg_symtab2.c +++ b/coregrind/vg_symtab2.c @@ -2024,14 +2024,14 @@ static UInt *regaddr(ThreadId tid, Int regno) ThreadState *tst = &VG_(threads)[tid]; switch(regno) { - case R_EAX: ret = &tst->m_eax; break; - case R_ECX: ret = &tst->m_ecx; break; - case R_EDX: ret = &tst->m_edx; break; - case R_EBX: ret = &tst->m_ebx; break; - case R_ESP: ret = &tst->m_esp; break; - case R_EBP: ret = &tst->m_ebp; break; - case R_ESI: ret = &tst->m_esi; break; - case R_EDI: ret = &tst->m_edi; break; + case R_EAX: ret = &tst->arch.m_eax; break; + case R_ECX: ret = &tst->arch.m_ecx; break; + case R_EDX: ret = &tst->arch.m_edx; break; + case R_EBX: ret = &tst->arch.m_ebx; break; + case R_ESP: ret = &tst->arch.m_esp; break; + case R_EBP: ret = &tst->arch.m_ebp; break; + case R_ESI: ret = &tst->arch.m_esi; break; + case R_EDI: ret = &tst->arch.m_edi; break; default: break; } diff --git a/coregrind/vg_syscalls.c b/coregrind/vg_syscalls.c index 9c836bb667..39591cebae 100644 --- a/coregrind/vg_syscalls.c +++ b/coregrind/vg_syscalls.c @@ -1010,14 +1010,14 @@ static Bool fd_allowed(Int fd, const Char *syscall, ThreadId tid, Bool soft) #define POSTALIAS(new, old) \ POST(new) __attribute__((alias(STR(after_##old)))) -#define SYSNO (tst->m_eax) /* in PRE(x) */ -#define res (tst->m_eax) /* in POST(x) */ -#define arg1 (tst->m_ebx) -#define arg2 (tst->m_ecx) -#define arg3 (tst->m_edx) -#define arg4 (tst->m_esi) -#define arg5 (tst->m_edi) -#define arg6 (tst->m_ebp) +#define SYSNO (tst->arch.m_eax) /* in PRE(x) */ +#define res (tst->arch.m_eax) /* in POST(x) */ +#define arg1 (tst->arch.m_ebx) +#define arg2 (tst->arch.m_ecx) +#define arg3 (tst->arch.m_edx) +#define arg4 (tst->arch.m_esi) +#define arg5 (tst->arch.m_edi) +#define arg6 (tst->arch.m_ebp) PRE(exit_group) { @@ -6284,7 +6284,7 @@ static void restart_syscall(ThreadId tid) vg_assert(tst->syscallno != -1); SYSNO = tst->syscallno; - tst->m_eip -= 2; /* sizeof(int $0x80) */ + tst->arch.m_eip -= 2; /* sizeof(int $0x80) */ /* Make sure our caller is actually sane, and we're really backing back over a syscall. @@ -6292,12 +6292,12 @@ static void restart_syscall(ThreadId tid) int $0x80 == CD 80 */ { - UChar *p = (UChar *)tst->m_eip; + UChar *p = (UChar *)tst->arch.m_eip; if (p[0] != 0xcd || p[1] != 0x80) VG_(message)(Vg_DebugMsg, "?! restarting over syscall at %p %02x %02x\n", - tst->m_eip, p[0], p[1]); + tst->arch.m_eip, p[0], p[1]); vg_assert(p[0] == 0xcd && p[1] == 0x80); } diff --git a/coregrind/vg_translate.c b/coregrind/vg_translate.c index 688db25c83..b88c1f8a27 100644 --- a/coregrind/vg_translate.c +++ b/coregrind/vg_translate.c @@ -1589,8 +1589,8 @@ Bool uInstrMentionsTempReg ( UInstr* u, Int tempreg ) static void vg_improve ( UCodeBlock* cb ) { Int i, j, k, m, n, ar, tr, told, actual_areg; - Int areg_map[8]; - Bool annul_put[8]; + Int areg_map[N_ARCH_REGS]; + Bool annul_put[N_ARCH_REGS]; Int tempUse[VG_MAX_REGS_USED]; Bool isWrites[VG_MAX_REGS_USED]; UInstr* u; @@ -1636,14 +1636,14 @@ static void vg_improve ( UCodeBlock* cb ) # define BIND_ARCH_TO_TEMP(archreg,tempreg)\ { Int q; \ /* Invalidate any old binding(s) to tempreg. */ \ - for (q = 0; q < 8; q++) \ + for (q = 0; q < N_ARCH_REGS; q++) \ if (areg_map[q] == tempreg) areg_map[q] = -1; \ /* Add the new binding. */ \ areg_map[archreg] = (tempreg); \ } /* Set up the A-reg map. */ - for (i = 0; i < 8; i++) areg_map[i] = -1; + for (i = 0; i < N_ARCH_REGS; i++) areg_map[i] = -1; /* Scan insns. */ for (i = 0; i < cb->used; i++) { @@ -1735,7 +1735,7 @@ static void vg_improve ( UCodeBlock* cb ) wr = isWrites[j]; if (!wr) continue; tr = tempUse[j]; - for (m = 0; m < 8; m++) + for (m = 0; m < N_ARCH_REGS; m++) if (areg_map[m] == tr) areg_map[m] = -1; } } @@ -1749,7 +1749,7 @@ static void vg_improve ( UCodeBlock* cb ) in-memory value of %ESP to be up to date. Although this isn't actually required by other analyses (cache simulation), it's simplest to be consistent for all end-uses. */ - for (j = 0; j < 8; j++) + for (j = 0; j < N_ARCH_REGS; j++) annul_put[j] = False; for (i = cb->used-1; i >= 0; i--) { @@ -1775,7 +1775,7 @@ static void vg_improve ( UCodeBlock* cb ) } else if (u->opcode == JMP || u->opcode == JIFZ || u->opcode == CALLM) { - for (j = 0; j < 8; j++) + for (j = 0; j < N_ARCH_REGS; j++) annul_put[j] = False; } else { diff --git a/coregrind/x86/Makefile.am b/coregrind/x86/Makefile.am index 5e84ea7ae2..e6995219b6 100644 --- a/coregrind/x86/Makefile.am +++ b/coregrind/x86/Makefile.am @@ -1,6 +1,15 @@ +include $(top_srcdir)/Makefile.all.am +include $(top_srcdir)/Makefile.core-AM_CPPFLAGS.am + +AM_CFLAGS = $(WERROR) -Winline -Wall -Wshadow -O -fomit-frame-pointer -g + noinst_HEADERS = \ + core_arch.h \ + core_arch_asm.h \ ume_archdefs.h +noinst_LIBRARIES = libarch.a + EXTRA_DIST = \ ume_archdefs.c \ ume_entry.S \ @@ -9,6 +18,9 @@ EXTRA_DIST = \ BUILT_SOURCES = stage2.lds CLEANFILES = stage2.lds +libarch_a_SOURCES = \ + state.c + # Extract ld's default linker script and hack it to our needs stage2.lds: Makefile $(CC) -Wl,--verbose -nostdlib 2>&1 | sed \ diff --git a/coregrind/x86/core_arch.h b/coregrind/x86/core_arch.h new file mode 100644 index 0000000000..a73717b359 --- /dev/null +++ b/coregrind/x86/core_arch.h @@ -0,0 +1,149 @@ + +/*--------------------------------------------------------------------*/ +/*--- x86/core_arch.h ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, an extensible x86 protected-mode + emulator for monitoring program execution on x86-Unixes. + + Copyright (C) 2000-2004 Nicholas Nethercote + njn25@cam.ac.uk + + 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. +*/ + +#ifndef __X86_CORE_ARCH_H +#define __X86_CORE_ARCH_H + +#include "core_arch_asm.h" // arch-specific asm stuff +#include "tool_arch.h" // arch-specific tool stuff + +/* --------------------------------------------------------------------- + Exports of vg_ldt.c + ------------------------------------------------------------------ */ + +/* This is the hardware-format for a segment descriptor, ie what the + x86 actually deals with. It is 8 bytes long. It's ugly. */ + +typedef struct _LDT_ENTRY { + union { + struct { + UShort LimitLow; + UShort BaseLow; + unsigned BaseMid : 8; + unsigned Type : 5; + unsigned Dpl : 2; + unsigned Pres : 1; + unsigned LimitHi : 4; + unsigned Sys : 1; + unsigned Reserved_0 : 1; + unsigned Default_Big : 1; + unsigned Granularity : 1; + unsigned BaseHi : 8; + } Bits; + struct { + UInt word1; + UInt word2; + } Words; + } + LdtEnt; +} VgLdtEntry; + +/* --------------------------------------------------------------------- + Constants pertaining to the simulated CPU state, VG_(baseBlock), + which need to go here to avoid ugly circularities. + ------------------------------------------------------------------ */ + +/* How big is the saved SSE/SSE2 state? Note that this subsumes the + FPU state. On machines without SSE, we just save/restore the FPU + state into the first part of this area. */ +/* A general comment about SSE save/restore: It appears that the 7th + word (which is the MXCSR) has to be &ed with 0x0000FFBF in order + that restoring from it later does not cause a GP fault (which is + delivered as a segfault). I guess this will have to be done + any time we do fxsave :-( 7th word means word offset 6 or byte + offset 24 from the start address of the save area. + */ +#define VG_SIZE_OF_SSESTATE 512 +/* ... and in words ... */ +#define VG_SIZE_OF_SSESTATE_W ((VG_SIZE_OF_SSESTATE+3)/4) + + +// Architecture-specific part of a ThreadState +typedef struct { + /* Pointer to this thread's Local (Segment) Descriptor Table. + Starts out as NULL, indicating there is no table, and we hope to + keep it that way. If the thread does __NR_modify_ldt to create + entries, we allocate a 8192-entry table at that point. This is + a straight copy of the Linux kernel's scheme. Don't forget to + deallocate this at thread exit. */ + VgLdtEntry* ldt; + + + /* TLS table. This consists of a small number (currently 3) of + entries from the Global Descriptor Table. */ + VgLdtEntry tls[VKI_GDT_TLS_ENTRIES]; + + /* Saved machine context. Note the FPU state, %EIP and segment + registers are not shadowed. + + Although the segment registers are 16 bits long, storage + management here and in VG_(baseBlock) is + simplified if we pretend they are 32 bits. */ + UInt m_cs; + UInt m_ss; + UInt m_ds; + UInt m_es; + UInt m_fs; + UInt m_gs; + + UInt m_eax; + UInt m_ebx; + UInt m_ecx; + UInt m_edx; + UInt m_esi; + UInt m_edi; + UInt m_ebp; + UInt m_esp; + UInt m_eflags; + UInt m_eip; + + /* The SSE/FPU state. This array does not (necessarily) have the + required 16-byte alignment required to get stuff in/out by + fxsave/fxrestore. So we have to do it "by hand". + */ + UInt m_sse[VG_SIZE_OF_SSESTATE_W]; + + UInt sh_eax; + UInt sh_ebx; + UInt sh_ecx; + UInt sh_edx; + UInt sh_esi; + UInt sh_edi; + UInt sh_ebp; + UInt sh_esp; + UInt sh_eflags; +} +arch_thread_t; + +#endif // __X86_CORE_ARCH_H + +/*--------------------------------------------------------------------*/ +/*--- end ---*/ +/*--------------------------------------------------------------------*/ diff --git a/coregrind/x86/core_arch_asm.h b/coregrind/x86/core_arch_asm.h new file mode 100644 index 0000000000..dfb16ac847 --- /dev/null +++ b/coregrind/x86/core_arch_asm.h @@ -0,0 +1,43 @@ +/*--------------------------------------------------------------------*/ +/*--- x86/core_arch_asm.h ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, an extensible x86 protected-mode + emulator for monitoring program execution on x86-Unixes. + + Copyright (C) 2000-2004 Nicholas Nethercote + njn25@cam.ac.uk + + 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. +*/ + +#ifndef __X86_CORE_ARCH_ASM_H +#define __X86_CORE_ARCH_ASM_H + +/* size of call instruction put into generated code at jump sites */ +#define VG_PATCHME_CALLSZ 5 + +/* size of jmp instruction which overwrites the call */ +#define VG_PATCHME_JMPSZ 5 + +#endif // __X86_CORE_ARCH_ASM_H + +/*--------------------------------------------------------------------*/ +/*--- end ---*/ +/*--------------------------------------------------------------------*/ diff --git a/coregrind/x86/state.c b/coregrind/x86/state.c new file mode 100644 index 0000000000..a27e9bcb43 --- /dev/null +++ b/coregrind/x86/state.c @@ -0,0 +1,209 @@ + +/*--------------------------------------------------------------------*/ +/*--- x86 registers, etc. state.c ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, an extensible x86 protected-mode + emulator for monitoring program execution on x86-Unixes. + + Copyright (C) 2000-2004 Nicholas Nethercote + njn25@cam.ac.uk + + 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 "core.h" + +static Int extractDflag(UInt eflags) +{ + return ( eflags & EFlagD ? -1 : 1 ); +} + +static UInt insertDflag(UInt eflags, Int d) +{ + vg_assert(d == 1 || d == -1); + eflags &= ~EFlagD; + if (d < 0) eflags |= EFlagD; + return eflags; +} + + +/* Junk to fill up a thread's shadow regs with when shadow regs aren't + being used. */ +#define VG_UNUSED_SHADOW_REG_VALUE 0x27182818 + +void VGA_(load_state) ( arch_thread_t* arch, ThreadId tid ) +{ + Int i; + + VG_(baseBlock)[VGOFF_(ldt)] = (UInt)arch->ldt; + VG_(baseBlock)[VGOFF_(tls_ptr)] = (UInt)arch->tls; + VG_(baseBlock)[VGOFF_(m_cs)] = arch->m_cs; + VG_(baseBlock)[VGOFF_(m_ss)] = arch->m_ss; + VG_(baseBlock)[VGOFF_(m_ds)] = arch->m_ds; + VG_(baseBlock)[VGOFF_(m_es)] = arch->m_es; + VG_(baseBlock)[VGOFF_(m_fs)] = arch->m_fs; + VG_(baseBlock)[VGOFF_(m_gs)] = arch->m_gs; + + VG_(baseBlock)[VGOFF_(m_eax)] = arch->m_eax; + VG_(baseBlock)[VGOFF_(m_ebx)] = arch->m_ebx; + VG_(baseBlock)[VGOFF_(m_ecx)] = arch->m_ecx; + VG_(baseBlock)[VGOFF_(m_edx)] = arch->m_edx; + VG_(baseBlock)[VGOFF_(m_esi)] = arch->m_esi; + VG_(baseBlock)[VGOFF_(m_edi)] = arch->m_edi; + VG_(baseBlock)[VGOFF_(m_ebp)] = arch->m_ebp; + VG_(baseBlock)[VGOFF_(m_esp)] = arch->m_esp; + VG_(baseBlock)[VGOFF_(m_eflags)] = arch->m_eflags & ~EFlagD; + VG_(baseBlock)[VGOFF_(m_dflag)] = extractDflag(arch->m_eflags); + VG_(baseBlock)[VGOFF_(m_eip)] = arch->m_eip; + + for (i = 0; i < VG_SIZE_OF_SSESTATE_W; i++) + VG_(baseBlock)[VGOFF_(m_ssestate) + i] = arch->m_sse[i]; + + if (VG_(needs).shadow_regs) { + VG_(baseBlock)[VGOFF_(sh_eax)] = arch->sh_eax; + VG_(baseBlock)[VGOFF_(sh_ebx)] = arch->sh_ebx; + VG_(baseBlock)[VGOFF_(sh_ecx)] = arch->sh_ecx; + VG_(baseBlock)[VGOFF_(sh_edx)] = arch->sh_edx; + VG_(baseBlock)[VGOFF_(sh_esi)] = arch->sh_esi; + VG_(baseBlock)[VGOFF_(sh_edi)] = arch->sh_edi; + VG_(baseBlock)[VGOFF_(sh_ebp)] = arch->sh_ebp; + VG_(baseBlock)[VGOFF_(sh_esp)] = arch->sh_esp; + VG_(baseBlock)[VGOFF_(sh_eflags)] = arch->sh_eflags; + } else { + /* Fields shouldn't be used -- check their values haven't changed. */ + vg_assert( + VG_UNUSED_SHADOW_REG_VALUE == arch->sh_eax && + VG_UNUSED_SHADOW_REG_VALUE == arch->sh_ebx && + VG_UNUSED_SHADOW_REG_VALUE == arch->sh_ecx && + VG_UNUSED_SHADOW_REG_VALUE == arch->sh_edx && + VG_UNUSED_SHADOW_REG_VALUE == arch->sh_esi && + VG_UNUSED_SHADOW_REG_VALUE == arch->sh_edi && + VG_UNUSED_SHADOW_REG_VALUE == arch->sh_ebp && + VG_UNUSED_SHADOW_REG_VALUE == arch->sh_esp && + VG_UNUSED_SHADOW_REG_VALUE == arch->sh_eflags); + } + +} + +void VGA_(save_state)( arch_thread_t *arch, ThreadId tid ) +{ + Int i; + const UInt junk = 0xDEADBEEF; + + /* We don't copy out the LDT entry, because it can never be changed + by the normal actions of the thread, only by the modify_ldt + syscall, in which case we will correctly be updating + VG_(threads)[tid].ldt. This printf happens iff the following + assertion fails. */ + if ((void*)arch->ldt != (void*)VG_(baseBlock)[VGOFF_(ldt)]) + VG_(printf)("VG_(threads)[%d].ldt=%p VG_(baseBlock)[VGOFF_(ldt)]=%p\n", + tid, (void*)arch->ldt, + (void*)VG_(baseBlock)[VGOFF_(ldt)]); + + vg_assert((void*)arch->ldt == (void*)VG_(baseBlock)[VGOFF_(ldt)]); + + /* We don't copy out the TLS entry, because it can never be changed + by the normal actions of the thread, only by the set_thread_area + syscall, in which case we will correctly be updating + arch->tls. This printf happens iff the following + assertion fails. */ + if ((void*)arch->tls != (void*)VG_(baseBlock)[VGOFF_(tls_ptr)]) + VG_(printf)("VG_(threads)[%d].tls=%p VG_(baseBlock)[VGOFF_(tls_ptr)]=%p\ +n", + tid, (void*)arch->tls, + (void*)VG_(baseBlock)[VGOFF_(tls_ptr)]); + + vg_assert((void*)arch->tls + == (void*)VG_(baseBlock)[VGOFF_(tls_ptr)]); + + arch->m_cs = VG_(baseBlock)[VGOFF_(m_cs)]; + arch->m_ss = VG_(baseBlock)[VGOFF_(m_ss)]; + arch->m_ds = VG_(baseBlock)[VGOFF_(m_ds)]; + arch->m_es = VG_(baseBlock)[VGOFF_(m_es)]; + arch->m_fs = VG_(baseBlock)[VGOFF_(m_fs)]; + arch->m_gs = VG_(baseBlock)[VGOFF_(m_gs)]; + + arch->m_eax = VG_(baseBlock)[VGOFF_(m_eax)]; + arch->m_ebx = VG_(baseBlock)[VGOFF_(m_ebx)]; + arch->m_ecx = VG_(baseBlock)[VGOFF_(m_ecx)]; + arch->m_edx = VG_(baseBlock)[VGOFF_(m_edx)]; + arch->m_esi = VG_(baseBlock)[VGOFF_(m_esi)]; + arch->m_edi = VG_(baseBlock)[VGOFF_(m_edi)]; + arch->m_ebp = VG_(baseBlock)[VGOFF_(m_ebp)]; + arch->m_esp = VG_(baseBlock)[VGOFF_(m_esp)]; + arch->m_eflags + = insertDflag(VG_(baseBlock)[VGOFF_(m_eflags)], + VG_(baseBlock)[VGOFF_(m_dflag)]); + arch->m_eip = VG_(baseBlock)[VGOFF_(m_eip)]; + + for (i = 0; i < VG_SIZE_OF_SSESTATE_W; i++) + arch->m_sse[i] + = VG_(baseBlock)[VGOFF_(m_ssestate) + i]; + + if (VG_(needs).shadow_regs) { + arch->sh_eax = VG_(baseBlock)[VGOFF_(sh_eax)]; + arch->sh_ebx = VG_(baseBlock)[VGOFF_(sh_ebx)]; + arch->sh_ecx = VG_(baseBlock)[VGOFF_(sh_ecx)]; + arch->sh_edx = VG_(baseBlock)[VGOFF_(sh_edx)]; + arch->sh_esi = VG_(baseBlock)[VGOFF_(sh_esi)]; + arch->sh_edi = VG_(baseBlock)[VGOFF_(sh_edi)]; + arch->sh_ebp = VG_(baseBlock)[VGOFF_(sh_ebp)]; + arch->sh_esp = VG_(baseBlock)[VGOFF_(sh_esp)]; + arch->sh_eflags = VG_(baseBlock)[VGOFF_(sh_eflags)]; + } else { + /* Fill with recognisable junk */ + arch->sh_eax = + arch->sh_ebx = + arch->sh_ecx = + arch->sh_edx = + arch->sh_esi = + arch->sh_edi = + arch->sh_ebp = + arch->sh_esp = + arch->sh_eflags = VG_UNUSED_SHADOW_REG_VALUE; + } + /* Fill it up with junk. */ + VG_(baseBlock)[VGOFF_(ldt)] = junk; + VG_(baseBlock)[VGOFF_(tls_ptr)] = junk; + VG_(baseBlock)[VGOFF_(m_cs)] = junk; + VG_(baseBlock)[VGOFF_(m_ss)] = junk; + VG_(baseBlock)[VGOFF_(m_ds)] = junk; + VG_(baseBlock)[VGOFF_(m_es)] = junk; + VG_(baseBlock)[VGOFF_(m_fs)] = junk; + VG_(baseBlock)[VGOFF_(m_gs)] = junk; + + VG_(baseBlock)[VGOFF_(m_eax)] = junk; + VG_(baseBlock)[VGOFF_(m_ebx)] = junk; + VG_(baseBlock)[VGOFF_(m_ecx)] = junk; + VG_(baseBlock)[VGOFF_(m_edx)] = junk; + VG_(baseBlock)[VGOFF_(m_esi)] = junk; + VG_(baseBlock)[VGOFF_(m_edi)] = junk; + VG_(baseBlock)[VGOFF_(m_ebp)] = junk; + VG_(baseBlock)[VGOFF_(m_esp)] = junk; + VG_(baseBlock)[VGOFF_(m_eflags)] = junk; + VG_(baseBlock)[VGOFF_(m_eip)] = junk; + + for (i = 0; i < VG_SIZE_OF_SSESTATE_W; i++) + VG_(baseBlock)[VGOFF_(m_ssestate) + i] = junk; +} + +/*--------------------------------------------------------------------*/ +/*--- end ---*/ +/*--------------------------------------------------------------------*/ diff --git a/include/Makefile.am b/include/Makefile.am index 3861cf5e34..6680b586a2 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -1,3 +1,6 @@ + +SUBDIRS = $(VG_ARCH) . + EXTRA_DIST = \ vg_profile.c \ tool.h.base diff --git a/include/tool.h.base b/include/tool.h.base index 5b69c7a052..36f86b0d06 100644 --- a/include/tool.h.base +++ b/include/tool.h.base @@ -35,9 +35,7 @@ #include /* for jmp_buf */ #include "tool_asm.h" // asm stuff - -// XXX: here temporarily, will eventually go in arch-specific headers... -#define REGPARM(x) __attribute__((regparm (x))) +#include "tool_arch.h" // arch-specific tool stuff /* --------------------------------------------------------------------- Where to send bug reports to. diff --git a/include/tool_asm.h b/include/tool_asm.h index 9480ff579f..9e0ea2acb9 100644 --- a/include/tool_asm.h +++ b/include/tool_asm.h @@ -43,6 +43,7 @@ #define VG_(str) VGAPPEND(vgPlain_,str) #define VGP_(str) VGAPPEND(vgProf_,str) #define VGOFF_(str) VGAPPEND(vgOff_,str) +#define VGA_(str) VGAPPEND(vgArch_,str) /* Tool-specific ones. Note that final name still starts with "vg". */ #define SK_(str) VGAPPEND(vgSkin_,str) diff --git a/include/x86/.cvsignore b/include/x86/.cvsignore new file mode 100644 index 0000000000..282522db03 --- /dev/null +++ b/include/x86/.cvsignore @@ -0,0 +1,2 @@ +Makefile +Makefile.in diff --git a/include/x86/Makefile.am b/include/x86/Makefile.am new file mode 100644 index 0000000000..7d61728860 --- /dev/null +++ b/include/x86/Makefile.am @@ -0,0 +1,4 @@ +incincdir = $(includedir)/valgrind/x86 + +incinc_HEADERS = tool_arch.h + diff --git a/include/x86/tool_arch.h b/include/x86/tool_arch.h new file mode 100644 index 0000000000..2e10c75c3b --- /dev/null +++ b/include/x86/tool_arch.h @@ -0,0 +1,44 @@ +/*--------------------------------------------------------------------*/ +/*--- x86/tool_arch.h ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, an extensible x86 protected-mode + emulator for monitoring program execution on x86-Unixes. + + Copyright (C) 2000-2004 Nicholas Nethercote + njn25@cam.ac.uk + + 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. +*/ + +#ifndef __X86_TOOL_ARCH_H +#define __X86_TOOL_ARCH_H + +#define REGPARM(n) __attribute__((regparm(n))) + +#define FIRST_ARCH_REG R_EAX +#define LAST_ARCH_REG R_EDI + +#define N_ARCH_REGS 8 + +#endif // __X86_TOOL_ARCH_H + +/*--------------------------------------------------------------------*/ +/*--- end ---*/ +/*--------------------------------------------------------------------*/ diff --git a/memcheck/mc_main.c b/memcheck/mc_main.c index bfad60b8ad..a8369cfadf 100644 --- a/memcheck/mc_main.c +++ b/memcheck/mc_main.c @@ -722,7 +722,7 @@ void mc_set_perms (Addr a, UInt len, Bool rr, Bool ww, Bool xx) static void mc_post_regs_write_init ( void ) { UInt i; - for (i = R_EAX; i <= R_EDI; i++) + for (i = FIRST_ARCH_REG; i <= LAST_ARCH_REG; i++) VG_(set_shadow_archreg)( i, VGM_WORD_VALID ); VG_(set_shadow_eflags)( VGM_EFLAGS_VALID ); } diff --git a/valgrind.spec.in b/valgrind.spec.in index c16a2db13b..92f9c841d2 100644 --- a/valgrind.spec.in +++ b/valgrind.spec.in @@ -40,6 +40,7 @@ make install DESTDIR=$RPM_BUILD_ROOT /usr/include/valgrind/tool_asm.h /usr/include/valgrind/vg_kerneliface.h /usr/include/valgrind/vg_skin.h +/usr/include/valgrind/x86/tool_arch.h /usr/bin/valgrind /usr/bin/cg_annotate /usr/lib/valgrind