about summary refs log tree commit diff
path: root/sysdeps
diff options
context:
space:
mode:
Diffstat (limited to 'sysdeps')
-rw-r--r--sysdeps/generic/register-dump.h21
-rw-r--r--sysdeps/generic/segfault.c55
-rw-r--r--sysdeps/i386/register-dump.h256
-rw-r--r--sysdeps/powerpc/register-dump.h73
-rw-r--r--sysdeps/unix/sysv/linux/i386/profil-counter.h5
-rw-r--r--sysdeps/unix/sysv/linux/ldd-rewrite.sed2
-rw-r--r--sysdeps/unix/sysv/linux/powerpc/chown.c131
-rw-r--r--sysdeps/unix/sysv/linux/powerpc/clone.S78
-rw-r--r--sysdeps/unix/sysv/linux/powerpc/lchown.S35
-rw-r--r--sysdeps/unix/sysv/linux/powerpc/profil-counter.h36
-rw-r--r--sysdeps/unix/sysv/linux/powerpc/sigcontextinfo.h24
-rw-r--r--sysdeps/unix/sysv/linux/powerpc/syscalls.list4
-rw-r--r--sysdeps/unix/sysv/linux/sys/mount.h6
13 files changed, 642 insertions, 84 deletions
diff --git a/sysdeps/generic/register-dump.h b/sysdeps/generic/register-dump.h
new file mode 100644
index 0000000000..42c222c2ed
--- /dev/null
+++ b/sysdeps/generic/register-dump.h
@@ -0,0 +1,21 @@
+/* Dump registers.
+   Copyright (C) 1998 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+/* In general we cannot do anything.  */
diff --git a/sysdeps/generic/segfault.c b/sysdeps/generic/segfault.c
index 6504123e18..090f91a657 100644
--- a/sysdeps/generic/segfault.c
+++ b/sysdeps/generic/segfault.c
@@ -18,16 +18,21 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
+#include <ctype.h>
 #include <execinfo.h>
 #include <fcntl.h>
 #include <signal.h>
 #include <stdlib.h>
+#include <string.h>
 #include <unistd.h>
 
 /* This file defines macros to access the content of the sigcontext element
    passed up by the signal handler.  */
 #include <sigcontextinfo.h>
 
+/* Get code to possibly dump the content of all registers.  */
+#include <register-dump.h>
+
 /* This is a global variable set at program start time.  It marks the
    highest used stack address.  */
 extern void *__libc_stack_end;
@@ -76,6 +81,8 @@ catch_segfault (int signal, SIGCONTEXT ctx)
   int fd;
   void **arr;
   size_t cnt;
+  struct sigaction sa;
+  const char *sigstring;
 
   /* This is the name of the file we are writing to.  If none is given
      or we cannot write to this file write to stderr.  */
@@ -88,9 +95,17 @@ catch_segfault (int signal, SIGCONTEXT ctx)
 	fd = 2;
     }
 
-#define WRITE_STRING(s) write (fd, s, sizeof (s) - 1)
-  WRITE_STRING ("*** Segmentation Fault\n");
-  WRITE_STRING ("Backtrace:\n");
+#define WRITE_STRING(s) write (fd, s, strlen (s))
+  WRITE_STRING ("*** ");
+  sigstring = strsignal (signal);
+  WRITE_STRING (sigstring);
+  WRITE_STRING ("\n");
+
+#ifdef REGISTER_DUMP
+  REGISTER_DUMP;
+#endif
+
+  WRITE_STRING ("\nBacktrace:\n");
 
   top_frame = GET_FRAME (ctx);
   top_stack = GET_STACK (ctx);
@@ -124,8 +139,12 @@ catch_segfault (int signal, SIGCONTEXT ctx)
   /* Now generate nicely formatted output.  */
   __backtrace_symbols_fd (arr, cnt, fd);
 
-  /* Nothing else to do.  */
-  _exit (128 + SIGSEGV);
+  /* Pass on the signal (so that a core file is produced).  */
+  sa.sa_handler = SIG_DFL;
+  sigemptyset (&sa.sa_mask);
+  sa.sa_flags = 0;
+  sigaction (signal, &sa, NULL);
+  raise (signal);
 }
 
 
