]> granicus.if.org Git - strace/commitdiff
Enhance personality switching
authorDmitry V. Levin <ldv@altlinux.org>
Fri, 23 Dec 2011 00:50:49 +0000 (00:50 +0000)
committerDmitry V. Levin <ldv@altlinux.org>
Fri, 23 Dec 2011 00:50:49 +0000 (00:50 +0000)
On syscall entry, save current personality in the tcb structure
along with scno.
On syscall exit, restore current personality from the tcb structure.
* defs.h (struct tcb) [SUPPORTED_PERSONALITIES > 1]: Add currpers
field.
* strace.c (alloc_tcb) [SUPPORTED_PERSONALITIES > 1]: Initialize
tcp->currpers.
* syscall.c (update_personality) [SUPPORTED_PERSONALITIES > 1]: New
function.
(get_scno, trace_syscall_exiting): Use it.

Reported-by: Michael A Fetterman <mafetter@nvidia.com>
defs.h
strace.c
syscall.c

diff --git a/defs.h b/defs.h
index 98c6a0b3e613adeb0cd17142c24ca66b467a283d..2f4c98ba0d7ca5e99eade0aed47c96a9feca3a63 100644 (file)
--- a/defs.h
+++ b/defs.h
@@ -407,6 +407,9 @@ struct tcb {
        long long u_lrval;      /* long long return value */
 #endif
        int ptrace_errno;
+#if SUPPORTED_PERSONALITIES > 1
+       int currpers;           /* Personality at the time of scno update */
+#endif
        int curcol;             /* Output column for this process */
        FILE *outf;             /* Output file for this process */
        const char *auxstr;     /* Auxiliary info from syscall (see RVAL_STR) */
index 8f8c74c63ab07d4c6fd77c8c2aff6918f0364917..2e963059de8c7212a3a13587ab9a6077826dbcc5 100644 (file)
--- a/strace.c
+++ b/strace.c
@@ -1276,6 +1276,9 @@ alloc_tcb(int pid, int command_options_parsed)
                        tcp->pid = pid;
                        tcp->flags = TCB_INUSE;
                        tcp->outf = outf; /* Initialise to current out file */
+#if SUPPORTED_PERSONALITIES > 1
+                       tcp->currpers = current_personality;
+#endif
 #ifdef USE_PROCFS
                        tcp->pfd = -1;
 #endif
index 77df174524626b7d7834d96fa99c82d52d0e6c4b..ec3eaab77103a53bd9bc2687d9de81b04e461cb2 100644 (file)
--- a/syscall.c
+++ b/syscall.c
@@ -273,6 +273,27 @@ set_personality(int personality)
        current_personality = personality;
 }
 
+#if SUPPORTED_PERSONALITIES > 1
+static void
+update_personality(struct tcb *tcp, int personality)
+{
+       if (personality == current_personality)
+               return;
+       set_personality(personality);
+
+       if (personality == tcp->currpers)
+               return;
+       tcp->currpers = personality;
+
+#if defined(POWERPC64) || defined(X86_64)
+       if (!qflag) {
+               static const char *const names[] = {"64 bit", "32 bit"};
+               fprintf(stderr, "[ Process PID=%d runs in %s mode. ]\n",
+                       tcp->pid, names[personality]);
+       }
+#endif
+}
+#endif
 
 static int qual_syscall(), qual_signal(), qual_fault(), qual_desc();
 
@@ -877,12 +898,7 @@ get_scno(struct tcb *tcp)
                currpers = 0;
        else
                currpers = 1;
-       if (currpers != current_personality) {
-               static const char *const names[] = {"64 bit", "32 bit"};
-               set_personality(currpers);
-               fprintf(stderr, "[ Process PID=%d runs in %s mode. ]\n",
-                               pid, names[current_personality]);
-       }
+       update_personality(tcp, currpers);
 #  endif
 # elif defined(AVR32)
        /* Read complete register set in one go. */
@@ -947,12 +963,7 @@ get_scno(struct tcb *tcp)
                        break;
        }
 #  endif
-       if (currpers != current_personality) {
-               static const char *const names[] = {"64 bit", "32 bit"};
-               set_personality(currpers);
-               fprintf(stderr, "[ Process PID=%d runs in %s mode. ]\n",
-                               tcp->pid, names[current_personality]);
-       }
+       update_personality(tcp, currpers);
 # elif defined(IA64)
 #      define IA64_PSR_IS      ((long)1 << 34)
        if (upeek(tcp, PT_CR_IPSR, &psr) >= 0)
@@ -1014,10 +1025,10 @@ get_scno(struct tcb *tcp)
                        /*
                         * Handle ARM specific syscall
                         */
-                       set_personality(1);
+                       update_personality(tcp, 1);
                        scno &= 0x0000ffff;
                } else
-                       set_personality(0);
+                       update_personality(tcp, 0);
 
        } else {
                fprintf(stderr, "pid %d stray syscall entry\n", tcp->pid);
@@ -1093,11 +1104,11 @@ get_scno(struct tcb *tcp)
        switch (trap) {
        case 0x91d02010:
                /* Linux/SPARC syscall trap. */
-               set_personality(0);
+               update_personality(tcp, 0);
                break;
        case 0x91d0206d:
                /* Linux/SPARC64 syscall trap. */
-               set_personality(2);
+               update_personality(tcp, 2);
                break;
        case 0x91d02000:
                /* SunOS syscall trap. (pers 1) */
@@ -1105,7 +1116,7 @@ get_scno(struct tcb *tcp)
                return -1;
        case 0x91d02008:
                /* Solaris 2.x syscall trap. (per 2) */
-               set_personality(1);
+               update_personality(tcp, 1);
                break;
        case 0x91d02009:
                /* NetBSD/FreeBSD syscall trap. */
@@ -1113,7 +1124,7 @@ get_scno(struct tcb *tcp)
                return -1;
        case 0x91d02027:
                /* Solaris 2.x gettimeofday */
-               set_personality(1);
+               update_personality(tcp, 1);
                break;
        default:
 #  if defined (SPARC64)
@@ -2325,6 +2336,9 @@ trace_syscall_exiting(struct tcb *tcp)
        if (dtime || cflag)
                gettimeofday(&tv, NULL);
 
+#if SUPPORTED_PERSONALITIES > 1
+       update_personality(tcp, tcp->currpers);
+#endif
        res = get_syscall_result(tcp);
        if (res == 0)
                return res;