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, &regs);
 #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 = &regs->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 = &regs->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)( &regs->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)(&regs->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( &regs->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 >= &sectors[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