@@ -134,12 +153,36 @@ __attribute__ ((constructor))
 install_handler (void)
 {
   struct sigaction sa;
+  const char *sigs = getenv ("SEGFAULT_SIGNALS");
 
   sa.sa_handler = (void *) catch_segfault;
   sigemptyset (&sa.sa_mask);
   sa.sa_flags = SA_RESTART;
 
-  sigaction (SIGSEGV, &sa, NULL);
+  if (sigs == NULL)
+    sigaction (SIGSEGV, &sa, NULL);
+  else if (sigs[0] == '\0')
+    /* Do not do anything.  */
+    return;
+  else
+    {
+      const char *where;
+      int all = __strcasecmp (sigs, "all");
+
+#define INSTALL_FOR_SIG(sig, name) \
+      where = __strcasestr (sigs, name);				      \
+      if (all || (where != NULL						      \
+		  && (where == sigs || !isalnum (where[-1]))		      \
+		  && !isalnum (where[sizeof (name) - 1])))		      \
+	sigaction (sig, &sa, NULL);
+
+      INSTALL_FOR_SIG (SIGSEGV, "segv");
+      INSTALL_FOR_SIG (SIGILL, "ill");
+      INSTALL_FOR_SIG (SIGBUS, "bus");
+      INSTALL_FOR_SIG (SIGSTKFLT, "stkflt");
+      INSTALL_FOR_SIG (SIGABRT, "abrt");
+      INSTALL_FOR_SIG (SIGFPE, "fpe");
+    }
 
   /* Maybe we are expected to use an alternative stack.  */
   if (getenv ("SEGFAULT_USE_ALTSTACK") != 0)
diff --git a/sysdeps/i386/register-dump.h b/sysdeps/i386/register-dump.h
new file mode 100644
index 0000000000..34501fe1be
--- /dev/null
+++ b/sysdeps/i386/register-dump.h
@@ -0,0 +1,256 @@
+/* Dump registers.
+   Copyright (C) 1998 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <sys/uio.h>
+#include <stdio-common/_itoa.h>
+
+/* We will print the register dump in this format:
+
+ EAX: XXXXXXXX   EBX: XXXXXXXX   ECX: XXXXXXXX   EDX: XXXXXXXX
+ ESI: XXXXXXXX   EDI: XXXXXXXX   EBP: XXXXXXXX   ESP: XXXXXXXX
+
+ EIP: XXXXXXXX   EFLAGS: XXXXXXXX
+
+ CS:  XXXX   DS: XXXX   ES: XXXX   FS: XXXX   GS: XXXX   SS: XXXX
+
+ Trap:  XXXXXXXX   Error: XXXXXXXX   OldMask: XXXXXXXX
+ ESP/SIGNAL: XXXXXXXX   CR2: XXXXXXXX
+
+ FPUCW: XXXXXXXX   FPUSW: XXXXXXXX   TAG: XXXXXXXX
+ IPOFF: XXXXXXXX   CSSEL: XXXX   DATAOFF: XXXXXXXX   DATASEL: XXXX
+
+ ST(0) XXXX XXXXXXXXXXXXXXXX   ST(1) XXXX XXXXXXXXXXXXXXXX
+ ST(2) XXXX XXXXXXXXXXXXXXXX   ST(3) XXXX XXXXXXXXXXXXXXXX
+ ST(4) XXXX XXXXXXXXXXXXXXXX   ST(5) XXXX XXXXXXXXXXXXXXXX
+ ST(6) XXXX XXXXXXXXXXXXXXXX   ST(7) XXXX XXXXXXXXXXXXXXXX
+
+ */
+
+static void
+hexvalue (unsigned long int value, char *buf, size_t len)
+{
+  char *cp = _itoa_word (value, buf + len, 16, 0);
+  while (cp > buf)
+    *--cp = '0';
+}
+
+static void
+register_dump (int fd, struct sigcontext *ctx)
+{
+  char regs[21][8];
+  char fpregs[31][8];
+  struct iovec iov[97];
+  size_t nr = 0;
+
+#define ADD_STRING(str) \
+  iov[nr].iov_base = (char *) str;					      \
+  iov[nr].iov_len = strlen (str);					      \
+  ++nr
+#define ADD_MEM(str, len) \
+  iov[nr].iov_base = str;						      \
+  iov[nr].iov_len = len;						      \
+  ++nr
+
+  /* Generate strings of register contents.  */
+  hexvalue (ctx->eax, regs[0], 8);
+  hexvalue (ctx->ebx, regs[1], 8);
+  hexvalue (ctx->ecx, regs[2], 8);
+  hexvalue (ctx->edx, regs[3], 8);
+  hexvalue (ctx->esi, regs[4], 8);
+  hexvalue (ctx->edi, regs[5], 8);
+  hexvalue (ctx->ebp, regs[6], 8);
+  hexvalue (ctx->esp, regs[7], 8);
+  hexvalue (ctx->eip, regs[8], 8);
+  hexvalue (ctx->eflags, regs[9], 8);
+  hexvalue (ctx->cs, regs[10], 4);
+  hexvalue (ctx->ds, regs[11], 4);
+  hexvalue (ctx->es, regs[12], 4);
+  hexvalue (ctx->fs, regs[13], 4);
+  hexvalue (ctx->gs, regs[14], 4);
+  hexvalue (ctx->ss, regs[15], 4);
+  hexvalue (ctx->trapno, regs[16], 8);
+  hexvalue (ctx->err, regs[17], 8);
+  hexvalue (ctx->oldmask, regs[18], 8);
+  hexvalue (ctx->esp_at_signal, regs[19], 8);
+  hexvalue (ctx->cr2, regs[20], 8);
+
+  /* Generate the output.  */
+  ADD_STRING ("Register dump:\n\n EAX: ");
+  ADD_MEM (regs[0], 8);
+  ADD_STRING ("   EBX: ");
+  ADD_MEM (regs[1], 8);
+  ADD_STRING ("   ECX: ");
+  ADD_MEM (regs[2], 8);
+  ADD_STRING ("   EDX: ");
+  ADD_MEM (regs[3], 8);
+  ADD_STRING ("\n ESI: ");
+  ADD_MEM (regs[4], 8);
+  ADD_STRING ("   EDI: ");
+  ADD_MEM (regs[5], 8);
+  ADD_STRING ("   EBP: ");
+  ADD_MEM (regs[6], 8);
+  ADD_STRING ("   ESP: ");
+  ADD_MEM (regs[7], 8);
+  ADD_STRING ("\n\n EIP: ");
+  ADD_MEM (regs[8], 8);
+  ADD_STRING ("   EFLAGS: ");
+  ADD_MEM (regs[9], 8);
+  ADD_STRING ("\n\n CS: ");
+  ADD_MEM (regs[10], 4);
+  ADD_STRING ("   DS: ");
+  ADD_MEM (regs[11], 4);
+  ADD_STRING ("   ES: ");
+  ADD_MEM (regs[12], 4);
+  ADD_STRING ("   FS: ");
+  ADD_MEM (regs[13], 4);
+  ADD_STRING ("   GS: ");
+  ADD_MEM (regs[14], 4);
+  ADD_STRING ("   SS: ");
+  ADD_MEM (regs[15], 4);
+  ADD_STRING ("\n\n Trap: ");
+  ADD_MEM (regs[16], 8);
+  ADD_STRING ("   Error: ");
+  ADD_MEM (regs[17], 8);
+  ADD_STRING ("   OldMask: ");
+  ADD_MEM (regs[18], 8);
+  ADD_STRING ("\n ESP/signal: ");
+  ADD_MEM (regs[19], 8);
+  ADD_STRING ("   CR2: ");
+  ADD_MEM (regs[20], 8);
+
+  if (ctx->fpstate != NULL)
+    {
+
+      /* Generate output for the FPU control/status registers.  */
+      hexvalue (ctx->fpstate->cw, fpregs[0], 8);
+      hexvalue (ctx->fpstate->sw, fpregs[1], 8);
+      hexvalue (ctx->fpstate->tag, fpregs[2], 8);
+      hexvalue (ctx->fpstate->ipoff, fpregs[3], 8);
+      hexvalue (ctx->fpstate->cssel, fpregs[4], 4);
+      hexvalue (ctx->fpstate->dataoff, fpregs[5], 8);
+      hexvalue (ctx->fpstate->datasel, fpregs[6], 4);
+
+      ADD_STRING ("\n\n FPUCW: ");
+      ADD_MEM (fpregs[0], 8);
+      ADD_STRING ("   FPUSW: ");
+      ADD_MEM (fpregs[1], 8);
+      ADD_STRING ("   TAG: ");
+      ADD_MEM (fpregs[2], 8);
+      ADD_STRING ("\n IPOFF: ");
+      ADD_MEM (fpregs[3], 8);
+      ADD_STRING ("   CSSEL: ");
+      ADD_MEM (fpregs[4], 4);
+      ADD_STRING ("   DATAOFF: ");
+      ADD_MEM (fpregs[5], 8);
+      ADD_STRING ("   DATASEL: ");
+      ADD_MEM (fpregs[6], 4);
+
+      /* Now the real FPU registers.  */
+      hexvalue (ctx->fpstate->_st[0].exponent, fpregs[7], 8);
+      hexvalue (ctx->fpstate->_st[0].significand[3] << 16
+		| ctx->fpstate->_st[0].significand[2], fpregs[8], 8);
+      hexvalue (ctx->fpstate->_st[0].significand[1] << 16
+		| ctx->fpstate->_st[0].significand[0], fpregs[9], 8);
+      hexvalue (ctx->fpstate->_st[1].exponent, fpregs[10], 8);
+      hexvalue (ctx->fpstate->_st[1].significand[3] << 16
+		| ctx->fpstate->_st[1].significand[2], fpregs[11], 8);
+      hexvalue (ctx->fpstate->_st[1].significand[1] << 16
+		| ctx->fpstate->_st[1].significand[0], fpregs[12], 8);
+      hexvalue (ctx->fpstate->_st[2].exponent, fpregs[13], 8);
+      hexvalue (ctx->fpstate->_st[2].significand[3] << 16
+		| ctx->fpstate->_st[2].significand[2], fpregs[14], 8);
+      hexvalue (ctx->fpstate->_st[2].significand[1] << 16
+		| ctx->fpstate->_st[2].significand[0], fpregs[15], 8);
+      hexvalue (ctx->fpstate->_st[3].exponent, fpregs[16], 8);
+      hexvalue (ctx->fpstate->_st[3].significand[3] << 16
+		| ctx->fpstate->_st[3].significand[2], fpregs[17], 8);
+      hexvalue (ctx->fpstate->_st[3].significand[1] << 16
+		| ctx->fpstate->_st[3].significand[0], fpregs[18], 8);
+      hexvalue (ctx->fpstate->_st[4].exponent, fpregs[19], 8);
+      hexvalue (ctx->fpstate->_st[4].significand[3] << 16
+		| ctx->fpstate->_st[4].significand[2], fpregs[20], 8);
+      hexvalue (ctx->fpstate->_st[4].significand[1] << 16
+		| ctx->fpstate->_st[4].significand[0], fpregs[21], 8);
+      hexvalue (ctx->fpstate->_st[5].exponent, fpregs[22], 8);
+      hexvalue (ctx->fpstate->_st[5].significand[3] << 16
+		| ctx->fpstate->_st[5].significand[2], fpregs[23], 8);
+      hexvalue (ctx->fpstate->_st[5].significand[1] << 16
+		| ctx->fpstate->_st[5].significand[0], fpregs[24], 8);
+      hexvalue (ctx->fpstate->_st[6].exponent, fpregs[25], 8);
+      hexvalue (ctx->fpstate->_st[6].significand[3] << 16
+		| ctx->fpstate->_st[6].significand[2], fpregs[26], 8);
+      hexvalue (ctx->fpstate->_st[6].significand[1] << 16
+		| ctx->fpstate->_st[6].significand[0], fpregs[27], 8);
+      hexvalue (ctx->fpstate->_st[7].exponent, fpregs[28], 8);
+      hexvalue (ctx->fpstate->_st[7].significand[3] << 16
+		| ctx->fpstate->_st[7].significand[2], fpregs[29], 8);
+      hexvalue (ctx->fpstate->_st[7].significand[1] << 16
+		| ctx->fpstate->_st[7].significand[0], fpregs[30], 8);
+
+      ADD_STRING ("\n\n ST(0) ");
+      ADD_MEM (fpregs[7], 4);
+      ADD_STRING (" ");
+      ADD_MEM (fpregs[8], 8);
+      ADD_MEM (fpregs[9], 8);
+      ADD_STRING ("   ST(1) ");
+      ADD_MEM (fpregs[10], 4);
+      ADD_STRING (" ");
+      ADD_MEM (fpregs[11], 8);
+      ADD_MEM (fpregs[12], 8);
+      ADD_STRING ("\n ST(2) ");
+      ADD_MEM (fpregs[13], 4);
+      ADD_STRING (" ");
+      ADD_MEM (fpregs[14], 8);
+      ADD_MEM (fpregs[15], 8);
+      ADD_STRING ("   ST(3) ");
+      ADD_MEM (fpregs[16], 4);
+      ADD_STRING (" ");
+      ADD_MEM (fpregs[17], 8);
+      ADD_MEM (fpregs[18], 8);
+      ADD_STRING ("\n ST(4) ");
+      ADD_MEM (fpregs[19], 4);
+      ADD_STRING (" ");
+      ADD_MEM (fpregs[20], 8);
+      ADD_MEM (fpregs[21], 8);
+      ADD_STRING ("   ST(5) ");
+      ADD_MEM (fpregs[22], 4);
+      ADD_STRING (" ");
+      ADD_MEM (fpregs[23], 8);
+      ADD_MEM (fpregs[24], 8);
+      ADD_STRING ("\n ST(6) ");
+      ADD_MEM (fpregs[25], 4);
+      ADD_STRING (" ");
+      ADD_MEM (fpregs[26], 8);
+      ADD_MEM (fpregs[27], 8);
+      ADD_STRING ("   ST(7) ");
+      ADD_MEM (fpregs[28], 4);
+      ADD_STRING (" ");
+      ADD_MEM (fpregs[29], 8);
+      ADD_MEM (fpregs[30], 8);
+    }
+
+  ADD_STRING ("\n");
+
+  /* Write the stuff out.  */
+  writev (fd, iov, nr);
+}
+
+
+#define REGISTER_DUMP register_dump (fd, &ctx)
diff --git a/sysdeps/powerpc/register-dump.h b/sysdeps/powerpc/register-dump.h
new file mode 100644
index 0000000000..428b6073b9
--- /dev/null
+++ b/sysdeps/powerpc/register-dump.h
@@ -0,0 +1,73 @@
+/* Dump registers.
+   Copyright (C) 1998 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <sys/uio.h>
+#include <stdio-common/_itoa.h>
+
+static const char *regnames[] =
+{
+  "\nr0 =", " sp =", " r2 =", " r3 =", " r4 =", " r5 =",
+  "\nr6 =", " r7 =", " r8 =", " r9 =", " r10=", " r11=",
+  "\nr12=", " r13=", " r14=", " r15=", " r16=", " r17=",
+  "\nr18=", " r19=", " r20=", " r21=", " r22=", " r23=",
+  "\nr24=", " r25=", " r26=", " r27=", " r28=", " r29=",
+  "\nr30=", " r31=", " nip=", " msr=", " r3*=", " ctr=",
+  "\nlr =", " xer=", " ccr=", " mq =", " trap=",
+  "\naddress of fault=", " dsisr=",
+};
+
+static void
+register_dump (int fd, void **ctx)
+{
+  char buffer[(sizeof (regnames) / sizeof (regnames[0])) * 8];
+  char *bufferpos = buffer + sizeof (buffer);
+  struct iovec iov[(sizeof (regnames) / sizeof (regnames[0])) * 2 + 1];
+  int nr = 0;
+
+#define ADD_STRING(str) \
+  iov[nr].iov_base = (char *) str;					      \
+  iov[nr].iov_len = strlen (str);					      \
+  ++nr
+#define ADD_HEX(str, len) \
+  do {									      \
+    char *s = _itoa_word ((unsigned long int) x, bufferpos, 16, 0);	      \
+    while (bufferpos - s < 8)						      \
+      *--s = '0';							      \
+    iov[nr].iov_base = s;						      \
+    iov[nr].iov_len = bufferpos - s;					      \
+    bufferpos = s;							      \
+  } while (0)
+
+  /* Generate the output.  */
+  ADD_STRING ("Register dump:\n\n");
+  for (i = 0; i < sizeof (regnames)  / sizeof (regnames[0]); i++)
+    {
+      ADD_STRING (regnames[i]);
+      ADD_HEX (ctx[i]);
+    }
+
+  /* Write the output.  */
+  writev (fd, iov, nr);
+}
+
+
+#define REGISTER_DUMP \
+  ctx += 8;	/* FIXME!!!!  Why is this necessary?  Is it necessary?  */    \
+  register_dump (fd, ctx)
diff --git a/sysdeps/unix/sysv/linux/i386/profil-counter.h b/sysdeps/unix/sysv/linux/i386/profil-counter.h
index a24ea19654..50186932be 100644
--- a/sysdeps/unix/sysv/linux/i386/profil-counter.h
+++ b/sysdeps/unix/sysv/linux/i386/profil-counter.h
@@ -18,9 +18,10 @@
    Boston, MA 02111-1307, USA.  */
 
 #include <signal.h>
