/* See LICENSE file for copyright and license details. */ #include "common.h" #include #include #include #include #define LOWEST_BIT(X) ((X) & ~((X) - 1)) #define POST_HIGHEST_OF_CONSECUTIVELY_BITS(X) ((X) + LOWEST_BIT(X)) static inline signed char trailing_zeroes(unsigned long long int x) { int r = 0; if (x == 0) return -1; for (; (x & 1) == 0; x >>= 1) r += 1; return (signed char)r; } static int signed_named_number_cmp(const void *a_, const void *b_) { const struct libsyscalls_named_number *a = a_, *b = b_; return a->number.s < b->number.s ? -1 : a->number.s > b->number.s; } static int unsigned_named_number_cmp(const void *a_, const void *b_) { const struct libsyscalls_named_number *a = a_, *b = b_; return a->number.u < b->number.u ? -1 : a->number.u > b->number.u; } static const char * extract_signal(enum libsyscalls_os os, enum libsyscalls_arch arch, unsigned long long int *valuep, char *fallback_out, int is_signed) { const struct libsyscalls_named_number *signals, *found; size_t nsignals; struct libsyscalls_named_number key = {.number.u = *valuep}; if (libsyscalls_get_signals(os, arch, &signals, &nsignals)) return NULL; found = bsearch(&key, signals, nsignals, sizeof(key), is_signed ? &signed_named_number_cmp : &unsigned_named_number_cmp); if (!found) return NULL; *valuep = 0; return found->name; } static struct libsyscalls_syscall_display_info * build_syscall_display_info(void *data, size_t data_size, size_t data_align, libsyscalls_symbol_printer_function **funcs, const struct libsyscalls_syscall_abi *syscall, int nargs, int nsyms) { struct libsyscalls_syscall_display_info *ret; size_t size, dataoff, paramoff; int i; size = sizeof(*ret); if (size & (data_align - 1)) { size |= data_align - 1; size += 1; } dataoff = size; size += nsyms * data_size; if (size & (alignof(*ret->params) - 1)) { size |= alignof(*ret->params) - 1; size += 1; } paramoff = size; size += (nargs + 1) * sizeof(*ret->params); ret = calloc(1, size); if (!ret) return NULL; ret->size = sizeof(*ret); ret->params = (void *)&((char *)ret)[paramoff]; ret->retvalue = &ret->params[nargs]; nsyms = 0; for (i = 0; i < nargs; i++) { ret->params[i].type = syscall->parameters_types[i]; if (funcs[i]) { ret->params[i].function = funcs[i]; ret->params[i].data = (void *)&((char *)ret)[dataoff + nsyms * data_size]; memcpy(ret->params[i].data, &((char *)data)[i * data_size], data_size); nsyms++; } } ret->retvalue->type = syscall->return_type; ret->retvalue->expect_zero = syscall->expect_zero; if (funcs[i]) { ret->retvalue->function = funcs[i]; ret->retvalue->data = (void *)&((char *)ret)[dataoff + nsyms * data_size]; memcpy(ret->retvalue->data, &((char *)data)[i * data_size], data_size); } return ret; } #include "generated/symbols.c" enum libsyscalls_error libsyscalls_get_syscall_display_info(enum libsyscalls_os os, enum libsyscalls_arch arch, const struct libsyscalls_syscall_abi *syscall, long long int syscall_number, unsigned long long int *syscall_arguments, struct libsyscalls_syscall_display_info **info_out) { struct libsyscalls_syscall_display_info *info; if (!syscall || !syscall_arguments || !info_out) return LIBSYSCALLS_E_INVAL; #define CASE(UPPERCASE, LOWERCASE)\ case LIBSYSCALLS_OS_##UPPERCASE:\ info = get_##LOWERCASE##_syscall_display_info(arch, syscall, syscall_number, syscall_arguments);\ break switch ((int)os) { LIST_OSES(CASE, ;); default: return LIBSYSCALLS_E_OSNOSUP; } #undef CASE if (!info) return LIBSYSCALLS_E_NOMEM; *info_out = info; return LIBSYSCALLS_E_OK; }