Finally, valgrind on ppc32.
Plenty still to do, but simple programs like ls seem to run ok
Thanks, Paul, for having your ppc port of valgrind 2.4 to work from!
git-svn-id: svn://svn.valgrind.org/valgrind/trunk@3969 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/NOTES.txt b/NOTES.txt
index 4a26f23..f4f7f73 100644
--- a/NOTES.txt
+++ b/NOTES.txt
@@ -1,3 +1,10 @@
+20 Jun 05
+~~~~~~~~~
+PPC32 port
+* Paul wrote some code to deal with setting/clearing reservations.
+ (grep USE_MACHINE_RESERVATION, ARCH_SWITCH_TO, lwarx, stwcx.)
+ Not yet looked into, but this may be needed.
+
11 May 05
~~~~~~~~~
ToDo: vex-amd64: check above/below the line for reg-alloc
diff --git a/cachegrind/cg-ppc32.c b/cachegrind/cg-ppc32.c
new file mode 100644
index 0000000..42800ff
--- /dev/null
+++ b/cachegrind/cg-ppc32.c
@@ -0,0 +1,332 @@
+
+/*--------------------------------------------------------------------*/
+/*--- PPC32-specific definitions. ppc32/cg-ppc32.c ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+ This file is part of Cachegrind, a Valgrind tool for cache
+ profiling programs.
+
+ Copyright (C) 2005 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 "pub_tool_basics.h"
+#include "pub_tool_libcbase.h"
+#include "pub_tool_libcassert.h"
+#include "pub_tool_libcprint.h"
+
+#include "cg_arch.h"
+
+// All CPUID info taken from sandpile.org/a32/cpuid.htm */
+// Probably only works for Intel and AMD chips, and probably only for some of
+// them.
+
+//.. static void micro_ops_warn(Int actual_size, Int used_size, Int line_size)
+//.. {
+//.. VG_(message)(Vg_DebugMsg,
+//.. "warning: Pentium with %d K micro-op instruction trace cache",
+//.. actual_size);
+//.. VG_(message)(Vg_DebugMsg,
+//.. " Simulating a %d KB cache with %d B lines",
+//.. used_size, line_size);
+//.. }
+
+/* Intel method is truly wretched. We have to do an insane indexing into an
+ * array of pre-defined configurations for various parts of the memory
+ * hierarchy.
+ */
+//.. static
+//.. Int Intel_cache_info(Int level, cache_t* I1c, cache_t* D1c, cache_t* L2c)
+//.. {
+//.. UChar info[16];
+//.. Int i, trials;
+//.. Bool L2_found = False;
+//..
+//.. if (level < 2) {
+//.. VG_(message)(Vg_DebugMsg,
+//.. "warning: CPUID level < 2 for Intel processor (%d)",
+//.. level);
+//.. return -1;
+//.. }
+//..
+//.. VG_(cpuid)(2, (Int*)&info[0], (Int*)&info[4],
+//.. (Int*)&info[8], (Int*)&info[12]);
+//.. trials = info[0] - 1; /* AL register - bits 0..7 of %eax */
+//.. info[0] = 0x0; /* reset AL */
+//..
+//.. if (0 != trials) {
+//.. VG_(message)(Vg_DebugMsg,
+//.. "warning: non-zero CPUID trials for Intel processor (%d)",
+//.. trials);
+//.. return -1;
+//.. }
+//..
+//.. for (i = 0; i < 16; i++) {
+//..
+//.. switch (info[i]) {
+//..
+//.. case 0x0: /* ignore zeros */
+//.. break;
+//..
+//.. /* TLB info, ignore */
+//.. case 0x01: case 0x02: case 0x03: case 0x04:
+//.. case 0x50: case 0x51: case 0x52: case 0x5b: case 0x5c: case 0x5d:
+//.. case 0xb0: case 0xb3:
+//.. break;
+//..
+//.. case 0x06: *I1c = (cache_t) { 8, 4, 32 }; break;
+//.. case 0x08: *I1c = (cache_t) { 16, 4, 32 }; break;
+//.. case 0x30: *I1c = (cache_t) { 32, 8, 64 }; break;
+//..
+//.. case 0x0a: *D1c = (cache_t) { 8, 2, 32 }; break;
+//.. case 0x0c: *D1c = (cache_t) { 16, 4, 32 }; break;
+//.. case 0x2c: *D1c = (cache_t) { 32, 8, 64 }; break;
+//..
+//.. /* IA-64 info -- panic! */
+//.. case 0x10: case 0x15: case 0x1a:
+//.. case 0x88: case 0x89: case 0x8a: case 0x8d:
+//.. case 0x90: case 0x96: case 0x9b:
+//.. VG_(tool_panic)("IA-64 cache detected?!");
+//..
+//.. case 0x22: case 0x23: case 0x25: case 0x29:
+//.. VG_(message)(Vg_DebugMsg,
+//.. "warning: L3 cache detected but ignored\n");
+//.. break;
+//..
+//.. /* These are sectored, whatever that means */
+//.. case 0x39: *L2c = (cache_t) { 128, 4, 64 }; L2_found = True; break;
+//.. case 0x3c: *L2c = (cache_t) { 256, 4, 64 }; L2_found = True; break;
+//..
+//.. /* If a P6 core, this means "no L2 cache".
+//.. If a P4 core, this means "no L3 cache".
+//.. We don't know what core it is, so don't issue a warning. To detect
+//.. a missing L2 cache, we use 'L2_found'. */
+//.. case 0x40:
+//.. break;
+//..
+//.. case 0x41: *L2c = (cache_t) { 128, 4, 32 }; L2_found = True; break;
+//.. case 0x42: *L2c = (cache_t) { 256, 4, 32 }; L2_found = True; break;
+//.. case 0x43: *L2c = (cache_t) { 512, 4, 32 }; L2_found = True; break;
+//.. case 0x44: *L2c = (cache_t) { 1024, 4, 32 }; L2_found = True; break;
+//.. case 0x45: *L2c = (cache_t) { 2048, 4, 32 }; L2_found = True; break;
+//..
+//.. /* These are sectored, whatever that means */
+//.. case 0x60: *D1c = (cache_t) { 16, 8, 64 }; break; /* sectored */
+//.. case 0x66: *D1c = (cache_t) { 8, 4, 64 }; break; /* sectored */
+//.. case 0x67: *D1c = (cache_t) { 16, 4, 64 }; break; /* sectored */
+//.. case 0x68: *D1c = (cache_t) { 32, 4, 64 }; break; /* sectored */
+//..
+//.. /* HACK ALERT: Instruction trace cache -- capacity is micro-ops based.
+//.. * conversion to byte size is a total guess; treat the 12K and 16K
+//.. * cases the same since the cache byte size must be a power of two for
+//.. * everything to work!. Also guessing 32 bytes for the line size...
+//.. */
+//.. case 0x70: /* 12K micro-ops, 8-way */
+//.. *I1c = (cache_t) { 16, 8, 32 };
+//.. micro_ops_warn(12, 16, 32);
+//.. break;
+//.. case 0x71: /* 16K micro-ops, 8-way */
+//.. *I1c = (cache_t) { 16, 8, 32 };
+//.. micro_ops_warn(16, 16, 32);
+//.. break;
+//.. case 0x72: /* 32K micro-ops, 8-way */
+//.. *I1c = (cache_t) { 32, 8, 32 };
+//.. micro_ops_warn(32, 32, 32);
+//.. break;
+//..
+//.. /* These are sectored, whatever that means */
+//.. case 0x79: *L2c = (cache_t) { 128, 8, 64 }; L2_found = True; break;
+//.. case 0x7a: *L2c = (cache_t) { 256, 8, 64 }; L2_found = True; break;
+//.. case 0x7b: *L2c = (cache_t) { 512, 8, 64 }; L2_found = True; break;
+//.. case 0x7c: *L2c = (cache_t) { 1024, 8, 64 }; L2_found = True; break;
+//.. case 0x7e: *L2c = (cache_t) { 256, 8, 128 }; L2_found = True; break;
+//..
+//.. case 0x81: *L2c = (cache_t) { 128, 8, 32 }; L2_found = True; break;
+//.. case 0x82: *L2c = (cache_t) { 256, 8, 32 }; L2_found = True; break;
+//.. case 0x83: *L2c = (cache_t) { 512, 8, 32 }; L2_found = True; break;
+//.. case 0x84: *L2c = (cache_t) { 1024, 8, 32 }; L2_found = True; break;
+//.. case 0x85: *L2c = (cache_t) { 2048, 8, 32 }; L2_found = True; break;
+//.. case 0x86: *L2c = (cache_t) { 512, 4, 64 }; L2_found = True; break;
+//.. case 0x87: *L2c = (cache_t) { 1024, 8, 64 }; L2_found = True; break;
+//..
+//.. default:
+//.. VG_(message)(Vg_DebugMsg,
+//.. "warning: Unknown Intel cache config value "
+//.. "(0x%x), ignoring", info[i]);
+//.. break;
+//.. }
+//.. }
+//..
+//.. if (!L2_found)
+//.. VG_(message)(Vg_DebugMsg,
+//.. "warning: L2 cache not installed, ignore L2 results.");
+//..
+//.. return 0;
+//.. }
+
+/* AMD method is straightforward, just extract appropriate bits from the
+ * result registers.
+ *
+ * Bits, for D1 and I1:
+ * 31..24 data L1 cache size in KBs
+ * 23..16 data L1 cache associativity (FFh=full)
+ * 15.. 8 data L1 cache lines per tag
+ * 7.. 0 data L1 cache line size in bytes
+ *
+ * Bits, for L2:
+ * 31..16 unified L2 cache size in KBs
+ * 15..12 unified L2 cache associativity (0=off, FFh=full)
+ * 11.. 8 unified L2 cache lines per tag
+ * 7.. 0 unified L2 cache line size in bytes
+ *
+ * #3 The AMD K7 processor's L2 cache must be configured prior to relying
+ * upon this information. (Whatever that means -- njn)
+ *
+ * Also, according to Cyrille Chepelov, Duron stepping A0 processors (model
+ * 0x630) have a bug and misreport their L2 size as 1KB (it's really 64KB),
+ * so we detect that.
+ *
+ * Returns 0 on success, non-zero on failure.
+ */
+//.. static
+//.. Int AMD_cache_info(cache_t* I1c, cache_t* D1c, cache_t* L2c)
+//.. {
+//.. UInt ext_level;
+//.. UInt dummy, model;
+//.. UInt I1i, D1i, L2i;
+//..
+//.. VG_(cpuid)(0x80000000, &ext_level, &dummy, &dummy, &dummy);
+//..
+//.. if (0 == (ext_level & 0x80000000) || ext_level < 0x80000006) {
+//.. VG_(message)(Vg_UserMsg,
+//.. "warning: ext_level < 0x80000006 for AMD processor (0x%x)",
+//.. ext_level);
+//.. return -1;
+//.. }
+//..
+//.. VG_(cpuid)(0x80000005, &dummy, &dummy, &D1i, &I1i);
+//.. VG_(cpuid)(0x80000006, &dummy, &dummy, &L2i, &dummy);
+//..
+//.. VG_(cpuid)(0x1, &model, &dummy, &dummy, &dummy);
+//..
+//.. /* Check for Duron bug */
+//.. if (model == 0x630) {
+//.. VG_(message)(Vg_UserMsg,
+//.. "Buggy Duron stepping A0. Assuming L2 size=65536 bytes");
+//.. L2i = (64 << 16) | (L2i & 0xffff);
+//.. }
+//..
+//.. D1c->size = (D1i >> 24) & 0xff;
+//.. D1c->assoc = (D1i >> 16) & 0xff;
+//.. D1c->line_size = (D1i >> 0) & 0xff;
+//..
+//.. I1c->size = (I1i >> 24) & 0xff;
+//.. I1c->assoc = (I1i >> 16) & 0xff;
+//.. I1c->line_size = (I1i >> 0) & 0xff;
+//..
+//.. L2c->size = (L2i >> 16) & 0xffff; /* Nb: different bits used for L2 */
+//.. L2c->assoc = (L2i >> 12) & 0xf;
+//.. L2c->line_size = (L2i >> 0) & 0xff;
+//..
+//.. return 0;
+//.. }
+
+//.. static
+//.. Int get_caches_from_CPUID(cache_t* I1c, cache_t* D1c, cache_t* L2c)
+//.. {
+//.. Int level, ret;
+//.. Char vendor_id[13];
+//..
+//.. if (!VG_(has_cpuid)()) {
+//.. VG_(message)(Vg_DebugMsg, "CPUID instruction not supported");
+//.. return -1;
+//.. }
+//..
+//.. VG_(cpuid)(0, &level, (int*)&vendor_id[0],
+//.. (int*)&vendor_id[8], (int*)&vendor_id[4]);
+//.. vendor_id[12] = '\0';
+//..
+//.. if (0 == level) {
+//.. VG_(message)(Vg_DebugMsg, "CPUID level is 0, early Pentium?\n");
+//.. return -1;
+//.. }
+//..
+//.. /* Only handling Intel and AMD chips... no Cyrix, Transmeta, etc */
+//.. if (0 == VG_(strcmp)(vendor_id, "GenuineIntel")) {
+//.. ret = Intel_cache_info(level, I1c, D1c, L2c);
+//..
+//.. } else if (0 == VG_(strcmp)(vendor_id, "AuthenticAMD")) {
+//.. ret = AMD_cache_info(I1c, D1c, L2c);
+//..
+//.. } else if (0 == VG_(strcmp)(vendor_id, "CentaurHauls")) {
+//.. /* Total kludge. Pretend to be a VIA Nehemiah. */
+//.. D1c->size = 64;
+//.. D1c->assoc = 16;
+//.. D1c->line_size = 16;
+//.. I1c->size = 64;
+//.. I1c->assoc = 4;
+//.. I1c->line_size = 16;
+//.. L2c->size = 64;
+//.. L2c->assoc = 16;
+//.. L2c->line_size = 16;
+//.. ret = 0;
+//..
+//.. } else {
+//.. VG_(message)(Vg_DebugMsg, "CPU vendor ID not recognised (%s)",
+//.. vendor_id);
+//.. return -1;
+//.. }
+//..
+//.. /* Successful! Convert sizes from KB to bytes */
+//.. I1c->size *= 1024;
+//.. D1c->size *= 1024;
+//.. L2c->size *= 1024;
+//..
+//.. return ret;
+//.. }
+
+
+void VGA_(configure_caches)(cache_t* I1c, cache_t* D1c, cache_t* L2c,
+ Bool all_caches_clo_defined)
+{
+ tl_assert(0);
+
+//.. Int res;
+//..
+//.. // Set caches to default.
+//.. *I1c = (cache_t) { 65536, 2, 64 };
+//.. *D1c = (cache_t) { 65536, 2, 64 };
+//.. *L2c = (cache_t) { 262144, 8, 64 };
+//..
+//.. // Then replace with any info we can get from CPUID.
+//.. res = get_caches_from_CPUID(I1c, D1c, L2c);
+//..
+//.. // Warn if CPUID failed and config not completely specified from cmd line.
+//.. if (res != 0 && !all_caches_clo_defined) {
+//.. VG_(message)(Vg_DebugMsg,
+//.. "Warning: Couldn't auto-detect cache config, using one "
+//.. "or more defaults ");
+//.. }
+}
+
+/*--------------------------------------------------------------------*/
+/*--- end ---*/
+/*--------------------------------------------------------------------*/
diff --git a/cachegrind/tests/ppc32/Makefile.am b/cachegrind/tests/ppc32/Makefile.am
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/cachegrind/tests/ppc32/Makefile.am
diff --git a/configure.in b/configure.in
index 99c59a1..ad41cb8 100644
--- a/configure.in
+++ b/configure.in
@@ -93,7 +93,7 @@
AC_MSG_CHECKING([for a supported CPU])
AC_SUBST(VG_ARCH)
AC_SUBST(VG_ARCH_ALL)
-VG_ARCH_ALL="amd64 arm x86"
+VG_ARCH_ALL="amd64 arm ppc32 x86"
AC_SUBST(KICKSTART_BASE)
AC_SUBST(ARCH_CORE_AM_CFLAGS)
AC_SUBST(ARCH_TOOL_AM_CFLAGS)
@@ -137,13 +137,12 @@
;;
powerpc*)
- AC_MSG_RESULT([no (${host_cpu})])
- VG_ARCH="ppc"
- KICKSTART_BASE="0x70000000"
+ AC_MSG_RESULT([ok (${host_cpu})])
+ VG_ARCH="ppc32"
+ KICKSTART_BASE="0x10000000"
ARCH_CORE_AM_CFLAGS=""
ARCH_TOOL_AM_CFLAGS="-fpic"
ARCH_CORE_AM_CCASFLAGS="-Wa,-maltivec"
- AC_MSG_ERROR([PowerPC not supported. Sorry])
;;
*)
@@ -200,12 +199,12 @@
AC_MSG_CHECKING([for a supported CPU/OS combination])
AC_SUBST(VG_PLATFORM)
AC_SUBST(VG_PLATFORM_ALL)
-VG_PLATFORM_ALL="amd64-linux arm-linux x86-linux"
+VG_PLATFORM_ALL="amd64-linux arm-linux ppc32-linux x86-linux"
VG_PLATFORM="$VG_ARCH-$VG_OS"
case $VG_PLATFORM in
- x86-linux|amd64-linux|arm-linux)
+ x86-linux|amd64-linux|arm-linux|ppc32-linux)
AC_MSG_RESULT([ok (${host_cpu}-${host_os})])
;;
@@ -437,12 +436,14 @@
memcheck/tests/Makefile
memcheck/tests/amd64/Makefile
memcheck/tests/arm/Makefile
+ memcheck/tests/ppc32/Makefile
memcheck/tests/x86/Makefile
memcheck/docs/Makefile
cachegrind/Makefile
cachegrind/tests/Makefile
cachegrind/tests/amd64/Makefile
cachegrind/tests/arm/Makefile
+ cachegrind/tests/ppc32/Makefile
cachegrind/tests/x86/Makefile
cachegrind/docs/Makefile
cachegrind/cg_annotate
@@ -463,6 +464,7 @@
none/tests/Makefile
none/tests/amd64/Makefile
none/tests/arm/Makefile
+ none/tests/ppc32/Makefile
none/tests/x86/Makefile
none/docs/Makefile
)
diff --git a/coregrind/Makefile.am b/coregrind/Makefile.am
index 706c789..003d156 100644
--- a/coregrind/Makefile.am
+++ b/coregrind/Makefile.am
@@ -76,6 +76,7 @@
vki_unistd.h \
vki_unistd-amd64-linux.h\
vki_unistd-arm-linux.h \
+ vki_unistd-ppc32-linux.h\
vki_unistd-x86-linux.h
EXTRA_DIST = \
diff --git a/coregrind/m_aspacemgr/aspacemgr.c b/coregrind/m_aspacemgr/aspacemgr.c
index 3a88b95..a87827a 100644
--- a/coregrind/m_aspacemgr/aspacemgr.c
+++ b/coregrind/m_aspacemgr/aspacemgr.c
@@ -1540,6 +1540,10 @@
if (0)
VG_(message)(Vg_DebugMsg, "ignoring --pointercheck (unimplemented)");
return True;
+#elif defined(VGP_ppc32_linux)
+ if (0)
+ VG_(message)(Vg_DebugMsg, "ignoring --pointercheck (unimplemented)");
+ return True;
#else
# error Unknown architecture
#endif
diff --git a/coregrind/m_cpuid.S b/coregrind/m_cpuid.S
index fd40a77..9c4bf2d 100644
--- a/coregrind/m_cpuid.S
+++ b/coregrind/m_cpuid.S
@@ -60,6 +60,8 @@
VG_(has_cpuid):
movq $1, %rax
ret
+#elif defined(VGA_appc32)
+//CAB: TODO
#endif
/*
@@ -141,6 +143,8 @@
movq %rbp, %rsp
popq %rbp
ret
+#elif defined(VGA_appc32)
+//CAB: TODO
#endif
/* Let the linker know we don't need an executable stack */
diff --git a/coregrind/m_debugger.c b/coregrind/m_debugger.c
index 7cb883d..9a4a7a5 100644
--- a/coregrind/m_debugger.c
+++ b/coregrind/m_debugger.c
@@ -68,6 +68,9 @@
return ptrace(PTRACE_SETREGS, pid, NULL, ®s);
#elif defined(VGA_amd64)
I_die_here;
+#elif defined(VGA_ppc32)
+ I_die_here;
+ regs.gpr[0] = 0; // stop compiler complaints
#else
# error Unknown arch
#endif
diff --git a/coregrind/m_debuginfo/dwarf.c b/coregrind/m_debuginfo/dwarf.c
index 7721001..46203a2 100644
--- a/coregrind/m_debuginfo/dwarf.c
+++ b/coregrind/m_debuginfo/dwarf.c
@@ -1305,6 +1305,10 @@
# define FP_REG 6
# define SP_REG 7
# define RA_REG_DEFAULT 16
+#elif defined(VGP_ppc32_linux)
+# define FP_REG 1
+# define SP_REG 1
+# define RA_REG_DEFAULT 8 // CAB: What's a good default ?
#else
# error Unknown platform
#endif
@@ -2189,6 +2193,11 @@
Int n_CIEs = 0;
UChar* data = ehframe;
+#if defined(VGP_ppc32_linux)
+ // CAB: tmp hack for ppc - no stacktraces for now...
+ return;
+#endif
+
if (VG_(clo_trace_cfi)) {
VG_(printf)("\n-----------------------------------------------\n");
VG_(printf)("CFI info: ehframe %p, ehframe_sz %d\n",
diff --git a/coregrind/m_debuginfo/symtab.c b/coregrind/m_debuginfo/symtab.c
index a55e289..3b5b67b 100644
--- a/coregrind/m_debuginfo/symtab.c
+++ b/coregrind/m_debuginfo/symtab.c
@@ -2177,6 +2177,45 @@
case 15: return (Addr) & arch->vex.guest_R15;
default: return 0;
}
+#elif defined(VGA_ppc32)
+ /* This is the Intel register encoding -- integer regs. */
+# define R_STACK_PTR 1
+# define R_FRAME_PTR 1
+ switch (regno) {
+ case 0: return (Addr) & arch->vex.guest_GPR0;
+ case R_STACK_PTR: return (Addr) & arch->vex.guest_GPR1;
+ case 2: return (Addr) & arch->vex.guest_GPR2;
+ case 3: return (Addr) & arch->vex.guest_GPR3;
+ case 4: return (Addr) & arch->vex.guest_GPR4;
+ case 5: return (Addr) & arch->vex.guest_GPR5;
+ case 6: return (Addr) & arch->vex.guest_GPR6;
+ case 7: return (Addr) & arch->vex.guest_GPR7;
+ case 8: return (Addr) & arch->vex.guest_GPR8;
+ case 9: return (Addr) & arch->vex.guest_GPR9;
+ case 10: return (Addr) & arch->vex.guest_GPR10;
+ case 11: return (Addr) & arch->vex.guest_GPR11;
+ case 12: return (Addr) & arch->vex.guest_GPR12;
+ case 13: return (Addr) & arch->vex.guest_GPR13;
+ case 14: return (Addr) & arch->vex.guest_GPR14;
+ case 15: return (Addr) & arch->vex.guest_GPR15;
+ case 16: return (Addr) & arch->vex.guest_GPR16;
+ case 17: return (Addr) & arch->vex.guest_GPR17;
+ case 18: return (Addr) & arch->vex.guest_GPR18;
+ case 19: return (Addr) & arch->vex.guest_GPR19;
+ case 20: return (Addr) & arch->vex.guest_GPR20;
+ case 21: return (Addr) & arch->vex.guest_GPR21;
+ case 22: return (Addr) & arch->vex.guest_GPR22;
+ case 23: return (Addr) & arch->vex.guest_GPR23;
+ case 24: return (Addr) & arch->vex.guest_GPR24;
+ case 25: return (Addr) & arch->vex.guest_GPR25;
+ case 26: return (Addr) & arch->vex.guest_GPR26;
+ case 27: return (Addr) & arch->vex.guest_GPR27;
+ case 28: return (Addr) & arch->vex.guest_GPR28;
+ case 29: return (Addr) & arch->vex.guest_GPR29;
+ case 30: return (Addr) & arch->vex.guest_GPR30;
+ case 31: return (Addr) & arch->vex.guest_GPR31;
+ default: return 0;
+ }
#else
# error Unknown platform
#endif
diff --git a/coregrind/m_debuglog.c b/coregrind/m_debuglog.c
index 8cd0136..a578280 100644
--- a/coregrind/m_debuglog.c
+++ b/coregrind/m_debuglog.c
@@ -125,6 +125,39 @@
return __res;
}
+#elif defined(VGP_ppc32_linux)
+
+static UInt local_sys_write_stderr ( HChar* buf, Int n )
+{
+ UInt __res;
+ __asm__ volatile (
+ "li %%r0,4\n\t" /* set %r0 = __NR_write */
+ "li %%r3,2\n\t" /* set %r3 = stderr */
+ "mr %%r4,%1\n\t" /* set %r4 = buf */
+ "mr %%r5,%2\n\t" /* set %r5 = n */
+ "sc\n\t" /* write(stderr, buf, n) */
+ "mr %0,%%r3\n" /* set __res = r3 */
+ : "=mr" (__res)
+ : "g" (buf), "g" (n)
+ : "r0", "r3", "r4", "r5" );
+ if (__res < 0)
+ __res = -1;
+ return __res;
+}
+
+static UInt local_sys_getpid ( void )
+{
+ UInt __res;
+ __asm__ volatile (
+ "li %%r0,20\n" /* set %r0 = __NR_getpid */
+ "\tsc\n" /* getpid() */
+ "\tmr %0,%%r3\n" /* set __res = r3 */
+ : "=mr" (__res)
+ :
+ : "r0" );
+ return __res;
+}
+
#else
# error Unknown platform
#endif
diff --git a/coregrind/m_dispatch/dispatch-amd64.S b/coregrind/m_dispatch/dispatch-amd64.S
index 9c178d9..64e8573 100644
--- a/coregrind/m_dispatch/dispatch-amd64.S
+++ b/coregrind/m_dispatch/dispatch-amd64.S
@@ -1,7 +1,7 @@
##--------------------------------------------------------------------##
##--- The core dispatch loop, for jumping to a code address. ---##
-##--- amd64/dispatch.S ---##
+##--- dispatch-amd64.S ---##
##--------------------------------------------------------------------##
/*
diff --git a/coregrind/m_dispatch/dispatch-arm.S b/coregrind/m_dispatch/dispatch-arm.S
index a7cf36f..7f7c9bc 100644
--- a/coregrind/m_dispatch/dispatch-arm.S
+++ b/coregrind/m_dispatch/dispatch-arm.S
@@ -1,7 +1,7 @@
##--------------------------------------------------------------------##
##--- The core dispatch loop, for jumping to a code address. ---##
-##--- arm/dispatch.S ---##
+##--- dispatch-arm.S ---##
##--------------------------------------------------------------------##
/*
diff --git a/coregrind/m_dispatch/dispatch-ppc32.S b/coregrind/m_dispatch/dispatch-ppc32.S
new file mode 100644
index 0000000..d0035c2
--- /dev/null
+++ b/coregrind/m_dispatch/dispatch-ppc32.S
@@ -0,0 +1,264 @@
+
+##--------------------------------------------------------------------##
+##--- The core dispatch loop, for jumping to a code address. ---##
+##--- dispatch-ppc32.S ---##
+##--------------------------------------------------------------------##
+
+/*
+ This file is part of Valgrind, a dynamic binary instrumentation
+ framework.
+
+ Copyright (C) 2005 Cerion Armour-Brown <cerion@open-works.co.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 "pub_tool_basics_asm.h"
+#include "pub_core_dispatch_asm.h"
+#include "pub_core_transtab_asm.h"
+#include "libvex_guest_offsets.h" /* for OFFSET_ppc32_CIA */
+
+
+/*------------------------------------------------------------*/
+/*--- The dispatch loop. ---*/
+/*------------------------------------------------------------*/
+
+/* signature: UWord VG_(run_innerloop) ( void* guest_state ) */
+
+ .globl VG_(run_innerloop)
+VG_(run_innerloop):
+ /* ----- entry point to VG_(run_innerloop) ----- */
+
+ /* Save lr, sp */
+ mflr 0
+ stw 0,4(1)
+
+ /* New stack frame: save callee-saved regs */
+ stwu 1,-88(1)
+ stw 31,84(1)
+ stw 30,80(1)
+ stw 29,76(1)
+ stw 28,72(1)
+ stw 27,68(1)
+ stw 26,64(1)
+ stw 25,60(1)
+ stw 24,56(1)
+ stw 23,52(1)
+ stw 22,48(1)
+ stw 21,44(1)
+ stw 20,40(1)
+ stw 19,36(1)
+ stw 18,32(1)
+ stw 17,28(1)
+ stw 16,24(1)
+ stw 15,20(1)
+ stw 14,16(1)
+
+ /* r3 holds guest_state */
+ mr 31,3
+ stw 3,12(1) /* spill orig guest_state ptr */
+
+// CAB TODO: Use a caller-saved reg for orig guest_state ptr
+// - rem to set non-allocateable in isel.c
+
+ /* hold dispach_ctr in ctr reg */
+ lis 17,VG_(dispatch_ctr)@ha
+ lwz 17,VG_(dispatch_ctr)@l(17)
+ mtctr 17
+
+ /* fetch %CIA into r30 */
+ lwz 30,OFFSET_ppc32_CIA(31)
+
+ /* make a stack frame for the code we are calling */
+ stwu 1,-16(1)
+
+/* CAB TODO:
+ Store any other regs?
+ Set any other regs to known state?
+ - FPU, XER, CR
+*/
+
+ /* fall into main loop */
+
+/* Live regs:
+ r1 (=sp)
+ r30 (=CIA = jump address)
+ r31 (=guest_state)
+ ctr (=dispatch_ctr)
+ Stack state:
+ 28(r1) (=orig guest_state)
+*/
+
+dispatch_boring:
+ /* save the jump address in the guest state */
+ stw 30,OFFSET_ppc32_CIA(31)
+
+ /* Are we out of timeslice? If yes, defer to scheduler. */
+ bdz counter_is_zero /* decrements ctr reg */
+
+ /* try a fast lookup in the translation cache */
+ rlwinm 4,30,2,VG_TT_FAST_MASK<<2 /* r4=((r30<<2) & (MASK<<2)) */
+// CAB: use a caller-saved reg for this ?
+ addis 5,4,VG_(tt_fast)@ha
+ lwz 5,VG_(tt_fast)@l(5)
+ lwz 6,4(5) /* big-endian, so comparing 2nd 32bit word */
+ cmpw 30,6
+ bne fast_lookup_failed
+
+ /* increment bb profile counter */
+// CAB: use a caller-saved reg for this ?
+ addis 6,4,VG_(tt_fastN)@ha
+ lwz 7,VG_(tt_fastN)@l(6)
+ lwz 8,0(7)
+ addi 8,8,1
+ stw 8,0(7)
+
+ /* Found a match. Call tce[1], which is 8 bytes along, since
+ each tce element is a 64-bit int. */
+ addi 8,5,8
+ mtlr 8
+
+ /* stop ctr being clobbered */
+// CAB: use a caller-saved reg for this ?
+// but then (bdz) => (decr, cmp, bc)... still better than a stw?
+ mfctr 9
+ stw 9,24(1)
+
+ blrl
+
+
+ /* On return from guest code:
+ r3 holds destination (original) address.
+
+ r31 may be unchanged (guest_state), or may indicate further
+ details of the control transfer requested to *r3.
+
+ If r31 is unchanged (== 28(r1)), just jump next to r3.
+
+ Otherwise fall out, back to the scheduler, and let it
+ figure out what to do next.
+ */
+
+ /* reinstate clobbered ctr */
+ lwz 9,24(1)
+ mtctr 9
+
+ mr 30,3 /* put CIA (=r3) in r30 */
+ lwz 16,28(1) /* original guest_state ptr */
+ cmpw 16,31
+ beq dispatch_boring /* r31 unchanged... */
+
+ mr 3,31 /* put return val (=r31) in r3 */
+ b dispatch_exceptional
+
+/* All exits from the dispatcher go through here.
+ r3 holds the return value.
+*/
+run_innerloop_exit:
+ /* We're leaving. Check that nobody messed with
+ %mxcsr or %fpucw. We can't mess with %eax here as it
+ holds the tentative return value, but any other is OK. */
+// CAB: TODO
+
+//.. pushl $0
+//.. fstcw (%esp)
+//.. cmpl $0x027F, (%esp)
+//.. popl %esi /* get rid of the word without trashing %eflags */
+//.. jnz invariant_violation
+
+//.. pushl $0
+//.. stmxcsr (%esp)
+//.. andl $0xFFFFFFC0, (%esp) /* mask out status flags */
+//.. cmpl $0x1F80, (%esp)
+//.. popl %esi
+//.. jnz invariant_violation
+
+ /* otherwise we're OK */
+ b run_innerloop_exit_REALLY
+
+
+invariant_violation:
+ li 3,VG_TRC_INVARIANT_FAILED
+ b run_innerloop_exit_REALLY
+
+run_innerloop_exit_REALLY:
+ /* r3 holds VG_TRC_* value to return */
+
+ addi 1,1,16
+
+ mfctr 17
+ lis 18,VG_(dispatch_ctr)@ha
+ stw 17,VG_(dispatch_ctr)@l(18)
+
+ lwz 14,16(1)
+ lwz 15,20(1)
+ lwz 16,24(1)
+ lwz 17,28(1)
+ lwz 18,32(1)
+ lwz 19,36(1)
+ lwz 20,40(1)
+ lwz 21,44(1)
+ lwz 22,48(1)
+ lwz 23,52(1)
+ lwz 24,56(1)
+ lwz 25,60(1)
+ lwz 26,64(1)
+ lwz 27,68(1)
+ lwz 28,72(1)
+ lwz 29,76(1)
+ lwz 30,80(1)
+ lwz 31,84(1)
+ lwz 0,92(1)
+ mtlr 0
+ addi 1,1,88
+ blr
+
+
+/* Other ways of getting out of the inner loop. Placed out-of-line to
+ make it look cleaner.
+*/
+dispatch_exceptional:
+ /* this is jumped to only, not fallen-through from above */
+ /* save r30 in %CIA and defer to sched */
+ lwz 16,28(1)
+ stw 30,OFFSET_ppc32_CIA(16)
+ b run_innerloop_exit
+
+fast_lookup_failed:
+ /* %CIA is up to date here since dispatch_boring dominates */
+ mfctr 17
+ addi 17,17,1
+ mtctr 17
+ li 3,VG_TRC_INNER_FASTMISS
+ b run_innerloop_exit
+
+
+counter_is_zero:
+ /* %CIA is up to date here since dispatch_boring dominates */
+ mfctr 17
+ addi 17,17,1
+ mtctr 17
+ li 3,VG_TRC_INNER_COUNTERZERO
+ b run_innerloop_exit
+
+/* Let the linker know we don't need an executable stack */
+.section .note.GNU-stack,"",@progbits
+
+##--------------------------------------------------------------------##
+##--- end ---##
+##--------------------------------------------------------------------##
diff --git a/coregrind/m_dispatch/dispatch-x86.S b/coregrind/m_dispatch/dispatch-x86.S
index 1e97563..6d20d4c 100644
--- a/coregrind/m_dispatch/dispatch-x86.S
+++ b/coregrind/m_dispatch/dispatch-x86.S
@@ -1,7 +1,7 @@
##--------------------------------------------------------------------##
##--- The core dispatch loop, for jumping to a code address. ---##
-##--- x86/dispatch.S ---##
+##--- dispatch-x86.S ---##
##--------------------------------------------------------------------##
/*
diff --git a/coregrind/m_libcassert.c b/coregrind/m_libcassert.c
index 404b4f5..fdc3ac8 100644
--- a/coregrind/m_libcassert.c
+++ b/coregrind/m_libcassert.c
@@ -55,6 +55,12 @@
"movq %%rbp, %1;" \
: "=r" (sp),\
"=r" (fp));
+#elif defined(VGP_ppc32_linux)
+# define GET_REAL_SP_AND_FP(sp, fp) \
+ asm("mr %0,1;" \
+ "mr %1,1;" \
+ : "=r" (sp),\
+ "=r" (fp));
#else
# error Unknown platform
#endif
diff --git a/coregrind/m_libcfile.c b/coregrind/m_libcfile.c
index cc91434..291bce5 100644
--- a/coregrind/m_libcfile.c
+++ b/coregrind/m_libcfile.c
@@ -343,7 +343,7 @@
static
Int my_socket ( Int domain, Int type, Int protocol )
{
-# if defined(VGP_x86_linux)
+#if defined(VGP_x86_linux)
SysRes res;
UWord args[3];
args[0] = domain;
@@ -351,18 +351,26 @@
args[2] = protocol;
res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_SOCKET, (UWord)&args);
return res.isError ? -1 : res.val;
-# else
+
+#elif defined(VGP_amd64_linux)
// AMD64/Linux doesn't define __NR_socketcall... see comment above
// VG_(sigpending)() for more details.
I_die_here;
-# endif
+
+#elif defined(VGP_ppc32_linux)
+//CAB: TODO
+ I_die_here;
+
+#else
+# error Unknown arch
+#endif
}
static
Int my_connect ( Int sockfd, struct vki_sockaddr_in* serv_addr,
Int addrlen )
{
-# if defined(VGP_x86_linux)
+#if defined(VGP_x86_linux)
SysRes res;
UWord args[3];
args[0] = sockfd;
@@ -370,11 +378,19 @@
args[2] = addrlen;
res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_CONNECT, (UWord)&args);
return res.isError ? -1 : res.val;
-# else
+
+#elif defined(VGP_amd64_linux)
// AMD64/Linux doesn't define __NR_socketcall... see comment above
// VG_(sigpending)() for more details.
I_die_here;
-# endif
+
+#elif defined(VGP_ppc32_linux)
+//CAB: TODO
+ I_die_here;
+
+#else
+# error Unknown arch
+#endif
}
Int VG_(write_socket)( Int sd, void *msg, Int count )
@@ -385,7 +401,7 @@
error is still returned. */
Int flags = VKI_MSG_NOSIGNAL;
-# if defined(VGP_x86_linux)
+#if defined(VGP_x86_linux)
SysRes res;
UWord args[4];
args[0] = sd;
@@ -394,18 +410,27 @@
args[3] = flags;
res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_SEND, (UWord)&args);
return res.isError ? -1 : res.val;
-# else
+
+#elif defined(VGP_amd64_linux)
// AMD64/Linux doesn't define __NR_socketcall... see comment above
// VG_(sigpending)() for more details.
I_die_here;
-# endif
+
+#elif defined(VGP_ppc32_linux)
+//CAB: TODO
+ I_die_here;
+ flags = 0; // stop compiler complaints
+
+#else
+# error Unknown arch
+#endif
}
Int VG_(getsockname) ( Int sd, struct vki_sockaddr *name, Int *namelen)
{
SysRes res;
-# if defined(VGP_x86_linux)
+#if defined(VGP_x86_linux)
UWord args[3];
args[0] = sd;
args[1] = (UWord)name;
@@ -413,21 +438,25 @@
res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_GETSOCKNAME, (UWord)&args);
return res.isError ? -1 : res.val;
-# elif defined(VGP_amd64_linux)
+#elif defined(VGP_amd64_linux)
res = VG_(do_syscall3)( __NR_getsockname,
(UWord)sd, (UWord)name, (UWord)namelen );
return res.isError ? -1 : res.val;
-# else
+#elif defined(VGP_ppc32_linux)
+//CAB: TODO
I_die_here;
-# endif
+ return res.isError ? -1 : res.val;
+#else
+# error Unknown arch
+#endif
}
Int VG_(getpeername) ( Int sd, struct vki_sockaddr *name, Int *namelen)
{
SysRes res;
-# if defined(VGP_x86_linux)
+#if defined(VGP_x86_linux)
UWord args[3];
args[0] = sd;
args[1] = (UWord)name;
@@ -435,14 +464,19 @@
res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_GETPEERNAME, (UWord)&args);
return res.isError ? -1 : res.val;
-# elif defined(VGP_amd64_linux)
+#elif defined(VGP_amd64_linux)
res = VG_(do_syscall3)( __NR_getpeername,
(UWord)sd, (UWord)name, (UWord)namelen );
return res.isError ? -1 : res.val;
-# else
+#elif defined(VGP_ppc32_linux)
+//CAB: TODO
I_die_here;
-# endif
+ return res.isError ? -1 : res.val;
+
+#else
+# error Unknown arch
+#endif
}
Int VG_(getsockopt) ( Int sd, Int level, Int optname, void *optval,
@@ -450,7 +484,7 @@
{
SysRes res;
-# if defined(VGP_x86_linux)
+#if defined(VGP_x86_linux)
UWord args[5];
args[0] = sd;
args[1] = level;
@@ -460,15 +494,20 @@
res = VG_(do_syscall2)(__NR_socketcall, VKI_SYS_GETSOCKOPT, (UWord)&args);
return res.isError ? -1 : res.val;
-# elif defined(VGP_amd64_linux)
+#elif defined(VGP_amd64_linux)
res = VG_(do_syscall5)( __NR_getsockopt,
(UWord)sd, (UWord)level, (UWord)optname,
(UWord)optval, (UWord)optlen );
return res.isError ? -1 : res.val;
-# else
+#elif defined(VGP_ppc32_linux)
+//CAB: TODO
I_die_here;
-# endif
+ return res.isError ? -1 : res.val;
+
+#else
+# error Unknown arch
+#endif
}
diff --git a/coregrind/m_libcmman.c b/coregrind/m_libcmman.c
index 35db189..70fcb83 100644
--- a/coregrind/m_libcmman.c
+++ b/coregrind/m_libcmman.c
@@ -41,7 +41,7 @@
UInt fd, OffT offset)
{
SysRes res;
-# if defined(VGP_x86_linux)
+#if defined(VGP_x86_linux)
{
UWord args[6];
args[0] = (UWord)start;
@@ -52,12 +52,15 @@
args[5] = offset;
res = VG_(do_syscall1)(__NR_mmap, (UWord)args );
}
-# elif defined(VGP_amd64_linux)
+#elif defined(VGP_amd64_linux)
res = VG_(do_syscall6)(__NR_mmap, (UWord)start, length,
prot, flags, fd, offset);
-# else
-# error Unknown platform
-# endif
+#elif defined(VGP_ppc32_linux)
+ res = VG_(do_syscall6)(__NR_mmap, (UWord)(start), (length),
+ prot, flags, fd, offset);
+#else
+# error Unknown platform
+#endif
return res;
}
diff --git a/coregrind/m_machine.c b/coregrind/m_machine.c
index bca38a9..71c41b5 100644
--- a/coregrind/m_machine.c
+++ b/coregrind/m_machine.c
@@ -123,6 +123,43 @@
(*f)(vex->guest_R13);
(*f)(vex->guest_R14);
(*f)(vex->guest_R15);
+#elif defined(VGA_ppc32)
+ /* XXX ask tool about validity? */
+ (*f)(vex->guest_GPR0);
+ (*f)(vex->guest_GPR1);
+ (*f)(vex->guest_GPR2);
+ (*f)(vex->guest_GPR3);
+ (*f)(vex->guest_GPR4);
+ (*f)(vex->guest_GPR5);
+ (*f)(vex->guest_GPR6);
+ (*f)(vex->guest_GPR7);
+ (*f)(vex->guest_GPR8);
+ (*f)(vex->guest_GPR9);
+ (*f)(vex->guest_GPR10);
+ (*f)(vex->guest_GPR11);
+ (*f)(vex->guest_GPR12);
+ (*f)(vex->guest_GPR13);
+ (*f)(vex->guest_GPR14);
+ (*f)(vex->guest_GPR15);
+ (*f)(vex->guest_GPR16);
+ (*f)(vex->guest_GPR17);
+ (*f)(vex->guest_GPR18);
+ (*f)(vex->guest_GPR19);
+ (*f)(vex->guest_GPR20);
+ (*f)(vex->guest_GPR21);
+ (*f)(vex->guest_GPR22);
+ (*f)(vex->guest_GPR23);
+ (*f)(vex->guest_GPR24);
+ (*f)(vex->guest_GPR25);
+ (*f)(vex->guest_GPR26);
+ (*f)(vex->guest_GPR27);
+ (*f)(vex->guest_GPR28);
+ (*f)(vex->guest_GPR29);
+ (*f)(vex->guest_GPR30);
+ (*f)(vex->guest_GPR31);
+ (*f)(vex->guest_CTR);
+ (*f)(vex->guest_LR);
+
#else
# error Unknown arch
#endif
diff --git a/coregrind/m_main.c b/coregrind/m_main.c
index 6149ecd..da96fcc 100644
--- a/coregrind/m_main.c
+++ b/coregrind/m_main.c
@@ -64,6 +64,7 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <sys/mman.h>
#include "memcheck/memcheck.h"
@@ -119,6 +120,14 @@
static Int vg_argc;
static Char **vg_argv;
+#if defined(VGP_ppc32_linux)
+/* From the aux vector */
+Int VG_(cache_line_size);
+UInt VG_(hardware_capabilities);
+Addr VG_(vdso_base);
+Addr VG_(vdso_end);
+#endif
+
/*====================================================================*/
/*=== Counters, for profiling purposes only ===*/
@@ -143,13 +152,31 @@
/*====================================================================*/
+/*=== Miscellaneous global functions ===*/
+/*====================================================================*/
+
+#if defined(VGP_ppc32_linux)
+/* Used in scanning /proc/pid/maps for the VDSO */
+static int find_vdso(char *start, char *end, const char *perm,
+ off_t offset, int maj, int min, int ino, void *extra)
+{
+ if ((Addr)start != VG_(vdso_base))
+ return 1; /* keep looking */
+ /* found it */
+ VG_(vdso_end) = (Addr)end;
+ return 0;
+}
+#endif
+
+
+/*====================================================================*/
/*=== Check we were launched by stage 1 ===*/
/*====================================================================*/
/* Look for our AUXV table */
static int scan_auxv(void* init_sp)
{
- const struct ume_auxv *auxv = find_auxv((UWord*)init_sp);
+ struct ume_auxv *auxv = find_auxv((UWord*)init_sp);
int padfile = -1, found = 0;
for (; auxv->a_type != AT_NULL; auxv++)
@@ -164,9 +191,33 @@
found |= 2;
break;
+#if defined(VGP_ppc32_linux)
+ case AT_DCACHEBSIZE:
+ case AT_ICACHEBSIZE:
+ case AT_UCACHEBSIZE:
+ VG_(debugLog)(0, "main", "PPC32 cache line size %lu (type %lu)\n",
+ auxv->u.a_val, auxv->a_type );
+ if (auxv->u.a_val)
+ VG_(cache_line_size) = auxv->u.a_val;
+ // XXX: Nasty hack to stop use of badly implemented cache-control instns in vex
+ auxv->u.a_val = 0;
+ break;
+
+ case AT_HWCAP:
+ VG_(hardware_capabilities) = auxv->u.a_val;
+ break;
+#endif
+
case AT_PHDR:
VG_(valgrind_base) = VG_PGROUNDDN(auxv->u.a_val);
break;
+
+#if defined(VGP_ppc32_linux)
+ case AT_SYSINFO_EHDR:
+ VG_(vdso_base) = auxv->u.a_val;
+ foreach_map(find_vdso, NULL);
+ break;
+#endif
}
if ( found != (1|2) ) {
@@ -240,8 +291,27 @@
vg_assert(!res.isError);
// Make client hole
+#if defined(VGP_ppc32_linux)
+ {
+ Int ires;
+ if (VG_(vdso_end) > VG_(client_base) && VG_(vdso_base) < VG_(client_end)) {
+ if (VG_(client_base) < VG_(vdso_base)) {
+ ires = munmap((void *)VG_(client_base), VG_(vdso_base) - VG_(client_base));
+ vg_assert(ires == 0);
+ }
+ if (VG_(vdso_end) < VG_(client_end)) {
+ ires = munmap((void *)VG_(vdso_end), VG_(client_end) - VG_(vdso_end));
+ vg_assert(ires == 0);
+ }
+ } else {
+ ires = munmap((void*)VG_(client_base), client_size);
+ vg_assert(ires == 0);
+ }
+ }
+#else
res = VG_(munmap_native)((void*)VG_(client_base), client_size);
vg_assert(!res.isError);
+#endif
// Map shadow memory.
// Initially all inaccessible, incrementally initialized as it is used
@@ -734,6 +804,10 @@
auxsize += sizeof(*cauxv);
}
+#if defined(VGP_ppc32_linux)
+ auxsize += 2 * sizeof(*cauxv);
+#endif
+
/* OK, now we know how big the client stack is */
stacksize =
sizeof(Word) + /* argc */
@@ -809,6 +883,14 @@
auxv = (struct ume_auxv *)ptr;
*client_auxv = (UInt *)auxv;
+#if defined(VGP_ppc32_linux)
+ auxv[0].a_type = AT_IGNOREPPC;
+ auxv[0].u.a_val = AT_IGNOREPPC;
+ auxv[1].a_type = AT_IGNOREPPC;
+ auxv[1].u.a_val = AT_IGNOREPPC;
+ auxv += 2;
+#endif
+
for (; orig_auxv->a_type != AT_NULL; auxv++, orig_auxv++) {
/* copy the entry... */
*auxv = *orig_auxv;
@@ -857,6 +939,9 @@
case AT_DCACHEBSIZE:
case AT_ICACHEBSIZE:
case AT_UCACHEBSIZE:
+#if defined(VGP_ppc32_linux)
+ case AT_IGNOREPPC:
+#endif
/* All these are pointerless, so we don't need to do anything
about them. */
break;
@@ -876,14 +961,16 @@
when we set up the client trampoline code page */
break;
+#if !defined(VGP_ppc32_linux)
case AT_SYSINFO_EHDR:
/* Trash this, because we don't reproduce it */
auxv->a_type = AT_IGNORE;
break;
+#endif
default:
/* stomp out anything we don't know about */
- if (0)
+ if (1)
printf("stomping auxv entry %lld\n", (ULong)auxv->a_type);
auxv->a_type = AT_IGNORE;
break;
@@ -2156,6 +2243,7 @@
asm volatile("movw %%cs, %0" : : "m" (arch->vex.guest_CS));
asm volatile("movw %%ds, %0" : : "m" (arch->vex.guest_DS));
asm volatile("movw %%ss, %0" : : "m" (arch->vex.guest_SS));
+
#elif defined(VGA_amd64)
vg_assert(0 == sizeof(VexGuestAMD64State) % 8);
@@ -2169,6 +2257,21 @@
/* Put essential stuff into the new state. */
arch->vex.guest_RSP = sp_at_startup;
arch->vex.guest_RIP = client_ip;
+
+#elif defined(VGA_ppc32)
+ vg_assert(0 == sizeof(VexGuestPPC32State) % 8);
+
+ /* Zero out the initial state, and set up the simulated FPU in a
+ sane way. */
+ LibVEX_GuestPPC32_initialise(&arch->vex);
+
+ /* Zero out the shadow area. */
+ VG_(memset)(&arch->vex_shadow, 0, sizeof(VexGuestPPC32State));
+
+ /* Put essential stuff into the new state. */
+ arch->vex.guest_GPR1 = sp_at_startup;
+ arch->vex.guest_CIA = client_ip;
+
#else
# error Unknown arch
#endif
diff --git a/coregrind/m_redir.c b/coregrind/m_redir.c
index 38cb832..8455077 100644
--- a/coregrind/m_redir.c
+++ b/coregrind/m_redir.c
@@ -388,6 +388,8 @@
VG_(client_trampoline_code)+VG_(tramp_gettimeofday_offset));
add_redirect_addr_to_addr(0xFFFFFFFFFF600400ULL,
VG_(client_trampoline_code)+VG_(tramp_time_offset));
+#elif defined(VGP_ppc32_linux)
+//CAB: TODO
#else
# error Unknown platform
#endif
diff --git a/coregrind/m_scheduler/scheduler.c b/coregrind/m_scheduler/scheduler.c
index 1ae50a1..0e19591 100644
--- a/coregrind/m_scheduler/scheduler.c
+++ b/coregrind/m_scheduler/scheduler.c
@@ -760,6 +760,16 @@
VG_(synth_sigill)(tid, VG_(get_IP)(tid));
break;
+ case VEX_TRC_JMP_TINVAL:
+#if defined(VGA_ppc32)
+ VG_(discard_translations)(
+ (Addr64)VG_(threads)[tid].arch.vex.guest_TISTART,
+ VG_(threads)[tid].arch.vex.guest_TISTART );
+ if (0)
+ VG_(printf)("dump translations done.\n");
+#endif
+ break;
+
default:
vg_assert2(0, "VG_(scheduler), phase 3: "
"unexpected thread return code (%u)", trc);
@@ -823,6 +833,9 @@
#elif defined(VGA_arm)
# define VGA_CLREQ_ARGS guest_R0
# define VGA_CLREQ_RET guest_R0
+#elif defined(VGA_ppc32)
+# define VGA_CLREQ_ARGS guest_GPR4
+# define VGA_CLREQ_RET guest_GPR3
#else
# error Unknown arch
#endif
diff --git a/coregrind/m_sigframe/sigframe-ppc32-linux.c b/coregrind/m_sigframe/sigframe-ppc32-linux.c
new file mode 100644
index 0000000..6c65474
--- /dev/null
+++ b/coregrind/m_sigframe/sigframe-ppc32-linux.c
@@ -0,0 +1,760 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Create/destroy signal delivery frames. ---*/
+/*--- sigframe-ppc32-linux.c ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+ This file is part of Valgrind, a dynamic binary instrumentation
+ framework.
+
+ Copyright (C) 2005 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 "pub_core_basics.h"
+#include "pub_core_threadstate.h"
+#include "pub_core_aspacemgr.h"
+#include "pub_core_libcbase.h"
+#include "pub_core_libcassert.h"
+#include "pub_core_libcprint.h"
+#include "pub_core_machine.h"
+#include "pub_core_options.h"
+#include "pub_core_sigframe.h"
+#include "pub_core_signals.h"
+#include "pub_core_tooliface.h"
+#include "pub_core_trampoline.h"
+
+
+/* This module creates and removes signal frames for signal deliveries
+ on ppc32-linux.
+
+ Note, this file contains kernel-specific knowledge in the form of
+ 'struct sigframe' and 'struct rt_sigframe'. How does that relate
+ to the vki kernel interface stuff?
+
+ Either a 'struct sigframe' or a 'struct rtsigframe' is pushed
+ onto the client's stack. This contains a subsidiary
+ vki_ucontext. That holds the vcpu's state across the signal,
+ so that the sighandler can mess with the vcpu state if it
+ really wants.
+
+ FIXME: sigcontexting is basically broken for the moment. When
+ delivering a signal, the integer registers and %eflags are
+ correctly written into the sigcontext, however the FP and SSE state
+ is not. When returning from a signal, only the integer registers
+ are restored from the sigcontext; the rest of the CPU state is
+ restored to what it was before the signal.
+
+ This will be fixed.
+*/
+
+
+/*------------------------------------------------------------*/
+/*--- Signal frame layouts ---*/
+/*------------------------------------------------------------*/
+
+// A structure in which to save the application's registers
+// during the execution of signal handlers.
+
+// Linux has 2 signal frame structures: one for normal signal
+// deliveries, and one for SA_SIGINFO deliveries (also known as RT
+// signals).
+//
+// In theory, so long as we get the arguments to the handler function
+// right, it doesn't matter what the exact layout of the rest of the
+// frame is. Unfortunately, things like gcc's exception unwinding
+// make assumptions about the locations of various parts of the frame,
+// so we need to duplicate it exactly.
+
+/* Valgrind-specific parts of the signal frame */
+struct vg_sigframe
+{
+ /* Sanity check word. */
+ UInt magicPI;
+
+ UInt handlerflags; /* flags for signal handler */
+
+
+ /* Safely-saved version of sigNo, as described above. */
+ Int sigNo_private;
+
+ /* XXX This is wrong. Surely we should store the shadow values
+ into the shadow memory behind the actual values? */
+ VexGuestPPC32State vex_shadow;
+
+ /* HACK ALERT */
+ VexGuestPPC32State vex;
+ /* end HACK ALERT */
+
+ /* saved signal mask to be restored when handler returns */
+ vki_sigset_t mask;
+
+ /* Sanity check word. Is the highest-addressed word; do not
+ move!*/
+ UInt magicE;
+};
+
+struct sigframe
+{
+ /* Sig handler's return address */
+ Addr retaddr;
+ Int sigNo;
+
+ struct vki_sigcontext sigContext;
+//.. struct _vki_fpstate fpstate;
+
+ struct vg_sigframe vg;
+};
+
+struct rt_sigframe
+{
+ /* Sig handler's return address */
+ Addr retaddr;
+ Int sigNo;
+
+ /* ptr to siginfo_t. */
+ Addr psigInfo;
+
+ /* ptr to ucontext */
+ Addr puContext;
+ /* pointed to by psigInfo */
+ vki_siginfo_t sigInfo;
+
+ /* pointed to by puContext */
+ struct vki_ucontext uContext;
+//.. struct _vki_fpstate fpstate;
+
+ struct vg_sigframe vg;
+};
+
+
+//:: /*------------------------------------------------------------*/
+//:: /*--- Signal operations ---*/
+//:: /*------------------------------------------------------------*/
+//::
+//:: /*
+//:: Great gobs of FP state conversion taken wholesale from
+//:: linux/arch/i386/kernel/i387.c
+//:: */
+//::
+//:: /*
+//:: * FXSR floating point environment conversions.
+//:: */
+//:: #define X86_FXSR_MAGIC 0x0000
+//::
+//:: /*
+//:: * FPU tag word conversions.
+//:: */
+//::
+//:: static inline unsigned short twd_i387_to_fxsr( unsigned short twd )
+//:: {
+//:: unsigned int tmp; /* to avoid 16 bit prefixes in the code */
+//::
+//:: /* Transform each pair of bits into 01 (valid) or 00 (empty) */
+//:: tmp = ~twd;
+//:: tmp = (tmp | (tmp>>1)) & 0x5555; /* 0V0V0V0V0V0V0V0V */
+//:: /* and move the valid bits to the lower byte. */
+//:: tmp = (tmp | (tmp >> 1)) & 0x3333; /* 00VV00VV00VV00VV */
+//:: tmp = (tmp | (tmp >> 2)) & 0x0f0f; /* 0000VVVV0000VVVV */
+//:: tmp = (tmp | (tmp >> 4)) & 0x00ff; /* 00000000VVVVVVVV */
+//:: return tmp;
+//:: }
+//::
+//:: static unsigned long twd_fxsr_to_i387( const struct i387_fxsave_struct *fxsave )
+//:: {
+//:: struct _vki_fpxreg *st = NULL;
+//:: unsigned long twd = (unsigned long) fxsave->twd;
+//:: unsigned long tag;
+//:: unsigned long ret = 0xffff0000u;
+//:: int i;
+//::
+//:: #define FPREG_ADDR(f, n) ((char *)&(f)->st_space + (n) * 16);
+//::
+//:: for ( i = 0 ; i < 8 ; i++ ) {
+//:: if ( twd & 0x1 ) {
+//:: st = (struct _vki_fpxreg *) FPREG_ADDR( fxsave, i );
+//::
+//:: switch ( st->exponent & 0x7fff ) {
+//:: case 0x7fff:
+//:: tag = 2; /* Special */
+//:: break;
+//:: case 0x0000:
+//:: if ( !st->significand[0] &&
+//:: !st->significand[1] &&
+//:: !st->significand[2] &&
+//:: !st->significand[3] ) {
+//:: tag = 1; /* Zero */
+//:: } else {
+//:: tag = 2; /* Special */
+//:: }
+//:: break;
+//:: default:
+//:: if ( st->significand[3] & 0x8000 ) {
+//:: tag = 0; /* Valid */
+//:: } else {
+//:: tag = 2; /* Special */
+//:: }
+//:: break;
+//:: }
+//:: } else {
+//:: tag = 3; /* Empty */
+//:: }
+//:: ret |= (tag << (2 * i));
+//:: twd = twd >> 1;
+//:: }
+//:: return ret;
+//:: }
+//::
+//:: static void convert_fxsr_to_user( struct _vki_fpstate *buf,
+//:: const struct i387_fxsave_struct *fxsave )
+//:: {
+//:: unsigned long env[7];
+//:: struct _vki_fpreg *to;
+//:: struct _vki_fpxreg *from;
+//:: int i;
+//::
+//:: env[0] = (unsigned long)fxsave->cwd | 0xffff0000ul;
+//:: env[1] = (unsigned long)fxsave->swd | 0xffff0000ul;
+//:: env[2] = twd_fxsr_to_i387(fxsave);
+//:: env[3] = fxsave->fip;
+//:: env[4] = fxsave->fcs | ((unsigned long)fxsave->fop << 16);
+//:: env[5] = fxsave->foo;
+//:: env[6] = fxsave->fos;
+//::
+//:: VG_(memcpy)(buf, env, 7 * sizeof(unsigned long));
+//::
+//:: to = &buf->_st[0];
+//:: from = (struct _vki_fpxreg *) &fxsave->st_space[0];
+//:: for ( i = 0 ; i < 8 ; i++, to++, from++ ) {
+//:: unsigned long __user *t = (unsigned long __user *)to;
+//:: unsigned long *f = (unsigned long *)from;
+//::
+//:: t[0] = f[0];
+//:: t[1] = f[1];
+//:: to->exponent = from->exponent;
+//:: }
+//:: }
+//::
+//:: static void convert_fxsr_from_user( struct i387_fxsave_struct *fxsave,
+//:: const struct _vki_fpstate *buf )
+//:: {
+//:: unsigned long env[7];
+//:: struct _vki_fpxreg *to;
+//:: const struct _vki_fpreg *from;
+//:: int i;
+//::
+//:: VG_(memcpy)(env, buf, 7 * sizeof(long));
+//::
+//:: fxsave->cwd = (unsigned short)(env[0] & 0xffff);
+//:: fxsave->swd = (unsigned short)(env[1] & 0xffff);
+//:: fxsave->twd = twd_i387_to_fxsr((unsigned short)(env[2] & 0xffff));
+//:: fxsave->fip = env[3];
+//:: fxsave->fop = (unsigned short)((env[4] & 0xffff0000ul) >> 16);
+//:: fxsave->fcs = (env[4] & 0xffff);
+//:: fxsave->foo = env[5];
+//:: fxsave->fos = env[6];
+//::
+//:: to = (struct _vki_fpxreg *) &fxsave->st_space[0];
+//:: from = &buf->_st[0];
+//:: for ( i = 0 ; i < 8 ; i++, to++, from++ ) {
+//:: unsigned long *t = (unsigned long *)to;
+//:: unsigned long __user *f = (unsigned long __user *)from;
+//::
+//:: t[0] = f[0];
+//:: t[1] = f[1];
+//:: to->exponent = from->exponent;
+//:: }
+//:: }
+//::
+//:: static inline void save_i387_fsave( arch_thread_t *regs, struct _vki_fpstate *buf )
+//:: {
+//:: struct i387_fsave_struct *fs = ®s->m_sse.fsave;
+//::
+//:: fs->status = fs->swd;
+//:: VG_(memcpy)(buf, fs, sizeof(*fs));
+//:: }
+//::
+//:: static void save_i387_fxsave( arch_thread_t *regs, struct _vki_fpstate *buf )
+//:: {
+//:: const struct i387_fxsave_struct *fx = ®s->m_sse.fxsave;
+//:: convert_fxsr_to_user( buf, fx );
+//::
+//:: buf->status = fx->swd;
+//:: buf->magic = X86_FXSR_MAGIC;
+//:: VG_(memcpy)(buf->_fxsr_env, fx, sizeof(struct i387_fxsave_struct));
+//:: }
+//::
+//:: static void save_i387( arch_thread_t *regs, struct _vki_fpstate *buf )
+//:: {
+//:: if ( VG_(have_ssestate) )
+//:: save_i387_fxsave( regs, buf );
+//:: else
+//:: save_i387_fsave( regs, buf );
+//:: }
+//::
+//:: static inline void restore_i387_fsave( arch_thread_t *regs, const struct _vki_fpstate __user *buf )
+//:: {
+//:: VG_(memcpy)( ®s->m_sse.fsave, buf, sizeof(struct i387_fsave_struct) );
+//:: }
+//::
+//:: static void restore_i387_fxsave( arch_thread_t *regs, const struct _vki_fpstate __user *buf )
+//:: {
+//:: VG_(memcpy)(®s->m_sse.fxsave, &buf->_fxsr_env[0],
+//:: sizeof(struct i387_fxsave_struct) );
+//:: /* mxcsr reserved bits must be masked to zero for security reasons */
+//:: regs->m_sse.fxsave.mxcsr &= 0xffbf;
+//:: convert_fxsr_from_user( ®s->m_sse.fxsave, buf );
+//:: }
+//::
+//:: static void restore_i387( arch_thread_t *regs, const struct _vki_fpstate __user *buf )
+//:: {
+//:: if ( VG_(have_ssestate) ) {
+//:: restore_i387_fxsave( regs, buf );
+//:: } else {
+//:: restore_i387_fsave( regs, buf );
+//:: }
+//:: }
+
+
+
+
+/*------------------------------------------------------------*/
+/*--- Creating signal frames ---*/
+/*------------------------------------------------------------*/
+
+//.. /* Create a plausible-looking sigcontext from the thread's
+//.. Vex guest state. NOTE: does not fill in the FP or SSE
+//.. bits of sigcontext at the moment.
+//.. */
+//.. static
+//.. void synth_ucontext(ThreadId tid, const vki_siginfo_t *si,
+//.. const vki_sigset_t *set, struct vki_ucontext *uc)
+//.. {
+//.. ThreadState *tst = VG_(get_ThreadState)(tid);
+//.. struct vki_sigcontext *sc = &uc->uc_mcontext;
+//..
+//.. VG_(memset)(uc, 0, sizeof(*uc));
+//..
+//.. uc->uc_flags = 0;
+//.. uc->uc_link = 0;
+//.. uc->uc_sigmask = *set;
+//.. uc->uc_stack = tst->altstack;
+//.. sc->fpstate = fpstate;
+//..
+//.. // FIXME: save_i387(&tst->arch, fpstate);
+//..
+//.. # define SC2(reg,REG) sc->reg = tst->arch.vex.guest_##REG
+//.. SC2(gs,GS);
+//.. SC2(fs,FS);
+//.. SC2(es,ES);
+//.. SC2(ds,DS);
+//..
+//.. SC2(edi,EDI);
+//.. SC2(esi,ESI);
+//.. SC2(ebp,EBP);
+//.. SC2(esp,ESP);
+//.. SC2(ebx,EBX);
+//.. SC2(edx,EDX);
+//.. SC2(ecx,ECX);
+//.. SC2(eax,EAX);
+//..
+//.. SC2(eip,EIP);
+//.. SC2(cs,CS);
+//.. sc->eflags = LibVEX_GuestX86_get_eflags(&tst->arch.vex);
+//.. SC2(ss,SS);
+//.. /* XXX esp_at_signal */
+//.. /* XXX trapno */
+//.. /* XXX err */
+//.. # undef SC2
+//..
+//.. sc->cr2 = (UInt)si->_sifields._sigfault._addr;
+//.. }
+/*
+//.. #define SET_SIGNAL_ESP(zztid, zzval) \
+//.. SET_THREAD_REG(zztid, zzval, STACK_PTR, post_reg_write, \
+//.. Vg_CoreSignal, zztid, O_STACK_PTR, sizeof(Addr))
+*/
+//.. /* Extend the stack segment downwards if needed so as to ensure the
+//.. new signal frames are mapped to something. Return a Bool
+//.. indicating whether or not the operation was successful.
+//.. */
+//.. static Bool extend ( ThreadState *tst, Addr addr, SizeT size )
+//.. {
+//.. ThreadId tid = tst->tid;
+//.. Segment *stackseg = NULL;
+//..
+//.. if (VG_(extend_stack)(addr, tst->client_stack_szB)) {
+//.. stackseg = VG_(find_segment)(addr);
+//.. if (0 && stackseg)
+//.. VG_(printf)("frame=%p seg=%p-%p\n",
+//.. addr, stackseg->addr, stackseg->addr+stackseg->len);
+//.. }
+//..
+//.. if (stackseg == NULL
+//.. || (stackseg->prot & (VKI_PROT_READ|VKI_PROT_WRITE)) == 0) {
+//.. VG_(message)(
+//.. Vg_UserMsg,
+//.. "Can't extend stack to %p during signal delivery for thread %d:",
+//.. addr, tid);
+//.. if (stackseg == NULL)
+//.. VG_(message)(Vg_UserMsg, " no stack segment");
+//.. else
+//.. VG_(message)(Vg_UserMsg, " too small or bad protection modes");
+//..
+//.. /* set SIGSEGV to default handler */
+//.. VG_(set_default_handler)(VKI_SIGSEGV);
+//.. VG_(synth_fault_mapping)(tid, addr);
+//..
+//.. /* The whole process should be about to die, since the default
+//.. action of SIGSEGV to kill the whole process. */
+//.. return False;
+//.. }
+//..
+//.. /* For tracking memory events, indicate the entire frame has been
+//.. allocated. */
+//.. VG_TRACK( new_mem_stack_signal, addr, size );
+//..
+//.. return True;
+//.. }
+
+
+//.. /* Build the Valgrind-specific part of a signal frame. */
+//..
+//.. static void build_vg_sigframe(struct vg_sigframe *frame,
+//.. ThreadState *tst,
+//.. const vki_sigset_t *mask,
+//.. UInt flags,
+//.. Int sigNo)
+//.. {
+//.. frame->sigNo_private = sigNo;
+//.. frame->magicPI = 0x31415927;
+//.. frame->vex_shadow = tst->arch.vex_shadow;
+//.. /* HACK ALERT */
+//.. frame->vex = tst->arch.vex;
+//.. /* end HACK ALERT */
+//.. frame->mask = tst->sig_mask;
+//.. frame->handlerflags = flags;
+//.. frame->magicE = 0x27182818;
+//.. }
+
+
+//.. static Addr build_sigframe(ThreadState *tst,
+//.. Addr esp_top_of_frame,
+//.. const vki_siginfo_t *siginfo,
+//.. void *handler, UInt flags,
+//.. const vki_sigset_t *mask,
+//.. void *restorer)
+//.. {
+//.. struct sigframe *frame;
+//.. Addr esp = esp_top_of_frame;
+//.. Int sigNo = siginfo->si_signo;
+//.. struct vki_ucontext uc;
+//..
+//.. vg_assert((flags & VKI_SA_SIGINFO) == 0);
+//..
+//.. esp -= sizeof(*frame);
+//.. esp = ROUNDDN(esp, 16);
+//.. frame = (struct sigframe *)esp;
+//..
+//.. if (!extend(tst, esp, sizeof(*frame)))
+//.. return esp_top_of_frame;
+//..
+//.. /* retaddr, sigNo, siguContext fields are to be written */
+//.. VG_TRACK( pre_mem_write, Vg_CoreSignal, tst->tid, "signal handler frame",
+//.. esp, offsetof(struct sigframe, vg) );
+//..
+//.. frame->sigNo = sigNo;
+//..
+//.. if (flags & VKI_SA_RESTORER)
+//.. frame->retaddr = (Addr)restorer;
+//.. else
+//.. frame->retaddr
+//.. = VG_(client_trampoline_code)+VG_(tramp_sigreturn_offset);
+//..
+//.. synth_ucontext(tst->tid, siginfo, mask, &uc, &frame->fpstate);
+//..
+//.. VG_(memcpy)(&frame->sigContext, &uc.uc_mcontext,
+//.. sizeof(struct vki_sigcontext));
+//.. frame->sigContext.oldmask = mask->sig[0];
+//..
+//.. VG_TRACK( post_mem_write, Vg_CoreSignal, tst->tid,
+//.. esp, offsetof(struct sigframe, vg) );
+//..
+//.. build_vg_sigframe(&frame->vg, tst, mask, flags, sigNo);
+//..
+//.. return esp;
+//.. }
+
+
+//.. static Addr build_rt_sigframe(ThreadState *tst,
+//.. Addr esp_top_of_frame,
+//.. const vki_siginfo_t *siginfo,
+//.. void *handler, UInt flags,
+//.. const vki_sigset_t *mask,
+//.. void *restorer)
+//.. {
+//.. struct rt_sigframe *frame;
+//.. Addr esp = esp_top_of_frame;
+//.. Int sigNo = siginfo->si_signo;
+//..
+//.. vg_assert((flags & VKI_SA_SIGINFO) != 0);
+//..
+//.. esp -= sizeof(*frame);
+//.. esp = ROUNDDN(esp, 16);
+//.. frame = (struct rt_sigframe *)esp;
+//..
+//.. if (!extend(tst, esp, sizeof(*frame)))
+//.. return esp_top_of_frame;
+//..
+//.. /* retaddr, sigNo, pSiginfo, puContext fields are to be written */
+//.. VG_TRACK( pre_mem_write, Vg_CoreSignal, tst->tid, "rt signal handler frame",
+//.. esp, offsetof(struct rt_sigframe, vg) );
+//..
+//.. frame->sigNo = sigNo;
+//..
+//.. if (flags & VKI_SA_RESTORER)
+//.. frame->retaddr = (Addr)restorer;
+//.. else
+//.. frame->retaddr
+//.. = VG_(client_trampoline_code)+VG_(tramp_rt_sigreturn_offset);
+//..
+//.. frame->psigInfo = (Addr)&frame->sigInfo;
+//.. frame->puContext = (Addr)&frame->uContext;
+//.. VG_(memcpy)(&frame->sigInfo, siginfo, sizeof(vki_siginfo_t));
+//..
+//.. /* SIGILL defines addr to be the faulting address */
+//.. if (sigNo == VKI_SIGILL && siginfo->si_code > 0)
+//.. frame->sigInfo._sifields._sigfault._addr
+//.. = (void*)tst->arch.vex.guest_CIA;
+//..
+//.. synth_ucontext(tst->tid, siginfo, mask, &frame->uContext, &frame->fpstate);
+//..
+//.. VG_TRACK( post_mem_write, Vg_CoreSignal, tst->tid,
+//.. esp, offsetof(struct rt_sigframe, vg) );
+//..
+//.. build_vg_sigframe(&frame->vg, tst, mask, flags, sigNo);
+//..
+//.. return esp;
+//.. }
+
+
+/* EXPORTED */
+void VG_(sigframe_create)( ThreadId tid,
+ Addr sp_top_of_frame,
+ const vki_siginfo_t *siginfo,
+ void *handler,
+ UInt flags,
+ const vki_sigset_t *mask,
+ void *restorer )
+{
+ I_die_here;
+
+//.. Addr esp;
+//.. ThreadState* tst = VG_(get_ThreadState)(tid);
+//..
+//.. if (flags & VKI_SA_SIGINFO)
+//.. esp = build_rt_sigframe(tst, esp_top_of_frame, siginfo,
+//.. handler, flags, mask, restorer);
+//.. else
+//.. esp = build_sigframe(tst, esp_top_of_frame,
+//.. siginfo, handler, flags, mask, restorer);
+//..
+//.. /* Set the thread so it will next run the handler. */
+//.. /* tst->m_esp = esp; */
+//.. SET_SIGNAL_ESP(tid, esp);
+//..
+//.. //VG_(printf)("handler = %p\n", handler);
+//.. tst->arch.vex.guest_CIA = (Addr) 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 %%EIP = %p, status=%d\n",
+//.. esp, tst->arch.vex.guest_CIA, tst->status);
+}
+
+/*------------------------------------------------------------*/
+/*--- Destroying signal frames ---*/
+/*------------------------------------------------------------*/
+
+//.. /* Return False and don't do anything, just set the client to take a
+//.. segfault, if it looks like the frame is corrupted. */
+//.. static
+//.. Bool restore_vg_sigframe ( ThreadState *tst,
+//.. struct vg_sigframe *frame, Int *sigNo )
+//.. {
+//.. if (frame->magicPI != 0x31415927 ||
+//.. frame->magicE != 0x27182818) {
+//.. VG_(message)(Vg_UserMsg, "Thread %d return signal frame "
+//.. "corrupted. Killing process.",
+//.. tst->tid);
+//.. VG_(set_default_handler)(VKI_SIGSEGV);
+//.. VG_(synth_fault)(tst->tid);
+//.. *sigNo = VKI_SIGSEGV;
+//.. return False;
+//.. }
+//.. tst->sig_mask = frame->mask;
+//.. tst->tmp_sig_mask = frame->mask;
+//.. tst->arch.vex_shadow = frame->vex_shadow;
+//.. /* HACK ALERT */
+//.. tst->arch.vex = frame->vex;
+//.. /* end HACK ALERT */
+//.. *sigNo = frame->sigNo_private;
+//.. return True;
+//.. }
+
+//.. static
+//.. void restore_sigcontext( ThreadState *tst,
+//.. struct vki_sigcontext *sc )
+//.. //.. struct vki_sigcontext *sc, struct _vki_fpstate *fpstate )
+//.. {
+//.. tst->arch.vex.guest_EAX = sc->eax;
+//.. tst->arch.vex.guest_ECX = sc->ecx;
+//.. tst->arch.vex.guest_EDX = sc->edx;
+//.. tst->arch.vex.guest_EBX = sc->ebx;
+//.. tst->arch.vex.guest_EBP = sc->ebp;
+//.. tst->arch.vex.guest_ESP = sc->esp;
+//.. tst->arch.vex.guest_ESI = sc->esi;
+//.. tst->arch.vex.guest_EDI = sc->edi;
+//.. //:: tst->arch.vex.guest_eflags = sc->eflags;
+//.. //:: tst->arch.vex.guest_EIP = sc->eip;
+//..
+//.. tst->arch.vex.guest_CS = sc->cs;
+//.. tst->arch.vex.guest_SS = sc->ss;
+//.. tst->arch.vex.guest_DS = sc->ds;
+//.. tst->arch.vex.guest_ES = sc->es;
+//.. tst->arch.vex.guest_FS = sc->fs;
+//.. tst->arch.vex.guest_GS = sc->gs;
+//..
+//.. //:: restore_i387(&tst->arch, fpstate);
+//.. }
+
+
+//.. static
+//.. SizeT restore_sigframe ( ThreadState *tst,
+//.. struct sigframe *frame, Int *sigNo )
+//.. {
+//.. if (restore_vg_sigframe(tst, &frame->vg, sigNo))
+//.. restore_sigcontext(tst, &frame->sigContext, &frame->fpstate);
+//.. return sizeof(*frame);
+//.. }
+
+//.. static
+//.. SizeT restore_rt_sigframe ( ThreadState *tst,
+//.. struct rt_sigframe *frame, Int *sigNo )
+//.. {
+//.. if (restore_vg_sigframe(tst, &frame->vg, sigNo))
+//.. restore_sigcontext(tst, &frame->uContext.uc_mcontext, &frame->fpstate);
+//.. return sizeof(*frame);
+//.. }
+
+
+//.. /* EXPORTED */
+//.. void VG_(sigframe_destroy)( ThreadId tid, Bool isRT )
+//.. {
+//.. Addr esp;
+//.. ThreadState* tst;
+//.. SizeT size;
+//.. Int sigNo;
+//..
+//.. tst = VG_(get_ThreadState)(tid);
+//..
+//.. /* Correctly reestablish the frame base address. */
+//.. esp = tst->arch.vex.guest_ESP;
+//..
+//.. if (!isRT)
+//.. size = restore_sigframe(tst, (struct sigframe *)esp, &sigNo);
+//.. else
+//.. size = restore_rt_sigframe(tst, (struct rt_sigframe *)esp, &sigNo);
+//..
+//.. VG_TRACK( die_mem_stack_signal, esp, size );
+//..
+//.. if (VG_(clo_trace_signals))
+//.. VG_(message)(
+//.. Vg_DebugMsg,
+//.. "VGA_(signal_return) (thread %d): isRT=%d valid magic; EIP=%p",
+//.. tid, isRT, tst->arch.vex.guest_EIP);
+//..
+//.. /* tell the tools */
+//.. VG_TRACK( post_deliver_signal, tid, sigNo );
+//.. }
+
+//:: /*------------------------------------------------------------*/
+//:: /*--- Making coredumps ---*/
+//:: /*------------------------------------------------------------*/
+//::
+//:: void VGA_(fill_elfregs_from_tst)(struct vki_user_regs_struct* regs,
+//:: const arch_thread_t* arch)
+//:: {
+//:: regs->eflags = arch->m_eflags;
+//:: regs->esp = arch->m_esp;
+//:: regs->eip = arch->m_eip;
+//::
+//:: regs->ebx = arch->m_ebx;
+//:: regs->ecx = arch->m_ecx;
+//:: regs->edx = arch->m_edx;
+//:: regs->esi = arch->m_esi;
+//:: regs->edi = arch->m_edi;
+//:: regs->ebp = arch->m_ebp;
+//:: regs->eax = arch->m_eax;
+//::
+//:: regs->cs = arch->m_cs;
+//:: regs->ds = arch->m_ds;
+//:: regs->ss = arch->m_ss;
+//:: regs->es = arch->m_es;
+//:: regs->fs = arch->m_fs;
+//:: regs->gs = arch->m_gs;
+//:: }
+//::
+//:: static void fill_fpu(vki_elf_fpregset_t *fpu, const Char *from)
+//:: {
+//:: if (VG_(have_ssestate)) {
+//:: UShort *to;
+//:: Int i;
+//::
+//:: /* This is what the kernel does */
+//:: VG_(memcpy)(fpu, from, 7*sizeof(long));
+//::
+//:: to = (UShort *)&fpu->st_space[0];
+//:: from += 18 * sizeof(UShort);
+//::
+//:: for (i = 0; i < 8; i++, to += 5, from += 8)
+//:: VG_(memcpy)(to, from, 5*sizeof(UShort));
+//:: } else
+//:: VG_(memcpy)(fpu, from, sizeof(*fpu));
+//:: }
+//::
+//:: void VGA_(fill_elffpregs_from_tst)( vki_elf_fpregset_t* fpu,
+//:: const arch_thread_t* arch)
+//:: {
+//:: fill_fpu(fpu, (const Char *)&arch->m_sse);
+//:: }
+//::
+//:: void VGA_(fill_elffpxregs_from_tst) ( vki_elf_fpxregset_t* xfpu,
+//:: const arch_thread_t* arch )
+//:: {
+//:: VG_(memcpy)(xfpu, arch->m_sse.state, sizeof(*xfpu));
+//:: }
+
+/*--------------------------------------------------------------------*/
+/*--- end sigframe-ppc32-linux.c ---*/
+/*--------------------------------------------------------------------*/
diff --git a/coregrind/m_signals.c b/coregrind/m_signals.c
index 4c83d00..e954637 100644
--- a/coregrind/m_signals.c
+++ b/coregrind/m_signals.c
@@ -134,7 +134,7 @@
# define VGP_UCONTEXT_SYSCALL_NUM(uc) ((uc)->uc_mcontext.eax)
# define VGP_UCONTEXT_SYSCALL_SYSRES(uc) \
/* Convert the value in uc_mcontext.eax into a SysRes. */ \
- VG_(mk_SysRes)( (uc)->uc_mcontext.eax )
+ VG_(mk_SysRes_x86_linux)( (uc)->uc_mcontext.eax )
#elif defined(VGP_amd64_linux)
# define VGP_UCONTEXT_INSTR_PTR(uc) ((uc)->uc_mcontext.rip)
@@ -143,7 +143,7 @@
# define VGP_UCONTEXT_SYSCALL_NUM(uc) ((uc)->uc_mcontext.rax)
# define VGP_UCONTEXT_SYSCALL_SYSRES(uc) \
/* Convert the value in uc_mcontext.rax into a SysRes. */ \
- VG_(mk_SysRes)( (uc)->uc_mcontext.rax )
+ VG_(mk_SysRes_amd64_linux)( (uc)->uc_mcontext.rax )
#elif defined(VGP_arm_linux)
# define VGP_UCONTEXT_INSTR_PTR(uc) ((uc)->uc_mcontext.arm_pc)
@@ -152,6 +152,16 @@
# define VGP_UCONTEXT_SYSCALL_NUM(uc) ((uc)->uc_mcontext.arm_r0)
# error VGP_UCONTEXT_SYSCALL_RET undefined for ARM/Linux
+#elif defined(VGP_ppc32_linux)
+# define VGP_UCONTEXT_INSTR_PTR(uc) ((uc)->uc_mcontext.mc_gregs[VKI_PT_NIP])
+# define VGP_UCONTEXT_STACK_PTR(uc) ((uc)->uc_mcontext.mc_gregs[1])
+# define VGP_UCONTEXT_FRAME_PTR(uc) ((uc)->uc_mcontext.mc_gregs[1])
+# define VGP_UCONTEXT_SYSCALL_NUM(uc) ((uc)->uc_mcontext.mc_gregs[0])
+# define VGP_UCONTEXT_SYSCALL_SYSRES(uc) \
+ /* Convert the values in uc_mcontext r3,cr into a SysRes. */ \
+ VG_(mk_SysRes_ppc32_linux)( (uc)->uc_mcontext.mc_gregs[3], \
+ (uc)->uc_mcontext.mc_gregs[VKI_PT_CCR] )
+
#else
# error Unknown platform
#endif
@@ -396,6 +406,11 @@
"my_sigreturn:\n" \
" movq $" #name ", %rax\n" \
" syscall\n"
+#elif defined(VGP_ppc32_linux)
+# define _MYSIG(name) \
+ "my_sigreturn:\n" \
+ " li 0, " #name "\n" \
+ " sc\n"
#else
# error Unknown platform
#endif
diff --git a/coregrind/m_stacktrace.c b/coregrind/m_stacktrace.c
index 8b1f88d..f606de3 100644
--- a/coregrind/m_stacktrace.c
+++ b/coregrind/m_stacktrace.c
@@ -53,6 +53,10 @@
# define FIRST_STACK_FRAME(rbp) (rbp)
# define STACK_FRAME_RET(rbp) (((UWord*)rbp)[1])
# define STACK_FRAME_NEXT(rbp) (((UWord*)rbp)[0])
+#elif defined(VGA_ppc32)
+# define FIRST_STACK_FRAME(sp) (sp)
+# define STACK_FRAME_RET(sp) (((UWord*)sp)[1])
+# define STACK_FRAME_NEXT(sp) (((UWord*)sp)[0])
#else
# error Unknown platform
#endif
diff --git a/coregrind/m_syscall.c b/coregrind/m_syscall.c
index b3a7036..f130bc2 100644
--- a/coregrind/m_syscall.c
+++ b/coregrind/m_syscall.c
@@ -54,20 +54,31 @@
syscall returns a value in -1 .. -4095 as a valid result so we can
safely test with -4095.
*/
-SysRes VG_(mk_SysRes) ( UWord val ) {
+SysRes VG_(mk_SysRes_x86_linux) ( UWord val ) {
SysRes res;
-#if defined(VGP_x86_linux)
res.isError = val >= -4095 && val <= -1;
res.val = res.isError ? -val : val;
-#elif defined(VGP_amd64_linux)
- res.isError = val >= -4095 && val <= -1;
- res.val = res.isError ? -val : val;
-#else
-# error Unknown platform
-#endif
return res;
}
+/* Similarly .. */
+SysRes VG_(mk_SysRes_amd64_linux) ( UWord val ) {
+ SysRes res;
+ res.isError = val >= -4095 && val <= -1;
+ res.val = res.isError ? -val : val;
+ return res;
+}
+
+/* PPC uses the CR7.SO bit to flag an error (CR0 in IBM-speke)
+ */
+SysRes VG_(mk_SysRes_ppc32_linux) ( UInt val, UInt errflag ) {
+ SysRes res;
+ res.isError = errflag != 0;
+ res.val = val;
+ return res;
+}
+
+
SysRes VG_(mk_SysRes_Error) ( UWord val ) {
SysRes r = { val, True };
return r;
@@ -83,11 +94,6 @@
A function for doing syscalls.
------------------------------------------------------------------ */
-static UWord do_syscall_WRK (
- UWord syscall_no,
- UWord a1, UWord a2, UWord a3,
- UWord a4, UWord a5, UWord a6
- );
#if defined(VGP_x86_linux)
/* Incoming args (syscall number + up to 6 args) come on the stack.
(ie. the C calling convention).
@@ -100,6 +106,11 @@
clobbers, so we preserve all the callee-save regs (%esi, %edi, %ebx,
%ebp).
*/
+static UWord do_syscall_WRK (
+ UWord syscall_no,
+ UWord a1, UWord a2, UWord a3,
+ UWord a4, UWord a5, UWord a6
+ );
asm(
"do_syscall_WRK:\n"
" push %esi\n"
@@ -133,6 +144,11 @@
no matter, they are caller-save (the syscall clobbers no callee-save
regs, so we don't have to do any register saving/restoring).
*/
+static UWord do_syscall_WRK (
+ UWord syscall_no,
+ UWord a1, UWord a2, UWord a3,
+ UWord a4, UWord a5, UWord a6
+ );
asm(
"do_syscall_WRK:\n"
/* Convert function calling convention --> syscall calling
@@ -147,6 +163,36 @@
" syscall\n"
" ret\n"
);
+#elif defined(VGP_ppc32_linux)
+/* Incoming args (syscall number + up to 6 args) come in %r0, %r3:%r8
+
+ The syscall number goes in %r0. The args are passed to the syscall in
+ the regs %r3:%r8, i.e. the kernel's syscall calling convention.
+
+ The %cr0.so bit flags an error.
+ We return the syscall return value in %r3, and the %cr in %r4.
+ We return a ULong, of which %r3 is the high word, and %r4 the low.
+ No callee-save regs are clobbered, so no saving/restoring is needed.
+*/
+static ULong do_syscall_WRK (
+ UWord syscall_no,
+ UWord a1, UWord a2, UWord a3,
+ UWord a4, UWord a5, UWord a6
+ );
+asm(
+"do_syscall_WRK:\n"
+" mr 0,3\n"
+" mr 3,4\n"
+" mr 4,5\n"
+" mr 5,6\n"
+" mr 6,7\n"
+" mr 7,8\n"
+" mr 8,9\n"
+" sc\n" /* syscall: sets %cr0.so on error */
+" mfcr 4\n" /* %cr -> low word of return var */
+" rlwinm 4,4,4,31,31\n" /* rotate flag bit so to lsb, and mask it */
+" blr\n" /* and return */
+);
#else
# error Unknown platform
#endif
@@ -154,8 +200,20 @@
SysRes VG_(do_syscall) ( UWord sysno, UWord a1, UWord a2, UWord a3,
UWord a4, UWord a5, UWord a6 )
{
- UWord val = do_syscall_WRK(sysno,a1,a2,a3,a4,a5,a6);
- return VG_(mk_SysRes)( val );
+#if defined(VGP_x86_linux)
+ UWord val = do_syscall_WRK(sysno,a1,a2,a3,a4,a5,a6);
+ return VG_(mk_SysRes_x86_linux)( val );
+#elif defined(VGP_amd64_linux)
+ UWord val = do_syscall_WRK(sysno,a1,a2,a3,a4,a5,a6);
+ return VG_(mk_SysRes_amd64_linux)( val );
+#elif defined(VGP_ppc32_linux)
+ ULong ret = do_syscall_WRK(sysno,a1,a2,a3,a4,a5,a6);
+ UInt val = (UInt)(ret>>32);
+ UInt errflag = (UInt)(ret);
+ return VG_(mk_SysRes_ppc32_linux)( val, errflag );
+#else
+# error Unknown platform
+#endif
}
/*--------------------------------------------------------------------*/
diff --git a/coregrind/m_syswrap/syscall-ppc32-linux.S b/coregrind/m_syswrap/syscall-ppc32-linux.S
new file mode 100644
index 0000000..0658ac8
--- /dev/null
+++ b/coregrind/m_syswrap/syscall-ppc32-linux.S
@@ -0,0 +1,161 @@
+
+##--------------------------------------------------------------------##
+##--- Support for doing system calls. syscall-ppc32-linux.S ---##
+##--------------------------------------------------------------------##
+
+/*
+ This file is part of Valgrind, a dynamic binary instrumentation
+ framework.
+
+ Copyright (C) 2005 Paul Mackerras <paulus@samba.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ The GNU General Public License is contained in the file COPYING.
+*/
+
+#include "pub_tool_basics_asm.h"
+#include "vki_unistd.h"
+#include "libvex_guest_offsets.h"
+
+
+/*----------------------------------------------------------------*/
+/*
+ Perform a syscall for the client. This will run a syscall
+ with the client's specific per-thread signal mask.
+
+ The structure of this function is such that, if the syscall is
+ interrupted by a signal, we can determine exactly what
+ execution state we were in with respect to the execution of
+ the syscall by examining the value of NIP in the signal
+ handler. This means that we can always do the appropriate
+ thing to precisely emulate the kernel's signal/syscall
+ interactions.
+
+ The syscall number is taken from the argument, even though it
+ should also be in regs->m_gpr[0]. The syscall result is written
+ back to regs->m_gpr[3]/m_xer/m_result on completion.
+
+ Returns 0 if the syscall was successfully called (even if the
+ syscall itself failed), or a -ve error code if one of the
+ sigprocmasks failed (there's no way to determine which one
+ failed).
+
+ VGA_(interrupted_syscall)() does the thread state fixup in the
+ case where we were interrupted by a signal.
+
+ Prototype:
+
+ Int VGA_(do_syscall_for_client_WRK)(
+ Int syscallno, // r3
+ void* guest_state, // r4
+ const vki_sigset_t *sysmask, // r5
+ const vki_sigset_t *postmask, // r6
+ Int nsigwords) // r7
+*/
+/* from vki_arch.h */
+#define VKI_SIG_SETMASK 2
+
+.globl VGA_(do_syscall_for_client_WRK)
+VGA_(do_syscall_for_client_WRK):
+ /* make a stack frame */
+ stwu 1,-32(1)
+ stw 31,28(1)
+ stw 30,24(1)
+ stw 29,20(1)
+ stw 28,16(1)
+ mr 31,3 /* syscall number */
+ mr 30,4 /* guest_state */
+ mr 29,6 /* postmask */
+ mr 28,7 /* nsigwords */
+
+ /* set the signal mask for doing the system call */
+ /* set up for sigprocmask(SIG_SETMASK, sysmask, postmask) */
+1: li 0,__NR_sigprocmask
+ li 3,VKI_SIG_SETMASK
+ mr 4,5
+ mr 5,6
+ sc /* set the mask */
+ bso 7f /* if the sigprocmask fails */
+
+ /* load up syscall args from the threadstate */
+ lwz 3,OFFSET_ppc32_GPR3(30)
+ lwz 4,OFFSET_ppc32_GPR4(30)
+ lwz 5,OFFSET_ppc32_GPR5(30)
+ lwz 6,OFFSET_ppc32_GPR6(30)
+ lwz 7,OFFSET_ppc32_GPR7(30)
+ lwz 8,OFFSET_ppc32_GPR8(30)
+ mr 0,31 /* syscall number */
+2: sc /* do the syscall */
+
+ /* put the result back in the threadstate */
+ /* HACK: killing all of CR0 for simplicity (should get from gst) */
+3: stw 3,OFFSET_ppc32_GPR3(30) /* gst->GPR3 = sc result */
+ li 4,1
+ stw 4,OFFSET_ppc32_CC_OP(30) /* gst->CC_OP = 1 */
+ mfcr 5 /* r5 = CR */
+ andis. 5,5,0x1000 /* mask to only CR7.SO */
+ oris 5,5,0x2000 /* set CR7.EQ */
+ stw 5,OFFSET_ppc32_CC_DEP1(30) /* gst->CR7 = CR7 */
+
+ /* block signals again */
+ /* set up for sigprocmask(SIG_SETMASK, postmask, NULL) */
+4: li 0,__NR_sigprocmask
+ li 3,VKI_SIG_SETMASK
+ mr 4,29
+ li 5,0
+ mr 6,28
+ sc /* set the mask */
+ bso 7f /* if the sigprocmask fails */
+
+ /* now safe from signals */
+
+ /* pop off stack frame */
+5: lwz 28,16(1)
+ lwz 29,20(1)
+ lwz 30,24(1)
+ lwz 31,28(1)
+ addi 1,1,32
+ blr
+
+ /* failure: return -ve error code */
+7: neg 3,3
+ b 5b
+
+.section .rodata
+/* export the ranges so that
+ VG_(fixup_guest_state_after_syscall_interrupted) can do the
+ right thing */
+
+.globl VGA_(blksys_setup)
+.globl VGA_(blksys_restart)
+.globl VGA_(blksys_complete)
+.globl VGA_(blksys_committed)
+.globl VGA_(blksys_finished)
+VGA_(blksys_setup): .long 1b
+VGA_(blksys_restart): .long 2b
+VGA_(blksys_complete): .long 3b
+VGA_(blksys_committed): .long 4b
+VGA_(blksys_finished): .long 5b
+
+.previous
+
+/* Let the linker know we don't need an executable stack */
+.section .note.GNU-stack,"",@progbits
+
+##--------------------------------------------------------------------##
+##--- end ---##
+##--------------------------------------------------------------------##
diff --git a/coregrind/m_syswrap/syswrap-amd64-linux.c b/coregrind/m_syswrap/syswrap-amd64-linux.c
index f8dd3d2..43f6ea4 100644
--- a/coregrind/m_syswrap/syswrap-amd64-linux.c
+++ b/coregrind/m_syswrap/syswrap-amd64-linux.c
@@ -461,7 +461,7 @@
start_thread_NORETURN, stack, flags, &VG_(threads)[ctid],
child_tidptr, parent_tidptr, NULL
);
- res = VG_(mk_SysRes)( rax );
+ res = VG_(mk_SysRes_amd64_linux)( rax );
VG_(sigprocmask)(VKI_SIG_SETMASK, &savedmask, NULL);
@@ -696,7 +696,7 @@
denote either success or failure, we must set up so that the
driver logic copies it back unchanged. Also, note %RAX is of
the guest registers written by VG_(sigframe_destroy). */
- SET_STATUS_from_SysRes( VG_(mk_SysRes)( tst->arch.vex.guest_RAX ) );
+ SET_STATUS_from_SysRes( VG_(mk_SysRes_amd64_linux)( tst->arch.vex.guest_RAX ) );
/* Check to see if some any signals arose as a result of this. */
*flags |= SfPollAfter;
diff --git a/coregrind/m_syswrap/syswrap-generic.c b/coregrind/m_syswrap/syswrap-generic.c
index 4b516c2..718c742 100644
--- a/coregrind/m_syswrap/syswrap-generic.c
+++ b/coregrind/m_syswrap/syswrap-generic.c
@@ -3346,7 +3346,9 @@
case VKI_SOUND_PCM_READ_RATE:
case VKI_SOUND_PCM_READ_CHANNELS:
case VKI_SOUND_PCM_READ_BITS:
+#if !defined(VGA_ppc32)
case (VKI_SOUND_PCM_READ_BITS|0x40000000): /* what the fuck ? */
+#endif
case VKI_SOUND_PCM_READ_FILTER:
PRE_MEM_WRITE( "ioctl(SNDCTL_XXX|SOUND_XXX (SIOR, int))",
ARG3, sizeof(int));
@@ -3996,7 +3998,9 @@
case VKI_SOUND_PCM_READ_RATE:
case VKI_SOUND_PCM_READ_CHANNELS:
case VKI_SOUND_PCM_READ_BITS:
+#if !defined(VGA_ppc32)
case (VKI_SOUND_PCM_READ_BITS|0x40000000): /* what the fuck ? */
+#endif
case VKI_SOUND_PCM_READ_FILTER:
POST_MEM_WRITE(ARG3, sizeof(int));
break;
diff --git a/coregrind/m_syswrap/syswrap-main.c b/coregrind/m_syswrap/syswrap-main.c
index 56f1a8e..3cea5c2 100644
--- a/coregrind/m_syswrap/syswrap-main.c
+++ b/coregrind/m_syswrap/syswrap-main.c
@@ -267,7 +267,7 @@
void getSyscallArgsFromGuestState ( /*OUT*/SyscallArgs* canonical,
/*IN*/ VexGuestArchState* gst_vanilla )
{
-# if defined(VGP_x86_linux)
+#if defined(VGP_x86_linux)
VexGuestX86State* gst = (VexGuestX86State*)gst_vanilla;
canonical->sysno = gst->guest_EAX;
canonical->arg1 = gst->guest_EBX;
@@ -276,8 +276,8 @@
canonical->arg4 = gst->guest_ESI;
canonical->arg5 = gst->guest_EDI;
canonical->arg6 = gst->guest_EBP;
-# else
-# if defined(VGP_amd64_linux)
+
+#elif defined(VGP_amd64_linux)
VexGuestAMD64State* gst = (VexGuestAMD64State*)gst_vanilla;
canonical->sysno = gst->guest_RAX;
canonical->arg1 = gst->guest_RDI;
@@ -286,17 +286,27 @@
canonical->arg4 = gst->guest_R10;
canonical->arg5 = gst->guest_R8;
canonical->arg6 = gst->guest_R9;
-# else
-# error "getSyscallArgsFromGuestState: unknown arch"
-# endif
-# endif
+
+#elif defined(VGP_ppc32_linux)
+ VexGuestPPC32State* gst = (VexGuestPPC32State*)gst_vanilla;
+ canonical->sysno = gst->guest_GPR0;
+ canonical->arg1 = gst->guest_GPR3;
+ canonical->arg2 = gst->guest_GPR4;
+ canonical->arg3 = gst->guest_GPR5;
+ canonical->arg4 = gst->guest_GPR6;
+ canonical->arg5 = gst->guest_GPR7;
+ canonical->arg6 = gst->guest_GPR8;
+
+#else
+# error "getSyscallArgsFromGuestState: unknown arch"
+#endif
}
static
void putSyscallArgsIntoGuestState ( /*IN*/ SyscallArgs* canonical,
/*OUT*/VexGuestArchState* gst_vanilla )
{
-# if defined(VGP_x86_linux)
+#if defined(VGP_x86_linux)
VexGuestX86State* gst = (VexGuestX86State*)gst_vanilla;
gst->guest_EAX = canonical->sysno;
gst->guest_EBX = canonical->arg1;
@@ -305,8 +315,8 @@
gst->guest_ESI = canonical->arg4;
gst->guest_EDI = canonical->arg5;
gst->guest_EBP = canonical->arg6;
-# else
-# if defined(VGP_amd64_linux)
+
+#elif defined(VGP_amd64_linux)
VexGuestAMD64State* gst = (VexGuestAMD64State*)gst_vanilla;
gst->guest_RAX = canonical->sysno;
gst->guest_RDI = canonical->arg1;
@@ -315,31 +325,48 @@
gst->guest_R10 = canonical->arg4;
gst->guest_R8 = canonical->arg5;
gst->guest_R9 = canonical->arg6;
-# else
-# error "putSyscallArgsIntoGuestState: unknown arch"
-# endif
-# endif
+
+#elif defined(VGP_ppc32_linux)
+ VexGuestPPC32State* gst = (VexGuestPPC32State*)gst_vanilla;
+ gst->guest_GPR0 = canonical->sysno;
+ gst->guest_GPR3 = canonical->arg1;
+ gst->guest_GPR4 = canonical->arg2;
+ gst->guest_GPR5 = canonical->arg3;
+ gst->guest_GPR6 = canonical->arg4;
+ gst->guest_GPR7 = canonical->arg5;
+ gst->guest_GPR8 = canonical->arg6;
+
+#else
+# error "putSyscallArgsIntoGuestState: unknown arch"
+#endif
}
static
void getSyscallStatusFromGuestState ( /*OUT*/SyscallStatus* canonical,
/*IN*/ VexGuestArchState* gst_vanilla )
{
-# if defined(VGP_x86_linux)
+#if defined(VGP_x86_linux)
VexGuestX86State* gst = (VexGuestX86State*)gst_vanilla;
Int i = (Int)gst->guest_EAX;
canonical->what = i >= -4095 && i <= -1 ? SsFailure : SsSuccess;
canonical->val = (UWord)(canonical->what==SsFailure ? -i : i);
-# else
-# if defined(VGP_amd64_linux)
+
+#elif defined(VGP_amd64_linux)
VexGuestAMD64State* gst = (VexGuestAMD64State*)gst_vanilla;
Long i = (Long)gst->guest_RAX;
canonical->what = i >= -4095 && i <= -1 ? SsFailure : SsSuccess;
canonical->val = (UWord)(canonical->what==SsFailure ? -i : i);
-# else
-# error "getSyscallStatusFromGuestState: unknown arch"
-# endif
-# endif
+
+#elif defined(VGP_ppc32_linux)
+ VexGuestPPC32State* gst = (VexGuestPPC32State*)gst_vanilla;
+ UInt cr = LibVEX_GuestPPC32_get_cr7( gst );
+ UInt err = (cr >> 28) & 1; // CR7.SO
+ canonical->what = (err == 1) ? SsFailure : SsSuccess;
+ canonical->val = (UWord)gst->guest_GPR3;
+
+#else
+# error "getSyscallStatusFromGuestState: unknown arch"
+#endif
}
static
@@ -348,7 +375,7 @@
{
vg_assert(canonical->what == SsSuccess
|| canonical->what == SsFailure);
-# if defined(VGP_x86_linux)
+#if defined(VGP_x86_linux)
VexGuestX86State* gst = (VexGuestX86State*)gst_vanilla;
if (canonical->what == SsFailure) {
/* This isn't exactly right, in that really a Failure with res
@@ -358,8 +385,7 @@
} else {
gst->guest_EAX = canonical->val;
}
-# else
-# if defined(VGP_amd64_linux)
+#elif defined(VGP_amd64_linux)
VexGuestAMD64State* gst = (VexGuestAMD64State*)gst_vanilla;
if (canonical->what == SsFailure) {
/* This isn't exactly right, in that really a Failure with res
@@ -369,10 +395,22 @@
} else {
gst->guest_RAX = canonical->val;
}
-# else
-# error "putSyscallStatusIntoGuestState: unknown arch"
-# endif
-# endif
+
+#elif defined(VGP_ppc32_linux)
+ VexGuestPPC32State* gst = (VexGuestPPC32State*)gst_vanilla;
+ gst->guest_GPR3 = canonical->val;
+ gst->guest_CC_OP = 1;
+ /* XXX: Setting all of CR0, not just SO flag */
+ if (canonical->what == SsFailure) /* set cr0.SO */
+ gst->guest_CC_DEP1 = 0x30000000;
+ else /* clear cr0.SO */
+ gst->guest_CC_DEP1 = 0x20000000;
+// CAB: Need to set gpr0?
+ gst->guest_GPR0 = 0;
+
+#else
+# error "putSyscallStatusIntoGuestState: unknown arch"
+#endif
}
@@ -383,7 +421,7 @@
static
void getSyscallArgLayout ( /*OUT*/SyscallArgLayout* layout )
{
-# if defined(VGP_x86_linux)
+#if defined(VGP_x86_linux)
layout->o_sysno = OFFSET_x86_EAX;
layout->o_arg1 = OFFSET_x86_EBX;
layout->o_arg2 = OFFSET_x86_ECX;
@@ -392,8 +430,8 @@
layout->o_arg5 = OFFSET_x86_EDI;
layout->o_arg6 = OFFSET_x86_EBP;
layout->o_retval = OFFSET_x86_EAX;
-# else
-# if defined(VGP_amd64_linux)
+
+#elif defined(VGP_amd64_linux)
layout->o_sysno = OFFSET_amd64_RAX;
layout->o_arg1 = OFFSET_amd64_RDI;
layout->o_arg2 = OFFSET_amd64_RSI;
@@ -402,10 +440,20 @@
layout->o_arg5 = OFFSET_amd64_R8;
layout->o_arg6 = OFFSET_amd64_R9;
layout->o_retval = OFFSET_amd64_RAX;
-# else
-# error "getSyscallLayout: unknown arch"
-# endif
-# endif
+
+#elif defined(VGP_ppc32_linux)
+ layout->o_sysno = OFFSET_ppc32_GPR0;
+ layout->o_arg1 = OFFSET_ppc32_GPR3;
+ layout->o_arg2 = OFFSET_ppc32_GPR4;
+ layout->o_arg3 = OFFSET_ppc32_GPR5;
+ layout->o_arg4 = OFFSET_ppc32_GPR6;
+ layout->o_arg5 = OFFSET_ppc32_GPR7;
+ layout->o_arg6 = OFFSET_ppc32_GPR8;
+ layout->o_retval = OFFSET_ppc32_GPR3;
+
+#else
+# error "getSyscallLayout: unknown arch"
+#endif
}
@@ -866,7 +914,7 @@
void VG_(fixup_guest_state_to_restart_syscall) ( ThreadArchState* arch )
{
-# if defined(VGP_x86_linux)
+#if defined(VGP_x86_linux)
arch->vex.guest_EIP -= 2; // sizeof(int $0x80)
/* Make sure our caller is actually sane, and we're really backing
@@ -884,9 +932,8 @@
vg_assert(p[0] == 0xcd && p[1] == 0x80);
}
-# else
-# if defined(VGP_amd64_linux)
+#elif defined(VGP_amd64_linux)
arch->vex.guest_RIP -= 2; // sizeof(syscall)
/* Make sure our caller is actually sane, and we're really backing
@@ -904,11 +951,29 @@
vg_assert(p[0] == 0x0F && p[1] == 0x05);
}
-# else
-# error "VG_(fixup_guest_state_to_restart_syscall): unknown plat"
-# endif
-# endif
+#elif defined(VGP_ppc32_linux)
+ arch->vex.guest_CIA -= 4; // sizeof(ppc32 instr)
+
+ /* Make sure our caller is actually sane, and we're really backing
+ back over a syscall.
+
+ sc == 44 00 00 02
+ */
+ {
+ UChar *p = (UChar *)arch->vex.guest_CIA;
+
+ if (p[0] != 0x44 || p[1] != 0x0 || p[2] != 0x0 || p[3] != 0x02)
+ VG_(message)(Vg_DebugMsg,
+ "?! restarting over syscall at %p %02x %02x %02x %02x\n",
+ arch->vex.guest_CIA, p[0], p[1], p[2], p[3]);
+
+ vg_assert(p[0] == 0x44 && p[1] == 0x0 && p[2] == 0x0 && p[3] == 0x2);
+ }
+
+#else
+# error "VG_(fixup_guest_state_to_restart_syscall): unknown plat"
+#endif
}
/*
diff --git a/coregrind/m_syswrap/syswrap-ppc32-linux.c b/coregrind/m_syswrap/syswrap-ppc32-linux.c
new file mode 100644
index 0000000..35cfaeb
--- /dev/null
+++ b/coregrind/m_syswrap/syswrap-ppc32-linux.c
@@ -0,0 +1,1835 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Platform-specific syscalls stuff. syswrap-ppc32-linux.c ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+ This file is part of Valgrind, a dynamic binary instrumentation
+ framework.
+
+ Copyright (C) 2005 Nicholas Nethercote <njn25@cam.ac.uk>
+ Copyright (C) 2005 Cerion Armour-Brown <cerion@open-works.co.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 "pub_core_basics.h"
+#include "pub_core_threadstate.h"
+#include "pub_core_debuglog.h"
+#include "pub_core_aspacemgr.h"
+#include "pub_core_libcbase.h"
+#include "pub_core_libcassert.h"
+#include "pub_core_libcmman.h"
+#include "pub_core_libcprint.h"
+#include "pub_core_libcproc.h"
+#include "pub_core_libcsignal.h"
+#include "pub_core_main.h" // For VG_(shutdown_actions_NORETURN)()
+#include "pub_core_options.h"
+#include "pub_core_scheduler.h"
+#include "pub_core_sigframe.h" // For VG_(sigframe_destroy)()
+#include "pub_core_signals.h"
+#include "pub_core_syscall.h"
+#include "pub_core_syswrap.h"
+#include "pub_core_tooliface.h"
+
+#include "priv_types_n_macros.h"
+#include "priv_syswrap-generic.h" /* for decls of generic wrappers */
+#include "priv_syswrap-linux.h" /* for decls of linux-ish wrappers */
+#include "priv_syswrap-main.h"
+
+#include "vki_unistd.h" /* for the __NR_* constants */
+
+
+/* ---------------------------------------------------------------------
+ Stacks, thread wrappers, clone
+ Note. Why is this stuff here?
+ ------------------------------------------------------------------ */
+
+/*
+ Allocate a stack for this thread.
+ They're allocated lazily, but never freed.
+ */
+#define FILL 0xdeadbeef
+
+// Valgrind's stack size, in words.
+#define STACK_SIZE_W 16384
+
+static UWord* allocstack(ThreadId tid)
+{
+ ThreadState *tst = VG_(get_ThreadState)(tid);
+ UWord *sp;
+
+ if (tst->os_state.valgrind_stack_base == 0) {
+ void *stk = VG_(mmap)(0, STACK_SIZE_W * sizeof(UWord) + VKI_PAGE_SIZE,
+ VKI_PROT_READ|VKI_PROT_WRITE,
+ VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS,
+ SF_VALGRIND,
+ -1, 0);
+
+ if (stk != (void *)-1) {
+ VG_(mprotect)(stk, VKI_PAGE_SIZE, VKI_PROT_NONE); /* guard page */
+ tst->os_state.valgrind_stack_base = ((Addr)stk) + VKI_PAGE_SIZE;
+ tst->os_state.valgrind_stack_szB = STACK_SIZE_W * sizeof(UWord);
+ } else
+ return (UWord*)-1;
+ }
+
+ for (sp = (UWord*) tst->os_state.valgrind_stack_base;
+ sp < (UWord*)(tst->os_state.valgrind_stack_base +
+ tst->os_state.valgrind_stack_szB);
+ sp++)
+ *sp = FILL;
+ /* sp is left at top of stack */
+
+ if (0)
+ VG_(printf)("stack for tid %d at %p (%x); sp=%p\n",
+ tid, tst->os_state.valgrind_stack_base,
+ *(UWord*)(tst->os_state.valgrind_stack_base), sp);
+
+ vg_assert(VG_IS_16_ALIGNED(sp));
+
+ return sp;
+}
+
+/* NB: this is identical the the amd64 version. */
+/* Return how many bytes of this stack have not been used */
+SSizeT VGA_(stack_unused)(ThreadId tid)
+{
+ ThreadState *tst = VG_(get_ThreadState)(tid);
+ UWord* p;
+
+ for (p = (UWord*)tst->os_state.valgrind_stack_base;
+ p && (p < (UWord*)(tst->os_state.valgrind_stack_base +
+ tst->os_state.valgrind_stack_szB));
+ p++)
+ if (*p != FILL)
+ break;
+
+ if (0)
+ VG_(printf)("p=%p %x tst->os_state.valgrind_stack_base=%p\n",
+ p, *p, tst->os_state.valgrind_stack_base);
+
+ return ((Addr)p) - tst->os_state.valgrind_stack_base;
+}
+
+
+/* Run a thread all the way to the end, then do appropriate exit actions
+ (this is the last-one-out-turn-off-the-lights bit).
+*/
+static void run_a_thread_NORETURN ( Word tidW )
+{
+ ThreadId tid = (ThreadId)tidW;
+
+ VG_(debugLog)(1, "syscalls-ppc32-linux",
+ "run_a_thread_NORETURN(tid=%lld): "
+ "VG_(thread_wrapper) called\n",
+ (ULong)tidW);
+
+ /* Run the thread all the way through. */
+ VgSchedReturnCode src = VG_(thread_wrapper)(tid);
+
+ VG_(debugLog)(1, "syscalls-ppc32-linux",
+ "run_a_thread_NORETURN(tid=%lld): "
+ "VG_(thread_wrapper) done\n",
+ (ULong)tidW);
+
+ Int c = VG_(count_living_threads)();
+ vg_assert(c >= 1); /* stay sane */
+
+ if (c == 1) {
+
+ VG_(debugLog)(1, "syscalls-ppc32-linux",
+ "run_a_thread_NORETURN(tid=%lld): "
+ "last one standing\n",
+ (ULong)tidW);
+
+ /* We are the last one standing. Keep hold of the lock and
+ carry on to show final tool results, then exit the entire system. */
+ VG_(shutdown_actions_NORETURN)(tid, src);
+
+ } else {
+ VG_(debugLog)(1, "syscalls-ppc32-linux",
+ "run_a_thread_NORETURN(tid=%lld): "
+ "not last one standing\n",
+ (ULong)tidW);
+
+ /* OK, thread is dead, but others still exist. Just exit. */
+ ThreadState *tst = VG_(get_ThreadState)(tid);
+
+ /* This releases the run lock */
+ VG_(exit_thread)(tid);
+ vg_assert(tst->status == VgTs_Zombie);
+
+ /* We have to use this sequence to terminate the thread to
+ prevent a subtle race. If VG_(exit_thread)() had left the
+ ThreadState as Empty, then it could have been reallocated,
+ reusing the stack while we're doing these last cleanups.
+ Instead, VG_(exit_thread) leaves it as Zombie to prevent
+ reallocation. We need to make sure we don't touch the stack
+ between marking it Empty and exiting. Hence the
+ assembler. */
+
+ asm volatile (
+ "stw %1,%0\n\t" /* set tst->status = VgTs_Empty */
+ "li 0,%2\n\t" /* set r0 = __NR_exit */
+ "lwz 3,%3\n\t" /* set r3 = tst->os_state.exitcode */
+ "sc\n\t" /* exit(tst->os_state.exitcode) */
+ : "=m" (tst->status)
+ : "n" (VgTs_Empty), "n" (__NR_exit), "m" (tst->os_state.exitcode));
+
+ VG_(core_panic)("Thread exit failed?\n");
+ }
+
+ /*NOTREACHED*/
+ vg_assert(0);
+}
+
+
+/* Call f(arg1), but first switch stacks, using 'stack' as the new
+ stack, and use 'retaddr' as f's return-to address. Also, clear all
+ the integer registers before entering f.*/
+__attribute__((noreturn))
+void call_on_new_stack_0_1 ( Addr stack,
+ Addr retaddr,
+ void (*f)(Word),
+ Word arg1 );
+// r3 = stack
+// r4 = retaddr
+// r5 = f
+// r6 = arg1
+asm(
+"call_on_new_stack_0_1:\n"
+" mr %r1,%r3\n\t" // stack to %sp
+" mtlr %r4\n\t" // retaddr to %lr
+" mtctr %r5\n\t" // f to count reg
+" mr %r3,%r6\n\t" // arg1 to %r3
+" li 0,0\n\t" // zero all GP regs
+" li 4,0\n\t"
+" li 5,0\n\t"
+" li 6,0\n\t"
+" li 7,0\n\t"
+" li 8,0\n\t"
+" li 9,0\n\t"
+" li 10,0\n\t"
+" li 11,0\n\t"
+" li 12,0\n\t"
+" li 13,0\n\t"
+" li 14,0\n\t"
+" li 15,0\n\t"
+" li 16,0\n\t"
+" li 17,0\n\t"
+" li 18,0\n\t"
+" li 19,0\n\t"
+" li 20,0\n\t"
+" li 21,0\n\t"
+" li 22,0\n\t"
+" li 23,0\n\t"
+" li 24,0\n\t"
+" li 25,0\n\t"
+" li 26,0\n\t"
+" li 27,0\n\t"
+" li 28,0\n\t"
+" li 29,0\n\t"
+" li 30,0\n\t"
+" li 31,0\n\t"
+" mtxer 0\n\t" // CAB: Need this?
+" mtcr 0\n\t" // CAB: Need this?
+" bctr\n\t" // jump to dst
+" trap\n" // should never get here
+);
+
+
+/*
+ Allocate a stack for the main thread, and run it all the way to the
+ end.
+ */
+void VGP_(main_thread_wrapper_NORETURN)(ThreadId tid)
+{
+ VG_(debugLog)(1, "syscalls-ppc32-linux",
+ "entering VGP_(main_thread_wrapper_NORETURN)\n");
+
+ UWord* sp = allocstack(tid);
+
+ /* make a stack frame */
+ sp -= 16;
+ *(UWord *)sp = 0;
+
+ /* shouldn't be any other threads around yet */
+ vg_assert( VG_(count_living_threads)() == 1 );
+
+ call_on_new_stack_0_1(
+ (Addr)sp, /* stack */
+ 0, /*bogus return address*/
+ run_a_thread_NORETURN, /* fn to call */
+ (Word)tid /* arg to give it */
+ );
+
+ /*NOTREACHED*/
+ vg_assert(0);
+}
+
+#if 0
+static Int start_thread_NORETURN ( void* arg )
+{
+ ThreadState* tst = (ThreadState*)arg;
+ ThreadId tid = tst->tid;
+
+ run_a_thread_NORETURN ( (Word)tid );
+ /*NOTREACHED*/
+ vg_assert(0);
+}
+#endif
+
+/* ---------------------------------------------------------------------
+ clone() handling
+ ------------------------------------------------------------------ */
+
+/*
+ Perform a clone system call. clone is strange because it has
+ fork()-like return-twice semantics, so it needs special
+ handling here.
+
+ Upon entry, we have:
+
+ int (fn)(void*) in r3
+ void* child_stack in r4
+ int flags in r5
+ void* arg in r6
+ pid_t* child_tid in r7
+ pid_t* parent_tid in r8
+ void* tls_ptr in r9
+
+ System call requires:
+
+ int $__NR_clone in r0 (sc number)
+ int flags in r3 (sc arg1)
+ void* child_stack in r4 (sc arg2)
+ pid_t* parent_tid in r5 (sc arg3)
+ pid_t* child_tid in r6 (sc arg4)
+ void* tls_ptr in r7 (sc arg5)
+
+ Returns an Int encoded in the linux-ppc32 way, not a SysRes.
+ */
+#define STRINGIFZ(__str) #__str
+#define STRINGIFY(__str) STRINGIFZ(__str)
+#define __NR_CLONE STRINGIFY(__NR_clone)
+#define __NR_EXIT STRINGIFY(__NR_exit)
+
+extern
+ULong do_syscall_clone_ppc32_linux ( Int (*fn)(void *),
+ void* stack,
+ Int flags,
+ void* arg,
+ Int* child_tid,
+ Int* parent_tid,
+ vki_modify_ldt_t * );
+asm(
+"\n"
+"do_syscall_clone_ppc32_linux:\n"
+" stwu 1,-32(1)\n"
+" stw 29,20(1)\n"
+" stw 30,24(1)\n"
+" stw 31,28(1)\n"
+" mr 30,3\n" // preserve fn
+" mr 31,6\n" // preserve arg
+
+ // setup child stack
+" rlwinm 4,4,0,~0xf\n" // trim sp to multiple of 16 bytes
+" li 0,0\n"
+" stwu 0,-16(4)\n" // make initial stack frame
+" mr 29,4\n" // preserve sp
+
+ // setup syscall
+" li 0,"__NR_CLONE"\n" // syscall number
+" mr 3,5\n" // syscall arg1: flags
+ // r4 already setup // syscall arg2: child_stack
+" mr 5,8\n" // syscall arg3: parent_tid
+" mr 6,7\n" // syscall arg4: child_tid
+" mr 7,9\n" // syscall arg5: tls_ptr
+
+" sc\n" // clone()
+
+" mfcr 4\n" // return CR in r4 (low word of ULong)
+" cmpwi 3,0\n" // child if retval == 0
+" bne 1f\n" // jump if !child
+
+ /* CHILD - call thread function */
+ /* Note: 2.4 kernel doesn't set the child stack pointer,
+ so we do it here.
+ That does leave a small window for a signal to be delivered
+ on the wrong stack, unfortunately. */
+" mr 1,29\n"
+" mtctr 30\n" // ctr reg = fn
+" mr 3,31\n" // r3 = arg
+" bctrl\n" // call fn()
+
+ // exit with result
+" li 0,"__NR_EXIT"\n"
+" sc\n"
+
+ // Exit returned?!
+" .long 0\n"
+
+ // PARENT or ERROR - return
+"1: lwz 29,20(1)\n"
+" lwz 30,24(1)\n"
+" lwz 31,28(1)\n"
+" addi 1,1,32\n"
+" blr\n"
+);
+
+#undef __NR_CLONE
+#undef __NR_EXIT
+#undef STRINGIFY
+#undef STRINGIFZ
+
+// forward declarations
+//.. static void setup_child ( ThreadArchState*, ThreadArchState*, Bool );
+//.. static SysRes sys_set_thread_area ( ThreadId, vki_modify_ldt_t* );
+
+/*
+ When a client clones, we need to keep track of the new thread. This means:
+ 1. allocate a ThreadId+ThreadState+stack for the the thread
+
+ 2. initialize the thread's new VCPU state
+
+ 3. create the thread using the same args as the client requested,
+ but using the scheduler entrypoint for IP, and a separate stack
+ for SP.
+ */
+//.. static SysRes do_clone ( ThreadId ptid,
+//.. UInt flags, Addr esp,
+//.. Int *parent_tidptr,
+//.. Int *child_tidptr,
+//.. vki_modify_ldt_t *tlsinfo)
+//.. {
+//.. static const Bool debug = False;
+//..
+//.. ThreadId ctid = VG_(alloc_ThreadState)();
+//.. ThreadState *ptst = VG_(get_ThreadState)(ptid);
+//.. ThreadState *ctst = VG_(get_ThreadState)(ctid);
+//.. UWord *stack;
+//.. Segment *seg;
+//.. Int ret;
+//.. vki_sigset_t blockall, savedmask;
+//..
+//.. VG_(sigfillset)(&blockall);
+//..
+//.. vg_assert(VG_(is_running_thread)(ptid));
+//.. vg_assert(VG_(is_valid_tid)(ctid));
+//..
+//.. stack = allocstack(ctid);
+
+//? /* make a stack frame */
+//? stack -= 16;
+//? *(UWord *)stack = 0;
+
+//..
+//.. /* Copy register state
+//..
+//.. Both parent and child return to the same place, and the code
+//.. following the clone syscall works out which is which, so we
+//.. don't need to worry about it.
+//..
+//.. The parent gets the child's new tid returned from clone, but the
+//.. child gets 0.
+//..
+//.. If the clone call specifies a NULL esp for the new thread, then
+//.. it actually gets a copy of the parent's esp.
+//.. */
+//.. VGA_(setup_child)( &ctst->arch, &ptst->arch );
+//..
+//.. /* Make sys_clone appear to have returned Success(0) in the
+//.. child. */
+//.. ctst->arch.vex.guest_GPR3 = 0;
+//..
+//.. //guest_CC_OP = 1
+//.. //guest_CC_DEP1 = 0x20000000
+//..
+//.. if (esp != 0)
+//.. ctst->arch.vex.guest_ESP = esp;
+//..
+//.. ctst->os_state.parent = ptid;
+//.. ctst->os_state.clone_flags = flags;
+//.. ctst->os_state.parent_tidptr = parent_tidptr;
+//.. ctst->os_state.child_tidptr = child_tidptr;
+//..
+//.. /* inherit signal mask */
+//.. ctst->sig_mask = ptst->sig_mask;
+//.. ctst->tmp_sig_mask = ptst->sig_mask;
+//..
+//.. /* We don't really know where the client stack is, because its
+//.. allocated by the client. The best we can do is look at the
+//.. memory mappings and try to derive some useful information. We
+//.. assume that esp starts near its highest possible value, and can
+//.. only go down to the start of the mmaped segment. */
+//.. seg = VG_(find_segment)((Addr)esp);
+//.. if (seg) {
+//.. ctst->client_stack_highest_word = (Addr)PGROUNDUP(esp);
+//.. ctst->client_stack_szB = ctst->client_stack_highest_word - seg->addr;
+//..
+//.. if (debug)
+//.. VG_(printf)("tid %d: guessed client stack range %p-%p\n",
+//.. ctid, seg->addr, PGROUNDUP(esp));
+//.. } else {
+//.. VG_(message)(Vg_UserMsg, "!? New thread %d starts with ESP(%p) unmapped\n",
+//.. ctid, esp);
+//.. ctst->client_stack_szB = 0;
+//.. }
+//..
+//.. if (flags & VKI_CLONE_SETTLS) {
+//.. if (debug)
+//.. VG_(printf)("clone child has SETTLS: tls info at %p: idx=%d base=%p limit=%x; esp=%p fs=%x gs=%x\n",
+//.. tlsinfo, tlsinfo->entry_number, tlsinfo->base_addr, tlsinfo->limit,
+//.. ptst->arch.vex.guest_ESP,
+//.. ctst->arch.vex.guest_FS, ctst->arch.vex.guest_GS);
+//.. ret = VG_(sys_set_thread_area)(ctid, tlsinfo);
+//..
+//.. if (ret != 0)
+//.. goto out;
+//.. }
+//..
+//.. flags &= ~VKI_CLONE_SETTLS;
+//..
+//.. /* start the thread with everything blocked */
+//.. VG_(sigprocmask)(VKI_SIG_SETMASK, &blockall, &savedmask);
+//..
+//.. /* Create the new thread */
+//.. ret = VG_(clone)(start_thread, stack, flags, &VG_(threads)[ctid],
+//.. child_tidptr, parent_tidptr, NULL);
+//..
+//.. VG_(sigprocmask)(VKI_SIG_SETMASK, &savedmask, NULL);
+//..
+//.. out:
+//.. if (ret < 0) {
+//.. /* clone failed */
+//.. VGA_(cleanup_thread)(&ctst->arch);
+//.. ctst->status = VgTs_Empty;
+//.. }
+//..
+//.. return ret;
+//.. }
+
+
+/* Do a clone which is really a fork() */
+//.. static Int do_fork_clone( ThreadId tid,
+//.. UInt flags, Addr esp,
+//.. Int* parent_tidptr,
+//.. Int* child_tidptr )
+//.. {
+//.. vki_sigset_t fork_saved_mask;
+//.. vki_sigset_t mask;
+//.. Int ret;
+//..
+//.. if (flags & (VKI_CLONE_SETTLS | VKI_CLONE_FS | VKI_CLONE_VM | VKI_CLONE_FILES | VKI_CLONE_VFORK))
+//.. return -VKI_EINVAL;
+//..
+//.. /* Block all signals during fork, so that we can fix things up in
+//.. the child without being interrupted. */
+//.. VG_(sigfillset)(&mask);
+//.. VG_(sigprocmask)(VKI_SIG_SETMASK, &mask, &fork_saved_mask);
+//..
+//.. VG_(do_atfork_pre)(tid);
+//..
+//.. /* Since this is the fork() form of clone, we don't need all that
+//.. VG_(clone) stuff */
+//.. ret = VG_(do_syscall5)(__NR_clone, flags, (UWord)NULL, (UWord)parent_tidptr,
+//.. (UWord)NULL, (UWord)child_tidptr);
+//..
+//.. if (ret == 0) {
+//.. /* child */
+//.. VG_(do_atfork_child)(tid);
+//..
+//.. /* restore signal mask */
+//.. VG_(sigprocmask)(VKI_SIG_SETMASK, &fork_saved_mask, NULL);
+//.. } else if (ret > 0) {
+//.. /* parent */
+//.. if (VG_(clo_trace_syscalls))
+//.. VG_(printf)(" clone(fork): process %d created child %d\n", VG_(getpid)(), ret);
+//..
+//.. VG_(do_atfork_parent)(tid);
+//..
+//.. /* restore signal mask */
+//.. VG_(sigprocmask)(VKI_SIG_SETMASK, &fork_saved_mask, NULL);
+//.. }
+//..
+//.. return ret;
+//.. }
+
+
+
+
+/* ---------------------------------------------------------------------
+ LDT/GDT simulation
+ ------------------------------------------------------------------ */
+
+/* Details of the LDT simulation
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ When a program runs natively, the linux kernel allows each *thread*
+ in it to have its own LDT. Almost all programs never do this --
+ it's wildly unportable, after all -- and so the kernel never
+ allocates the structure, which is just as well as an LDT occupies
+ 64k of memory (8192 entries of size 8 bytes).
+
+ A thread may choose to modify its LDT entries, by doing the
+ __NR_modify_ldt syscall. In such a situation the kernel will then
+ allocate an LDT structure for it. Each LDT entry is basically a
+ (base, limit) pair. A virtual address in a specific segment is
+ translated to a linear address by adding the segment's base value.
+ In addition, the virtual address must not exceed the limit value.
+
+ To use an LDT entry, a thread loads one of the segment registers
+ (%cs, %ss, %ds, %es, %fs, %gs) with the index of the LDT entry (0
+ .. 8191) it wants to use. In fact, the required value is (index <<
+ 3) + 7, but that's not important right now. Any normal instruction
+ which includes an addressing mode can then be made relative to that
+ LDT entry by prefixing the insn with a so-called segment-override
+ prefix, a byte which indicates which of the 6 segment registers
+ holds the LDT index.
+
+ Now, a key constraint is that valgrind's address checks operate in
+ terms of linear addresses. So we have to explicitly translate
+ virtual addrs into linear addrs, and that means doing a complete
+ LDT simulation.
+
+ Calls to modify_ldt are intercepted. For each thread, we maintain
+ an LDT (with the same normally-never-allocated optimisation that
+ the kernel does). This is updated as expected via calls to
+ modify_ldt.
+
+ When a thread does an amode calculation involving a segment
+ override prefix, the relevant LDT entry for the thread is
+ consulted. It all works.
+
+ There is a conceptual problem, which appears when switching back to
+ native execution, either temporarily to pass syscalls to the
+ kernel, or permanently, when debugging V. Problem at such points
+ is that it's pretty pointless to copy the simulated machine's
+ segment registers to the real machine, because we'd also need to
+ copy the simulated LDT into the real one, and that's prohibitively
+ expensive.
+
+ Fortunately it looks like no syscalls rely on the segment regs or
+ LDT being correct, so we can get away with it. Apart from that the
+ simulation is pretty straightforward. All 6 segment registers are
+ tracked, although only %ds, %es, %fs and %gs are allowed as
+ prefixes. Perhaps it could be restricted even more than that -- I
+ am not sure what is and isn't allowed in user-mode.
+*/
+
+//.. /* Translate a struct modify_ldt_ldt_s to a VexGuestX86SegDescr, using
+//.. the Linux kernel's logic (cut-n-paste of code in
+//.. linux/kernel/ldt.c). */
+//..
+//.. static
+//.. void translate_to_hw_format ( /* IN */ vki_modify_ldt_t* inn,
+//.. /* OUT */ VexGuestX86SegDescr* out,
+//.. Int oldmode )
+//.. {
+//.. UInt entry_1, entry_2;
+//.. vg_assert(8 == sizeof(VexGuestX86SegDescr));
+//..
+//.. if (0)
+//.. VG_(printf)("translate_to_hw_format: base %p, limit %d\n",
+//.. inn->base_addr, inn->limit );
+//..
+//.. /* Allow LDTs to be cleared by the user. */
+//.. if (inn->base_addr == 0 && inn->limit == 0) {
+//.. if (oldmode ||
+//.. (inn->contents == 0 &&
+//.. inn->read_exec_only == 1 &&
+//.. inn->seg_32bit == 0 &&
+//.. inn->limit_in_pages == 0 &&
+//.. inn->seg_not_present == 1 &&
+//.. inn->useable == 0 )) {
+//.. entry_1 = 0;
+//.. entry_2 = 0;
+//.. goto install;
+//.. }
+//.. }
+//..
+//.. entry_1 = ((inn->base_addr & 0x0000ffff) << 16) |
+//.. (inn->limit & 0x0ffff);
+//.. entry_2 = (inn->base_addr & 0xff000000) |
+//.. ((inn->base_addr & 0x00ff0000) >> 16) |
+//.. (inn->limit & 0xf0000) |
+//.. ((inn->read_exec_only ^ 1) << 9) |
+//.. (inn->contents << 10) |
+//.. ((inn->seg_not_present ^ 1) << 15) |
+//.. (inn->seg_32bit << 22) |
+//.. (inn->limit_in_pages << 23) |
+//.. 0x7000;
+//.. if (!oldmode)
+//.. entry_2 |= (inn->useable << 20);
+//..
+//.. /* Install the new entry ... */
+//.. install:
+//.. out->LdtEnt.Words.word1 = entry_1;
+//.. out->LdtEnt.Words.word2 = entry_2;
+//.. }
+//..
+//..
+//.. /*
+//.. * linux/kernel/ldt.c
+//.. *
+//.. * Copyright (C) 1992 Krishna Balasubramanian and Linus Torvalds
+//.. * Copyright (C) 1999 Ingo Molnar <mingo@redhat.com>
+//.. */
+//..
+//.. /*
+//.. * read_ldt() is not really atomic - this is not a problem since
+//.. * synchronization of reads and writes done to the LDT has to be
+//.. * assured by user-space anyway. Writes are atomic, to protect
+//.. * the security checks done on new descriptors.
+//.. */
+//.. static
+//.. Int read_ldt ( ThreadId tid, UChar* ptr, UInt bytecount )
+//.. {
+//.. Int err;
+//.. UInt i, size;
+//.. UChar* ldt;
+//..
+//.. if (0)
+//.. VG_(printf)("read_ldt: tid = %d, ptr = %p, bytecount = %d\n",
+//.. tid, ptr, bytecount );
+//..
+//.. vg_assert(sizeof(HWord) == sizeof(VexGuestX86SegDescr*));
+//.. vg_assert(8 == sizeof(VexGuestX86SegDescr));
+//..
+//.. ldt = (Char*)(VG_(threads)[tid].arch.vex.guest_LDT);
+//.. err = 0;
+//.. if (ldt == NULL)
+//.. /* LDT not allocated, meaning all entries are null */
+//.. goto out;
+//..
+//.. size = VEX_GUEST_X86_LDT_NENT * sizeof(VexGuestX86SegDescr);
+//.. if (size > bytecount)
+//.. size = bytecount;
+//..
+//.. err = size;
+//.. for (i = 0; i < size; i++)
+//.. ptr[i] = ldt[i];
+//..
+//.. out:
+//.. return err;
+//.. }
+//..
+//..
+//.. static
+//.. Int write_ldt ( ThreadId tid, void* ptr, UInt bytecount, Int oldmode )
+//.. {
+//.. Int error;
+//.. VexGuestX86SegDescr* ldt;
+//.. vki_modify_ldt_t* ldt_info;
+//..
+//.. if (0)
+//.. VG_(printf)("write_ldt: tid = %d, ptr = %p, "
+//.. "bytecount = %d, oldmode = %d\n",
+//.. tid, ptr, bytecount, oldmode );
+//..
+//.. vg_assert(8 == sizeof(VexGuestX86SegDescr));
+//.. vg_assert(sizeof(HWord) == sizeof(VexGuestX86SegDescr*));
+//..
+//.. ldt = (VexGuestX86SegDescr*)VG_(threads)[tid].arch.vex.guest_LDT;
+//.. ldt_info = (vki_modify_ldt_t*)ptr;
+//..
+//.. error = -VKI_EINVAL;
+//.. if (bytecount != sizeof(vki_modify_ldt_t))
+//.. goto out;
+//..
+//.. error = -VKI_EINVAL;
+//.. if (ldt_info->entry_number >= VEX_GUEST_X86_LDT_NENT)
+//.. goto out;
+//.. if (ldt_info->contents == 3) {
+//.. if (oldmode)
+//.. goto out;
+//.. if (ldt_info->seg_not_present == 0)
+//.. goto out;
+//.. }
+//..
+//.. /* If this thread doesn't have an LDT, we'd better allocate it
+//.. now. */
+//.. if (ldt == (HWord)NULL) {
+//.. ldt = VG_(alloc_zeroed_x86_LDT)();
+//.. VG_(threads)[tid].arch.vex.guest_LDT = (HWord)ldt;
+//.. }
+//..
+//.. /* Install the new entry ... */
+//.. translate_to_hw_format ( ldt_info, &ldt[ldt_info->entry_number], oldmode );
+//.. error = 0;
+//..
+//.. out:
+//.. return error;
+//.. }
+//..
+//..
+//.. Int VG_(sys_modify_ldt) ( ThreadId tid,
+//.. Int func, void* ptr, UInt bytecount )
+//.. {
+//.. Int ret = -VKI_ENOSYS;
+//..
+//.. switch (func) {
+//.. case 0:
+//.. ret = read_ldt(tid, ptr, bytecount);
+//.. break;
+//.. case 1:
+//.. ret = write_ldt(tid, ptr, bytecount, 1);
+//.. break;
+//.. case 2:
+//.. VG_(unimplemented)("sys_modify_ldt: func == 2");
+//.. /* god knows what this is about */
+//.. /* ret = read_default_ldt(ptr, bytecount); */
+//.. /*UNREACHED*/
+//.. break;
+//.. case 0x11:
+//.. ret = write_ldt(tid, ptr, bytecount, 0);
+//.. break;
+//.. }
+//.. return ret;
+//.. }
+//..
+//..
+//.. Int VG_(sys_set_thread_area) ( ThreadId tid,
+//.. vki_modify_ldt_t* info )
+//.. {
+//.. Int idx;
+//.. VexGuestX86SegDescr* gdt;
+//..
+//.. vg_assert(8 == sizeof(VexGuestX86SegDescr));
+//.. vg_assert(sizeof(HWord) == sizeof(VexGuestX86SegDescr*));
+//..
+//.. if (info == NULL)
+//.. return -VKI_EFAULT;
+//..
+//.. gdt = (VexGuestX86SegDescr*)VG_(threads)[tid].arch.vex.guest_GDT;
+//..
+//.. /* If the thread doesn't have a GDT, allocate it now. */
+//.. if (!gdt) {
+//.. gdt = VG_(alloc_zeroed_x86_GDT)();
+//.. VG_(threads)[tid].arch.vex.guest_GDT = (HWord)gdt;
+//.. }
+//..
+//.. idx = info->entry_number;
+//..
+//.. if (idx == -1) {
+//.. /* Find and use the first free entry. */
+//.. for (idx = 0; idx < VEX_GUEST_X86_GDT_NENT; idx++) {
+//.. if (gdt[idx].LdtEnt.Words.word1 == 0
+//.. && gdt[idx].LdtEnt.Words.word2 == 0)
+//.. break;
+//.. }
+//..
+//.. if (idx == VEX_GUEST_X86_GDT_NENT)
+//.. return -VKI_ESRCH;
+//.. } else if (idx < 0 || idx >= VEX_GUEST_X86_GDT_NENT) {
+//.. return -VKI_EINVAL;
+//.. }
+//..
+//.. translate_to_hw_format(info, &gdt[idx], 0);
+//..
+//.. VG_TRACK( pre_mem_write, Vg_CoreSysCall, tid,
+//.. "set_thread_area(info->entry)",
+//.. (Addr) & info->entry_number, sizeof(unsigned int) );
+//.. info->entry_number = idx;
+//.. VG_TRACK( post_mem_write, Vg_CoreSysCall, tid,
+//.. (Addr) & info->entry_number, sizeof(unsigned int) );
+//..
+//.. return 0;
+//.. }
+//..
+//..
+//.. Int VG_(sys_get_thread_area) ( ThreadId tid,
+//.. vki_modify_ldt_t* info )
+//.. {
+//.. Int idx;
+//.. VexGuestX86SegDescr* gdt;
+//..
+//.. vg_assert(sizeof(HWord) == sizeof(VexGuestX86SegDescr*));
+//.. vg_assert(8 == sizeof(VexGuestX86SegDescr));
+//..
+//.. if (info == NULL)
+//.. return -VKI_EFAULT;
+//..
+//.. idx = info->entry_number;
+//..
+//.. if (idx < 0 || idx >= VEX_GUEST_X86_GDT_NENT)
+//.. return -VKI_EINVAL;
+//..
+//.. gdt = (VexGuestX86SegDescr*)VG_(threads)[tid].arch.vex.guest_GDT;
+//..
+//.. /* If the thread doesn't have a GDT, allocate it now. */
+//.. if (!gdt) {
+//.. gdt = VG_(alloc_zeroed_x86_GDT)();
+//.. VG_(threads)[tid].arch.vex.guest_GDT = (HWord)gdt;
+//.. }
+//..
+//.. info->base_addr = ( gdt[idx].LdtEnt.Bits.BaseHi << 24 ) |
+//.. ( gdt[idx].LdtEnt.Bits.BaseMid << 16 ) |
+//.. gdt[idx].LdtEnt.Bits.BaseLow;
+//.. info->limit = ( gdt[idx].LdtEnt.Bits.LimitHi << 16 ) |
+//.. gdt[idx].LdtEnt.Bits.LimitLow;
+//.. info->seg_32bit = gdt[idx].LdtEnt.Bits.Default_Big;
+//.. info->contents = ( gdt[idx].LdtEnt.Bits.Type >> 2 ) & 0x3;
+//.. info->read_exec_only = ( gdt[idx].LdtEnt.Bits.Type & 0x1 ) ^ 0x1;
+//.. info->limit_in_pages = gdt[idx].LdtEnt.Bits.Granularity;
+//.. info->seg_not_present = gdt[idx].LdtEnt.Bits.Pres ^ 0x1;
+//.. info->useable = gdt[idx].LdtEnt.Bits.Sys;
+//.. info->reserved = 0;
+//..
+//.. return 0;
+//.. }
+
+
+
+/* ---------------------------------------------------------------------
+ More thread stuff
+ ------------------------------------------------------------------ */
+
+void VGP_(cleanup_thread) ( ThreadArchState* arch )
+{
+//.. /* Release arch-specific resources held by this thread. */
+//.. /* On x86, we have to dump the LDT and GDT. */
+//.. deallocate_LGDTs_for_thread( &arch->vex );
+}
+
+
+//.. void VGA_(setup_child) ( /*OUT*/ ThreadArchState *child,
+//.. /*IN*/ ThreadArchState *parent )
+//.. {
+//.. /* We inherit our parent's guest state. */
+//.. child->vex = parent->vex;
+//.. child->vex_shadow = parent->vex_shadow;
+//.. /* We inherit our parent's LDT. */
+//.. if (parent->vex.guest_LDT == (HWord)NULL) {
+//.. /* We hope this is the common case. */
+//.. child->vex.guest_LDT = (HWord)NULL;
+//.. } else {
+//.. /* No luck .. we have to take a copy of the parent's. */
+//.. child->vex.guest_LDT = (HWord)VG_(alloc_zeroed_x86_LDT)();
+//.. copy_LDT_from_to( (VexGuestX86SegDescr*)parent->vex.guest_LDT,
+//.. (VexGuestX86SegDescr*)child->vex.guest_LDT );
+//.. }
+//..
+//.. /* We need an empty GDT. */
+//.. child->vex.guest_GDT = (HWord)NULL;
+//.. }
+
+
+
+/* ---------------------------------------------------------------------
+ PRE/POST wrappers for ppc32/Linux-specific syscalls
+ ------------------------------------------------------------------ */
+
+#define PRE(name) DEFN_PRE_TEMPLATE(ppc32_linux, name)
+#define POST(name) DEFN_POST_TEMPLATE(ppc32_linux, name)
+
+/* Add prototypes for the wrappers declared here, so that gcc doesn't
+ harass us for not having prototypes. Really this is a kludge --
+ the right thing to do is to make these wrappers 'static' since they
+ aren't visible outside this file, but that requires even more macro
+ magic. */
+
+DECL_TEMPLATE(ppc32_linux, sys_stat64);
+DECL_TEMPLATE(ppc32_linux, sys_fstat64);
+
+// XXX: lstat64/fstat64/stat64 are generic, but not necessarily
+// applicable to every architecture -- I think only to 32-bit archs.
+// We're going to need something like linux/core_os32.h for such
+// things, eventually, I think. --njn
+PRE(sys_stat64)
+{
+ PRINT("sys_stat64 ( %p, %p )",ARG1,ARG2);
+ PRE_REG_READ2(long, "stat64", char *, file_name, struct stat64 *, buf);
+ PRE_MEM_RASCIIZ( "stat64(file_name)", ARG1 );
+ PRE_MEM_WRITE( "stat64(buf)", ARG2, sizeof(struct vki_stat64) );
+}
+
+POST(sys_stat64)
+{
+ POST_MEM_WRITE( ARG2, sizeof(struct vki_stat64) );
+}
+
+PRE(sys_fstat64)
+{
+ PRINT("sys_fstat64 ( %d, %p )",ARG1,ARG2);
+ PRE_REG_READ2(long, "fstat64", unsigned long, fd, struct stat64 *, buf);
+ PRE_MEM_WRITE( "fstat64(buf)", ARG2, sizeof(struct vki_stat64) );
+}
+POST(sys_fstat64)
+{
+ POST_MEM_WRITE( ARG2, sizeof(struct vki_stat64) );
+}
+
+
+
+//.. PRE(old_select, MayBlock)
+//.. {
+//.. /* struct sel_arg_struct {
+//.. unsigned long n;
+//.. fd_set *inp, *outp, *exp;
+//.. struct timeval *tvp;
+//.. };
+//.. */
+//.. PRE_REG_READ1(long, "old_select", struct sel_arg_struct *, args);
+//.. PRE_MEM_READ( "old_select(args)", ARG1, 5*sizeof(UWord) );
+//..
+//.. {
+//.. UInt* arg_struct = (UInt*)ARG1;
+//.. UInt a1, a2, a3, a4, a5;
+//..
+//.. a1 = arg_struct[0];
+//.. a2 = arg_struct[1];
+//.. a3 = arg_struct[2];
+//.. a4 = arg_struct[3];
+//.. a5 = arg_struct[4];
+//..
+//.. PRINT("old_select ( %d, %p, %p, %p, %p )", a1,a2,a3,a4,a5);
+//.. if (a2 != (Addr)NULL)
+//.. PRE_MEM_READ( "old_select(readfds)", a2, a1/8 /* __FD_SETSIZE/8 */ );
+//.. if (a3 != (Addr)NULL)
+//.. PRE_MEM_READ( "old_select(writefds)", a3, a1/8 /* __FD_SETSIZE/8 */ );
+//.. if (a4 != (Addr)NULL)
+//.. PRE_MEM_READ( "old_select(exceptfds)", a4, a1/8 /* __FD_SETSIZE/8 */ );
+//.. if (a5 != (Addr)NULL)
+//.. PRE_MEM_READ( "old_select(timeout)", a5, sizeof(struct vki_timeval) );
+//.. }
+//.. }
+
+//.. PRE(sys_clone, Special)
+//.. {
+//.. UInt cloneflags;
+//..
+//.. PRINT("sys_clone ( %x, %p, %p, %p, %p )",ARG1,ARG2,ARG3,ARG4,ARG5);
+//.. PRE_REG_READ5(int, "clone",
+//.. unsigned long, flags,
+//.. void *, child_stack,
+//.. int *, parent_tidptr,
+//.. vki_modify_ldt_t *, tlsinfo,
+//.. int *, child_tidptr);
+//..
+//.. if (ARG1 & VKI_CLONE_PARENT_SETTID) {
+//.. PRE_MEM_WRITE("clone(parent_tidptr)", ARG3, sizeof(Int));
+//.. if (!VG_(is_addressable)(ARG3, sizeof(Int), VKI_PROT_WRITE)) {
+//.. SET_RESULT( -VKI_EFAULT );
+//.. return;
+//.. }
+//.. }
+//.. if (ARG1 & (VKI_CLONE_CHILD_SETTID | VKI_CLONE_CHILD_CLEARTID)) {
+//.. PRE_MEM_WRITE("clone(child_tidptr)", ARG5, sizeof(Int));
+//.. if (!VG_(is_addressable)(ARG5, sizeof(Int), VKI_PROT_WRITE)) {
+//.. SET_RESULT( -VKI_EFAULT );
+//.. return;
+//.. }
+//.. }
+//.. if (ARG1 & VKI_CLONE_SETTLS) {
+//.. PRE_MEM_READ("clone(tls_user_desc)", ARG4, sizeof(vki_modify_ldt_t));
+//.. if (!VG_(is_addressable)(ARG4, sizeof(vki_modify_ldt_t), VKI_PROT_READ)) {
+//.. SET_RESULT( -VKI_EFAULT );
+//.. return;
+//.. }
+//.. }
+//..
+//.. cloneflags = ARG1;
+//..
+//.. if (!VG_(client_signal_OK)(ARG1 & VKI_CSIGNAL)) {
+//.. SET_RESULT( -VKI_EINVAL );
+//.. return;
+//.. }
+//..
+//.. /* Only look at the flags we really care about */
+//.. switch(cloneflags & (VKI_CLONE_VM | VKI_CLONE_FS | VKI_CLONE_FILES | VKI_CLONE_VFORK)) {
+//.. case VKI_CLONE_VM | VKI_CLONE_FS | VKI_CLONE_FILES:
+//.. /* thread creation */
+//.. SET_RESULT(do_clone(tid,
+//.. ARG1, /* flags */
+//.. (Addr)ARG2, /* child ESP */
+//.. (Int *)ARG3, /* parent_tidptr */
+//.. (Int *)ARG5, /* child_tidptr */
+//.. (vki_modify_ldt_t *)ARG4)); /* set_tls */
+//.. break;
+//..
+//.. case VKI_CLONE_VFORK | VKI_CLONE_VM: /* vfork */
+//.. /* FALLTHROUGH - assume vfork == fork */
+//.. cloneflags &= ~(VKI_CLONE_VFORK | VKI_CLONE_VM);
+//..
+//.. case 0: /* plain fork */
+//.. SET_RESULT(do_fork_clone(tid,
+//.. cloneflags, /* flags */
+//.. (Addr)ARG2, /* child ESP */
+//.. (Int *)ARG3, /* parent_tidptr */
+//.. (Int *)ARG5)); /* child_tidptr */
+//.. break;
+//..
+//.. default:
+//.. /* should we just ENOSYS? */
+//.. VG_(message)(Vg_UserMsg, "Unsupported clone() flags: %x", ARG1);
+//.. VG_(unimplemented)
+//.. ("Valgrind does not support general clone(). The only supported uses "
+//.. "are via a threads library, fork, or vfork.");
+//.. }
+//..
+//.. if (!VG_(is_kerror)(RES)) {
+//.. if (ARG1 & VKI_CLONE_PARENT_SETTID)
+//.. POST_MEM_WRITE(ARG3, sizeof(Int));
+//.. if (ARG1 & (VKI_CLONE_CHILD_SETTID | VKI_CLONE_CHILD_CLEARTID))
+//.. POST_MEM_WRITE(ARG5, sizeof(Int));
+//..
+//.. /* Thread creation was successful; let the child have the chance
+//.. to run */
+//.. VG_(vg_yield)();
+//.. }
+//.. }
+
+//.. PRE(sys_sigreturn, Special)
+//.. {
+//.. PRINT("sigreturn ( )");
+//..
+//.. /* Adjust esp to point to start of frame; skip back up over
+//.. sigreturn sequence's "popl %eax" and handler ret addr */
+//.. tst->arch.vex.guest_ESP -= sizeof(Addr)+sizeof(Word);
+//..
+//.. /* This is only so that the EIP is (might be) useful to report if
+//.. something goes wrong in the sigreturn */
+//.. VGA_(restart_syscall)(&tst->arch);
+//..
+//.. VG_(sigframe_destroy)(tid, False);
+//..
+//.. /* Keep looking for signals until there are none */
+//.. VG_(poll_signals)(tid);
+//..
+//.. /* placate return-must-be-set assertion */
+//.. SET_RESULT(RES);
+//.. }
+
+//.. PRE(sys_rt_sigreturn, Special)
+//.. {
+//.. PRINT("rt_sigreturn ( )");
+//..
+//.. /* Adjust esp to point to start of frame; skip back up over handler
+//.. ret addr */
+//.. tst->arch.vex.guest_ESP -= sizeof(Addr);
+//..
+//.. /* This is only so that the EIP is (might be) useful to report if
+//.. something goes wrong in the sigreturn */
+//.. VGA_(restart_syscall)(&tst->arch);
+//..
+//.. VG_(sigframe_destroy)(tid, False);
+//..
+//.. /* Keep looking for signals until there are none */
+//.. VG_(poll_signals)(tid);
+//..
+//.. /* placate return-must-be-set assertion */
+//.. SET_RESULT(RES);
+//.. }
+
+//.. PRE(sys_modify_ldt, Special)
+//.. {
+//.. PRINT("sys_modify_ldt ( %d, %p, %d )", ARG1,ARG2,ARG3);
+//.. PRE_REG_READ3(int, "modify_ldt", int, func, void *, ptr,
+//.. unsigned long, bytecount);
+//..
+//.. if (ARG1 == 0) {
+//.. /* read the LDT into ptr */
+//.. PRE_MEM_WRITE( "modify_ldt(ptr)", ARG2, ARG3 );
+//.. }
+//.. if (ARG1 == 1 || ARG1 == 0x11) {
+//.. /* write the LDT with the entry pointed at by ptr */
+//.. PRE_MEM_READ( "modify_ldt(ptr)", ARG2, sizeof(vki_modify_ldt_t) );
+//.. }
+//.. /* "do" the syscall ourselves; the kernel never sees it */
+//.. SET_RESULT( VG_(sys_modify_ldt)( tid, ARG1, (void*)ARG2, ARG3 ) );
+//..
+//.. if (ARG1 == 0 && !VG_(is_kerror)(RES) && RES > 0) {
+//.. POST_MEM_WRITE( ARG2, RES );
+//.. }
+//.. }
+
+//.. PRE(sys_set_thread_area, Special)
+//.. {
+//.. PRINT("sys_set_thread_area ( %p )", ARG1);
+//.. PRE_REG_READ1(int, "set_thread_area", struct user_desc *, u_info)
+//.. PRE_MEM_READ( "set_thread_area(u_info)", ARG1, sizeof(vki_modify_ldt_t) );
+//..
+//.. /* "do" the syscall ourselves; the kernel never sees it */
+//.. SET_RESULT( VG_(sys_set_thread_area)( tid, (void *)ARG1 ) );
+//.. }
+
+//.. PRE(sys_get_thread_area, Special)
+//.. {
+//.. PRINT("sys_get_thread_area ( %p )", ARG1);
+//.. PRE_REG_READ1(int, "get_thread_area", struct user_desc *, u_info)
+//.. PRE_MEM_WRITE( "get_thread_area(u_info)", ARG1, sizeof(vki_modify_ldt_t) );
+//..
+//.. /* "do" the syscall ourselves; the kernel never sees it */
+//.. SET_RESULT( VG_(sys_get_thread_area)( tid, (void *)ARG1 ) );
+//..
+//.. if (!VG_(is_kerror)(RES)) {
+//.. POST_MEM_WRITE( ARG1, sizeof(vki_modify_ldt_t) );
+//.. }
+//.. }
+
+//.. // Parts of this are ppc32-specific, but the *PEEK* cases are generic.
+//.. // XXX: Why is the memory pointed to by ARG3 never checked?
+//.. PRE(sys_ptrace, 0)
+//.. {
+//.. PRINT("sys_ptrace ( %d, %d, %p, %p )", ARG1,ARG2,ARG3,ARG4);
+//.. PRE_REG_READ4(int, "ptrace",
+//.. long, request, long, pid, long, addr, long, data);
+//.. switch (ARG1) {
+//.. case VKI_PTRACE_PEEKTEXT:
+//.. case VKI_PTRACE_PEEKDATA:
+//.. case VKI_PTRACE_PEEKUSR:
+//.. PRE_MEM_WRITE( "ptrace(peek)", ARG4,
+//.. sizeof (long));
+//.. break;
+//.. case VKI_PTRACE_GETREGS:
+//.. PRE_MEM_WRITE( "ptrace(getregs)", ARG4,
+//.. sizeof (struct vki_user_regs_struct));
+//.. break;
+//.. case VKI_PTRACE_GETFPREGS:
+//.. PRE_MEM_WRITE( "ptrace(getfpregs)", ARG4,
+//.. sizeof (struct vki_user_i387_struct));
+//.. break;
+//.. case VKI_PTRACE_GETFPXREGS:
+//.. PRE_MEM_WRITE( "ptrace(getfpxregs)", ARG4,
+//.. sizeof(struct vki_user_fxsr_struct) );
+//.. break;
+//.. case VKI_PTRACE_SETREGS:
+//.. PRE_MEM_READ( "ptrace(setregs)", ARG4,
+//.. sizeof (struct vki_user_regs_struct));
+//.. break;
+//.. case VKI_PTRACE_SETFPREGS:
+//.. PRE_MEM_READ( "ptrace(setfpregs)", ARG4,
+//.. sizeof (struct vki_user_i387_struct));
+//.. break;
+//.. case VKI_PTRACE_SETFPXREGS:
+//.. PRE_MEM_READ( "ptrace(setfpxregs)", ARG4,
+//.. sizeof(struct vki_user_fxsr_struct) );
+//.. break;
+//.. default:
+//.. break;
+//.. }
+//.. }
+
+//.. POST(sys_ptrace)
+//.. {
+//.. switch (ARG1) {
+//.. case VKI_PTRACE_PEEKTEXT:
+//.. case VKI_PTRACE_PEEKDATA:
+//.. case VKI_PTRACE_PEEKUSR:
+//.. POST_MEM_WRITE( ARG4, sizeof (long));
+//.. break;
+//.. case VKI_PTRACE_GETREGS:
+//.. POST_MEM_WRITE( ARG4, sizeof (struct vki_user_regs_struct));
+//.. break;
+//.. case VKI_PTRACE_GETFPREGS:
+//.. POST_MEM_WRITE( ARG4, sizeof (struct vki_user_i387_struct));
+//.. break;
+//.. case VKI_PTRACE_GETFPXREGS:
+//.. POST_MEM_WRITE( ARG4, sizeof(struct vki_user_fxsr_struct) );
+//.. break;
+//.. default:
+//.. break;
+//.. }
+//.. }
+
+//.. // XXX: this duplicates a function in coregrind/vg_syscalls.c, yuk
+//.. static Addr deref_Addr ( ThreadId tid, Addr a, Char* s )
+//.. {
+//.. Addr* a_p = (Addr*)a;
+//.. PRE_MEM_READ( s, (Addr)a_p, sizeof(Addr) );
+//.. return *a_p;
+//.. }
+
+//.. // XXX: should use the constants here (eg. SHMAT), not the numbers directly!
+//.. PRE(sys_ipc, 0)
+//.. {
+//.. PRINT("sys_ipc ( %d, %d, %d, %d, %p, %d )", ARG1,ARG2,ARG3,ARG4,ARG5,ARG6);
+//.. // XXX: this is simplistic -- some args are not used in all circumstances.
+//.. PRE_REG_READ6(int, "ipc",
+//.. vki_uint, call, int, first, int, second, int, third,
+//.. void *, ptr, long, fifth)
+//..
+//.. switch (ARG1 /* call */) {
+//.. case VKI_SEMOP:
+//.. VG_(generic_PRE_sys_semop)( tid, ARG2, ARG5, ARG3 );
+//.. /* tst->sys_flags |= MayBlock; */
+//.. break;
+//.. case VKI_SEMGET:
+//.. break;
+//.. case VKI_SEMCTL:
+//.. {
+//.. UWord arg = deref_Addr( tid, ARG5, "semctl(arg)" );
+//.. VG_(generic_PRE_sys_semctl)( tid, ARG2, ARG3, ARG4, arg );
+//.. break;
+//.. }
+//.. case VKI_SEMTIMEDOP:
+//.. VG_(generic_PRE_sys_semtimedop)( tid, ARG2, ARG5, ARG3, ARG6 );
+//.. /* tst->sys_flags |= MayBlock; */
+//.. break;
+//.. case VKI_MSGSND:
+//.. VG_(generic_PRE_sys_msgsnd)( tid, ARG2, ARG5, ARG3, ARG4 );
+//.. /* if ((ARG4 & VKI_IPC_NOWAIT) == 0)
+//.. tst->sys_flags |= MayBlock;
+//.. */
+//.. break;
+//.. case VKI_MSGRCV:
+//.. {
+//.. Addr msgp;
+//.. Word msgtyp;
+//..
+//.. msgp = deref_Addr( tid,
+//.. (Addr) (&((struct vki_ipc_kludge *)ARG5)->msgp),
+//.. "msgrcv(msgp)" );
+//.. msgtyp = deref_Addr( tid,
+//.. (Addr) (&((struct vki_ipc_kludge *)ARG5)->msgtyp),
+//.. "msgrcv(msgp)" );
+//..
+//.. VG_(generic_PRE_sys_msgrcv)( tid, ARG2, msgp, ARG3, msgtyp, ARG4 );
+//..
+//.. /* if ((ARG4 & VKI_IPC_NOWAIT) == 0)
+//.. tst->sys_flags |= MayBlock;
+//.. */
+//.. break;
+//.. }
+//.. case VKI_MSGGET:
+//.. break;
+//.. case VKI_MSGCTL:
+//.. VG_(generic_PRE_sys_msgctl)( tid, ARG2, ARG3, ARG5 );
+//.. break;
+//.. case VKI_SHMAT:
+//.. PRE_MEM_WRITE( "shmat(raddr)", ARG4, sizeof(Addr) );
+//.. ARG5 = VG_(generic_PRE_sys_shmat)( tid, ARG2, ARG5, ARG3 );
+//.. if (ARG5 == 0)
+//.. SET_RESULT( -VKI_EINVAL );
+//.. break;
+//.. case VKI_SHMDT:
+//.. if (!VG_(generic_PRE_sys_shmdt)(tid, ARG5))
+//.. SET_RESULT( -VKI_EINVAL );
+//.. break;
+//.. case VKI_SHMGET:
+//.. break;
+//.. case VKI_SHMCTL: /* IPCOP_shmctl */
+//.. VG_(generic_PRE_sys_shmctl)( tid, ARG2, ARG3, ARG5 );
+//.. break;
+//.. default:
+//.. VG_(message)(Vg_DebugMsg, "FATAL: unhandled syscall(ipc) %d", ARG1 );
+//.. VG_(core_panic)("... bye!\n");
+//.. break; /*NOTREACHED*/
+//.. }
+//.. }
+
+//.. POST(sys_ipc)
+//.. {
+//.. switch (ARG1 /* call */) {
+//.. case VKI_SEMOP:
+//.. case VKI_SEMGET:
+//.. break;
+//.. case VKI_SEMCTL:
+//.. {
+//.. UWord arg = deref_Addr( tid, ARG5, "semctl(arg)" );
+//.. VG_(generic_PRE_sys_semctl)( tid, ARG2, ARG3, ARG4, arg );
+//.. break;
+//.. }
+//.. case VKI_SEMTIMEDOP:
+//.. case VKI_MSGSND:
+//.. break;
+//.. case VKI_MSGRCV:
+//.. {
+//.. Addr msgp;
+//.. Word msgtyp;
+//..
+//.. msgp = deref_Addr( tid,
+//.. (Addr) (&((struct vki_ipc_kludge *)ARG5)->msgp),
+//.. "msgrcv(msgp)" );
+//.. msgtyp = deref_Addr( tid,
+//.. (Addr) (&((struct vki_ipc_kludge *)ARG5)->msgtyp),
+//.. "msgrcv(msgp)" );
+//..
+//.. VG_(generic_POST_sys_msgrcv)( tid, RES, ARG2, msgp, ARG3, msgtyp, ARG4 );
+//.. break;
+//.. }
+//.. case VKI_MSGGET:
+//.. break;
+//.. case VKI_MSGCTL:
+//.. VG_(generic_POST_sys_msgctl)( tid, RES, ARG2, ARG3, ARG5 );
+//.. break;
+//.. case VKI_SHMAT:
+//.. {
+//.. Addr addr;
+//..
+//.. /* force readability. before the syscall it is
+//.. * indeed uninitialized, as can be seen in
+//.. * glibc/sysdeps/unix/sysv/linux/shmat.c */
+//.. POST_MEM_WRITE( ARG4, sizeof( Addr ) );
+//..
+//.. addr = deref_Addr ( tid, ARG4, "shmat(addr)" );
+//.. if ( addr > 0 ) {
+//.. VG_(generic_POST_sys_shmat)( tid, addr, ARG2, ARG5, ARG3 );
+//.. }
+//.. break;
+//.. }
+//.. case VKI_SHMDT:
+//.. VG_(generic_POST_sys_shmdt)( tid, RES, ARG5 );
+//.. break;
+//.. case VKI_SHMGET:
+//.. break;
+//.. case VKI_SHMCTL:
+//.. VG_(generic_POST_sys_shmctl)( tid, RES, ARG2, ARG3, ARG5 );
+//.. break;
+//.. default:
+//.. VG_(message)(Vg_DebugMsg,
+//.. "FATAL: unhandled syscall(ipc) %d",
+//.. ARG1 );
+//.. VG_(core_panic)("... bye!\n");
+//.. break; /*NOTREACHED*/
+//.. }
+//.. }
+
+
+//.. // jrs 20050207: this is from the svn branch
+//.. //PRE(sys_sigaction, Special)
+//.. //{
+//.. // PRINT("sys_sigaction ( %d, %p, %p )", ARG1,ARG2,ARG3);
+//.. // PRE_REG_READ3(int, "sigaction",
+//.. // int, signum, const struct old_sigaction *, act,
+//.. // struct old_sigaction *, oldact)
+//.. // if (ARG2 != 0)
+//.. // PRE_MEM_READ( "sigaction(act)", ARG2, sizeof(struct vki_old_sigaction));
+//.. // if (ARG3 != 0)
+//.. // PRE_MEM_WRITE( "sigaction(oldact)", ARG3, sizeof(struct vki_old_sigaction));
+//.. //
+//.. // VG_(do_sys_sigaction)(tid);
+//.. //}
+
+//.. /* Convert from non-RT to RT sigset_t's */
+//.. static void convert_sigset_to_rt(const vki_old_sigset_t *oldset, vki_sigset_t *set)
+//.. {
+//.. VG_(sigemptyset)(set);
+//.. set->sig[0] = *oldset;
+//.. }
+//.. PRE(sys_sigaction, Special)
+//.. {
+//.. struct vki_sigaction new, old;
+//.. struct vki_sigaction *newp, *oldp;
+//..
+//.. PRINT("sys_sigaction ( %d, %p, %p )", ARG1,ARG2,ARG3);
+//.. PRE_REG_READ3(int, "sigaction",
+//.. int, signum, const struct old_sigaction *, act,
+//.. struct old_sigaction *, oldact);
+//..
+//.. newp = oldp = NULL;
+//..
+//.. if (ARG2 != 0)
+//.. PRE_MEM_READ( "sigaction(act)", ARG2, sizeof(struct vki_old_sigaction));
+//..
+//.. if (ARG3 != 0) {
+//.. PRE_MEM_WRITE( "sigaction(oldact)", ARG3, sizeof(struct vki_old_sigaction));
+//.. oldp = &old;
+//.. }
+//..
+//.. //jrs 20050207: what?! how can this make any sense?
+//.. //if (VG_(is_kerror)(SYSRES))
+//.. // return;
+//..
+//.. if (ARG2 != 0) {
+//.. struct vki_old_sigaction *oldnew = (struct vki_old_sigaction *)ARG2;
+//..
+//.. new.ksa_handler = oldnew->ksa_handler;
+//.. new.sa_flags = oldnew->sa_flags;
+//.. new.sa_restorer = oldnew->sa_restorer;
+//.. convert_sigset_to_rt(&oldnew->sa_mask, &new.sa_mask);
+//.. newp = &new;
+//.. }
+//..
+//.. SET_RESULT( VG_(do_sys_sigaction)(ARG1, newp, oldp) );
+//..
+//.. if (ARG3 != 0 && RES == 0) {
+//.. struct vki_old_sigaction *oldold = (struct vki_old_sigaction *)ARG3;
+//..
+//.. oldold->ksa_handler = oldp->ksa_handler;
+//.. oldold->sa_flags = oldp->sa_flags;
+//.. oldold->sa_restorer = oldp->sa_restorer;
+//.. oldold->sa_mask = oldp->sa_mask.sig[0];
+//.. }
+//.. }
+
+//.. POST(sys_sigaction)
+//.. {
+//.. if (RES == 0 && ARG3 != 0)
+//.. POST_MEM_WRITE( ARG3, sizeof(struct vki_old_sigaction));
+//.. }
+
+#undef PRE
+#undef POST
+
+
+/* ---------------------------------------------------------------------
+ The ppc32/Linux syscall table
+ ------------------------------------------------------------------ */
+
+/* Add an ppc32-linux specific wrapper to a syscall table. */
+#define PLAX_(sysno, name) WRAPPER_ENTRY_X_(ppc32_linux, sysno, name)
+#define PLAXY(sysno, name) WRAPPER_ENTRY_XY(ppc32_linux, sysno, name)
+
+// This table maps from __NR_xxx syscall numbers (from
+// linux/include/asm-ppc/unistd.h) to the appropriate PRE/POST sys_foo()
+// wrappers on ppc32 (as per sys_call_table in linux/arch/ppc/kernel/entry.S).
+//
+// For those syscalls not handled by Valgrind, the annotation indicate its
+// arch/OS combination, eg. */* (generic), */Linux (Linux only), ?/?
+// (unknown).
+
+const SyscallTableEntry VGP_(syscall_table)[] = {
+//.. (restart_syscall) // 0
+ GENX_(__NR_exit, sys_exit), // 1
+//.. GENX_(__NR_fork, sys_fork), // 2
+ GENXY(__NR_read, sys_read), // 3
+ GENX_(__NR_write, sys_write), // 4
+
+ GENXY(__NR_open, sys_open), // 5
+ GENXY(__NR_close, sys_close), // 6
+//.. GENXY(__NR_waitpid, sys_waitpid), // 7
+//.. GENXY(__NR_creat, sys_creat), // 8
+//.. GENX_(__NR_link, sys_link), // 9
+//..
+//.. GENX_(__NR_unlink, sys_unlink), // 10
+//.. GENX_(__NR_execve, sys_execve), // 11
+//.. GENX_(__NR_chdir, sys_chdir), // 12
+//.. GENXY(__NR_time, sys_time), // 13
+//.. GENX_(__NR_mknod, sys_mknod), // 14
+//..
+//.. GENX_(__NR_chmod, sys_chmod), // 15
+//.. // (__NR_lchown, sys_lchown16), // 16 ## P
+//.. GENX_(__NR_break, sys_ni_syscall), // 17
+//.. // (__NR_oldstat, sys_stat), // 18 (obsolete)
+//.. GENX_(__NR_lseek, sys_lseek), // 19
+//..
+//.. GENX_(__NR_getpid, sys_getpid), // 20
+//.. LINX_(__NR_mount, sys_mount), // 21
+//.. LINX_(__NR_umount, sys_oldumount), // 22
+//.. GENX_(__NR_setuid, sys_setuid16), // 23 ## P
+//.. GENX_(__NR_getuid, sys_getuid16), // 24 ## P
+//..
+//.. // (__NR_stime, sys_stime), // 25 * (SVr4,SVID,X/OPEN)
+//.. PLAXY(__NR_ptrace, sys_ptrace), // 26
+//.. GENX_(__NR_alarm, sys_alarm), // 27
+//.. // (__NR_oldfstat, sys_fstat), // 28 * L -- obsolete
+//.. GENX_(__NR_pause, sys_pause), // 29
+//..
+//.. GENX_(__NR_utime, sys_utime), // 30
+//.. GENX_(__NR_stty, sys_ni_syscall), // 31
+//.. GENX_(__NR_gtty, sys_ni_syscall), // 32
+ GENX_(__NR_access, sys_access), // 33
+//.. GENX_(__NR_nice, sys_nice), // 34
+//..
+//.. GENX_(__NR_ftime, sys_ni_syscall), // 35
+//.. GENX_(__NR_sync, sys_sync), // 36
+//.. GENX_(__NR_kill, sys_kill), // 37
+//.. GENX_(__NR_rename, sys_rename), // 38
+//.. GENX_(__NR_mkdir, sys_mkdir), // 39
+//..
+//.. GENX_(__NR_rmdir, sys_rmdir), // 40
+//.. GENXY(__NR_dup, sys_dup), // 41
+//.. GENXY(__NR_pipe, sys_pipe), // 42
+//.. GENXY(__NR_times, sys_times), // 43
+//.. GENX_(__NR_prof, sys_ni_syscall), // 44
+//..
+ GENX_(__NR_brk, sys_brk), // 45
+//.. GENX_(__NR_setgid, sys_setgid16), // 46
+//.. GENX_(__NR_getgid, sys_getgid16), // 47
+//.. // (__NR_signal, sys_signal), // 48 */* (ANSI C)
+//.. GENX_(__NR_geteuid, sys_geteuid16), // 49
+//..
+//.. GENX_(__NR_getegid, sys_getegid16), // 50
+//.. GENX_(__NR_acct, sys_acct), // 51
+//.. LINX_(__NR_umount2, sys_umount), // 52
+//.. GENX_(__NR_lock, sys_ni_syscall), // 53
+ GENXY(__NR_ioctl, sys_ioctl), // 54
+//..
+//.. GENXY(__NR_fcntl, sys_fcntl), // 55
+//.. GENX_(__NR_mpx, sys_ni_syscall), // 56
+//.. GENX_(__NR_setpgid, sys_setpgid), // 57
+//.. GENX_(__NR_ulimit, sys_ni_syscall), // 58
+//.. // (__NR_oldolduname, sys_olduname), // 59 Linux -- obsolete
+//..
+//.. GENX_(__NR_umask, sys_umask), // 60
+//.. GENX_(__NR_chroot, sys_chroot), // 61
+//.. // (__NR_ustat, sys_ustat) // 62 SVr4 -- deprecated
+//.. GENXY(__NR_dup2, sys_dup2), // 63
+//.. GENXY(__NR_getppid, sys_getppid), // 64
+//..
+//.. GENX_(__NR_getpgrp, sys_getpgrp), // 65
+//.. GENX_(__NR_setsid, sys_setsid), // 66
+//.. PLAXY(__NR_sigaction, sys_sigaction), // 67
+//.. // (__NR_sgetmask, sys_sgetmask), // 68 */* (ANSI C)
+//.. // (__NR_ssetmask, sys_ssetmask), // 69 */* (ANSI C)
+//..
+//.. GENX_(__NR_setreuid, sys_setreuid16), // 70
+//.. GENX_(__NR_setregid, sys_setregid16), // 71
+//.. GENX_(__NR_sigsuspend, sys_sigsuspend), // 72
+//.. GENXY(__NR_sigpending, sys_sigpending), // 73
+//.. // (__NR_sethostname, sys_sethostname), // 74 */*
+//..
+//.. GENX_(__NR_setrlimit, sys_setrlimit), // 75
+//.. GENXY(__NR_getrlimit, sys_old_getrlimit), // 76
+//.. GENXY(__NR_getrusage, sys_getrusage), // 77
+//.. GENXY(__NR_gettimeofday, sys_gettimeofday), // 78
+//.. GENX_(__NR_settimeofday, sys_settimeofday), // 79
+//..
+//.. GENXY(__NR_getgroups, sys_getgroups16), // 80
+//.. GENX_(__NR_setgroups, sys_setgroups16), // 81
+//.. PLAX_(__NR_select, old_select), // 82
+//.. GENX_(__NR_symlink, sys_symlink), // 83
+//.. // (__NR_oldlstat, sys_lstat), // 84 -- obsolete
+//..
+//.. GENX_(__NR_readlink, sys_readlink), // 85
+//.. // (__NR_uselib, sys_uselib), // 86 */Linux
+//.. // (__NR_swapon, sys_swapon), // 87 */Linux
+//.. // (__NR_reboot, sys_reboot), // 88 */Linux
+//.. // (__NR_readdir, old_readdir), // 89 -- superseded
+
+ GENXY(__NR_mmap, sys_mmap2), // 90
+ GENXY(__NR_munmap, sys_munmap), // 91
+//.. GENX_(__NR_truncate, sys_truncate), // 92
+//.. GENX_(__NR_ftruncate, sys_ftruncate), // 93
+//.. GENX_(__NR_fchmod, sys_fchmod), // 94
+//..
+//.. GENX_(__NR_fchown, sys_fchown16), // 95
+//.. GENX_(__NR_getpriority, sys_getpriority), // 96
+//.. GENX_(__NR_setpriority, sys_setpriority), // 97
+//.. GENX_(__NR_profil, sys_ni_syscall), // 98
+//.. GENXY(__NR_statfs, sys_statfs), // 99
+//..
+//.. GENXY(__NR_fstatfs, sys_fstatfs), // 100
+//.. LINX_(__NR_ioperm, sys_ioperm), // 101
+//.. GENXY(__NR_socketcall, sys_socketcall), // 102
+//.. LINXY(__NR_syslog, sys_syslog), // 103
+//.. GENXY(__NR_setitimer, sys_setitimer), // 104
+//..
+//.. GENXY(__NR_getitimer, sys_getitimer), // 105
+ GENXY(__NR_stat, sys_newstat), // 106
+//.. GENXY(__NR_lstat, sys_newlstat), // 107
+//.. GENXY(__NR_fstat, sys_newfstat), // 108
+//.. // (__NR_olduname, sys_uname), // 109 -- obsolete
+//..
+//.. GENX_(__NR_iopl, sys_iopl), // 110
+//.. LINX_(__NR_vhangup, sys_vhangup), // 111
+//.. GENX_(__NR_idle, sys_ni_syscall), // 112
+//.. // (__NR_vm86old, sys_vm86old), // 113 x86/Linux-only
+//.. GENXY(__NR_wait4, sys_wait4), // 114
+//..
+//.. // (__NR_swapoff, sys_swapoff), // 115 */Linux
+//.. LINXY(__NR_sysinfo, sys_sysinfo), // 116
+//.. PLAXY(__NR_ipc, sys_ipc), // 117
+//.. GENX_(__NR_fsync, sys_fsync), // 118
+//.. PLAX_(__NR_sigreturn, sys_sigreturn), // 119 ?/Linux
+//..
+//.. PLAX_(__NR_clone, sys_clone), // 120
+//.. // (__NR_setdomainname, sys_setdomainname), // 121 */*(?)
+ GENXY(__NR_uname, sys_newuname), // 122
+//.. PLAX_(__NR_modify_ldt, sys_modify_ldt), // 123
+//.. LINXY(__NR_adjtimex, sys_adjtimex), // 124
+//..
+ GENXY(__NR_mprotect, sys_mprotect), // 125
+//.. GENXY(__NR_sigprocmask, sys_sigprocmask), // 126
+//.. // Nb: create_module() was removed 2.4-->2.6
+//.. GENX_(__NR_create_module, sys_ni_syscall), // 127
+//.. GENX_(__NR_init_module, sys_init_module), // 128
+//.. // (__NR_delete_module, sys_delete_module), // 129 (*/Linux)?
+//..
+//.. // Nb: get_kernel_syms() was removed 2.4-->2.6
+//.. GENX_(__NR_get_kernel_syms, sys_ni_syscall), // 130
+//.. GENX_(__NR_quotactl, sys_quotactl), // 131
+//.. GENX_(__NR_getpgid, sys_getpgid), // 132
+//.. GENX_(__NR_fchdir, sys_fchdir), // 133
+//.. // (__NR_bdflush, sys_bdflush), // 134 */Linux
+//..
+//.. // (__NR_sysfs, sys_sysfs), // 135 SVr4
+//.. LINX_(__NR_personality, sys_personality), // 136
+//.. GENX_(__NR_afs_syscall, sys_ni_syscall), // 137
+//.. LINX_(__NR_setfsuid, sys_setfsuid16), // 138
+//.. LINX_(__NR_setfsgid, sys_setfsgid16), // 139
+//..
+//.. LINXY(__NR__llseek, sys_llseek), // 140
+//.. GENXY(__NR_getdents, sys_getdents), // 141
+//.. GENX_(__NR__newselect, sys_select), // 142
+//.. GENX_(__NR_flock, sys_flock), // 143
+//.. GENX_(__NR_msync, sys_msync), // 144
+//..
+//.. GENXY(__NR_readv, sys_readv), // 145
+ GENX_(__NR_writev, sys_writev), // 146
+//.. GENX_(__NR_getsid, sys_getsid), // 147
+//.. GENX_(__NR_fdatasync, sys_fdatasync), // 148
+ LINXY(__NR__sysctl, sys_sysctl), // 149
+//..
+//.. GENX_(__NR_mlock, sys_mlock), // 150
+//.. GENX_(__NR_munlock, sys_munlock), // 151
+//.. GENX_(__NR_mlockall, sys_mlockall), // 152
+//.. GENX_(__NR_munlockall, sys_munlockall), // 153
+//.. GENXY(__NR_sched_setparam, sys_sched_setparam), // 154
+//..
+//.. GENXY(__NR_sched_getparam, sys_sched_getparam), // 155
+//.. GENX_(__NR_sched_setscheduler, sys_sched_setscheduler), // 156
+//.. GENX_(__NR_sched_getscheduler, sys_sched_getscheduler), // 157
+//.. GENX_(__NR_sched_yield, sys_sched_yield), // 158
+//.. GENX_(__NR_sched_get_priority_max, sys_sched_get_priority_max),// 159
+//..
+//.. GENX_(__NR_sched_get_priority_min, sys_sched_get_priority_min),// 160
+//.. // (__NR_sched_rr_get_interval, sys_sched_rr_get_interval), // 161 */*
+//.. GENXY(__NR_nanosleep, sys_nanosleep), // 162
+//.. GENX_(__NR_mremap, sys_mremap), // 163
+//.. LINX_(__NR_setresuid, sys_setresuid16), // 164
+//..
+//.. LINXY(__NR_getresuid, sys_getresuid16), // 165
+
+//.. GENX_(__NR_query_module, sys_ni_syscall), // 166
+//.. GENXY(__NR_poll, sys_poll), // 167
+//.. // (__NR_nfsservctl, sys_nfsservctl), // 168 */Linux
+//..
+//.. LINX_(__NR_setresgid, sys_setresgid16), // 169
+//.. LINXY(__NR_getresgid, sys_getresgid16), // 170
+//.. LINX_(__NR_prctl, sys_prctl), // 171
+//.. PLAX_(__NR_rt_sigreturn, sys_rt_sigreturn), // 172
+ GENXY(__NR_rt_sigaction, sys_rt_sigaction), // 173
+
+ GENXY(__NR_rt_sigprocmask, sys_rt_sigprocmask), // 174
+//.. GENXY(__NR_rt_sigpending, sys_rt_sigpending), // 175
+//.. GENXY(__NR_rt_sigtimedwait, sys_rt_sigtimedwait), // 176
+//.. GENXY(__NR_rt_sigqueueinfo, sys_rt_sigqueueinfo), // 177
+//.. GENX_(__NR_rt_sigsuspend, sys_rt_sigsuspend), // 178
+//..
+//.. GENXY(__NR_pread64, sys_pread64), // 179
+//.. GENX_(__NR_pwrite64, sys_pwrite64), // 180
+//.. GENX_(__NR_chown, sys_chown16), // 181
+//.. GENXY(__NR_getcwd, sys_getcwd), // 182
+//.. GENXY(__NR_capget, sys_capget), // 183
+//..
+//.. GENX_(__NR_capset, sys_capset), // 184
+//.. GENXY(__NR_sigaltstack, sys_sigaltstack), // 185
+//.. LINXY(__NR_sendfile, sys_sendfile), // 186
+//.. GENXY(__NR_getpmsg, sys_getpmsg), // 187
+//.. GENX_(__NR_putpmsg, sys_putpmsg), // 188
+//..
+//.. // Nb: we treat vfork as fork
+//.. GENX_(__NR_vfork, sys_fork), // 189
+ GENXY(__NR_ugetrlimit, sys_getrlimit), // 190
+//__NR_readahead // 191 ppc/Linux only?
+ GENXY(__NR_mmap2, sys_mmap2), // 192
+//.. GENX_(__NR_truncate64, sys_truncate64), // 193
+//.. GENX_(__NR_ftruncate64, sys_ftruncate64), // 194
+//..
+
+ PLAXY(__NR_stat64, sys_stat64), // 195
+//.. GENXY(__NR_lstat64, sys_lstat64), // 196
+ PLAXY(__NR_fstat64, sys_fstat64), // 197
+
+// __NR_pciconfig_read // 198
+// __NR_pciconfig_write // 199
+// __NR_pciconfig_iobase // 200
+// __NR_multiplexer // 201
+
+ GENXY(__NR_getdents64, sys_getdents64), // 202
+//.. // (__NR_pivot_root, sys_pivot_root), // 203 */Linux
+ GENXY(__NR_fcntl64, sys_fcntl64), // 204
+//.. GENX_(__NR_madvise, sys_madvise), // 205
+//.. GENXY(__NR_mincore, sys_mincore), // 206
+//.. LINX_(__NR_gettid, sys_gettid), // 207
+//.. LINX_(__NR_tkill, sys_tkill), // 208 */Linux
+//.. GENX_(__NR_setxattr, sys_setxattr), // 209
+//.. GENX_(__NR_lsetxattr, sys_lsetxattr), // 210
+//.. GENX_(__NR_fsetxattr, sys_fsetxattr), // 211
+//.. GENXY(__NR_getxattr, sys_getxattr), // 212
+//.. GENXY(__NR_lgetxattr, sys_lgetxattr), // 213
+//.. GENXY(__NR_fgetxattr, sys_fgetxattr), // 214
+//.. GENXY(__NR_listxattr, sys_listxattr), // 215
+//.. GENXY(__NR_llistxattr, sys_llistxattr), // 216
+//.. GENXY(__NR_flistxattr, sys_flistxattr), // 217
+//.. GENX_(__NR_removexattr, sys_removexattr), // 218
+//.. GENX_(__NR_lremovexattr, sys_lremovexattr), // 219
+//.. GENX_(__NR_fremovexattr, sys_fremovexattr), // 220
+
+ LINXY(__NR_futex, sys_futex), // 221
+//.. GENX_(__NR_sched_setaffinity, sys_sched_setaffinity), // 222
+//.. GENXY(__NR_sched_getaffinity, sys_sched_getaffinity), // 223
+/* 224 currently unused */
+
+// __NR_tuxcall // 225
+
+//.. LINXY(__NR_sendfile64, sys_sendfile64), // 226
+//..
+//.. LINX_(__NR_io_setup, sys_io_setup), // 227
+//.. LINX_(__NR_io_destroy, sys_io_destroy), // 228
+//.. LINXY(__NR_io_getevents, sys_io_getevents), // 229
+//.. LINX_(__NR_io_submit, sys_io_submit), // 230
+//.. LINXY(__NR_io_cancel, sys_io_cancel), // 231
+//..
+ LINX_(__NR_set_tid_address, sys_set_tid_address), // 232
+
+//.. LINX_(__NR_fadvise64, sys_fadvise64), // 233 */(Linux?)
+ LINX_(__NR_exit_group, sys_exit_group), // 234
+//.. GENXY(__NR_lookup_dcookie, sys_lookup_dcookie), // 235
+//.. LINXY(__NR_epoll_create, sys_epoll_create), // 236
+//.. LINX_(__NR_epoll_ctl, sys_epoll_ctl), // 237
+//.. LINXY(__NR_epoll_wait, sys_epoll_wait), // 238
+
+//.. // (__NR_remap_file_pages, sys_remap_file_pages), // 239 */Linux
+//.. GENXY(__NR_timer_create, sys_timer_create), // 240
+//.. GENXY(__NR_timer_settime, sys_timer_settime), // 241
+//.. GENXY(__NR_timer_gettime, sys_timer_gettime), // 242
+//.. GENX_(__NR_timer_getoverrun, sys_timer_getoverrun), // 243
+//.. GENX_(__NR_timer_delete, sys_timer_delete), // 244
+//.. GENX_(__NR_clock_settime, sys_clock_settime), // 245
+//.. GENXY(__NR_clock_gettime, sys_clock_gettime), // 246
+//.. GENXY(__NR_clock_getres, sys_clock_getres), // 247
+//.. // (__NR_clock_nanosleep, sys_clock_nanosleep), // 248
+
+// __NR_swapcontext // 249
+
+//.. LINX_(__NR_tgkill, sys_tgkill), // 250 */Linux
+//.. GENX_(__NR_utimes, sys_utimes), // 251
+//.. GENXY(__NR_statfs64, sys_statfs64), // 252
+//.. GENXY(__NR_fstatfs64, sys_fstatfs64), // 253
+//.. LINX_(__NR_fadvise64_64, sys_fadvise64_64), // 254 */(Linux?)
+
+// __NR_rtas // 255
+
+/* Number 256 is reserved for sys_debug_setcontext */
+/* Number 257 is reserved for vserver */
+/* Number 258 is reserved for new sys_remap_file_pages */
+/* Number 259 is reserved for new sys_mbind */
+/* Number 260 is reserved for new sys_get_mempolicy */
+/* Number 261 is reserved for new sys_set_mempolicy */
+
+//.. GENXY(__NR_mq_open, sys_mq_open), // 262
+//.. GENX_(__NR_mq_unlink, sys_mq_unlink), // 263
+//.. GENX_(__NR_mq_timedsend, sys_mq_timedsend), // 264
+//.. GENXY(__NR_mq_timedreceive, sys_mq_timedreceive), // 265
+//.. GENX_(__NR_mq_notify, sys_mq_notify), // 266
+//.. GENXY(__NR_mq_getsetattr, sys_mq_getsetattr), // 267
+
+// __NR_kexec_load // 268
+};
+
+const UInt VGP_(syscall_table_size) =
+ sizeof(VGP_(syscall_table)) / sizeof(VGP_(syscall_table)[0]);
+
+/*--------------------------------------------------------------------*/
+/*--- end ---*/
+/*--------------------------------------------------------------------*/
diff --git a/coregrind/m_syswrap/syswrap-x86-linux.c b/coregrind/m_syswrap/syswrap-x86-linux.c
index bc2ee3e..ebe69ff 100644
--- a/coregrind/m_syswrap/syswrap-x86-linux.c
+++ b/coregrind/m_syswrap/syswrap-x86-linux.c
@@ -477,7 +477,7 @@
start_thread_NORETURN, stack, flags, &VG_(threads)[ctid],
child_tidptr, parent_tidptr, NULL
);
- res = VG_(mk_SysRes)( eax );
+ res = VG_(mk_SysRes_x86_linux)( eax );
VG_(sigprocmask)(VKI_SIG_SETMASK, &savedmask, NULL);
@@ -1176,7 +1176,7 @@
denote either success or failure, we must set up so that the
driver logic copies it back unchanged. Also, note %EAX is of
the guest registers written by VG_(sigframe_destroy). */
- SET_STATUS_from_SysRes( VG_(mk_SysRes)( tst->arch.vex.guest_EAX ) );
+ SET_STATUS_from_SysRes( VG_(mk_SysRes_x86_linux)( tst->arch.vex.guest_EAX ) );
/* Check to see if some any signals arose as a result of this. */
*flags |= SfPollAfter;
@@ -1207,7 +1207,7 @@
denote either success or failure, we must set up so that the
driver logic copies it back unchanged. Also, note %EAX is of
the guest registers written by VG_(sigframe_destroy). */
- SET_STATUS_from_SysRes( VG_(mk_SysRes)( tst->arch.vex.guest_EAX ) );
+ SET_STATUS_from_SysRes( VG_(mk_SysRes_x86_linux)( tst->arch.vex.guest_EAX ) );
/* Check to see if some any signals arose as a result of this. */
*flags |= SfPollAfter;
diff --git a/coregrind/m_trampoline.S b/coregrind/m_trampoline.S
index 0973acf..85742f4 100644
--- a/coregrind/m_trampoline.S
+++ b/coregrind/m_trampoline.S
@@ -96,6 +96,15 @@
syscall_start:
/* unused on amd64 */
+#elif defined(VGP_ppc32_linux)
+// CAB: TODO
+// Not yet used, just keeping the compiler quiet
+sigreturn_start:
+rt_sigreturn_start:
+syscall_start:
+gettimeofday_start:
+time_start:
+
#else
# error Unknown platform
#endif
diff --git a/coregrind/m_translate.c b/coregrind/m_translate.c
index c2babb3..30deb0d 100644
--- a/coregrind/m_translate.c
+++ b/coregrind/m_translate.c
@@ -93,11 +93,18 @@
/* we need at least SSE state to operate. */
return False;
+
#elif defined(VGA_amd64)
vg_assert(VG_(has_cpuid)());
*vex_arch = VexArchAMD64;
*vex_subarch = VexSubArch_NONE;
return True;
+
+#elif defined(VGA_ppc32)
+ *vex_arch = VexArchPPC32;
+ *vex_subarch = VexSubArchPPC32_noAV;
+ return True;
+
#else
# error Unknown architecture
#endif
diff --git a/coregrind/m_transtab.c b/coregrind/m_transtab.c
index 557a005..d004ef4 100644
--- a/coregrind/m_transtab.c
+++ b/coregrind/m_transtab.c
@@ -327,6 +327,24 @@
invalidateFastCache();
}
+#if defined(VGA_ppc32)
+static void invalidate_icache(void *ptr, int nbytes)
+{
+ unsigned long startaddr = (unsigned long) ptr;
+ unsigned long endaddr = startaddr + nbytes;
+ unsigned long addr;
+ unsigned long cls = 16; //VG_(cache_line_size);
+
+ startaddr &= ~(cls - 1);
+ for (addr = startaddr; addr < endaddr; addr += cls)
+ asm volatile("dcbst 0,%0" : : "r" (addr));
+ asm volatile("sync");
+ for (addr = startaddr; addr < endaddr; addr += cls)
+ asm volatile("icbi 0,%0" : : "r" (addr));
+ asm volatile("sync; isync");
+}
+#endif
+
/* Add a translation of vge to TT/TC. The translation is temporarily
in code[0 .. code_len-1].
@@ -406,6 +424,10 @@
sectors[y].tc_next += reqdQ;
sectors[y].tt_n_inuse++;
+#if defined(VGA_ppc32)
+ invalidate_icache( dstP, code_len );
+#endif
+
/* more paranoia */
tce2 = sectors[y].tc_next;
vg_assert(tce2 >= §ors[y].tc[0]);
diff --git a/coregrind/pub_core_basics.h b/coregrind/pub_core_basics.h
index 42d6f20..c35bd37 100644
--- a/coregrind/pub_core_basics.h
+++ b/coregrind/pub_core_basics.h
@@ -52,6 +52,8 @@
# include "libvex_guest_x86.h"
#elif defined(VGA_amd64)
# include "libvex_guest_amd64.h"
+#elif defined(VGA_ppc32)
+# include "libvex_guest_ppc32.h"
#else
# error Unknown arch
#endif
diff --git a/coregrind/pub_core_machine.h b/coregrind/pub_core_machine.h
index e336143..2ccbdc9 100644
--- a/coregrind/pub_core_machine.h
+++ b/coregrind/pub_core_machine.h
@@ -51,6 +51,10 @@
# define VGA_ELF_ENDIANNESS ELFDATA2LSB
# define VGA_ELF_MACHINE EM_ARM
# define VGA_ELF_CLASS ELFCLASS32
+#elif defined(VGA_ppc32)
+# define VGA_ELF_ENDIANNESS ELFDATA2MSB
+# define VGA_ELF_MACHINE EM_PPC
+# define VGA_ELF_CLASS ELFCLASS32
#else
# error Unknown arch
#endif
@@ -73,6 +77,10 @@
# define VGA_INSTR_PTR guest_R15
# define VGA_STACK_PTR guest_R13
# define VGA_FRAME_PTR guest_R11
+#elif defined(VGA_ppc32)
+# define VGA_INSTR_PTR guest_CIA
+# define VGA_STACK_PTR guest_GPR1
+# define VGA_FRAME_PTR guest_GPR1 // No frame ptr for PPC
#else
# error Unknown arch
#endif
diff --git a/coregrind/pub_core_syscall.h b/coregrind/pub_core_syscall.h
index 17c3f55..120964f 100644
--- a/coregrind/pub_core_syscall.h
+++ b/coregrind/pub_core_syscall.h
@@ -61,9 +61,11 @@
#define vgPlain_do_syscall6(s,a,b,c,d,e,f) VG_(do_syscall)((s),(a),(b),\
(c),(d),(e),(f))
-extern SysRes VG_(mk_SysRes) ( UWord val );
-extern SysRes VG_(mk_SysRes_Error) ( UWord val );
-extern SysRes VG_(mk_SysRes_Success) ( UWord val );
+extern SysRes VG_(mk_SysRes_x86_linux) ( UWord val );
+extern SysRes VG_(mk_SysRes_amd64_linux) ( UWord val );
+extern SysRes VG_(mk_SysRes_ppc32_linux) ( UInt val, UInt errflag );
+extern SysRes VG_(mk_SysRes_Error) ( UWord val );
+extern SysRes VG_(mk_SysRes_Success) ( UWord val );
// The _WRK function is handwritten assembly. It has some very magic
// properties. See comments at the top of
diff --git a/coregrind/pub_core_threadstate.h b/coregrind/pub_core_threadstate.h
index 148d18e..caae070 100644
--- a/coregrind/pub_core_threadstate.h
+++ b/coregrind/pub_core_threadstate.h
@@ -81,6 +81,8 @@
typedef VexGuestAMD64State VexGuestArchState;
#elif defined(VGA_arm)
typedef VexGuestARMState VexGuestArchState;
+#elif defined(VGA_ppc32)
+ typedef VexGuestPPC32State VexGuestArchState;
#else
# error Unknown architecture
#endif
diff --git a/coregrind/ume.c b/coregrind/ume.c
index 4e1b6fd..75753ac 100644
--- a/coregrind/ume.c
+++ b/coregrind/ume.c
@@ -175,6 +175,60 @@
" ret\n" // jump to dst
" ud2\n" // should never get here
);
+
+#elif defined(VGA_ppc32)
+/* Jump to 'dst', but first set the stack pointer to 'stack'. Also,
+ clear all the integer registers before entering 'dst'. It's
+ important that the stack pointer is set to exactly 'stack' and not
+ (eg) stack - apparently_harmless_looking_small_offset. Basically
+ because the code at 'dst' might be wanting to scan the area above
+ 'stack' (viz, the auxv array), and putting spurious words on the
+ stack confuses it.
+*/
+// %r3 == stack
+// %r4 == dst
+asm(
+".global jump_and_switch_stacks\n"
+"jump_and_switch_stacks:\n"
+" mtctr %r4\n\t" // dst to %ctr
+" mr %r1,%r3\n\t" // stack to %sp
+" li 0,0\n\t" // zero all GP regs
+" li 3,0\n\t"
+" li 4,0\n\t"
+" li 5,0\n\t"
+" li 6,0\n\t"
+" li 7,0\n\t"
+" li 8,0\n\t"
+" li 9,0\n\t"
+" li 10,0\n\t"
+" li 11,0\n\t"
+" li 12,0\n\t"
+" li 13,0\n\t" // CAB: This right? r13 = small data area ptr
+" li 14,0\n\t"
+" li 15,0\n\t"
+" li 16,0\n\t"
+" li 17,0\n\t"
+" li 18,0\n\t"
+" li 19,0\n\t"
+" li 20,0\n\t"
+" li 21,0\n\t"
+" li 22,0\n\t"
+" li 23,0\n\t"
+" li 24,0\n\t"
+" li 25,0\n\t"
+" li 26,0\n\t"
+" li 27,0\n\t"
+" li 28,0\n\t"
+" li 29,0\n\t"
+" li 30,0\n\t"
+" li 31,0\n\t"
+" mtxer 0\n\t"
+" mtcr 0\n\t"
+" mtlr %r0\n\t"
+" bctr\n\t" // jump to dst
+" trap\n" // should never get here
+);
+
#else
# error Unknown architecture
#endif
@@ -195,6 +249,13 @@
sp++;
sp++;
+#if defined(VGA_ppc32)
+# if defined AT_IGNOREPPC
+ while (*sp == AT_IGNOREPPC) // skip AT_IGNOREPPC entries
+ sp += 2;
+# endif
+#endif
+
return (struct ume_auxv *)sp;
}
diff --git a/coregrind/vki_unistd-ppc32-linux.h b/coregrind/vki_unistd-ppc32-linux.h
new file mode 100644
index 0000000..50e6dba
--- /dev/null
+++ b/coregrind/vki_unistd-ppc32-linux.h
@@ -0,0 +1,302 @@
+
+/*
+ This file is part of Valgrind, a dynamic binary instrumentation
+ framework.
+
+ Copyright (C) 2005 Julian Seward
+ jseward@acm.org
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ The GNU General Public License is contained in the file COPYING.
+*/
+
+#ifndef __VKI_UNISTD_PPC32_LINUX_H
+#define __VKI_UNISTD_PPC32_LINUX_H
+
+// From linux-2.6.9/include/asm-ppc/unistd.h
+
+#define __NR_restart_syscall 0
+#define __NR_exit 1
+#define __NR_fork 2
+#define __NR_read 3
+#define __NR_write 4
+#define __NR_open 5
+#define __NR_close 6
+//#define __NR_waitpid 7
+//#define __NR_creat 8
+//#define __NR_link 9
+#define __NR_unlink 10
+#define __NR_execve 11
+//#define __NR_chdir 12
+//#define __NR_time 13
+//#define __NR_mknod 14
+//#define __NR_chmod 15
+//#define __NR_lchown 16
+//#define __NR_break 17
+//#define __NR_oldstat 18
+#define __NR_lseek 19
+#define __NR_getpid 20
+//#define __NR_mount 21
+//#define __NR_umount 22
+//#define __NR_setuid 23
+//#define __NR_getuid 24
+//#define __NR_stime 25
+//#define __NR_ptrace 26
+//#define __NR_alarm 27
+//#define __NR_oldfstat 28
+//#define __NR_pause 29
+//#define __NR_utime 30
+//#define __NR_stty 31
+//#define __NR_gtty 32
+#define __NR_access 33
+//#define __NR_nice 34
+//#define __NR_ftime 35
+//#define __NR_sync 36
+#define __NR_kill 37
+#define __NR_rename 38
+//#define __NR_mkdir 39
+//#define __NR_rmdir 40
+//#define __NR_dup 41
+#define __NR_pipe 42
+//#define __NR_times 43
+//#define __NR_prof 44
+#define __NR_brk 45
+//#define __NR_setgid 46
+//#define __NR_getgid 47
+//#define __NR_signal 48
+//#define __NR_geteuid 49
+//#define __NR_getegid 50
+//#define __NR_acct 51
+//#define __NR_umount2 52
+//#define __NR_lock 53
+#define __NR_ioctl 54
+#define __NR_fcntl 55
+//#define __NR_mpx 56
+#define __NR_setpgid 57
+//#define __NR_ulimit 58
+//#define __NR_oldolduname 59
+//#define __NR_umask 60
+//#define __NR_chroot 61
+//#define __NR_ustat 62
+#define __NR_dup2 63
+#define __NR_getppid 64
+#define __NR_getpgrp 65
+//#define __NR_setsid 66
+//#define __NR_sigaction 67
+//#define __NR_sgetmask 68
+//#define __NR_ssetmask 69
+//#define __NR_setreuid 70
+//#define __NR_setregid 71
+//#define __NR_sigsuspend 72
+#define __NR_sigpending 73
+//#define __NR_sethostname 74
+#define __NR_setrlimit 75
+#define __NR_getrlimit 76
+//#define __NR_getrusage 77
+#define __NR_gettimeofday 78
+//#define __NR_settimeofday 79
+//#define __NR_getgroups 80
+//#define __NR_setgroups 81
+//#define __NR_select 82
+//#define __NR_symlink 83
+//#define __NR_oldlstat 84
+#define __NR_readlink 85
+//#define __NR_uselib 86
+//#define __NR_swapon 87
+//#define __NR_reboot 88
+//#define __NR_readdir 89
+#define __NR_mmap 90
+#define __NR_munmap 91
+//#define __NR_truncate 92
+//#define __NR_ftruncate 93
+//#define __NR_fchmod 94
+//#define __NR_fchown 95
+//#define __NR_getpriority 96
+//#define __NR_setpriority 97
+//#define __NR_profil 98
+//#define __NR_statfs 99
+//#define __NR_fstatfs 100
+//#define __NR_ioperm 101
+#define __NR_socketcall 102
+//#define __NR_syslog 103
+//#define __NR_setitimer 104
+//#define __NR_getitimer 105
+#define __NR_stat 106
+//#define __NR_lstat 107
+#define __NR_fstat 108
+//#define __NR_olduname 109
+//#define __NR_iopl 110
+//#define __NR_vhangup 111
+//#define __NR_idle 112
+//#define __NR_vm86old 113
+#define __NR_wait4 114
+//#define __NR_swapoff 115
+//#define __NR_sysinfo 116
+#define __NR_ipc 117
+//#define __NR_fsync 118
+//#define __NR_sigreturn 119
+#define __NR_clone 120
+//#define __NR_setdomainname 121
+#define __NR_uname 122
+//#define __NR_modify_ldt 123
+//#define __NR_adjtimex 124
+#define __NR_mprotect 125
+#define __NR_sigprocmask 126
+//#define __NR_create_module 127
+//#define __NR_init_module 128
+//#define __NR_delete_module 129
+//#define __NR_get_kernel_syms 130
+//#define __NR_quotactl 131
+//#define __NR_getpgid 132
+//#define __NR_fchdir 133
+//#define __NR_bdflush 134
+//#define __NR_sysfs 135
+//#define __NR_personality 136
+//#define __NR_afs_syscall 137 /* Syscall for Andrew File System */
+//#define __NR_setfsuid 138
+//#define __NR_setfsgid 139
+//#define __NR__llseek 140
+#define __NR_getdents 141
+//#define __NR__newselect 142
+//#define __NR_flock 143
+//#define __NR_msync 144
+//#define __NR_readv 145
+#define __NR_writev 146
+//#define __NR_getsid 147
+//#define __NR_fdatasync 148
+#define __NR__sysctl 149
+//#define __NR_mlock 150
+//#define __NR_munlock 151
+//#define __NR_mlockall 152
+//#define __NR_munlockall 153
+//#define __NR_sched_setparam 154
+//#define __NR_sched_getparam 155
+//#define __NR_sched_setscheduler 156
+//#define __NR_sched_getscheduler 157
+#define __NR_sched_yield 158
+//#define __NR_sched_get_priority_max 159
+//#define __NR_sched_get_priority_min 160
+//#define __NR_sched_rr_get_interval 161
+#define __NR_nanosleep 162
+#define __NR_mremap 163
+//#define __NR_setresuid 164
+//#define __NR_getresuid 165
+//#define __NR_query_module 166
+#define __NR_poll 167
+//#define __NR_nfsservctl 168
+//#define __NR_setresgid 169
+//#define __NR_getresgid 170
+//#define __NR_prctl 171
+#define __NR_rt_sigreturn 172
+#define __NR_rt_sigaction 173
+#define __NR_rt_sigprocmask 174
+//#define __NR_rt_sigpending 175
+#define __NR_rt_sigtimedwait 176
+//#define __NR_rt_sigqueueinfo 177
+//#define __NR_rt_sigsuspend 178
+//#define __NR_pread64 179
+//#define __NR_pwrite64 180
+//#define __NR_chown 181
+#define __NR_getcwd 182
+//#define __NR_capget 183
+//#define __NR_capset 184
+#define __NR_sigaltstack 185
+//#define __NR_sendfile 186
+//#define __NR_getpmsg 187 /* some people actually want streams */
+//#define __NR_putpmsg 188 /* some people actually want streams */
+//#define __NR_vfork 189
+#define __NR_ugetrlimit 190 /* SuS compliant getrlimit */
+//#define __NR_readahead 191
+#define __NR_mmap2 192
+//#define __NR_truncate64 193
+//#define __NR_ftruncate64 194
+#define __NR_stat64 195
+//#define __NR_lstat64 196
+#define __NR_fstat64 197
+//#define __NR_pciconfig_read 198
+//#define __NR_pciconfig_write 199
+//#define __NR_pciconfig_iobase 200
+//#define __NR_multiplexer 201
+#define __NR_getdents64 202
+//#define __NR_pivot_root 203
+#define __NR_fcntl64 204
+//#define __NR_madvise 205
+//#define __NR_mincore 206
+#define __NR_gettid 207
+#define __NR_tkill 208
+//#define __NR_setxattr 209
+//#define __NR_lsetxattr 210
+//#define __NR_fsetxattr 211
+//#define __NR_getxattr 212
+//#define __NR_lgetxattr 213
+//#define __NR_fgetxattr 214
+//#define __NR_listxattr 215
+//#define __NR_llistxattr 216
+//#define __NR_flistxattr 217
+//#define __NR_removexattr 218
+//#define __NR_lremovexattr 219
+//#define __NR_fremovexattr 220
+#define __NR_futex 221
+//#define __NR_sched_setaffinity 222
+//#define __NR_sched_getaffinity 223
+/* 224 currently unused */
+//#define __NR_tuxcall 225
+//#define __NR_sendfile64 226
+//#define __NR_io_setup 227
+//#define __NR_io_destroy 228
+//#define __NR_io_getevents 229
+//#define __NR_io_submit 230
+//#define __NR_io_cancel 231
+#define __NR_set_tid_address 232
+//#define __NR_fadvise64 233
+#define __NR_exit_group 234
+//#define __NR_lookup_dcookie 235
+//#define __NR_epoll_create 236
+//#define __NR_epoll_ctl 237
+//#define __NR_epoll_wait 238
+//#define __NR_remap_file_pages 239
+//#define __NR_timer_create 240
+//#define __NR_timer_settime 241
+//#define __NR_timer_gettime 242
+//#define __NR_timer_getoverrun 243
+//#define __NR_timer_delete 244
+//#define __NR_clock_settime 245
+//#define __NR_clock_gettime 246
+//#define __NR_clock_getres 247
+//#define __NR_clock_nanosleep 248
+//#define __NR_swapcontext 249
+//#define __NR_tgkill 250
+//#define __NR_utimes 251
+//#define __NR_statfs64 252
+//#define __NR_fstatfs64 253
+//#define __NR_fadvise64_64 254
+//#define __NR_rtas 255
+/* Number 256 is reserved for sys_debug_setcontext */
+/* Number 257 is reserved for vserver */
+/* Number 258 is reserved for new sys_remap_file_pages */
+/* Number 259 is reserved for new sys_mbind */
+/* Number 260 is reserved for new sys_get_mempolicy */
+/* Number 261 is reserved for new sys_set_mempolicy */
+//#define __NR_mq_open 262
+//#define __NR_mq_unlink 263
+//#define __NR_mq_timedsend 264
+//#define __NR_mq_timedreceive 265
+//#define __NR_mq_notify 266
+//#define __NR_mq_getsetattr 267
+//#define __NR_kexec_load 268
+
+#endif /* __VKI_UNISTD_PPC32_LINUX_H */
diff --git a/coregrind/vki_unistd.h b/coregrind/vki_unistd.h
index 4953c1d..b5eff34 100644
--- a/coregrind/vki_unistd.h
+++ b/coregrind/vki_unistd.h
@@ -38,6 +38,8 @@
# include "vki_unistd-amd64-linux.h"
#elif defined(VGP_arm_linux)
# include "vki_unistd-arm-linux.h"
+#elif defined(VGP_ppc32_linux)
+# include "vki_unistd-ppc32-linux.h"
#else
# error Unknown platform
#endif
diff --git a/include/Makefile.am b/include/Makefile.am
index 50624ab..535255d 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -29,7 +29,9 @@
vki-linux.h \
vki-amd64-linux.h \
vki-arm-linux.h \
+ vki-ppc32-linux.h \
vki-x86-linux.h \
vki_posixtypes-amd64-linux.h \
vki_posixtypes-arm-linux.h \
+ vki_posixtypes-ppc32-linux.h \
vki_posixtypes-x86-linux.h
diff --git a/include/pub_tool_basics.h b/include/pub_tool_basics.h
index 03a9b7a..9b09d07 100644
--- a/include/pub_tool_basics.h
+++ b/include/pub_tool_basics.h
@@ -120,6 +120,8 @@
# define VGA_REGPARM(n) __attribute__((regparm(n)))
#elif defined(VGA_amd64) || defined(VGA_arm)
# define VGA_REGPARM(n) /* */
+#elif defined(VGA_ppc32)
+# define VGA_REGPARM(n) /* */
#else
# error Unknown arch
#endif
diff --git a/include/pub_tool_machine.h b/include/pub_tool_machine.h
index e5cc395..46ff9d6 100644
--- a/include/pub_tool_machine.h
+++ b/include/pub_tool_machine.h
@@ -45,6 +45,10 @@
# define VGA_MIN_INSTR_SZB 4
# define VGA_MAX_INSTR_SZB 4
# define VGA_STACK_REDZONE_SZB 0
+#elif defined(VGA_ppc32)
+# define VGA_MIN_INSTR_SZB 4
+# define VGA_MAX_INSTR_SZB 4
+# define VGA_STACK_REDZONE_SZB 0
#else
# error Unknown arch
#endif
diff --git a/include/valgrind.h b/include/valgrind.h
index 71a7e0d..963fc86 100644
--- a/include/valgrind.h
+++ b/include/valgrind.h
@@ -78,7 +78,7 @@
any inline asms. Note that in this file we're using the compiler's
CPP symbols for identifying architectures, which are different to
the ones we use within the rest of Valgrind. */
-#if !defined(__i386__) && !defined(__x86_64__)
+#if !defined(__i386__) && !defined(__x86_64__) && !defined(__powerpc__)
# ifndef NVALGRIND
# define NVALGRIND 1
# endif /* NVALGRIND */
@@ -185,6 +185,33 @@
// the return value match what the scheduler is expecting.
#endif // __arm__
+#ifdef __powerpc__
+#define VALGRIND_MAGIC_SEQUENCE( \
+ _zzq_rlval, _zzq_default, _zzq_request, \
+ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4) \
+ \
+ { volatile unsigned int _zzq_args[5]; \
+ register unsigned int _zzq_tmp __asm__("r3"); \
+ register volatile unsigned int *_zzq_ptr __asm__("r4"); \
+ _zzq_args[0] = (volatile unsigned int)(_zzq_request); \
+ _zzq_args[1] = (volatile unsigned int)(_zzq_arg1); \
+ _zzq_args[2] = (volatile unsigned int)(_zzq_arg2); \
+ _zzq_args[3] = (volatile unsigned int)(_zzq_arg3); \
+ _zzq_args[4] = (volatile unsigned int)(_zzq_arg4); \
+ _zzq_ptr = _zzq_args; \
+ asm volatile("tw 0,3,27\n\t" \
+ "rlwinm 0,0,29,0,0\n\t" \
+ "rlwinm 0,0,3,0,0\n\t" \
+ "rlwinm 0,0,13,0,0\n\t" \
+ "rlwinm 0,0,19,0,0\n\t" \
+ "nop\n\t" \
+ : "=r" (_zzq_tmp) \
+ : "0" (_zzq_default), "r" (_zzq_ptr) \
+ : "memory"); \
+ _zzq_rlval = (__typeof__(_zzq_rlval)) _zzq_tmp; \
+ }
+#endif // __powerpc__
+
// Insert assembly code for other architectures here...
#endif /* NVALGRIND */
diff --git a/include/vki-linux.h b/include/vki-linux.h
index 30b695c..7cc087f 100644
--- a/include/vki-linux.h
+++ b/include/vki-linux.h
@@ -70,6 +70,8 @@
# include "vki_posixtypes-x86-linux.h"
#elif defined(VGA_amd64)
# include "vki_posixtypes-amd64-linux.h"
+#elif defined(VGA_ppc32)
+# include "vki_posixtypes-ppc32-linux.h"
#else
# error Unknown platform
#endif
@@ -148,6 +150,8 @@
# include "vki-x86-linux.h"
#elif defined(VGA_amd64)
# include "vki-amd64-linux.h"
+#elif defined(VGA_ppc32)
+# include "vki-ppc32-linux.h"
#else
# error Unknown platform
#endif
@@ -1128,11 +1132,10 @@
__vki_s64 result2; /* secondary result */
};
-#define VKI_PADDED(x,y) x, y
#if defined(VKI_LITTLE_ENDIAN)
-#define VKI_PADDED(x,y) x, y
+# define VKI_PADDED(x,y) x, y
#elif defined(VKI_BIG_ENDIAN)
-#define VKI_PADDED(x,y) y, x
+# define VKI_PADDED(x,y) y, x
#else
#error edit for your odd byteorder.
#endif
diff --git a/include/vki-ppc32-linux.h b/include/vki-ppc32-linux.h
new file mode 100644
index 0000000..129c7bb
--- /dev/null
+++ b/include/vki-ppc32-linux.h
@@ -0,0 +1,888 @@
+
+/*--------------------------------------------------------------------*/
+/*--- PPC32/Linux-specific kernel interface. ---*/
+/*--- ppc32-linux/vki-ppc32-linux.h ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+ This file is part of Valgrind, a dynamic binary instrumentation
+ framework.
+
+ Copyright (C) 2005 Julian Seward
+ jseward@acm.org
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ The GNU General Public License is contained in the file COPYING.
+*/
+
+#ifndef __PPC32_LINUX_VKI_ARCH_H
+#define __PPC32_LINUX_VKI_ARCH_H
+
+// ppc32 is big-endian.
+#define VKI_BIG_ENDIAN 1
+
+//----------------------------------------------------------------------
+// From linux-2.6.9/include/asm-ppc/types.h
+//----------------------------------------------------------------------
+
+typedef unsigned char __vki_u8;
+
+typedef __signed__ short __vki_s16;
+typedef unsigned short __vki_u16;
+
+typedef unsigned int __vki_u32;
+
+typedef __signed__ long long __vki_s64;
+typedef unsigned long long __vki_u64;
+
+typedef unsigned short vki_u16;
+
+typedef unsigned int vki_u32;
+
+typedef struct {
+ __vki_u32 u[4];
+} __vki_vector128;
+
+//----------------------------------------------------------------------
+// From linux-2.6.9/include/asm-ppc/page.h
+//----------------------------------------------------------------------
+
+/* PAGE_SHIFT determines the page size */
+#define VKI_PAGE_SHIFT 12
+#define VKI_PAGE_SIZE (1UL << VKI_PAGE_SHIFT)
+
+//----------------------------------------------------------------------
+// From linux-2.6.9/include/asm-ppc/signal.h
+//----------------------------------------------------------------------
+
+#define VKI_MINSIGSTKSZ 2048
+
+#define VKI_SIG_BLOCK 0 /* for blocking signals */
+#define VKI_SIG_UNBLOCK 1 /* for unblocking signals */
+#define VKI_SIG_SETMASK 2 /* for setting the signal mask */
+
+/* Type of a signal handler. */
+typedef void __vki_signalfn_t(int);
+typedef __vki_signalfn_t __user *__vki_sighandler_t;
+
+typedef void __vki_restorefn_t(void);
+typedef __vki_restorefn_t __user *__vki_sigrestore_t;
+
+#define VKI_SIG_DFL ((__vki_sighandler_t)0) /* default signal handling */
+#define VKI_SIG_IGN ((__vki_sighandler_t)1) /* ignore signal */
+
+#define _VKI_NSIG 64
+#define _VKI_NSIG_BPW 32
+#define _VKI_NSIG_WORDS (_VKI_NSIG / _VKI_NSIG_BPW)
+
+typedef unsigned long vki_old_sigset_t; /* at least 32 bits */
+
+typedef struct {
+ unsigned long sig[_VKI_NSIG_WORDS];
+} vki_sigset_t;
+
+#define VKI_SIGHUP 1
+#define VKI_SIGINT 2
+#define VKI_SIGQUIT 3
+#define VKI_SIGILL 4
+#define VKI_SIGTRAP 5
+#define VKI_SIGABRT 6
+//#define VKI_SIGIOT 6
+#define VKI_SIGBUS 7
+#define VKI_SIGFPE 8
+#define VKI_SIGKILL 9
+#define VKI_SIGUSR1 10
+#define VKI_SIGSEGV 11
+#define VKI_SIGUSR2 12
+#define VKI_SIGPIPE 13
+#define VKI_SIGALRM 14
+#define VKI_SIGTERM 15
+#define VKI_SIGSTKFLT 16
+#define VKI_SIGCHLD 17
+#define VKI_SIGCONT 18
+#define VKI_SIGSTOP 19
+#define VKI_SIGTSTP 20
+#define VKI_SIGTTIN 21
+#define VKI_SIGTTOU 22
+#define VKI_SIGURG 23
+#define VKI_SIGXCPU 24
+#define VKI_SIGXFSZ 25
+#define VKI_SIGVTALRM 26
+#define VKI_SIGPROF 27
+#define VKI_SIGWINCH 28
+#define VKI_SIGIO 29
+#define VKI_SIGPWR 30
+#define VKI_SIGSYS 31
+#define VKI_SIGUNUSED 31
+
+/* These should not be considered constants from userland. */
+#define VKI_SIGRTMIN 32
+// [[This was (_NSIG-1) in 2.4.X... not sure if it matters.]]
+#define VKI_SIGRTMAX _VKI_NSIG
+
+#define VKI_SA_NOCLDSTOP 0x00000001
+#define VKI_SA_NOCLDWAIT 0x00000002
+#define VKI_SA_SIGINFO 0x00000004
+#define VKI_SA_ONSTACK 0x08000000
+#define VKI_SA_RESTART 0x10000000
+#define VKI_SA_NODEFER 0x40000000
+#define VKI_SA_RESETHAND 0x80000000
+
+#define VKI_SA_NOMASK VKI_SA_NODEFER
+#define VKI_SA_ONESHOT VKI_SA_RESETHAND
+//#define VKI_SA_INTERRUPT 0x20000000 /* dummy -- ignored */
+
+#define VKI_SA_RESTORER 0x04000000
+
+#define VKI_SS_ONSTACK 1
+#define VKI_SS_DISABLE 2
+
+//.. struct vki_old_sigaction {
+//.. // [[Nb: a 'k' prefix is added to "sa_handler" because
+//.. // bits/sigaction.h (which gets dragged in somehow via signal.h)
+//.. // #defines it as something else. Since that is done for glibc's
+//.. // purposes, which we don't care about here, we use our own name.]]
+//.. __vki_sighandler_t ksa_handler;
+//.. vki_old_sigset_t sa_mask;
+//.. unsigned long sa_flags;
+//.. __vki_sigrestore_t sa_restorer;
+//.. };
+
+struct vki_sigaction {
+ // [[See comment about extra 'k' above]]
+ __vki_sighandler_t ksa_handler;
+ unsigned long sa_flags;
+ __vki_sigrestore_t sa_restorer;
+ vki_sigset_t sa_mask; /* mask last for extensibility */
+};
+
+typedef struct vki_sigaltstack {
+ void __user *ss_sp;
+ int ss_flags;
+ vki_size_t ss_size;
+} vki_stack_t;
+
+
+//----------------------------------------------------------------------
+// From linux-2.6.9/include/asm-ppc/ptrace.h
+//----------------------------------------------------------------------
+
+struct vki_pt_regs {
+ unsigned long gpr[32];
+ unsigned long nip;
+ unsigned long msr;
+ unsigned long orig_gpr3; /* Used for restarting system calls */
+ unsigned long ctr;
+ unsigned long link;
+ unsigned long xer;
+ unsigned long ccr;
+ unsigned long mq; /* 601 only (not used at present) */
+ /* Used on APUS to hold IPL value. */
+ unsigned long trap; /* Reason for being here */
+ /* N.B. for critical exceptions on 4xx, the dar and dsisr
+ fields are overloaded to hold srr0 and srr1. */
+ unsigned long dar; /* Fault registers */
+ unsigned long dsisr; /* on 4xx/Book-E used for ESR */
+ unsigned long result; /* Result of a system call */
+};
+
+#define vki_user_regs_struct vki_pt_regs
+
+#define VKI_PT_R0 0
+#define VKI_PT_NIP 32
+#define VKI_PT_MSR 33
+#define VKI_PT_ORIG_R3 34
+#define VKI_PT_CTR 35
+#define VKI_PT_LNK 36
+#define VKI_PT_XER 37
+#define VKI_PT_CCR 38
+#define VKI_PT_MQ 39
+#define VKI_PT_TRAP 40
+#define VKI_PT_DAR 41
+#define VKI_PT_DSISR 42
+#define VKI_PT_RESULT 43
+
+//----------------------------------------------------------------------
+// From linux-2.6.9/include/asm-ppc/sigcontext.h
+//----------------------------------------------------------------------
+
+struct vki_sigcontext {
+ unsigned long _unused[4];
+ int signal;
+ unsigned long handler;
+ unsigned long oldmask;
+ struct vki_pt_regs *regs;
+};
+
+//----------------------------------------------------------------------
+// From linux-2.6.9/include/asm-ppc/mman.h
+//----------------------------------------------------------------------
+
+#define VKI_PROT_NONE 0x0 /* No page permissions */
+#define VKI_PROT_READ 0x1 /* page can be read */
+#define VKI_PROT_WRITE 0x2 /* page can be written */
+#define VKI_PROT_EXEC 0x4 /* page can be executed */
+
+#define VKI_MAP_SHARED 0x01 /* Share changes */
+#define VKI_MAP_PRIVATE 0x02 /* Changes are private */
+//#define VKI_MAP_TYPE 0x0f /* Mask for type of mapping */
+#define VKI_MAP_FIXED 0x10 /* Interpret addr exactly */
+#define VKI_MAP_ANONYMOUS 0x20 /* don't use a file */
+#define VKI_MAP_NORESERVE 0x40 /* don't reserve swap pages */
+
+//----------------------------------------------------------------------
+// From linux-2.6.9/include/asm-ppc/fcntl.h
+//----------------------------------------------------------------------
+
+#define VKI_O_RDONLY 00
+#define VKI_O_WRONLY 01
+#define VKI_O_RDWR 02
+#define VKI_O_CREAT 0100 /* not fcntl */
+#define VKI_O_EXCL 0200 /* not fcntl */
+#define VKI_O_TRUNC 01000 /* not fcntl */
+#define VKI_O_APPEND 02000
+#define VKI_O_NONBLOCK 04000
+
+#define VKI_F_DUPFD 0 /* dup */
+#define VKI_F_GETFD 1 /* get close_on_exec */
+#define VKI_F_SETFD 2 /* set/clear close_on_exec */
+#define VKI_F_GETFL 3 /* get file->f_flags */
+#define VKI_F_SETFL 4 /* set file->f_flags */
+#define VKI_F_GETLK 5
+#define VKI_F_SETLK 6
+#define VKI_F_SETLKW 7
+
+#define VKI_F_SETOWN 8 /* for sockets. */
+#define VKI_F_GETOWN 9 /* for sockets. */
+#define VKI_F_SETSIG 10 /* for sockets. */
+#define VKI_F_GETSIG 11 /* for sockets. */
+
+#define VKI_F_GETLK64 12 /* using 'struct flock64' */
+#define VKI_F_SETLK64 13
+#define VKI_F_SETLKW64 14
+
+/* for F_[GET|SET]FL */
+#define VKI_FD_CLOEXEC 1 /* actually anything with low bit set goes */
+
+#define VKI_F_LINUX_SPECIFIC_BASE 1024
+
+//----------------------------------------------------------------------
+// From linux-2.6.9/include/asm-ppc/resource.h
+//----------------------------------------------------------------------
+
+#define VKI_RLIMIT_DATA 2 /* max data size */
+#define VKI_RLIMIT_STACK 3 /* max stack size */
+#define VKI_RLIMIT_CORE 4 /* max core file size */
+#define VKI_RLIMIT_NOFILE 7 /* max number of open files */
+
+//----------------------------------------------------------------------
+// From linux-2.6.9/include/asm-ppc/socket.h
+//----------------------------------------------------------------------
+
+#define VKI_SOL_SOCKET 1
+#define VKI_SO_TYPE 3
+
+#define VKI_SIOCSPGRP 0x8902
+#define VKI_SIOCGPGRP 0x8904
+#define VKI_SIOCGSTAMP 0x8906 /* Get stamp */
+
+//----------------------------------------------------------------------
+// From linux-2.6.9/include/asm-ppc/stat.h
+//----------------------------------------------------------------------
+
+//.. #define VKI_S_IFMT 00170000
+//.. #define VKI_S_IFSOCK 0140000
+//.. #define VKI_S_IFLNK 0120000
+//.. #define VKI_S_IFREG 0100000
+//.. #define VKI_S_IFBLK 0060000
+//.. #define VKI_S_IFDIR 0040000
+//.. #define VKI_S_IFCHR 0020000
+//.. #define VKI_S_IFIFO 0010000
+//.. #define VKI_S_ISUID 0004000
+//.. #define VKI_S_ISGID 0002000
+//.. #define VKI_S_ISVTX 0001000
+//..
+//.. #define VKI_S_ISLNK(m) (((m) & VKI_S_IFMT) == VKI_S_IFLNK)
+//.. #define VKI_S_ISREG(m) (((m) & VKI_S_IFMT) == VKI_S_IFREG)
+//.. #define VKI_S_ISDIR(m) (((m) & VKI_S_IFMT) == VKI_S_IFDIR)
+//.. #define VKI_S_ISCHR(m) (((m) & VKI_S_IFMT) == VKI_S_IFCHR)
+//.. #define VKI_S_ISBLK(m) (((m) & VKI_S_IFMT) == VKI_S_IFBLK)
+//.. #define VKI_S_ISFIFO(m) (((m) & VKI_S_IFMT) == VKI_S_IFIFO)
+//.. #define VKI_S_ISSOCK(m) (((m) & VKI_S_IFMT) == VKI_S_IFSOCK)
+
+struct vki_stat {
+ unsigned st_dev;
+ unsigned long st_ino;
+ unsigned int st_mode;
+ unsigned short st_nlink;
+ unsigned int st_uid;
+ unsigned int st_gid;
+ unsigned st_rdev;
+ long st_size;
+ unsigned long st_blksize;
+ unsigned long st_blocks;
+ unsigned long st_atime;
+ unsigned long st_atime_nsec;
+ unsigned long st_mtime;
+ unsigned long st_mtime_nsec;
+ unsigned long st_ctime;
+ unsigned long st_ctime_nsec;
+ unsigned long __unused4;
+ unsigned long __unused5;
+};
+
+struct vki_stat64 {
+ unsigned long st_dev;
+ unsigned long st_ino;
+ unsigned long st_rdev;
+ long st_size;
+ unsigned long st_blocks;
+
+ unsigned int st_mode;
+ unsigned int st_uid;
+ unsigned int st_gid;
+ unsigned int st_blksize;
+ unsigned int st_nlink;
+ unsigned int __pad0;
+
+ unsigned long st_atime;
+ unsigned long st_atime_nsec;
+ unsigned long st_mtime;
+ unsigned long st_mtime_nsec;
+ unsigned long st_ctime;
+ unsigned long st_ctime_nsec;
+ long __unused[3];
+};
+
+//----------------------------------------------------------------------
+// From linux-2.6.9/include/asm-ppc/statfs.h
+//----------------------------------------------------------------------
+
+// [[Nb: asm-ppc/statfs.h just #include asm-generic/statfs.h directly]]
+struct vki_statfs {
+ __vki_u32 f_type;
+ __vki_u32 f_bsize;
+ __vki_u32 f_blocks;
+ __vki_u32 f_bfree;
+ __vki_u32 f_bavail;
+ __vki_u32 f_files;
+ __vki_u32 f_ffree;
+ __vki_kernel_fsid_t f_fsid;
+ __vki_u32 f_namelen;
+ __vki_u32 f_frsize;
+ __vki_u32 f_spare[5];
+};
+
+//----------------------------------------------------------------------
+// From linux-2.6.9/include/asm-ppc/termios.h
+//----------------------------------------------------------------------
+
+struct vki_winsize {
+ unsigned short ws_row;
+ unsigned short ws_col;
+ unsigned short ws_xpixel;
+ unsigned short ws_ypixel;
+};
+
+#define NCC 10
+struct vki_termio {
+ unsigned short c_iflag; /* input mode flags */
+ unsigned short c_oflag; /* output mode flags */
+ unsigned short c_cflag; /* control mode flags */
+ unsigned short c_lflag; /* local mode flags */
+ unsigned char c_line; /* line discipline */
+ unsigned char c_cc[NCC]; /* control characters */
+};
+
+//----------------------------------------------------------------------
+// From linux-2.6.9/include/asm-ppc/termbits.h
+//----------------------------------------------------------------------
+
+typedef unsigned char vki_cc_t;
+typedef unsigned int vki_speed_t;
+typedef unsigned int vki_tcflag_t;
+
+#define NCCS 19
+struct vki_termios {
+ vki_tcflag_t c_iflag; /* input mode flags */
+ vki_tcflag_t c_oflag; /* output mode flags */
+ vki_tcflag_t c_cflag; /* control mode flags */
+ vki_tcflag_t c_lflag; /* local mode flags */
+ vki_cc_t c_cc[NCCS]; /* control characters */
+ vki_cc_t c_line; /* line discipline (== c_cc[19]) */
+ vki_speed_t c_ispeed; /* input speed */
+ vki_speed_t c_ospeed; /* output speed */
+};
+
+//----------------------------------------------------------------------
+// From linux-2.6.9/include/asm-ppc/ioctl.h
+//----------------------------------------------------------------------
+
+#define _VKI_IOC_NRBITS 8
+#define _VKI_IOC_TYPEBITS 8
+#define _VKI_IOC_SIZEBITS 13
+#define _VKI_IOC_DIRBITS 3
+
+#define _VKI_IOC_NRMASK ((1 << _VKI_IOC_NRBITS)-1)
+#define _VKI_IOC_TYPEMASK ((1 << _VKI_IOC_TYPEBITS)-1)
+#define _VKI_IOC_SIZEMASK ((1 << _VKI_IOC_SIZEBITS)-1)
+#define _VKI_IOC_DIRMASK ((1 << _VKI_IOC_DIRBITS)-1)
+
+#define _VKI_IOC_NRSHIFT 0
+#define _VKI_IOC_TYPESHIFT (_VKI_IOC_NRSHIFT+_VKI_IOC_NRBITS)
+#define _VKI_IOC_SIZESHIFT (_VKI_IOC_TYPESHIFT+_VKI_IOC_TYPEBITS)
+#define _VKI_IOC_DIRSHIFT (_VKI_IOC_SIZESHIFT+_VKI_IOC_SIZEBITS)
+
+#define _VKI_IOC_NONE 1U
+#define _VKI_IOC_READ 2U
+#define _VKI_IOC_WRITE 4U
+
+#define _VKI_IOC(dir,type,nr,size) \
+ (((dir) << _VKI_IOC_DIRSHIFT) | \
+ ((type) << _VKI_IOC_TYPESHIFT) | \
+ ((nr) << _VKI_IOC_NRSHIFT) | \
+ ((size) << _VKI_IOC_SIZESHIFT))
+
+/* provoke compile error for invalid uses of size argument */
+extern unsigned int __VKI_invalid_size_argument_for_IOC;
+#define _VKI_IOC_TYPECHECK(t) \
+ ((sizeof(t) == sizeof(t[1]) && \
+ sizeof(t) < (1 << _VKI_IOC_SIZEBITS)) ? \
+ sizeof(t) : __VKI_invalid_size_argument_for_IOC)
+
+/* used to create numbers */
+#define _VKI_IO(type,nr) _VKI_IOC(_VKI_IOC_NONE,(type),(nr),0)
+#define _VKI_IOR(type,nr,size) _VKI_IOC(_VKI_IOC_READ,(type),(nr),(_VKI_IOC_TYPECHECK(size)))
+#define _VKI_IOW(type,nr,size) _VKI_IOC(_VKI_IOC_WRITE,(type),(nr),(_VKI_IOC_TYPECHECK(size)))
+#define _VKI_IOWR(type,nr,size) _VKI_IOC(_VKI_IOC_READ|_VKI_IOC_WRITE,(type),(nr),(_VKI_IOC_TYPECHECK(size)))
+
+/* used to decode them.. */
+#define _VKI_IOC_DIR(nr) (((nr) >> _VKI_IOC_DIRSHIFT) & _VKI_IOC_DIRMASK)
+//.. #define _VKI_IOC_TYPE(nr) (((nr) >> _VKI_IOC_TYPESHIFT) & _VKI_IOC_TYPEMASK)
+//.. #define _VKI_IOC_NR(nr) (((nr) >> _VKI_IOC_NRSHIFT) & _VKI_IOC_NRMASK)
+#define _VKI_IOC_SIZE(nr) (((nr) >> _VKI_IOC_SIZESHIFT) & _VKI_IOC_SIZEMASK)
+
+//----------------------------------------------------------------------
+// From linux-2.6.9/include/asm-ppc/ioctls.h
+//----------------------------------------------------------------------
+
+//#define VKI_FIOCLEX _VKI_IO('f', 1)
+//#define VKI_FIONCLEX _VKI_IO('f', 2)
+#define VKI_FIOASYNC _VKI_IOW('f', 125, int)
+#define VKI_FIONBIO _VKI_IOW('f', 126, int)
+#define VKI_FIONREAD _VKI_IOR('f', 127, int)
+//#define VKI_TIOCINQ VKI_FIONREAD
+//#define VKI_FIOQSIZE _VKI_IOR('f', 128, vki_loff_t)
+
+//#define VKI_TIOCGETP _VKI_IOR('t', 8, struct vki_sgttyb)
+//#define VKI_TIOCSETP _VKI_IOW('t', 9, struct vki_sgttyb)
+//#define VKI_TIOCSETN _VKI_IOW('t', 10, struct vki_sgttyb) /* TIOCSETP wo flush */
+
+//#define VKI_TIOCSETC _VKI_IOW('t', 17, struct vki_tchars)
+//#define VKI_TIOCGETC _VKI_IOR('t', 18, struct vki_tchars)
+#define VKI_TCGETS _VKI_IOR('t', 19, struct vki_termios)
+#define VKI_TCSETS _VKI_IOW('t', 20, struct vki_termios)
+#define VKI_TCSETSW _VKI_IOW('t', 21, struct vki_termios)
+#define VKI_TCSETSF _VKI_IOW('t', 22, struct vki_termios)
+
+#define VKI_TCGETA _VKI_IOR('t', 23, struct vki_termio)
+#define VKI_TCSETA _VKI_IOW('t', 24, struct vki_termio)
+#define VKI_TCSETAW _VKI_IOW('t', 25, struct vki_termio)
+#define VKI_TCSETAF _VKI_IOW('t', 28, struct vki_termio)
+
+#define VKI_TCSBRK _VKI_IO('t', 29)
+#define VKI_TCXONC _VKI_IO('t', 30)
+#define VKI_TCFLSH _VKI_IO('t', 31)
+
+#define VKI_TIOCSWINSZ _VKI_IOW('t', 103, struct vki_winsize)
+#define VKI_TIOCGWINSZ _VKI_IOR('t', 104, struct vki_winsize)
+//#define VKI_TIOCSTART _VKI_IO('t', 110) /* start output, like ^Q */
+//#define VKI_TIOCSTOP _VKI_IO('t', 111) /* stop output, like ^S */
+#define VKI_TIOCOUTQ _VKI_IOR('t', 115, int) /* output queue size */
+
+//#define VKI_TIOCGLTC _VKI_IOR('t', 116, struct vki_ltchars)
+//#define VKI_TIOCSLTC _VKI_IOW('t', 117, struct vki_ltchars)
+#define VKI_TIOCSPGRP _VKI_IOW('t', 118, int)
+#define VKI_TIOCGPGRP _VKI_IOR('t', 119, int)
+
+//#define VKI_TIOCEXCL 0x540C
+//#define VKI_TIOCNXCL 0x540D
+#define VKI_TIOCSCTTY 0x540E
+
+//#define VKI_TIOCSTI 0x5412
+//#define VKI_TIOCMGET 0x5415
+#define VKI_TIOCMBIS 0x5416
+#define VKI_TIOCMBIC 0x5417
+#define VKI_TIOCMSET 0x5418
+//# define VKI_TIOCM_LE 0x001
+//# define VKI_TIOCM_DTR 0x002
+//# define VKI_TIOCM_RTS 0x004
+//# define VKI_TIOCM_ST 0x008
+//# define VKI_TIOCM_SR 0x010
+//# define VKI_TIOCM_CTS 0x020
+//# define VKI_TIOCM_CAR 0x040
+//# define VKI_TIOCM_RNG 0x080
+//# define VKI_TIOCM_DSR 0x100
+//# define VKI_TIOCM_CD VKI_TIOCM_CAR
+//# define VKI_TIOCM_RI VKI_TIOCM_RNG
+
+//#define VKI_TIOCGSOFTCAR 0x5419
+//#define VKI_TIOCSSOFTCAR 0x541A
+#define VKI_TIOCLINUX 0x541C
+//#define VKI_TIOCCONS 0x541D
+//#define VKI_TIOCGSERIAL 0x541E
+//#define VKI_TIOCSSERIAL 0x541F
+//#define VKI_TIOCPKT 0x5420
+//# define VKI_TIOCPKT_DATA 0
+//# define VKI_TIOCPKT_FLUSHREAD 1
+//# define VKI_TIOCPKT_FLUSHWRITE 2
+//# define VKI_TIOCPKT_STOP 4
+//# define VKI_TIOCPKT_START 8
+//# define VKI_TIOCPKT_NOSTOP 16
+//# define VKI_TIOCPKT_DOSTOP 32
+
+//#define VKI_TIOCNOTTY 0x5422
+//#define VKI_TIOCSETD 0x5423
+//#define VKI_TIOCGETD 0x5424
+#define VKI_TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */
+//#define VKI_TIOCSBRK 0x5427 /* BSD compatibility */
+//#define VKI_TIOCCBRK 0x5428 /* BSD compatibility */
+//#define VKI_TIOCGSID 0x5429 /* Return the session ID of FD */
+#define VKI_TIOCGPTN _VKI_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
+#define VKI_TIOCSPTLCK _VKI_IOW('T',0x31, int) /* Lock/unlock Pty */
+
+//#define VKI_TIOCSERCONFIG 0x5453
+//#define VKI_TIOCSERGWILD 0x5454
+//#define VKI_TIOCSERSWILD 0x5455
+//#define VKI_TIOCGLCKTRMIOS 0x5456
+//#define VKI_TIOCSLCKTRMIOS 0x5457
+//#define VKI_TIOCSERGSTRUCT 0x5458 /* For debugging only */
+//#define VKI_TIOCSERGETLSR 0x5459 /* Get line status register */
+// /* ioctl (fd, VKI_TIOCSERGETLSR, &result) where result may be as below */
+//# define VKI_TIOCSER_TEMT 0x01 /* Transmitter physically empty */
+//#define VKI_TIOCSERGETMULTI 0x545A /* Get multiport config */
+//#define VKI_TIOCSERSETMULTI 0x545B /* Set multiport config */
+
+//#define VKI_TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */
+//#define VKI_TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */
+
+//----------------------------------------------------------------------
+// From linux-2.6.9/include/asm-ppc/poll.h
+//----------------------------------------------------------------------
+
+//.. /* These are specified by iBCS2 */
+//.. #define VKI_POLLIN 0x0001
+
+struct vki_pollfd {
+ int fd;
+ short events;
+ short revents;
+};
+
+//.. //----------------------------------------------------------------------
+//.. // From linux-2.6.8.1/include/asm-i386/user.h
+//.. //----------------------------------------------------------------------
+//..
+//.. struct vki_user_i387_struct {
+//.. long cwd;
+//.. long swd;
+//.. long twd;
+//.. long fip;
+//.. long fcs;
+//.. long foo;
+//.. long fos;
+//.. long st_space[20]; /* 8*10 bytes for each FP-reg = 80 bytes */
+//.. };
+//..
+//.. struct vki_user_fxsr_struct {
+//.. unsigned short cwd;
+//.. unsigned short swd;
+//.. unsigned short twd;
+//.. unsigned short fop;
+//.. long fip;
+//.. long fcs;
+//.. long foo;
+//.. long fos;
+//.. long mxcsr;
+//.. long reserved;
+//.. long st_space[32]; /* 8*16 bytes for each FP-reg = 128 bytes */
+//.. long xmm_space[32]; /* 8*16 bytes for each XMM-reg = 128 bytes */
+//.. long padding[56];
+//.. };
+//..
+//.. /*
+//.. * This is the old layout of "struct pt_regs", and
+//.. * is still the layout used by user mode (the new
+//.. * pt_regs doesn't have all registers as the kernel
+//.. * doesn't use the extra segment registers)
+//.. */
+//.. struct vki_user_regs_struct {
+//.. long ebx, ecx, edx, esi, edi, ebp, eax;
+//.. unsigned short ds, __ds, es, __es;
+//.. unsigned short fs, __fs, gs, __gs;
+//.. long orig_eax, eip;
+//.. unsigned short cs, __cs;
+//.. long eflags, esp;
+//.. unsigned short ss, __ss;
+//.. };
+
+//----------------------------------------------------------------------
+// From linux-2.6.9/include/asm-ppc/elf.h
+//----------------------------------------------------------------------
+
+#define VKI_ELF_NGREG 48 /* includes nip, msr, lr, etc. */
+#define VKI_ELF_NFPREG 33 /* includes fpscr */
+#define VKI_ELF_NVRREG 33 /* includes vscr */
+
+/* General registers */
+typedef unsigned long vki_elf_greg_t;
+typedef vki_elf_greg_t vki_elf_gregset_t[VKI_ELF_NGREG];
+
+/* Floating point registers */
+typedef double vki_elf_fpreg_t;
+typedef vki_elf_fpreg_t vki_elf_fpregset_t[VKI_ELF_NFPREG];
+
+/* Altivec registers */
+typedef __vki_vector128 vki_elf_vrreg_t;
+typedef vki_elf_vrreg_t vki_elf_vrregset_t[VKI_ELF_NVRREG];
+
+#define VKI_AT_DCACHEBSIZE 19
+#define VKI_AT_ICACHEBSIZE 20
+#define VKI_AT_UCACHEBSIZE 21
+/* A special ignored type value for PPC, for glibc compatibility. */
+#define VKI_AT_IGNOREPPC 22
+
+/* CAB: Do we want these? */
+//#define VKI_AT_SYSINFO 32
+//#define VKI_AT_SYSINFO_EHDR 33
+
+//----------------------------------------------------------------------
+// From linux-2.6.9/include/asm-ppc/ucontext.h
+//----------------------------------------------------------------------
+
+struct vki_mcontext {
+ vki_elf_gregset_t mc_gregs;
+ vki_elf_fpregset_t mc_fregs;
+ unsigned long mc_pad[2];
+ vki_elf_vrregset_t mc_vregs __attribute__((__aligned__(16)));
+};
+
+struct vki_ucontext {
+ unsigned long uc_flags;
+ struct vki_ucontext __user *uc_link;
+ vki_stack_t uc_stack;
+ int uc_pad[7];
+ struct vki_mcontext __user *uc_regs; /* points to uc_mcontext field */
+ vki_sigset_t uc_sigmask;
+ /* glibc has 1024-bit signal masks, ours are 64-bit */
+ int uc_maskext[30];
+ int uc_pad2[3];
+ struct vki_mcontext uc_mcontext;
+};
+
+//.. //----------------------------------------------------------------------
+//.. // From linux-2.6.8.1/include/asm-i386/segment.h
+//.. //----------------------------------------------------------------------
+//..
+//.. #define VKI_GDT_ENTRY_TLS_ENTRIES 3
+//.. #define VKI_GDT_ENTRY_TLS_MIN 6
+//.. #define VKI_GDT_ENTRY_TLS_MAX (VKI_GDT_ENTRY_TLS_MIN + VKI_GDT_ENTRY_TLS_ENTRIES - 1)
+
+//----------------------------------------------------------------------
+// From linux-2.6.9/include/asm-ppc/ldt.h
+//----------------------------------------------------------------------
+
+//.. /* [[Nb: This is the structure passed to the modify_ldt syscall. Just so as
+//.. to confuse and annoy everyone, this is _not_ the same as an
+//.. VgLdtEntry and has to be translated into such. The logic for doing
+//.. so, in vg_ldt.c, is copied from the kernel sources.]] */
+//.. struct vki_user_desc {
+//.. unsigned int entry_number;
+//.. unsigned long base_addr;
+//.. unsigned int limit;
+//.. unsigned int seg_32bit:1;
+//.. unsigned int contents:2;
+//.. unsigned int read_exec_only:1;
+//.. unsigned int limit_in_pages:1;
+//.. unsigned int seg_not_present:1;
+//.. unsigned int useable:1;
+//.. // [[Nb: this field is not in the kernel sources, but it has always
+//.. // been in the Valgrind sources so I will keep it there in case it's
+//.. // important... this is an x86-defined data structure so who
+//.. // knows; maybe it's important to set this field to zero at some
+//.. // point. --njn]]
+//.. unsigned int reserved:25;
+//.. };
+//..
+//.. // [[Nb: for our convenience within Valgrind, use a more specific name]]
+//.. typedef struct vki_user_desc vki_modify_ldt_t;
+
+// CAB: TODO
+typedef void vki_modify_ldt_t;
+
+
+//----------------------------------------------------------------------
+// From linux-2.6.9/include/asm-ppc/ipcbuf.h
+//----------------------------------------------------------------------
+
+struct vki_ipc64_perm
+{
+ __vki_kernel_key_t key;
+ __vki_kernel_uid_t uid;
+ __vki_kernel_gid_t gid;
+ __vki_kernel_uid_t cuid;
+ __vki_kernel_gid_t cgid;
+ __vki_kernel_mode_t mode;
+ unsigned long seq;
+ unsigned int __pad2;
+ unsigned long long __unused1;
+ unsigned long long __unused2;
+};
+
+//----------------------------------------------------------------------
+// From linux-2.6.9/include/asm-ppc/sembuf.h
+//----------------------------------------------------------------------
+
+struct vki_semid64_ds {
+ struct vki_ipc64_perm sem_perm; /* permissions .. see ipc.h */
+ unsigned int __unused1;
+ __vki_kernel_time_t sem_otime; /* last semop time */
+ unsigned int __unused2;
+ __vki_kernel_time_t sem_ctime; /* last change time */
+ unsigned long sem_nsems; /* no. of semaphores in array */
+ unsigned long __unused3;
+ unsigned long __unused4;
+};
+
+//----------------------------------------------------------------------
+// From linux-2.6.9/include/asm-ppc/msgbuf.h
+//----------------------------------------------------------------------
+
+struct vki_msqid64_ds {
+ struct vki_ipc64_perm msg_perm;
+ unsigned int __unused1;
+ __vki_kernel_time_t msg_stime; /* last msgsnd time */
+ unsigned int __unused2;
+ __vki_kernel_time_t msg_rtime; /* last msgrcv time */
+ unsigned int __unused3;
+ __vki_kernel_time_t msg_ctime; /* last change time */
+ unsigned long msg_cbytes; /* current number of bytes on queue */
+ unsigned long msg_qnum; /* number of messages in queue */
+ unsigned long msg_qbytes; /* max number of bytes on queue */
+ __vki_kernel_pid_t msg_lspid; /* pid of last msgsnd */
+ __vki_kernel_pid_t msg_lrpid; /* last receive pid */
+ unsigned long __unused4;
+ unsigned long __unused5;
+};
+
+//.. //----------------------------------------------------------------------
+//.. // From linux-2.6.8.1/include/asm-i386/ipc.h
+//.. //----------------------------------------------------------------------
+//..
+//.. struct vki_ipc_kludge {
+//.. struct vki_msgbuf __user *msgp;
+//.. long msgtyp;
+//.. };
+//..
+//.. #define VKI_SEMOP 1
+//.. #define VKI_SEMGET 2
+//.. #define VKI_SEMCTL 3
+//.. #define VKI_SEMTIMEDOP 4
+//.. #define VKI_MSGSND 11
+//.. #define VKI_MSGRCV 12
+//.. #define VKI_MSGGET 13
+//.. #define VKI_MSGCTL 14
+//.. #define VKI_SHMAT 21
+//.. #define VKI_SHMDT 22
+//.. #define VKI_SHMGET 23
+//.. #define VKI_SHMCTL 24
+
+//----------------------------------------------------------------------
+// From linux-2.6.9/include/asm-ppc/shmbuf.h
+//----------------------------------------------------------------------
+
+struct vki_shmid64_ds {
+ struct vki_ipc64_perm shm_perm; /* operation perms */
+ unsigned int __unused1;
+ __vki_kernel_time_t shm_atime; /* last attach time */
+ unsigned int __unused2;
+ __vki_kernel_time_t shm_dtime; /* last detach time */
+ unsigned int __unused3;
+ __vki_kernel_time_t shm_ctime; /* last change time */
+ unsigned int __unused4;
+ vki_size_t shm_segsz; /* size of segment (bytes) */
+ __vki_kernel_pid_t shm_cpid; /* pid of creator */
+ __vki_kernel_pid_t shm_lpid; /* pid of last operator */
+ unsigned long shm_nattch; /* no. of current attaches */
+ unsigned long __unused5;
+ unsigned long __unused6;
+};
+
+struct vki_shminfo64 {
+ unsigned long shmmax;
+ unsigned long shmmin;
+ unsigned long shmmni;
+ unsigned long shmseg;
+ unsigned long shmall;
+ unsigned long __unused1;
+ unsigned long __unused2;
+ unsigned long __unused3;
+ unsigned long __unused4;
+};
+
+//.. //----------------------------------------------------------------------
+//.. // DRM ioctls
+//.. //----------------------------------------------------------------------
+//..
+//.. // jrs 20050207: where did all this stuff come from? Is it really
+//.. // i386 specific, or should it go into the linux-generic category?
+//.. //struct vki_drm_buf_pub {
+//.. // Int idx; /**< Index into the master buffer list */
+//.. // Int total; /**< Buffer size */
+//.. // Int used; /**< Amount of buffer in use (for DMA) */
+//.. // void __user *address; /**< Address of buffer */
+//.. //};
+//.. //
+//.. //struct vki_drm_buf_map {
+//.. // Int count; /**< Length of the buffer list */
+//.. // void __user *virtual; /**< Mmap'd area in user-virtual */
+//.. // struct vki_drm_buf_pub __user *list; /**< Buffer information */
+//.. //};
+//.. //
+//.. ///* We need to pay attention to this, because it mmaps memory */
+//.. //#define VKI_DRM_IOCTL_MAP_BUFS _VKI_IOWR('d', 0x19, struct vki_drm_buf_map)
+
+//.. //----------------------------------------------------------------------
+//.. // From linux-2.6.9/include/asm-i386/ptrace.h
+//.. //----------------------------------------------------------------------
+//..
+//.. #define VKI_PTRACE_GETREGS 12
+//.. #define VKI_PTRACE_SETREGS 13
+//.. #define VKI_PTRACE_GETFPREGS 14
+//.. #define VKI_PTRACE_SETFPREGS 15
+//.. #define VKI_PTRACE_GETFPXREGS 18
+//.. #define VKI_PTRACE_SETFPXREGS 19
+
+//----------------------------------------------------------------------
+// And that's it!
+//----------------------------------------------------------------------
+
+#endif // __PPC32_LINUX_VKI_ARCH_H
+
+/*--------------------------------------------------------------------*/
+/*--- end ---*/
+/*--------------------------------------------------------------------*/
diff --git a/include/vki_posixtypes-ppc32-linux.h b/include/vki_posixtypes-ppc32-linux.h
new file mode 100644
index 0000000..a4117ea
--- /dev/null
+++ b/include/vki_posixtypes-ppc32-linux.h
@@ -0,0 +1,68 @@
+
+/*--------------------------------------------------------------------*/
+/*--- PPC32/Linux-specific kernel interface: posix types. ---*/
+/*--- vki_posixtypes-ppc32-linux.h ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+ This file is part of Valgrind, a dynamic binary instrumentation
+ framework.
+
+ Copyright (C) 2005 Julian Seward
+ jseward@acm.org
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ The GNU General Public License is contained in the file COPYING.
+*/
+
+#ifndef __PPC32_LINUX_VKI_ARCH_POSIXTYPES_H
+#define __PPC32_LINUX_VKI_ARCH_POSIXTYPES_H
+
+//----------------------------------------------------------------------
+// From linux-2.6.9/include/asm-ppc/posix_types.h
+//----------------------------------------------------------------------
+
+typedef unsigned int __vki_kernel_mode_t;
+typedef long __vki_kernel_off_t;
+typedef int __vki_kernel_pid_t;
+typedef unsigned short __vki_kernel_ipc_pid_t;
+typedef unsigned int __vki_kernel_uid_t;
+typedef unsigned int __vki_kernel_gid_t;
+typedef unsigned int __vki_kernel_size_t;
+typedef long __vki_kernel_time_t;
+typedef long __vki_kernel_suseconds_t;
+typedef long __vki_kernel_clock_t;
+typedef int __vki_kernel_timer_t;
+typedef int __vki_kernel_clockid_t;
+typedef char * __vki_kernel_caddr_t;
+typedef unsigned int __vki_kernel_uid32_t;
+typedef unsigned int __vki_kernel_gid32_t;
+
+typedef unsigned int __vki_kernel_old_uid_t;
+typedef unsigned int __vki_kernel_old_gid_t;
+
+typedef long long __vki_kernel_loff_t;
+
+typedef struct {
+ int val[2];
+} __vki_kernel_fsid_t;
+
+#endif // __PPC32_LINUX_VKI_ARCH_POSIXTYPES_H
+
+/*--------------------------------------------------------------------*/
+/*--- end ---*/
+/*--------------------------------------------------------------------*/
diff --git a/memcheck/tests/ppc32/Makefile.am b/memcheck/tests/ppc32/Makefile.am
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/memcheck/tests/ppc32/Makefile.am
diff --git a/none/tests/ppc32/Makefile.am b/none/tests/ppc32/Makefile.am
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/none/tests/ppc32/Makefile.am