From: Andreas Schwab Date: Mon, 12 Jul 2010 19:39:57 +0000 (+0200) Subject: Add biarch support for powerpc64 X-Git-Tag: v4.6~104 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=d69fa497f4729373618fb7b506a2362422487ab1;p=strace Add biarch support for powerpc64 * 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. --- diff --git a/acinclude.m4 b/acinclude.m4 index da66c646..1741ab99 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 76f55d29..40fa15b9 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 a7e87933..419b12e5 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 854548f7..afdbf328 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 00000000..441c66bc --- /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 00000000..72eeaf19 --- /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 00000000..d31e6a4a --- /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 00000000..49ccb8af --- /dev/null +++ b/linux/powerpc/syscallent1.h @@ -0,0 +1 @@ +#include "syscallent.h" diff --git a/signal.c b/signal.c index bf97e900..337dd6ab 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 ba2185c8..f33ae4ce 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 bd12c0f7..07cbfded 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;