]> granicus.if.org Git - strace/commitdiff
print_pc: fix multiple personalities support
authorDmitry V. Levin <ldv@altlinux.org>
Sun, 15 Feb 2015 15:52:02 +0000 (15:52 +0000)
committerDmitry V. Levin <ldv@altlinux.org>
Mon, 16 Feb 2015 02:39:21 +0000 (02:39 +0000)
* syscall.c (print_pc): Choose instruction pointer format depending
on current_wordsize, not the size of long integer type.
* tests/pc.c: New file.
* tests/pc.test: New test.
* tests/Makefile.am (check_PROGRAMS): Add pc.
(TESTS): Add pc.test.
* tests/.gitignore: Add pc.

syscall.c
tests/.gitignore
tests/Makefile.am
tests/pc.c [new file with mode: 0644]
tests/pc.test [new file with mode: 0755]

index 29aa6d198741d994b3c8c85868f8285bcb4fb885..2aeb0a373d7da36e5fa016557265522d3c6c416d 100644 (file)
--- a/syscall.c
+++ b/syscall.c
@@ -793,140 +793,138 @@ static long get_regs_error;
 void
 print_pc(struct tcb *tcp)
 {
-#define PRINTBADPC tprintf(sizeof(long) == 4 ? "[????????] " : \
-                          sizeof(long) == 8 ? "[????????????????] " : \
-                          NULL /* crash */)
+       const char *fmt;
+       const char *bad;
+
+#if SUPPORTED_PERSONALITIES > 1
+# define pc_wordsize personality_wordsize[tcp->currpers]
+#else
+# define pc_wordsize current_wordsize
+#endif
+
+       if (pc_wordsize == 4) {
+               fmt = "[%08lx] ";
+               bad = "[????????] ";
+       } else {
+               fmt = "[%016lx] ";
+               bad = "[????????????????] ";
+       }
+
+#undef pc_wordsize
+#define PRINTBADPC tprints(bad)
+
        if (get_regs_error) {
                PRINTBADPC;
                return;
        }
+
 #if defined(I386)
-       tprintf("[%08lx] ", i386_regs.eip);
+       tprintf(fmt, i386_regs.eip);
+#elif defined(X86_64) || defined(X32)
+       if (x86_io.iov_len == sizeof(i386_regs))
+               tprintf(fmt, (unsigned long) i386_regs.eip);
+       else
+               tprintf(fmt, (unsigned long) x86_64_regs.rip);
 #elif defined(S390) || defined(S390X)
        long psw;
        if (upeek(tcp->pid, PT_PSWADDR, &psw) < 0) {
                PRINTBADPC;
                return;
        }
-# ifdef S390
-       tprintf("[%08lx] ", psw);
-# elif S390X
-       tprintf("[%016lx] ", psw);
-# endif
-#elif defined(X86_64) || defined(X32)
-       if (x86_io.iov_len == sizeof(i386_regs)) {
-               tprintf("[%08x] ", (unsigned) i386_regs.eip);
-       } else {
-# if defined(X86_64)
-               tprintf("[%016lx] ", (unsigned long) x86_64_regs.rip);
-# elif defined(X32)
-               /* Note: this truncates 64-bit rip to 32 bits */
-               tprintf("[%08lx] ", (unsigned long) x86_64_regs.rip);
-# endif
-       }
+       tprintf(fmt, psw);
 #elif defined(IA64)
        long ip;
        if (upeek(tcp->pid, PT_B0, &ip) < 0) {
                PRINTBADPC;
                return;
        }
-       tprintf("[%08lx] ", ip);
+       tprintf(fmt, ip);
 #elif defined(POWERPC)
-       long pc = ppc_regs.nip;
-# ifdef POWERPC64
-       tprintf("[%016lx] ", pc);
-# else
-       tprintf("[%08lx] ", pc);
-# endif
+       tprintf(fmt, ppc_regs.nip);
 #elif defined(M68K)
        long pc;
        if (upeek(tcp->pid, 4*PT_PC, &pc) < 0) {
-               tprints("[????????] ");
+               PRINTBADPC;
                return;
        }
-       tprintf("[%08lx] ", pc);
+       tprintf(fmt, pc);
 #elif defined(ALPHA)
        long pc;
        if (upeek(tcp->pid, REG_PC, &pc) < 0) {
-               tprints("[????????????????] ");
+               PRINTBADPC;
                return;
        }