+#include <sigcontextinfo.h>
 
 static void
-profil_counter (int signo, struct sigcontext sc)
+profil_counter (int signo, SIGCONTEXT scp)
 {
-  profil_count ((void *) sc.eip);
+  profil_count ((void *) GET_PC (scp));
 }
diff --git a/sysdeps/unix/sysv/linux/ldd-rewrite.sed b/sysdeps/unix/sysv/linux/ldd-rewrite.sed
index 0ad5bc4f93..7b8b6bdee0 100644
--- a/sysdeps/unix/sysv/linux/ldd-rewrite.sed
+++ b/sysdeps/unix/sysv/linux/ldd-rewrite.sed
@@ -1,7 +1,7 @@
 /Maybe extra code for non-ELF binaries/a\
   file=$1\
   # Run the ldd stub.\
-  lddlibc4 $file\
+  lddlibc4 "$file"\
   # Test the result.\
   if test $? -lt 3; then\
     return 0;\
diff --git a/sysdeps/unix/sysv/linux/powerpc/chown.c b/sysdeps/unix/sysv/linux/powerpc/chown.c
new file mode 100644
index 0000000000..5f6c3d29ce
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/powerpc/chown.c
@@ -0,0 +1,131 @@
+/* chown() compatibility.
+   Copyright (C) 1998 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <limits.h>
+#include <sys/syscall.h>
+#include <stdlib.h>
+
+/*
+  In Linux 2.1.x the chown functions have been changed.  A new function lchown
+  was introduced.  The new chown now follows symlinks - the old chown and the
+  new lchown do not follow symlinks.
+  This file emulates chown() under the old kernels.
+*/
+
+extern int __syscall_chown (const char *__file,
+			    uid_t __owner, gid_t __group);
+
+int
+__chown (const char *file, uid_t owner, gid_t group)
+{
+   int err;
+   int old_errno;
+   char link[PATH_MAX+2];
+   char path[2*PATH_MAX+4];
+   int loopct;
+   int filelen;
+   static int libc_old_chown = 0 /* -1=old linux, 1=new linux, 0=unknown */;
+   
+   if (libc_old_chown == 1)
+     return __syscall_chown (file, owner, group);
+
+   old_errno = errno;
+
+#ifdef __NR_lchown
+   if (libc_old_chown == 0)
+     {
+       err = __syscall_chown (file, owner, group);
+       if (err != -1 || errno != ENOSYS)
+	 {
+	   libc_old_chown = 1;
+	   return err;
+	 }
+       libc_old_chown = -1;
+     }
+#endif
+   
+   err = __readlink (file, link, PATH_MAX+1);
+   if (err == -1)
+     {
+       errno = old_errno;
+       return __lchown(file, owner, group);
+     }
+
+   filelen = strlen (file) + 1;
+   if (filelen > sizeof(path))
+     {
+       errno = ENAMETOOLONG;
+       return -1;
+     }
+   memcpy (path, file, filelen);
+
+   /* 'The system has an arbitrary limit...'  In practise, we'll hit
+      ENAMETOOLONG before this, usually.  */
+   for (loopct = 0; loopct < 128; loopct++)
+   {
+     int linklen;
+     
+     if (err >= PATH_MAX+1)
+       {
+	 errno = ENAMETOOLONG;
+	 return -1;
+       }
+
+      link[err] = 0;  /* Null-terminate string, just-in-case.  */
+
+      linklen = strlen (link) + 1;
+      
+      if (link[0] == '/')
+	memcpy (path, link, linklen);
+      else
+	{
+	  filelen = strlen (path);
+	  
+	  while (filelen > 1 && path[filelen-1] == '/')
+	    filelen--;
+	  while (filelen > 0 && path[filelen-1] != '/')
+	    filelen--;
+	  if (filelen + linklen > sizeof(path))
+	    {
+	      errno = ENAMETOOLONG;
+	      return -1;
+	    }
+	  memcpy (path+filelen, link, linklen);
+	}
+
+      err = __readlink(path, link, PATH_MAX+1);
+      
+      if (err == -1)
+      {  
+	errno = old_errno;
+	return __lchown(path, owner, group);
+      }
+   }
+   errno = ELOOP;
+   return -1;
+}
+
+#if defined PIC && defined DO_VERSIONING
+default_symbol_version (__chown, chown, GLIBC_2.1);
+#else
+weak_alias (__chown, chown)
+#endif
diff --git a/sysdeps/unix/sysv/linux/powerpc/clone.S b/sysdeps/unix/sysv/linux/powerpc/clone.S
index 6209922b6b..69d2c5f586 100644
--- a/sysdeps/unix/sysv/linux/powerpc/clone.S
+++ b/sysdeps/unix/sysv/linux/powerpc/clone.S
@@ -1,5 +1,5 @@
 /* Wrapper around clone system call.
-   Copyright (C) 1997 Free Software Foundation, Inc.
+   Copyright (C) 1997, 1998 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -28,56 +28,60 @@
 /* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg); */
 
 ENTRY(__clone)
