]> granicus.if.org Git - strace/commitdiff
Eliminate MAX_QUALS, make qualifier array dynamic
authorDenys Vlasenko <vda.linux@googlemail.com>
Fri, 22 Feb 2013 12:37:36 +0000 (13:37 +0100)
committerDenys Vlasenko <vda.linux@googlemail.com>
Fri, 22 Feb 2013 12:37:36 +0000 (13:37 +0100)
MAX_QUALS was 2048, even though most arches used less than 500 entries
in it. MAX_QUALS had to be maintained by hand to be higher than syscall
count. It also limited the highest possible fd to track.

This change makes qual_flagsN[] arrays start sized to the required minimum
(number of syscalls) and grow dynamically if user requested
-e read=BIGNUM. As a precaution, BIGNUM should be < 2^15, but this limit
can be raised with no cost for normal strace invocations.

qual_flags is now a define to qual_vec[current_personality].

As a bonus, this patch aliases sysent, errnoent, signalent, ioctlent
names in one-personality arches to their corresponding <foo>0 arrays,
removing one indirection level.

  text   data    bss    dec    hex filename
244471    700  12928 258099  3f033 strace.t7/strace
244627    680  10860 256167  3e8a7 strace.t8/strace

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
defs.h
syscall.c

diff --git a/defs.h b/defs.h
index 980dd3af364fbaafbfd75f55f5810ca659c8fe21..3212418c4f43a9d8db262d3edf8f905a2e00d4c8 100644 (file)
--- a/defs.h
+++ b/defs.h
@@ -91,13 +91,6 @@ extern char *stpcpy(char *dst, const char *src);
 #endif
 
 /* Configuration section */
-#ifndef MAX_QUALS
-# if defined(MIPS)
-#  define MAX_QUALS    7000    /* maximum number of syscalls, signals, etc. */
-# else
-#  define MAX_QUALS    2048    /* maximum number of syscalls, signals, etc. */
-# endif
-#endif
 #ifndef DEFAULT_STRLEN
 /* default maximum # of bytes printed in `printstr', change with -s switch */
 # define DEFAULT_STRLEN        32
@@ -524,7 +517,6 @@ typedef enum {
        CFLAG_BOTH
 } cflag_t;
 extern cflag_t cflag;
-extern qualbits_t *qual_flags;
 extern bool debug_flag;
 extern bool Tflag;
 extern bool qflag;
@@ -745,14 +737,28 @@ extern unsigned current_wordsize;
 # define widen_to_long(v) ((long)(v))
 #endif
 
+extern const struct_sysent sysent0[];
+extern const char *const errnoent0[];
+extern const char *const signalent0[];
+extern const struct_ioctlent ioctlent0[];
+extern qualbits_t *qual_vec[SUPPORTED_PERSONALITIES];
+#define qual_flags (qual_vec[current_personality])
+#if SUPPORTED_PERSONALITIES > 1
 extern const struct_sysent *sysent;
-extern unsigned nsyscalls;
 extern const char *const *errnoent;
-extern unsigned nerrnos;
-extern const struct_ioctlent *ioctlent;
-extern unsigned nioctlents;
 extern const char *const *signalent;
+extern const struct_ioctlent *ioctlent;
+#else
+# define sysent     sysent0
+# define errnoent   errnoent0
+# define signalent  signalent0
+# define ioctlent   ioctlent0
+#endif
+extern unsigned nsyscalls;
+extern unsigned nerrnos;
 extern unsigned nsignals;
+extern unsigned nioctlents;
+extern unsigned num_quals;
 
 /*
  * If you need non-NULL sysent[scno].sys_func and sysent[scno].sys_name
index b92ddc0efbecb672a632a3fc2d83c82b72f103b7..ef14a0afa04b2554f2d830cecec17c54871b1d30 100644 (file)
--- a/syscall.c
+++ b/syscall.c
 #define NF SYSCALL_NEVER_FAILS
 #define MA MAX_ARGS
 
-static const struct_sysent sysent0[] = {
+const struct_sysent sysent0[] = {
 #include "syscallent.h"
 };
 
@@ -153,20 +153,19 @@ static const struct_sysent sysent2[] = {
  * in "/usr/include".
  */
 