-       tprintf("[%08lx] ", pc);
+       tprintf(fmt, pc);
 #elif defined(SPARC)
-       tprintf("[%08lx] ", sparc_regs.pc);
+       tprintf(fmt, sparc_regs.pc);
 #elif defined(SPARC64)
-       tprintf("[%08lx] ", sparc_regs.tpc);
+       tprintf(fmt, sparc_regs.tpc);
 #elif defined(HPPA)
        long pc;
        if (upeek(tcp->pid, PT_IAOQ0, &pc) < 0) {
-               tprints("[????????] ");
+               PRINTBADPC;
                return;
        }
-       tprintf("[%08lx] ", pc);
-#elif defined LINUX_MIPSN64
-       tprintf("[%016lx] ", mips_REG_EPC);
+       tprintf(fmt, pc);
 #elif defined MIPS
-       tprintf("[%08lx] ", (unsigned long) mips_REG_EPC);
+       tprintf(fmt, (unsigned long) mips_REG_EPC);
 #elif defined(SH)
        long pc;
        if (upeek(tcp->pid, 4*REG_PC, &pc) < 0) {
-               tprints("[????????] ");
+               PRINTBADPC;
                return;
        }
-       tprintf("[%08lx] ", pc);
+       tprintf(fmt, pc);
 #elif defined(SH64)
        long pc;
        if (upeek(tcp->pid, REG_PC, &pc) < 0) {
-               tprints("[????????????????] ");
+               PRINTBADPC;
                return;
        }
-       tprintf("[%08lx] ", pc);
+       tprintf(fmt, pc);
 #elif defined(ARM)
-       tprintf("[%08lx] ", arm_regs.ARM_pc);
-#elif defined(AARCH64)
-       /* tprintf("[%016lx] ", aarch64_regs.regs[???]); */
+       tprintf(fmt, arm_regs.ARM_pc);
 #elif defined(AVR32)
-       tprintf("[%08lx] ", avr32_regs.pc);
+       tprintf(fmt, avr32_regs.pc);
 #elif defined(BFIN)
        long pc;
        if (upeek(tcp->pid, PT_PC, &pc) < 0) {
                PRINTBADPC;
                return;
        }
-       tprintf("[%08lx] ", pc);
+       tprintf(fmt, pc);
 #elif defined(CRISV10)
        long pc;
        if (upeek(tcp->pid, 4*PT_IRP, &pc) < 0) {
                PRINTBADPC;
                return;
        }
-       tprintf("[%08lx] ", pc);
+       tprintf(fmt, pc);
 #elif defined(CRISV32)
        long pc;
        if (upeek(tcp->pid, 4*PT_ERP, &pc) < 0) {
                PRINTBADPC;
                return;
        }
-       tprintf("[%08lx] ", pc);
+       tprintf(fmt, pc);
 #elif defined(TILE)
-# ifdef _LP64
-       tprintf("[%016lx] ", (unsigned long) tile_regs.pc);
-# else
-       tprintf("[%08lx] ", (unsigned long) tile_regs.pc);
-# endif
+       tprintf(fmt, (unsigned long) tile_regs.pc);
 #elif defined(OR1K)
-       tprintf("[%08lx] ", or1k_regs.pc);
+       tprintf(fmt, or1k_regs.pc);
 #elif defined(METAG)
-       tprintf("[%08lx] ", metag_regs.pc);
+       tprintf(fmt, metag_regs.pc);
 #elif defined(XTENSA)
        long pc;
        if (upeek(tcp->pid, REG_PC, &pc) < 0) {
                PRINTBADPC;
                return;
        }
-       tprintf("[%08lx] ", pc);
+       tprintf(fmt, pc);
 #elif defined(ARC)
-       tprintf("[%08lx] ", arc_regs.efa);
+       tprintf(fmt, arc_regs.efa);
+#else
+# warning print_pc is not implemented for this architecture
+       PRINTBADPC;
 #endif /* architecture */
 }
 
index debbda8c4a58641b5091a2a486306eb50289cfe5..a55b55693770ad03510142182d327e414acfa151 100644 (file)
@@ -10,6 +10,7 @@ mmsg
 net-accept-connect
 netlink_inet_diag
 netlink_unix_diag