-	/* Set up stack frame, save registers.  */
-	stwu  %r1,-32(%r1)
 	/* Check for child_stack == NULL || fn == NULL.  */
-	cmpwi %cr0,%r4,0
-	stw   %r31,16(%r1)
-	cmpwi %cr1,%r3,0
-	stw   %r30,20(%r1)
-	beq-  %cr0,badargs
-	beq-  %cr1,badargs
+	cmpwi	%cr0,%r4,0
+	cmpwi	%cr1,%r3,0
+	cror	cr0*4+eq,cr1*4+eq,cr0*4+eq
+	beq-	%cr0,L(badargs)
 
+	/* Set up stack frame for parent.  */
+	stwu	%r1,-32(%r1)
+	stmw	%r29,16(%r1)
+	
 	/* Set up stack frame for child.  */
-	addi  %r4,%r4,-16
-	clrrwi %r4,%r4,4
-	li    %r0,0
-	stw   %r0,0(%r4)
+	clrrwi	%r4,%r4,4
+	li	%r0,0
+	stwu	%r0,-16(%r4)
 
-	/* Save fn, args across syscall.  */
-	mr    %r30,%r3		/* Function in r30.  */
-	mr    %r31,%r6		/* Arguments in r31.  */
+	/* Save fn, args, stack across syscall.  */
+	mr	%r29,%r3		/* Function in r29.  */
+	mr	%r30,%r4		/* Stack pointer in r30.  */
+	mr	%r31,%r6		/* Argument in r31.  */
 
 	/* 'flags' argument is first parameter to clone syscall. (The other
 	   argument is the stack pointer, already in r4.)  */
