diff options
Diffstat (limited to 'linux/symbols.c')
-rw-r--r-- | linux/symbols.c | 321 |
1 files changed, 321 insertions, 0 deletions
diff --git a/linux/symbols.c b/linux/symbols.c new file mode 100644 index 0000000..d91880f --- /dev/null +++ b/linux/symbols.c @@ -0,0 +1,321 @@ +/* See LICENSE file for copyright and license details. */ + +/* This file is included from ../libsyscalls_get_syscall_display_info.c */ + +/* TODO (see syscalls.h) */ +#define extract_linux_symbol_madvise extract_linux_symbol_noflags +#define extract_linux_symbol_msync extract_linux_symbol_noflags +#define extract_linux_symbol_mlock extract_linux_symbol_noflags +#define extract_linux_symbol_mcl extract_linux_symbol_noflags +#define extract_linux_symbol_epoll extract_linux_symbol_noflags +#define extract_linux_symbol_sock_fd extract_linux_symbol_noflags +#define extract_linux_symbol_dup3 extract_linux_symbol_noflags +#define extract_linux_symbol_pipe extract_linux_symbol_noflags +#define extract_linux_symbol_inotify_fd extract_linux_symbol_noflags +#define extract_linux_symbol_fan_event_f extract_linux_symbol_noflags +#define extract_linux_symbol_mq_open extract_linux_symbol_noflags +#define extract_linux_symbol_swapon extract_linux_symbol_noflags +#define extract_linux_symbol_inotify_mask extract_linux_symbol_noflags +#define extract_linux_symbol_shmget extract_linux_symbol_noflags +#define extract_linux_symbol_fan_class extract_linux_symbol_noflags +#define extract_linux_symbol_fan_mark extract_linux_symbol_noflags +#define extract_linux_symbol_fan extract_linux_symbol_noflags +#define extract_linux_symbol_socket extract_linux_symbol_noflags +#define extract_linux_symbol_reboot extract_linux_symbol_noflags + + +static const char * +extract_linux_symbol_signal(struct libsyscalls_symbol_printer_data *data, unsigned long long int *valuep, char *fallback_out) +{ + return extract_signal(LIBSYSCALLS_OS_LINUX, data->arch, valuep, fallback_out, + 0 /* doesn't matter, unsigned is probably faster */); +} + + +static const char * +extract_linux_symbol_mode(struct libsyscalls_symbol_printer_data *data, unsigned long long int *valuep, char *fallback_out) +{ + unsigned long long int value; + size_t i; + *fallback_out = 'o'; + *valuep ^= value = *valuep & 07777ULL; + i = 0; + data->buf[i++] = '0'; + if (value & 07000) goto digits4; + if (value & 0700) goto digits3; + if (value & 070) goto digits2; + if (value & 07) goto digits1; + if (0) { + digits4: + data->buf[i++] = '0' | (value & 07000); + digits3: + data->buf[i++] = '0' | (value & 0700); + digits2: + data->buf[i++] = '0' | (value & 070); + digits1: + data->buf[i++] = '0' | (value & 07); + } + data->buf[i++] = ' '; + data->buf[i++] = '('; + data->buf[i++] = (value & 0400) ? 'r' : '-'; + data->buf[i++] = (value & 0200) ? 'w' : '-'; + if (value & 04000) + data->buf[i++] = (value & 0100) ? 's' : 'S'; + else + data->buf[i++] = (value & 0100) ? 'x' : '-'; + data->buf[i++] = (value & 040) ? 'r' : '-'; + data->buf[i++] = (value & 020) ? 'w' : '-'; + if (value & 02000) + data->buf[i++] = (value & 010) ? 's' : 'S'; + else + data->buf[i++] = (value & 010) ? 'x' : '-'; + data->buf[i++] = (value & 04) ? 'r' : '-'; + data->buf[i++] = (value & 02) ? 'w' : '-'; + if (value & 01000) + data->buf[i++] = (value & 01) ? 't' : 'T'; + else + data->buf[i++] = (value & 01) ? 'x' : '-'; + data->buf[i++] = ')'; + data->buf[i] = '\0'; + return data->buf; +} + + +static const char * +extract_linux_symbol_umask(struct libsyscalls_symbol_printer_data *data, unsigned long long int *valuep, char *fallback_out) +{ + unsigned long long int value; + size_t i; + *fallback_out = 'o'; + *valuep ^= value = *valuep & 0777ULL; + i = 0; + data->buf[i++] = '0'; + if (value & 0700) goto digits3; + if (value & 070) goto digits2; + if (value & 07) goto digits1; + if (0) { + digits3: + data->buf[i++] = '0' | (value & 0700); + digits2: + data->buf[i++] = '0' | (value & 070); + digits1: + data->buf[i++] = '0' | (value & 07); + } + data->buf[i++] = ' '; + data->buf[i++] = '('; + data->buf[i++] = 'u'; + data->buf[i++] = ':'; + data->buf[i++] = ':'; + data->buf[i++] = (value & 0400) ? '-' : 'r'; + data->buf[i++] = (value & 0200) ? '-' : 'w'; + data->buf[i++] = (value & 0100) ? '-' : 'x'; + data->buf[i++] = ','; + data->buf[i++] = 'g'; + data->buf[i++] = ':'; + data->buf[i++] = ':'; + data->buf[i++] = (value & 040) ? '-' : 'r'; + data->buf[i++] = (value & 020) ? '-' : 'w'; + data->buf[i++] = (value & 010) ? '-' : 'x'; + data->buf[i++] = ','; + data->buf[i++] = 'o'; + data->buf[i++] = ':'; + data->buf[i++] = ':'; + data->buf[i++] = (value & 04) ? '-' : 'r'; + data->buf[i++] = (value & 02) ? '-' : 'w'; + data->buf[i++] = (value & 01) ? '-' : 'x'; + data->buf[i++] = ')'; + data->buf[i] = '\0'; + return data->buf; +} + + +static const char * +extract_linux_symbol_dev(struct libsyscalls_symbol_printer_data *data, unsigned long long int *valuep, char *fallback_out) +{ + unsigned long long int value; + unsigned long long int major, major1, major2; + unsigned long long int minor, minor1, minor2; + + *fallback_out = 'x'; + + major1 = 0xFFFFF00000000000ULL; + minor1 = 0x00000FFFFFF00000ULL; + major2 = 0x00000000000FFF00ULL; + minor2 = 0x00000000000000FFULL; + + *valuep ^= value = *valuep & (major1 | minor1 | major2 | minor2); + + major1 = (value & major1) / LOWEST_BIT(major1) * POST_HIGHEST_OF_CONSECUTIVELY_BITS(major2); + major2 = (value & major2) / LOWEST_BIT(major2); + + minor1 = (value & minor1) / LOWEST_BIT(minor1) * POST_HIGHEST_OF_CONSECUTIVELY_BITS(minor2); + minor2 = (value & minor2) / LOWEST_BIT(minor2); + + major = major1 | major2; + minor = minor1 | minor1; + + sprintf(data->buf, "%llu (%llu:%llu)", value, major, minor); + return data->buf; +} + + +static const char * +extract_linux_symbol_clockid_t(struct libsyscalls_symbol_printer_data *data, unsigned long long int *valuep, char *fallback_out) +{ + if (*valuep >= 0) + return NULL; + else if ((*valuep & 7) == 2) + sprintf(data->buf, "%lli (pid: %llu)", (long long int)*valuep, ~*valuep / 8); + else if ((*valuep & 7) == 3) + sprintf(data->buf, "%lli (fd: %llu)", (long long int)*valuep, ~*valuep / 8); + else if ((*valuep & 7) == 6) + sprintf(data->buf, "%lli (tid: %llu)", (long long int)*valuep, ~*valuep / 8); + else + sprintf(data->buf, "%lli (~%llu*8 + %u)", (long long int)*valuep, ~*valuep / 8, *valuep & 7); + *valuep = 0; + return data->buf; +} + + +#define SYMBOL_PRINTERS_ONLY +#include "syscalls.h" +#undef SYMBOL_PRINTERS_ONLY + +#include "../generated/linux-symbol-extractors.h" + + +static int +get_linux_symbol_extractor_by_sym_nr(LIBSYSCALLS_SYMBOL_PRINTER printer, libsyscalls_symbol_printer_function **function_out, + enum libsyscalls_arch arch, const struct libsyscalls_syscall_abi *syscall, int nr, + struct libsyscalls_symbol_printer_data *data_out) +{ + int ret; + +#define CASE(E, F, N)\ + case E:\ + *function_out = &F;\ + ret = N;\ + break + + switch (printer) { + LIST_LINUX_EXTRACTORS(CASE, ;); + + case LINUX_SYMBOL_PRINTER_SIGNAL: + *function_out = &extract_linux_symbol_signal; + ret = 1; + break; + + default: + abort(); + } + +#undef CASE + + data_out->arch = arch; + data_out->nr = nr; + + (void) syscall; + return ret; +} + + +static libsyscalls_symbol_printer_function * +get_linux_symbol_extractor_by_arg_nr(enum libsyscalls_arch arch, const struct libsyscalls_syscall_abi *syscall, + int arg, struct libsyscalls_symbol_printer_data *data_out) +{ + int nr, n; + unsigned mask; + LIBSYSCALLS_SYMBOL_PRINTER first, second; + libsyscalls_symbol_printer_function *function; + + if (!syscall->symbol_printer || arg >= NPARAMS) { + return NULL; + } else if (arg < 0) { + if (syscall->symbolic_return) + nr = 0; + else + return NULL; + } else if ((syscall->symbolic_mask >> arg) & 1) { + mask = (unsigned)syscall->symbolic_mask; + nr = (int)syscall->symbolic_return; + for (mask &= (1U << arg) - 1; mask; mask >>= 1) + nr += (int)mask & 1; + } else { + return NULL; + } + + first = (syscall->symbol_printer & 0x00FF) >> 0; + second = (syscall->symbol_printer & 0xFF00) >> 8; + if (second && !first) + second = syscall->symbol_printer; + + if (first) { + n = get_linux_symbol_extractor_by_sym_nr(first, &function, arch, syscall, nr, data_out); + if (nr < n) + goto have_fun; + nr -= n; + } + + if (second) { + n = get_linux_symbol_extractor_by_sym_nr(second, &function, arch, syscall, nr, data_out); + if (nr < n) + goto have_fun; + } + + abort(); + +have_fun: + return function; +} + + +static struct libsyscalls_syscall_display_info * +get_linux_syscall_display_info(enum libsyscalls_arch arch, const struct libsyscalls_syscall_abi *syscall, + long long int syscall_number, unsigned long long int *syscall_argument) +{ + LIBSYSCALLS_SYMBOL_PRINTER_DATA *data; + libsyscalls_symbol_printer_function **funcs; + int i, nargs, nsyms; + size_t data_size = offsetof(LIBSYSCALLS_SYMBOL_PRINTER_DATA, buf); + size_t data_align = alignof(*data); + size_t bufspace, bufspace1, bufspace2; + LIBSYSCALLS_SYMBOL_PRINTER first, second; + + nargs = (int)syscall->max_argument_count; + nargs = nargs < 0 ? 0 : nargs; + + first = (syscall->symbol_printer & 0x00FF) >> 0; + second = (syscall->symbol_printer & 0xFF00) >> 8; + if (second && !first) + second = syscall->symbol_printer; + + bufspace1 = LINUX_REQUIRE_SYMBOL_BUFFER(first); + bufspace2 = LINUX_REQUIRE_SYMBOL_BUFFER(second); + bufspace = bufspace1 > bufspace2 ? bufspace1 : bufspace2; + data_size += bufspace; + if (bufspace & (data_align - 1)) { + data_size |= data_align - 1; + data_size += 1; + } + + { + char data_vla_buf[(nargs + 1) * data_size + data_align]; + libsyscalls_symbol_printer_function *funcs_vla[nargs + 1]; + + data = (void *)ALIGN_BUF(data_vla_buf, data_align); + funcs = funcs_vla; + + nsyms = 0; + for (i = 0; i < nargs; i++) { + funcs[i] = get_linux_symbol_extractor_by_arg_nr(arch, syscall, i, &data[i]); + nsyms += !!funcs[i]; + } + funcs[i] = get_linux_symbol_extractor_by_arg_nr(arch, syscall, -1, &data[i]); + nsyms += !!funcs[i]; + + (void) syscall_argument; + (void) syscall_number; + + return build_syscall_display_info(data, data_size, data_align, funcs, syscall, nargs, nsyms); + } +} |