+pc
 scm_rights
 select
 set_ptracer_any
index 731df057b4347a73ece6dfd71d6186ec62c37701..e5899de75ee6fbe416e257cc4ce95a01bd542736 100644 (file)
@@ -15,6 +15,7 @@ check_PROGRAMS = \
        net-accept-connect \
        netlink_inet_diag \
        netlink_unix_diag \
+       pc \
        scm_rights \
        select \
        set_ptracer_any \
@@ -60,6 +61,7 @@ TESTS = \
        net.test \
        net-fd.test \
        net-yy.test \
+       pc.test \
        sun_path.test \
        unix-yy.test \
        uid.test \
diff --git a/tests/pc.c b/tests/pc.c
new file mode 100644 (file)
index 0000000..909a2ef
--- /dev/null
@@ -0,0 +1,35 @@
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
+
+int main(void)
+{
+       const unsigned long size = sysconf(_SC_PAGESIZE);
+       const unsigned long mask = ~(size - 1);
+
+       /* write instruction pointer length to the log */
+       if (write(-1, NULL, 2 * sizeof(void *)) >= 0)
+               return 77;
+       /* just a noticeable line in the log */
+       if (munmap(&munmap, 0) >= 0)
+               return 77;
+
+       int pid = fork();
+       if (pid < 0)
+               return 77;
+
+       if (!pid) {
+               munmap((void *) ((unsigned long) &munmap & mask), size);
+               /* SIGSEGV is expected */
+               munmap((void *) (((unsigned long) &munmap & mask) + size), size);
+               return 77;
+       }
+
+       int status;
+       if (wait(&status) != pid ||
+           !WIFSIGNALED(status) ||
+           WTERMSIG(status) != SIGSEGV)
+               return 77;
+
+       return 0;
+}
diff --git a/tests/pc.test b/tests/pc.test
new file mode 100755 (executable)
index 0000000..4f90cb3
--- /dev/null
@@ -0,0 +1,47 @@
+#!/bin/sh
+
+# Check -i option.
+
+. "${srcdir=.}/init.sh"
+
+check_prog grep
+
+OUT="$LOG.out"
+
+./pc > /dev/null ||
+       framework_skip_ 'munmap/fork/wait do not behave as expected'
+
+args="-if ./pc"
+$STRACE $args > "$OUT" 2> "$LOG" || {
+       cat "$LOG"
+       fail_ "$STRACE $args does not work"
+}
+
+len="$(sed -n 's/^\[[[:xdigit:]]\+\] write(-1, NULL, \([[:digit:]]\{1,2\}\))[[:space:]]\+= -1 .*/\1/p' "$LOG")" &&
+[ -n "$len" ] &&
+pid="$(sed -n 's/^\[[[:xdigit:]]\{'"$len"'\}\] --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_KILLED, si_pid=\([[:digit:]]\+\), .*/\1/p' "$LOG")" &&
+[ -n "$pid" ] &&
+ip="$(sed -n 's/^\[pid \+'"$pid"'\] \[\([[:xdigit:]]\{'"$len"'\}\)] --- SIGSEGV {.*} ---$/\1/p' "$LOG")" &&
+[ -n "$ip" ] &&
+addr="$(echo "$ip" |sed 's/^0\+//')" &&
+[ -n "$addr" ] || {
+       cat "$LOG"
+       fail_ "$STRACE $args output mismatch"
+}
+
+grep_log()
+{
+       LC_ALL=C grep -x -e "$*" < "$LOG" > /dev/null || {
+               cat "$LOG"
+               fail_ "$STRACE $args output mismatch"
+       }
+}
+
+grep_log '\[[[:xdigit:]]\{'"$len"'\}\] munmap(0x[[:xdigit:]]\+, 0)[[:space:]]\+= -1 .*'
+grep_log '\[pid \+'"$pid"'\] \['"$ip"'\] --- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0x'"$addr"'} ---'
+grep_log '\[pid \+'"$pid"'\] \[?\{'"$len"'\}\] +++ killed by SIGSEGV +++'
+grep_log '\[?\{'"$len"'\}\] +++ exited with 0 +++'
+
+rm -f "$OUT"
+
+exit 0