-	mr    %r3,%r5
+	mr	%r3,%r5
 
 	/* Do the call.  */
 	DO_CALL(SYS_ify(clone))
-	bso-  error
-	beq   child
 
-	/* Parent.  Restore registers & return.  */
-	lwz   %r31,16(%r1)
-	lwz   %r30,20(%r1)
-	addi  %r1,%r1,32
-	blr
+	/* Check for child process.  */
+	cmpwi	%cr1,%r3,0
+	crandc	cr1*4+eq,cr1*4+eq,cr0*4+so
+	bne-	%cr1,L(parent)		/* The '-' is to minimise the race.  */
 
-child:
+	/* On at least mklinux DR3a5, clone() doesn't actually change
+	   the stack pointer.  I'm pretty sure this is a bug, because
+	   it adds a race condition if a signal is sent to a thread
+	   just after it is created (in the previous three instructions).  */
+	mr	%r1,%r30
 	/* Call procedure.  */
-	mtlr  %r30
-	mr    %r3,%r31
-	blrl
+	mtctr	%r29
+	mr	%r3,%r31
+	bctrl
 	/* Call _exit with result from procedure.  */
-	b JUMPTARGET(_exit)
-
-badargs:
-	li    %r3,EINVAL
-error:
-	lwz   %r31,16(%r1)
-	lwz   %r30,20(%r1)
-	addi  %r1,%r1,32
-	b JUMPTARGET(__syscall_error)
+	b	JUMPTARGET(_exit)
+
+L(parent):
+	/* Parent.  Restore registers & return.  */
+	lmw	%r29,16(%r1)
+	addi	%r1,%r1,32
+	bnslr+
+	b	JUMPTARGET(__syscall_error)
+
+L(badargs):
+	li	%r3,EINVAL
+	b	JUMPTARGET(__syscall_error)
 END (__clone)
 
 weak_alias (__clone, clone)
