- 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
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)
## 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 \
tests/vg_regtest
tests/unused/Makefile
include/Makefile
+ include/x86/Makefile
auxprogs/Makefile
coregrind/Makefile
coregrind/demangle/Makefile
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
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
#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"
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
------------------------------------------------------------------ */
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) */
/* 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;
/* 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)
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 );
/* ---------------------------------------------------------------------
#include "config.h"
+#endif /* ndef __CORE_H */
+
/*--------------------------------------------------------------------*/
/*--- end ---*/
/*--------------------------------------------------------------------*/
#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. */
#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
vgSkin_*;
vgProf_*;
vgOff_*;
+ vgArch_*;
local:
*; # default to hidden
} 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;
}
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;
}
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");
}
}
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");
}
}
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");
}
}
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 */
"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;
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 ... */
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;
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)",
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 ) |
} 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 &&
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 */
}
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
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));
*/
reply.u.syscallno = tst->syscallno;
- tst->m_eax = -VKI_ERESTARTSYS;
+ tst->arch.m_eax = -VKI_ERESTARTSYS;
px->state = PXS_IntReply;
break;
*/
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))
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",
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));
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;
}
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)
);
}
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;
*/
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;
}
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;
/* 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
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;
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?
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);
# 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
/* 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");
}
}
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? */
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]);
__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
"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 :) */
}
/* 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 */
}
# 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]);
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);
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;
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;
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 );
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)
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
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,
}
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;
}
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,
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);
&& /* 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;
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 );
(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) );
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;
/* 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
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 */);
/* 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
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;
}
}
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)) {
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));
}
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);
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);
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;
}
#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)
{
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.
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);
}
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;
# 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++) {
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;
}
}
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--) {
}
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 {
+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 \
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 \
--- /dev/null
+
+/*--------------------------------------------------------------------*/
+/*--- 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 ---*/
+/*--------------------------------------------------------------------*/
--- /dev/null
+/*--------------------------------------------------------------------*/
+/*--- 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 ---*/
+/*--------------------------------------------------------------------*/
--- /dev/null
+
+/*--------------------------------------------------------------------*/
+/*--- 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 ---*/
+/*--------------------------------------------------------------------*/
+
+SUBDIRS = $(VG_ARCH) .
+
EXTRA_DIST = \
vg_profile.c \
tool.h.base
#include <setjmp.h> /* 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.
#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)
--- /dev/null
+Makefile
+Makefile.in
--- /dev/null
+incincdir = $(includedir)/valgrind/x86
+
+incinc_HEADERS = tool_arch.h
+
--- /dev/null
+/*--------------------------------------------------------------------*/
+/*--- 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 ---*/
+/*--------------------------------------------------------------------*/
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 );
}
/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