[PATCH/v2] Add biarch support for powerpc64
Andreas Schwab
schwab at linux-m68k.org
Mon Jul 12 19:48:20 UTC 2010
* acinclude.m4 (AC_LITTLE_ENDIAN_LONG_LONG): Use int instead of
long.
* configure.ac [$host_cpu = powerpc*]: Also define POWERPC64 if
$host_cpu = powerpc64.
* defs.h (SUPPORTED_PERSONALITIES, PERSONALITY0_WORDSIZE)
(PERSONALITY1_WORDSIZE) [POWERPC64]: Define.
* file.c: (struct stat_powerpc32, printstat_powerpc32) [POWERPC64]:
Define.
(printstat) [LINUX && POWERPC64]: Use printstat_powerpc32 in
32-bit personality.
(sys_newfstatat) [POWERPC64]: Handle personalities.
* signal.c (sys_sigreturn) [POWERPC64]: Likewise.
* util.c (printllval) [POWERPC64]: Likewise.
(printcall) [POWERPC64]: Use wider format for IP prefix.
* syscall.c (get_scno) [POWERPC64]: Check for 64/32 bit mode.
* linux/powerpc/errnoent1.h: New file.
* linux/powerpc/ioctlent1.h: New file.
* linux/powerpc/signalent1.h: New file.
* linux/powerpc/syscallent1.h: New file.
---
acinclude.m4 | 2 +-
configure.ac | 3 ++
defs.h | 7 ++++
file.c | 79 ++++++++++++++++++++++++++++++++++++++++++-
linux/powerpc/errnoent1.h | 1 +
linux/powerpc/ioctlent1.h | 1 +
linux/powerpc/signalent1.h | 1 +
linux/powerpc/syscallent1.h | 1 +
signal.c | 7 +++-
syscall.c | 23 ++++++++++++
util.c | 16 ++++++--
11 files changed, 133 insertions(+), 8 deletions(-)
create mode 100644 linux/powerpc/errnoent1.h
create mode 100644 linux/powerpc/ioctlent1.h
create mode 100644 linux/powerpc/signalent1.h
create mode 100644 linux/powerpc/syscallent1.h
diff --git a/acinclude.m4 b/acinclude.m4
index da66c64..1741ab9 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -280,7 +280,7 @@ AC_CACHE_VAL(ac_cv_have_little_endian_long_long,
int main () {
union {
long long ll;
- long l [2];
+ int l [2];
} u;
u.ll = 0x12345678;
if (u.l[0] == 0x12345678)
diff --git a/configure.ac b/configure.ac
index 76f55d2..40fa15b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -79,6 +79,9 @@ alpha*)
powerpc*)
arch=powerpc
AC_DEFINE([POWERPC], 1, [Define for the PowerPC architecture.])
+ if test $host_cpu = powerpc64; then
+ AC_DEFINE([POWERPC64], 1, [Define for the PowerPC64 architecture.])
+ fi
;;
arm*)
arch=arm
diff --git a/defs.h b/defs.h
index a7e8793..419b12e 100644
--- a/defs.h
+++ b/defs.h
@@ -246,6 +246,13 @@ extern int ptrace(int, int, char *, int, ...);
#define PERSONALITY1_WORDSIZE 4
#endif
+#ifdef POWERPC64
+#undef SUPPORTED_PERSONALITIES
+#define SUPPORTED_PERSONALITIES 2
+#define PERSONALITY0_WORDSIZE 8
+#define PERSONALITY1_WORDSIZE 4
+#endif
+
#ifdef SVR4
#ifdef HAVE_MP_PROCFS
extern int mp_ioctl (int f, int c, void *a, int s);
diff --git a/file.c b/file.c
index 854548f..afdbf32 100644
--- a/file.c
+++ b/file.c
@@ -859,6 +859,71 @@ printstat_sparc64(struct tcb *tcp, long addr)
#endif /* SPARC64 */
#endif /* LINUXSPARC */
+#if defined LINUX && defined POWERPC64
+struct stat_powerpc32 {
+ unsigned int st_dev;
+ unsigned int st_ino;
+ unsigned int st_mode;
+ unsigned short st_nlink;
+ unsigned int st_uid;
+ unsigned int st_gid;
+ unsigned int st_rdev;
+ unsigned int st_size;
+ unsigned int st_blksize;
+ unsigned int st_blocks;
+ unsigned int st_atime;
+ unsigned int st_atime_nsec;
+ unsigned int st_mtime;
+ unsigned int st_mtime_nsec;
+ unsigned int st_ctime;
+ unsigned int st_ctime_nsec;
+ unsigned int __unused4;
+ unsigned int __unused5;
+};
+
+static void
+printstat_powerpc32(struct tcb *tcp, long addr)
+{
+ struct stat_powerpc32 statbuf;
+
+ if (umove(tcp, addr, &statbuf) < 0) {
+ tprintf("{...}");
+ return;
+ }
+
+ if (!abbrev(tcp)) {
+ tprintf("{st_dev=makedev(%u, %u), st_ino=%u, st_mode=%s, ",
+ major(statbuf.st_dev), minor(statbuf.st_dev),
+ statbuf.st_ino,
+ sprintmode(statbuf.st_mode));
+ tprintf("st_nlink=%u, st_uid=%u, st_gid=%u, ",
+ statbuf.st_nlink, statbuf.st_uid, statbuf.st_gid);
+ tprintf("st_blksize=%u, ", statbuf.st_blksize);
+ tprintf("st_blocks=%u, ", statbuf.st_blocks);
+ }
+ else
+ tprintf("{st_mode=%s, ", sprintmode(statbuf.st_mode));
+ switch (statbuf.st_mode & S_IFMT) {
+ case S_IFCHR: case S_IFBLK:
+ tprintf("st_rdev=makedev(%lu, %lu), ",
+ (unsigned long) major(statbuf.st_rdev),
+ (unsigned long) minor(statbuf.st_rdev));
+ break;
+ default:
+ tprintf("st_size=%u, ", statbuf.st_size);
+ break;
+ }
+ if (!abbrev(tcp)) {
+ tprintf("st_atime=%s, ", sprinttime(statbuf.st_atime));
+ tprintf("st_mtime=%s, ", sprinttime(statbuf.st_mtime));
+ tprintf("st_ctime=%s", sprinttime(statbuf.st_ctime));
+ tprintf("}");
+ }
+ else
+ tprintf("...}");
+}
+#endif /* LINUX && POWERPC64 */
+
static const struct xlat fileflags[] = {
#ifdef FREEBSD
{ UF_NODUMP, "UF_NODUMP" },
@@ -998,6 +1063,13 @@ printstat(struct tcb *tcp, long addr)
#endif
#endif /* LINUXSPARC */
+#if defined LINUX && defined POWERPC64
+ if (current_personality == 1) {
+ printstat_powerpc32(tcp, addr);
+ return;
+ }
+#endif
+
if (umove(tcp, addr, &statbuf) < 0) {
tprintf("{...}");
return;
@@ -1259,7 +1331,12 @@ sys_newfstatat(struct tcb *tcp)
printpath(tcp, tcp->u_arg[1]);
tprintf(", ");
} else {
-#if defined HAVE_STAT64 && !(defined POWERPC && defined __powerpc64__)
+#ifdef POWERPC64
+ if (current_personality == 0)
+ printstat(tcp, tcp->u_arg[2]);
+ else
+ printstat64(tcp, tcp->u_arg[2]);
+#elif defined HAVE_STAT64
printstat64(tcp, tcp->u_arg[2]);
#else
printstat(tcp, tcp->u_arg[2]);
diff --git a/linux/powerpc/errnoent1.h b/linux/powerpc/errnoent1.h
new file mode 100644
index 0000000..441c66b
--- /dev/null
+++ b/linux/powerpc/errnoent1.h
@@ -0,0 +1 @@
+#include "../errnoent.h"
diff --git a/linux/powerpc/ioctlent1.h b/linux/powerpc/ioctlent1.h
new file mode 100644
index 0000000..72eeaf1
--- /dev/null
+++ b/linux/powerpc/ioctlent1.h
@@ -0,0 +1 @@
+#include "ioctlent.h"
diff --git a/linux/powerpc/signalent1.h b/linux/powerpc/signalent1.h
new file mode 100644
index 0000000..d31e6a4
--- /dev/null
+++ b/linux/powerpc/signalent1.h
@@ -0,0 +1 @@
+#include "../signalent.h"
diff --git a/linux/powerpc/syscallent1.h b/linux/powerpc/syscallent1.h
new file mode 100644
index 0000000..49ccb8a
--- /dev/null
+++ b/linux/powerpc/syscallent1.h
@@ -0,0 +1 @@
+#include "syscallent.h"
diff --git a/signal.c b/signal.c
index bf97e90..337dd6a 100644
--- a/signal.c
+++ b/signal.c
@@ -1330,8 +1330,11 @@ sys_sigreturn(struct tcb *tcp)
if (upeek(tcp, sizeof(unsigned long)*PT_R1, &esp) < 0)
return 0;
/* Skip dummy stack frame. */
-#ifdef __powerpc64__
- esp += 128;
+#ifdef POWERPC64
+ if (current_personality == 0)
+ esp += 128;
+ else
+ esp += 64;
#else
esp += 64;
#endif
diff --git a/syscall.c b/syscall.c
index ba2185c..f33ae4c 100644
--- a/syscall.c
+++ b/syscall.c
@@ -883,6 +883,29 @@ get_scno(struct tcb *tcp)
return 0;
}
}
+
+# ifdef POWERPC64
+ if (!(tcp->flags & TCB_INSYSCALL)) {
+ static int currpers = -1;
+ long val;
+ int pid = tcp->pid;
+
+ /* Check for 64/32 bit mode. */
+ if (upeek(tcp, sizeof (unsigned long)*PT_MSR, &val) < 0)
+ return -1;
+ /* SF is bit 0 of MSR */
+ if (val < 0)
+ currpers = 0;
+ else
+ currpers = 1;
+ if (currpers != current_personality) {
+ static const char *const names[] = {"64 bit", "32 bit"};
+ set_personality(currpers);
+ printf("[ Process PID=%d runs in %s mode. ]\n",
+ pid, names[current_personality]);
+ }
+ }
+# endif
# elif defined(AVR32)
/*
* Read complete register set in one go.
diff --git a/util.c b/util.c
index bd12c0f..07cbfde 100644
--- a/util.c
+++ b/util.c
@@ -251,20 +251,24 @@ int
printllval(struct tcb *tcp, const char *format, int llarg)
{
# if defined(FREEBSD) \
- || (defined(LINUX) && defined(POWERPC) && !defined(__powerpc64__)) \
+ || (defined(LINUX) && defined(POWERPC) && !defined(POWERPC64)) \
|| defined (LINUX_MIPSO32)
/* Align 64bit argument to 64bit boundary. */
if (llarg % 2) llarg++;
# endif
-# if defined LINUX && defined X86_64
+# if defined LINUX && (defined X86_64 || defined POWERPC64)
if (current_personality == 0) {
tprintf(format, tcp->u_arg[llarg]);
llarg++;
} else {
+# ifdef POWERPC64
+ /* Align 64bit argument to 64bit boundary. */
+ if (llarg % 2) llarg++;
+# endif
tprintf(format, LONG_LONG(tcp->u_arg[llarg], tcp->u_arg[llarg + 1]));
llarg += 2;
}
-# elif defined IA64 || defined ALPHA || (defined POWERPC && defined __powerpc64__)
+# elif defined IA64 || defined ALPHA
tprintf(format, tcp->u_arg[llarg]);
llarg++;
# elif defined LINUX_MIPSN32
@@ -1110,10 +1114,14 @@ printcall(struct tcb *tcp)
long pc;
if (upeek(tcp, sizeof(unsigned long)*PT_NIP, &pc) < 0) {
- tprintf ("[????????] ");
+ PRINTBADPC;
return;
}
+# ifdef POWERPC64
+ tprintf("[%016lx] ", pc);
+# else
tprintf("[%08lx] ", pc);
+# endif
# elif defined(M68K)
long pc;
--
1.7.1.1
--
Andreas Schwab, schwab at linux-m68k.org
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756 01D3 44D5 214B 8276 4ED5
"And now for something completely different."
More information about the Strace-devel
mailing list