diff --git a/sysdeps/unix/sysv/linux/powerpc/lchown.S b/sysdeps/unix/sysv/linux/powerpc/lchown.S
new file mode 100644
index 0000000000..9195eab516
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/powerpc/lchown.S
@@ -0,0 +1,35 @@
+/* lchown system call.
+   Copyright (C) 1998 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+/* Some old kernel headers call lchown() 'chown'.  The number is
+   the same.  */
+	
+#include <sysdep.h>
+
+#ifdef __NR_lchown
+	PSEUDO (__lchown, lchown, 3)
+#else
+	PSEUDO (__lchown, chown, 3)
+#endif
+	ret
+	PSEUDO_END(__lchown)
+	weak_alias (__lchown, lchown)
+#if defined PIC && defined DO_VERSIONING
+	symbol_version (__lchown, chown, GLIBC_2.0);
+#endif
diff --git a/sysdeps/unix/sysv/linux/powerpc/profil-counter.h b/sysdeps/unix/sysv/linux/powerpc/profil-counter.h
index 4be6f11270..8a6a0bcf3d 100644
--- a/sysdeps/unix/sysv/linux/powerpc/profil-counter.h
+++ b/sysdeps/unix/sysv/linux/powerpc/profil-counter.h
@@ -1,34 +1,2 @@
-/* Low-level statistical profiling support function.  Linux/PowerPC version.
-   Copyright (C) 1996, 1997 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Library General Public License as
-   published by the Free Software Foundation; either version 2 of the
-   License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Library General Public License for more details.
-
-   You should have received a copy of the GNU Library General Public
-   License along with the GNU C Library; see the file COPYING.LIB.  If not,
-   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-   Boston, MA 02111-1307, USA.  */
-
-#include <sys/ptrace.h>
-
-/* You can also do this by using
-   void
-   profil_counter (int signo, struct pt_regs *pt)
-   {
-     profil_count ((void *) pt->nip);
-   }
-   */
-
-void
-profil_counter (int signo, void **regs)
-{
-  profil_count (regs[PT_NIP]);
-}
+/* We can use the ix86 version.  */
+#include <sysdeps/unix/sysv/linux/i386/profil-counter.h>
diff --git a/sysdeps/unix/sysv/linux/powerpc/sigcontextinfo.h b/sysdeps/unix/sysv/linux/powerpc/sigcontextinfo.h
new file mode 100644
index 0000000000..2a7a2fe5c8
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/powerpc/sigcontextinfo.h
@@ -0,0 +1,24 @@
+/* Copyright (C) 1998 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <sys/ptrace.h>
+
+#define SIGCONTEXT void **
+#define GET_PC(ctx)	((ctx)[PT_NIP])
+#define GET_FRAME(ctx)	(*(void **)(ctx)[PT_R1])
+#define GET_STACK(ctx)	((ctx)[PT_R1])
diff --git a/sysdeps/unix/sysv/linux/powerpc/syscalls.list b/sysdeps/unix/sysv/linux/powerpc/syscalls.list
index 605762a2a4..3af0c5b6f8 100644
--- a/sysdeps/unix/sysv/linux/powerpc/syscalls.list
+++ b/sysdeps/unix/sysv/linux/powerpc/syscalls.list
@@ -1,6 +1,4 @@
 # File name	Caller	Syscall name	# args	Strong name	Weak names
 
 s_llseek	llseek	_llseek		5	__sys_llseek
-
-getresuid	-	getresuid	3	getresuid
-getresgid	-	getresgid	3	getresgid
+s_chown		chown	chown		3	__syscall_chown
diff --git a/sysdeps/unix/sysv/linux/sys/mount.h b/sysdeps/unix/sysv/linux/sys/mount.h
index f29d158fb5..862c1f0407 100644
--- a/sysdeps/unix/sysv/linux/sys/mount.h
+++ b/sysdeps/unix/sysv/linux/sys/mount.h
@@ -83,7 +83,11 @@ enum
 
 
 /* Possible value for FLAGS parameter of `umount2'.  */
-#define MNT_FORCE		/* Force unmounting.  */
+enum
+{
+  MNT_FORCE = 1			/* Force unmounting.  */
+#define MNT_FORCE MNT_FORCE
+};
 
 
 __BEGIN_DECLS