summaryrefslogtreecommitdiff
path: root/syscall.c
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2013-02-21 15:46:34 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2013-02-21 15:46:34 +0100
commit7270de551ca6b3ea097c114005b6b028990ce3dc (patch)
tree9d5d4f1de04037ad1a8085f3440a9b04d2e50795 /syscall.c
parente7030e5a7ef541f0ffda46a2850ef720245f01a5 (diff)
downloadstrace-7270de551ca6b3ea097c114005b6b028990ce3dc.tar.gz
strace-7270de551ca6b3ea097c114005b6b028990ce3dc.tar.bz2
strace-7270de551ca6b3ea097c114005b6b028990ce3dc.tar.xz
ARM: make it one-personality arch
ARM in fact _is_ one personality. We had two personalities for it because it has a handful of syscalls with huge scnos (0x000f00xx). Extending syscall table to have [0x000f0005] index is of course not a good idea. Someone decided to handle that by having a separate personality just for these syscalls. But multi-personality arch does a bit more work in other parts. This patch is another alternative: "move" 0x000f00nn syscalls down to the entries just above last ordinary syscall, by manipulating scno if it falls into the 0x000f00xx range. In order to not worsen genuine undefined scnos' printing, the code remaps scno back to actual value before printing "syscall_NNN" string. * defs.h: Remove multi-reprsonality defines from ARM. * syscall.c (shuffle_scno): New function. (undefined_scno_name): New function. (get_scno): [ARM] Replace personality setting with scno shuffling. (trace_syscall_entering): Print unknown syscall name using undefined_scno_name(). (trace_syscall_exiting): Likewise. * linux/arm/syscallent.h: Add ARM specific syscalls at the end. * linux/arm/errnoent1.h: Deleted. * linux/arm/ioctlent1.h: Deleted. * linux/arm/signalent1.h: Deleted. * linux/arm/syscallent1.h: Deleted. Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'syscall.c')
-rw-r--r--syscall.c60
1 files changed, 50 insertions, 10 deletions
diff --git a/syscall.c b/syscall.c
index 7e2d0e8..b1a407b 100644
--- a/syscall.c
+++ b/syscall.c
@@ -899,6 +899,51 @@ printcall(struct tcb *tcp)
#endif /* architecture */
}
+/* Shuffle syscall numbers so that we don't have huge gaps in syscall table.
+ * The shuffling should be reversible: shuffle_scno(shuffle_scno(n)) == n.
+ */
+#if defined(ARM) /* So far only ARM needs this */
+static long
+shuffle_scno(unsigned long scno)
+{
+ if (scno <= ARM_LAST_ORDINARY_SYSCALL)
+ return scno;
+
+ /* __ARM_NR_cmpxchg? Swap with LAST_ORDINARY+1 */
+ if (scno == 0x000ffff0)
+ return ARM_LAST_ORDINARY_SYSCALL+1;
+ if (scno == ARM_LAST_ORDINARY_SYSCALL+1)
+ return 0x000ffff0;
+
+ /* Is it ARM specific syscall?
+ * Swap with [LAST_ORDINARY+2, LAST_ORDINARY+2 + LAST_SPECIAL] range.
+ */
+ if (scno >= 0x000f0000
+ && scno <= 0x000f0000 + ARM_LAST_SPECIAL_SYSCALL
+ ) {
+ return scno - 0x000f0000 + (ARM_LAST_ORDINARY_SYSCALL+2);
+ }
+ if (/* scno >= ARM_LAST_ORDINARY_SYSCALL+2 - always true */ 1
+ && scno <= (ARM_LAST_ORDINARY_SYSCALL+2) + ARM_LAST_SPECIAL_SYSCALL
+ ) {
+ return scno + 0x000f0000 - (ARM_LAST_ORDINARY_SYSCALL+2);
+ }
+
+ return scno;
+}
+#else
+# define shuffle_scno(scno) ((long)(scno))
+#endif
+
+static char*
+undefined_scno_name(struct tcb *tcp)
+{
+ static char buf[sizeof("syscall_%lu") + sizeof(long)*3];
+
+ sprintf(buf, "syscall_%lu", shuffle_scno(tcp->scno));
+ return buf;
+}
+
#ifndef get_regs
long get_regs_error;
void
@@ -1246,13 +1291,8 @@ get_scno(struct tcb *tcp)
scno &= 0x000fffff;
}
}
- if (scno & 0x000f0000) {
- /* ARM specific syscall. We handle it as a separate "personality" */
- update_personality(tcp, 1);
- scno &= 0x0000ffff;
- } else {
- update_personality(tcp, 0);
- }
+
+ scno = shuffle_scno(scno);
#elif defined(M68K)
if (upeek(tcp, 4*PT_ORIG_D0, &scno) < 0)
return -1;
@@ -1835,7 +1875,7 @@ trace_syscall_entering(struct tcb *tcp)
if (scno_good != 1)
tprints("????" /* anti-trigraph gap */ "(");
else if (!SCNO_IS_VALID(tcp->scno))
- tprintf("syscall_%lu(", tcp->scno);
+ tprintf("%s(", undefined_scno_name(tcp));
else
tprintf("%s(", sysent[tcp->scno].sys_name);
/*
@@ -1882,7 +1922,7 @@ trace_syscall_entering(struct tcb *tcp)
printleader(tcp);
if (!SCNO_IS_VALID(tcp->scno))
- tprintf("syscall_%lu(", tcp->scno);
+ tprintf("%s(", undefined_scno_name(tcp));
else
tprintf("%s(", sysent[tcp->scno].sys_name);
if (!SCNO_IS_VALID(tcp->scno) ||
@@ -2369,7 +2409,7 @@ trace_syscall_exiting(struct tcb *tcp)
tcp->flags &= ~TCB_REPRINT;
printleader(tcp);
if (!SCNO_IS_VALID(tcp->scno))
- tprintf("<... syscall_%lu resumed> ", tcp->scno);
+ tprintf("<... %s resumed> ", undefined_scno_name(tcp));
else
tprintf("<... %s resumed> ", sysent[tcp->scno].sys_name);
}