-static const char *const errnoent0[] = {
+const char *const errnoent0[] = {
 #include "errnoent.h"
 };
-static const char *const signalent0[] = {
+const char *const signalent0[] = {
 #include "signalent.h"
 };
-static const struct_ioctlent ioctlent0[] = {
+const struct_ioctlent ioctlent0[] = {
 #include "ioctlent.h"
 };
 enum { nsyscalls0 = ARRAY_SIZE(sysent0) };
 enum { nerrnos0 = ARRAY_SIZE(errnoent0) };
 enum { nsignals0 = ARRAY_SIZE(signalent0) };
 enum { nioctlents0 = ARRAY_SIZE(ioctlent0) };
-qualbits_t qual_flags0[MAX_QUALS];
 
 #if SUPPORTED_PERSONALITIES > 1
 static const char *const errnoent1[] = {
@@ -182,7 +181,6 @@ enum { nsyscalls1 = ARRAY_SIZE(sysent1) };
 enum { nerrnos1 = ARRAY_SIZE(errnoent1) };
 enum { nsignals1 = ARRAY_SIZE(signalent1) };
 enum { nioctlents1 = ARRAY_SIZE(ioctlent1) };
-qualbits_t qual_flags1[MAX_QUALS];
 #endif
 
 #if SUPPORTED_PERSONALITIES > 2
@@ -199,18 +197,60 @@ enum { nsyscalls2 = ARRAY_SIZE(sysent2) };
 enum { nerrnos2 = ARRAY_SIZE(errnoent2) };
 enum { nsignals2 = ARRAY_SIZE(signalent2) };
 enum { nioctlents2 = ARRAY_SIZE(ioctlent2) };
-qualbits_t qual_flags2[MAX_QUALS];
 #endif
 
+#if SUPPORTED_PERSONALITIES > 1
 const struct_sysent *sysent = sysent0;
 const char *const *errnoent = errnoent0;
 const char *const *signalent = signalent0;
 const struct_ioctlent *ioctlent = ioctlent0;
+#endif
 unsigned nsyscalls = nsyscalls0;
 unsigned nerrnos = nerrnos0;
 unsigned nsignals = nsignals0;
 unsigned nioctlents = nioctlents0;
-qualbits_t *qual_flags = qual_flags0;
+
+unsigned num_quals;
+qualbits_t *qual_vec[SUPPORTED_PERSONALITIES];
+
+static const unsigned nsyscall_vec[SUPPORTED_PERSONALITIES] = {
+       nsyscalls0,
+#if SUPPORTED_PERSONALITIES > 1
+       nsyscalls1,
+#endif
+#if SUPPORTED_PERSONALITIES > 2
+       nsyscalls2,
+#endif
+};
+static const struct_sysent *const sysent_vec[SUPPORTED_PERSONALITIES] = {
+       sysent0,
+#if SUPPORTED_PERSONALITIES > 1
+       sysent1,
+#endif
+#if SUPPORTED_PERSONALITIES > 2
+       sysent2,
+#endif
+};
+
+enum {
+       MAX_NSYSCALLS1 = (nsyscalls0
+#if SUPPORTED_PERSONALITIES > 1
+                       > nsyscalls1 ? nsyscalls0 : nsyscalls1
+#endif
+                       ),
+       MAX_NSYSCALLS2 = (MAX_NSYSCALLS1
+#if SUPPORTED_PERSONALITIES > 2
+                       > nsyscalls2 ? MAX_NSYSCALLS1 : nsyscalls2
+#endif
+                       ),
+       MAX_NSYSCALLS = MAX_NSYSCALLS2,
+       /* We are ready for arches with up to 255 signals,
+        * even though the largest known signo is on MIPS and it is 128.
+        * The number of existing syscalls on all arches is
+        * larger that 255 anyway, so it is just a pedantic matter.
+        */
+       MIN_QUALS = MAX_NSYSCALLS > 255 ? MAX_NSYSCALLS : 255
+};
 
 #if SUPPORTED_PERSONALITIES > 1
 unsigned current_personality;
@@ -229,42 +269,36 @@ static const int personality_wordsize[SUPPORTED_PERSONALITIES] = {
 void
 set_personality(int personality)
 {
+       nsyscalls = nsyscall_vec[personality];
+       sysent = sysent_vec[personality];
+
        switch (personality) {
        case 0:
                errnoent = errnoent0;
                nerrnos = nerrnos0;
-               sysent = sysent0;
-               nsyscalls = nsyscalls0;
                ioctlent = ioctlent0;
                nioctlents = nioctlents0;
                signalent = signalent0;
                nsignals = nsignals0;
-               qual_flags = qual_flags0;
                break;
 
        case 1:
                errnoent = errnoent1;
                nerrnos = nerrnos1;
-               sysent = sysent1;
-               nsyscalls = nsyscalls1;
                ioctlent = ioctlent1;
                nioctlents = nioctlents1;
                signalent = signalent1;
                nsignals = nsignals1;
-               qual_flags = qual_flags1;
                break;
 
 # if SUPPORTED_PERSONALITIES > 2
        case 2:
                errnoent = errnoent2;
                nerrnos = nerrnos2;
-               sysent = sysent2;
-               nsyscalls = nsyscalls2;
                ioctlent = ioctlent2;
                nioctlents = nioctlents2;
                signalent = signalent2;
                nsignals = nsignals2;
-               qual_flags = qual_flags2;
                break;
 # endif
        }
@@ -348,72 +382,63 @@ static const struct qual_options {
        { 0,            NULL,           NULL,           NULL            },
 };
 
+static void
+reallocate_qual(int n)
+{
+       unsigned p;
+       qualbits_t *qp;
+       for (p = 0; p < SUPPORTED_PERSONALITIES; p++) {
+               qp = qual_vec[p] = realloc(qual_vec[p], n * sizeof(qualbits_t));
+               if (!qp)
+                       die_out_of_memory();
+               memset(&qp[num_quals], 0, (n - num_quals) * sizeof(qualbits_t));
+       }
+       num_quals = n;
+}
+
 static void
 qualify_one(int n, int bitflag, int not, int pers)
 {
-       if (pers == 0 || pers < 0) {
-               if (not)
-                       qual_flags0[n] &= ~bitflag;
-               else
-                       qual_flags0[n] |= bitflag;
-       }
+       unsigned p;
 
-#if SUPPORTED_PERSONALITIES > 1
-       if (pers == 1 || pers < 0) {
-               if (not)
-                       qual_flags1[n] &= ~bitflag;
-               else
-                       qual_flags1[n] |= bitflag;
-       }
-#endif
+       if (num_quals <= n)
+               reallocate_qual(n + 1);
 
-#if SUPPORTED_PERSONALITIES > 2
-       if (pers == 2 || pers < 0) {
-               if (not)
-                       qual_flags2[n] &= ~bitflag;
-               else
-                       qual_flags2[n] |= bitflag;
+       for (p = 0; p < SUPPORTED_PERSONALITIES; p++) {
+               if (pers == p || pers < 0) {
+                       if (not)
+                               qual_vec[p][n] &= ~bitflag;
+                       else
+                               qual_vec[p][n] |= bitflag;
+               }
        }
-#endif
 }
 
 static int
 qual_syscall(const char *s, int bitflag, int not)
 {
-       int i;
+       unsigned p;
+       unsigned i;
        int rc = -1;
 
        if (*s >= '0' && *s <= '9') {
-               int i = string_to_uint(s);
-               if (i < 0 || i >= MAX_QUALS)
+               i = string_to_uint(s);
+               if (i > MAX_NSYSCALLS)
                        return -1;
                qualify_one(i, bitflag, not, -1);
                return 0;
        }
-       for (i = 0; i < nsyscalls0; i++)
-               if (sysent0[i].sys_name &&
-                   strcmp(s, sysent0[i].sys_name) == 0) {
-                       qualify_one(i, bitflag, not, 0);
-                       rc = 0;
-               }
-
-#if SUPPORTED_PERSONALITIES > 1
-       for (i = 0; i < nsyscalls1; i++)
-               if (sysent1[i].sys_name &&
-                   strcmp(s, sysent1[i].sys_name) == 0) {
-                       qualify_one(i, bitflag, not, 1);
-                       rc = 0;
-               }
-#endif
 
-#if SUPPORTED_PERSONALITIES > 2
-       for (i = 0; i < nsyscalls2; i++)
-               if (sysent2[i].sys_name &&
-                   strcmp(s, sysent2[i].sys_name) == 0) {
-                       qualify_one(i, bitflag, not, 2);
-                       rc = 0;
+       for (p = 0; p < SUPPORTED_PERSONALITIES; p++) {
+               for (i = 0; i < nsyscall_vec[p]; i++) {
+                       if (sysent_vec[p][i].sys_name
+                        && strcmp(s, sysent_vec[p][i].sys_name) == 0
+                       ) {
+                               qualify_one(i, bitflag, not, 0);
+                               rc = 0;
+                       }
                }
-#endif
+       }
 
        return rc;
 }
@@ -425,7 +450,7 @@ qual_signal(const char *s, int bitflag, int not)
 
        if (*s >= '0' && *s <= '9') {
                int signo = string_to_uint(s);
-               if (signo < 0 || signo >= MAX_QUALS)
+               if (signo < 0 || signo > 255)
                        return -1;
                qualify_one(signo, bitflag, not, -1);
                return 0;
@@ -446,7 +471,7 @@ qual_desc(const char *s, int bitflag, int not)
 {
        if (*s >= '0' && *s <= '9') {
                int desc = string_to_uint(s);
-               if (desc < 0 || desc >= MAX_QUALS)
+               if (desc < 0 || desc > 0x7fff) /* paranoia */
                        return -1;
                qualify_one(desc, bitflag, not, -1);
                return 0;
@@ -483,6 +508,9 @@ qualify(const char *s)
        const char *p;
        int i, n;
 
+       if (num_quals == 0)
+               reallocate_qual(MIN_QUALS);
+
        opt = &qual_options[0];
        for (i = 0; (p = qual_options[i].option_name); i++) {
                n = strlen(p);
@@ -502,12 +530,12 @@ qualify(const char *s)
                s = "all";
        }
        if (strcmp(s, "all") == 0) {
-               for (i = 0; i < MAX_QUALS; i++) {
+               for (i = 0; i < num_quals; i++) {
                        qualify_one(i, opt->bitflag, not, -1);
                }
                return;
        }
-       for (i = 0; i < MAX_QUALS; i++) {
+       for (i = 0; i < num_quals; i++) {
                qualify_one(i, opt->bitflag, !not, -1);
        }
        copy = strdup(s);
@@ -515,22 +543,12 @@ qualify(const char *s)
                die_out_of_memory();
        for (p = strtok(copy, ","); p; p = strtok(NULL, ",")) {
                if (opt->bitflag == QUAL_TRACE && (n = lookup_class(p)) > 0) {
-                       for (i = 0; i < nsyscalls0; i++)
-                               if (sysent0[i].sys_flags & n)
-                                       qualify_one(i, opt->bitflag, not, 0);
-
-#if SUPPORTED_PERSONALITIES > 1
-                       for (i = 0; i < nsyscalls1; i++)
-                               if (sysent1[i].sys_flags & n)
-                                       qualify_one(i, opt->bitflag, not, 1);
-#endif
-
-#if SUPPORTED_PERSONALITIES > 2
-                       for (i = 0; i < nsyscalls2; i++)
-                               if (sysent2[i].sys_flags & n)
-                                       qualify_one(i, opt->bitflag, not, 2);
-#endif
-
+                       unsigned pers;
+                       for (pers = 0; pers < SUPPORTED_PERSONALITIES; pers++) {
+                               for (i = 0; i < nsyscall_vec[pers]; i++)
+                                       if (sysent_vec[pers][i].sys_flags & n)
+                                               qualify_one(i, opt->bitflag, not, 0);
+                       }
                        continue;
                }
                if (opt->qualify(p, opt->bitflag, not)) {
@@ -2336,7 +2354,7 @@ dumpio(struct tcb *tcp)
 
        if (syserror(tcp))
                return;
-       if ((unsigned long) tcp->u_arg[0] >= MAX_QUALS)
+       if ((unsigned long) tcp->u_arg[0] >= num_quals)
                return;
        func = tcp->s_ent->sys_func;
        if (func == printargs)