/
githubmirror
/
audit-userspace
Обзор
Документация
Войти
/
githubmirror
/
audit-userspace
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
lib/gen_tables64.c
567 строк
18 KB
Steve Grubb
Resolve long standing FIXME's
02 авг 2025, 17:33
02 авг 2025, 17:33
194b36c
Код
Авторство
О чём код?
/* gen_tables64.c -- Generator of lookup tables with 64-bit support. * Copyright 2025 Red Hat Inc. * All Rights Reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb <sgrubb@redhat.com> (64-bit extensions) * Based on previous work by Miloslav Trmač */ #include "config.h" #include <assert.h> #include <ctype.h> #include <errno.h> #include <limits.h> #include <linux/net.h> #include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdint.h> #include <inttypes.h> #include <sys/stat.h> #include <sys/personality.h> #include <sys/mount.h> #ifndef MS_DIRSYNC #include <linux/fs.h> #endif #include "gen_tables64.h" #include "libaudit.h" #include "auparse-defs.h" /* This is from asm/ipc.h. Copying it for now as some platforms * * have broken headers. */ #define SEMOP 1 #define SEMGET 2 #define SEMCTL 3 #define SEMTIMEDOP 4 #define MSGSND 11 #define MSGRCV 12 #define MSGGET 13 #define MSGCTL 14 #define SHMAT 21 #define SHMDT 22 #define SHMGET 23 #define SHMCTL 24 #define DIPC 25 /* * Defines EHWPOISON to the value found in uapi/asm-generic/errno.h, * which is correct for most (but not all architectures). */ #ifndef EHWPOISON #define EHWPOISON 133 #endif /* The ratio of table size to number of non-empty elements allowed for a "direct" s2i lookup table. Dense integer ranges can be represented as direct-index arrays for O(1) i2s lookups, while sparse tables fall back to bsearch() generated tables. String-to-integer conversions always use binary search since strings can't be indexed directly. 2 looks like a lot at a first glance, but the bsearch tables need twice as much space per element, so with the ratio equal to 2 the direct table uses no more memory and is faster. */ #define DIRECT_THRESHOLD 2 /* Allow more than one string defined for a single integer value */ static bool allow_duplicate_ints; /* = false; */ /* Flag to indicate if we're generating 64-bit tables */ static bool use_64bit = false; struct value { int64_t val; /* Changed from int to int64_t to support 64-bit values */ const char *s; size_t s_offset; size_t orig_index; }; /* The mapping to store. */ static struct value values[] = { #define _S(VAL, S) { (VAL), (S), 0, 0 }, #include TABLE_H #undef _S }; #define NUM_VALUES (sizeof(values) / sizeof(*values)) /* Compare two "struct value" members by name. */ static int cmp_value_strings(const void *xa, const void *xb) { const struct value *a, *b; a = xa; b = xb; return strcmp(a->s, b->s); } /* Compare two "struct value" members by value. */ static int cmp_value_vals(const void *xa, const void *xb) { const struct value *a, *b; a = xa; b = xb; if (a->val > b->val) return 1; if (a->val < b->val) return -1; /* Preserve the original order if there is an ambiguity, to always use the first specified value. */ if (a->orig_index > b->orig_index) return 1; if (a->orig_index < b->orig_index) return -1; return 0; } /* Compare two "struct value" members by orig_index. */ static int cmp_value_orig_index(const void *xa, const void *xb) { const struct value *a, *b; a = xa; b = xb; if (a->orig_index > b->orig_index) return 1; if (a->orig_index < b->orig_index) return -1; return 0; } /* Output the string table, initialize values[*]->s_offset. */ static void output_strings(const char *prefix) { size_t i, offset; offset = 0; for (i = 0; i < NUM_VALUES; i++) { values[i].s_offset = offset; offset += strlen(values[i].s) + 1; } printf("static const char %s_strings[] = \"", prefix); assert(NUM_VALUES > 0); for (i = 0; i < NUM_VALUES; i++) { const char *c; if (i != 0 && i % 10 == 0) fputs("\"\n" "\t\"", stdout); for (c = values[i].s; *c != '\0'; c++) { assert(*c != '"' && *c != '\\' && isprint((unsigned char)*c)); putc(*c, stdout); } if (i != NUM_VALUES - 1) fputs("\\0", stdout); } fputs("\";\n", stdout); } /* Output the string to integer mapping code. Assume strings are all uppercase or all lowercase if specified by parameters; in that case, make the search case-insensitive. values must be sorted by strings. */ static void output_s2i(const char *prefix, bool uppercase, bool lowercase) { size_t i; for (i = 0; i < NUM_VALUES - 1; i++) { assert(strcmp(values[i].s, values[i + 1].s) <= 0); if (strcmp(values[i].s, values[i + 1].s) == 0) { fprintf(stderr, "Duplicate value `%s': %" PRId64 ", %" PRId64 "\n", values[i].s, values[i].val, values[i + 1].val); abort(); } } printf("static const unsigned %s_s2i_s[] = {", prefix); for (i = 0; i < NUM_VALUES; i++) { if (i % 10 == 0) fputs("\n\t", stdout); assert(values[i].s_offset <= UINT_MAX); printf("%zu,", values[i].s_offset); } printf("\n" "};\n"); /* Output either int or int64_t array based on use_64bit flag */ if (use_64bit) { printf("static const int64_t %s_s2i_i[] = {", prefix); } else { printf("static const int %s_s2i_i[] = {", prefix); } for (i = 0; i < NUM_VALUES; i++) { if (i % 10 == 0) fputs("\n\t", stdout); if (use_64bit) { printf("%" PRId64 ",", values[i].val); } else { /* For 32-bit compatibility, check if values fit in 32-bit int range */ if (values[i].val > INT_MAX || values[i].val < INT_MIN) { fprintf(stderr, "Warning: Value %" PRId64 " exceeds 32-bit int range. " "Consider using --64bit option.\n", values[i].val); } printf("%d,", (int)values[i].val); } } fputs("\n" "};\n", stdout); assert(!(uppercase && lowercase)); if (uppercase) { for (i = 0; i < NUM_VALUES; i++) { const char *c; for (c = values[i].s; *c != '\0'; c++) assert(isascii((unsigned char)*c) && !GT_ISLOWER(*c)); } } else if (lowercase) { for (i = 0; i < NUM_VALUES; i++) { const char *c; for (c = values[i].s; *c != '\0'; c++) assert(isascii((unsigned char)*c) && !GT_ISUPPER(*c)); } } /* Generate the appropriate s2i function based on 32/64-bit mode */ if (use_64bit) { if (uppercase || lowercase) { printf("static int %s_s2i(const char *s, int64_t *value) {\n" "\tsize_t len, i;\n" "\t if (s == NULL || value == NULL)\n" "\t\treturn 0;\n" "\tlen = strlen(s);\n" "\t{ char copy[len + 1];\n" "\tfor (i = 0; i < len; i++) {\n" "\t\tchar c = s[i];\n", prefix); if (uppercase) fputs("\t\tcopy[i] = GT_ISLOWER(c) ? c - 'a' + 'A' " ": c;\n", stdout); else fputs("\t\tcopy[i] = GT_ISUPPER(c) ? c - 'A' + 'a' " ": c;\n", stdout); printf("\t}\n" "\tcopy[i] = 0;\n" "\treturn s2i_64__(%s_strings, %s_s2i_s, %s_s2i_i, %zu, " "copy, value);\n" "\t}\n" "}\n", prefix, prefix, prefix, NUM_VALUES); } else { printf("static int %s_s2i(const char *s, int64_t *value) {\n" "\treturn s2i_64__(%s_strings, %s_s2i_s, %s_s2i_i, %zu, s, " "value);\n" "}\n", prefix, prefix, prefix, prefix, NUM_VALUES); } } else { /* Original 32-bit code */ if (uppercase || lowercase) { printf("static int %s_s2i(const char *s, int *value) {\n" "\tsize_t len, i;\n" "\t if (s == NULL || value == NULL)\n" "\t\treturn 0;\n" "\tlen = strlen(s);\n" "\t{ char copy[len + 1];\n" "\tfor (i = 0; i < len; i++) {\n" "\t\tchar c = s[i];\n", prefix); if (uppercase) fputs("\t\tcopy[i] = GT_ISLOWER(c) ? c - 'a' + 'A' " ": c;\n", stdout); else fputs("\t\tcopy[i] = GT_ISUPPER(c) ? c - 'A' + 'a' " ": c;\n", stdout); printf("\t}\n" "\tcopy[i] = 0;\n" "\treturn s2i__(%s_strings, %s_s2i_s, %s_s2i_i, %zu, " "copy, value);\n" "\t}\n" "}\n", prefix, prefix, prefix, NUM_VALUES); } else { printf("static int %s_s2i(const char *s, int *value) {\n" "\treturn s2i__(%s_strings, %s_s2i_s, %s_s2i_i, %zu, s, " "value);\n" "}\n", prefix, prefix, prefix, prefix, NUM_VALUES); } } } /* Output the string to integer mapping table. values must be sorted by strings. */ static void output_i2s(const char *prefix) { struct value *unique_values; int64_t min_val, max_val; size_t i, n; assert(NUM_VALUES > 0); for (i = 0; i < NUM_VALUES - 1; i++) { assert(values[i].val <= values[i + 1].val); if (!allow_duplicate_ints && values[i].val == values[i + 1].val) { fprintf(stderr, "Duplicate value %" PRId64 ": `%s', `%s'\n", values[i].val, values[i].s, values[i + 1].s); abort(); } } unique_values = malloc(NUM_VALUES * sizeof(*unique_values)); if (unique_values == NULL) { fprintf(stderr, "Out of memory. Check %s file, %d line", __FILE__, __LINE__); abort(); } n = 0; for (i = 0; i < NUM_VALUES; i++) { if (n == 0 || unique_values[n - 1].val != values[i].val) { unique_values[n] = values[i]; n++; } } min_val = unique_values[0].val; max_val = unique_values[n - 1].val; /* Check if the direct table approach is feasible */ /* For 64-bit values, we need to be more restrictive with direct tables * to avoid huge memory usage */ bool use_direct = false; int64_t table_size = (int64_t)max_val - (int64_t)min_val + 1; if (use_64bit) { /* For 64-bit mode: Only use direct tables if the range is manageable * (under 1024 entries) */ if (table_size > 0 && table_size < 1024 && ((double)table_size / n <= DIRECT_THRESHOLD)) { use_direct = true; } } else { /* Original 32-bit criteria */ if (((double)max_val - (double)min_val) / n <= DIRECT_THRESHOLD) { use_direct = true; } } if (use_direct) { int64_t next_index; printf("static const unsigned %s_i2s_direct[] = {", prefix); next_index = min_val; i = 0; for (;;) { if ((next_index - min_val) % 10 == 0) fputs("\n\t", stdout); while (i < n && unique_values[i].val < next_index) /* This can happen if (allow_duplicate_ints) */ i++; if (i < n && unique_values[i].val == next_index) { assert(unique_values[i].s_offset <= UINT_MAX); printf("%zu,", unique_values[i].s_offset); } else fputs("-1u,", stdout); if (next_index == max_val) /* Done like this to avoid integer overflow */ break; next_index++; } printf("\n" "};\n"); if (use_64bit) { printf("static const char *%s_i2s(int64_t v) {\n" "\treturn i2s_64_direct__(%s_strings, %s_i2s_direct, %" PRId64 ", " "%" PRId64 ", v);\n" "}\n", prefix, prefix, prefix, min_val, max_val); } else { printf("static const char *%s_i2s(int v) {\n" "\treturn i2s_direct__(%s_strings, %s_i2s_direct, %d, " "%d, v);\n" "}\n", prefix, prefix, prefix, (int)min_val, (int)max_val); } } else { /* Use binary search tables */ if (use_64bit) { printf("static const int64_t %s_i2s_i[] = {", prefix); for (i = 0; i < n; i++) { if (i % 10 == 0) fputs("\n\t", stdout); printf("%" PRId64 ",", unique_values[i].val); } } else { printf("static const int %s_i2s_i[] = {", prefix); for (i = 0; i < n; i++) { if (i % 10 == 0) fputs("\n\t", stdout); printf("%d,", (int)unique_values[i].val); } } printf("\n" "};\n" "static const unsigned %s_i2s_s[] = {", prefix); for (i = 0; i < n; i++) { if (i % 10 == 0) fputs("\n\t", stdout); assert(unique_values[i].s_offset <= UINT_MAX); printf("%zu,", unique_values[i].s_offset); } printf("\n" "};\n"); if (use_64bit) { printf("static const char *%s_i2s(int64_t v) {\n" "\treturn i2s_64_bsearch__(%s_strings, %s_i2s_i, %s_i2s_s, " "%zu, v);\n" "}\n", prefix, prefix, prefix, prefix, n); } else { printf("static const char *%s_i2s(int v) {\n" "\treturn i2s_bsearch__(%s_strings, %s_i2s_i, %s_i2s_s, " "%zu, v);\n" "}\n", prefix, prefix, prefix, prefix, n); } } free(unique_values); } /* Output the string to integer mapping table as a transtab[]. values must be sorted in the desired order. */ static void output_i2s_transtab(const char *prefix) { size_t i; char *uc_prefix; if (use_64bit) { printf("static const struct transtab64 %s_table[] = {", prefix); for (i = 0; i < NUM_VALUES; i++) { if (i % 10 == 0) fputs("\n\t", stdout); printf("{%" PRId64 ",%zu},", values[i].val, values[i].s_offset); } } else { printf("static const struct transtab %s_table[] = {", prefix); for (i = 0; i < NUM_VALUES; i++) { if (i % 10 == 0) fputs("\n\t", stdout); printf("{%d,%zu},", (int)values[i].val, values[i].s_offset); } } uc_prefix = strdup(prefix); if (uc_prefix == NULL) { fprintf(stderr, "Out of memory. Check %s file, %d line", __FILE__, __LINE__); abort(); } for (i = 0; uc_prefix[i] != '\0'; i++) uc_prefix[i] = toupper((unsigned char)uc_prefix[i]); printf("\n" "};\n" "#define %s_NUM_ENTRIES " "(sizeof(%s_table) / sizeof(*%s_table))\n", uc_prefix, prefix, prefix); free(uc_prefix); } int main(int argc, char **argv) { bool gen_i2s, gen_i2s_transtab, gen_s2i, uppercase, lowercase; char *prefix; size_t i; /* This is required by gen_tables.h */ assert(NUM_VALUES <= (SSIZE_MAX / 2 + 1)); /* To make sure GT_ISUPPER and GT_ISLOWER work. */ assert('Z' == 'A' + 25 && 'z' == 'a' + 25); gen_i2s = false; gen_i2s_transtab = false; gen_s2i = false; uppercase = false; lowercase = false; prefix = NULL; assert (argc > 1); for (i = 1; i < (size_t)argc; i++) { if (strcmp(argv[i], "--i2s") == 0) gen_i2s = true; else if (strcmp(argv[i], "--i2s-transtab") == 0) gen_i2s_transtab = true; else if (strcmp(argv[i], "--s2i") == 0) gen_s2i = true; else if (strcmp(argv[i], "--uppercase") == 0) uppercase = true; else if (strcmp(argv[i], "--lowercase") == 0) lowercase = true; else if (strcmp(argv[i], "--duplicate-ints") == 0) allow_duplicate_ints = true; else if (strcmp(argv[i], "--64bit") == 0) use_64bit = true; else { assert(*argv[i] != '-'); assert(prefix == NULL); prefix = argv[i]; } } assert(prefix != NULL); assert(!(uppercase && lowercase)); printf("/* This is a generated file, see Makefile.am for its " "inputs. */\n"); /* Add include for inttypes.h if using 64-bit mode */ if (use_64bit) { printf("#include <inttypes.h>\n"); } for (i = 0; i < NUM_VALUES; i++) values[i].orig_index = i; qsort(values, NUM_VALUES, sizeof(*values), cmp_value_strings); /* * Generated lookup tables are in lexicographic order. Alternative * orderings, such as reordering BFS nodes or retaining the * original input order, provide negligible cache benefits. */ output_strings(prefix); if (gen_s2i) output_s2i(prefix, uppercase, lowercase); if (gen_i2s) { qsort(values, NUM_VALUES, sizeof(*values), cmp_value_vals); output_i2s(prefix); } if (gen_i2s_transtab) { qsort(values, NUM_VALUES, sizeof(*values), cmp_value_orig_index); output_i2s_transtab(prefix); } return EXIT_SUCCESS; }