/* See LICENSE file for copyright and license details. */ #include "common.h" static inline signed char trailing_zeroes(unsigned long long int x) { #ifndef HAVE_BUILTIN_FFSLL # if defined(__HAVE_BUILTIN_FFSLL) # define HAVE_BUILTIN_FFSLL # elif defined(__clang__) # if __clang_major__ >= 5 # define HAVE_BUILTIN_FFSLL # endif # elif defined(__GNUC__) # if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) # define HAVE_BUILTIN_FFSLL # endif # endif #endif #ifdef HAVE_BUILTIN_FFSLL # if defined(__GNUC__) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wsign-conversion" # endif return (signed char)(__builtin_ffsll(x) - 1); /* the type for x has changed over time */ # if defined(__GNUC__) # pragma GCC diagnostic pop # endif #else int r = 0; if (x == 0) return -1; for (; (x & 1) == 0; x >>= 1) r += 1; return (signed char)r; #endif } static const char * extract_signal(enum libsyscalls_os os, enum libsyscalls_arch arch, unsigned long long int *valuep, char *fallback_out) { const struct libsyscalls_named_number *signals, *found; size_t nsignals; int is_signed; if (libsyscalls_get_signals(os, arch, &signals, &nsignals, &is_signed)) return NULL; found = libsyscalls_find_named_number(*valuep, is_signed, signals, nsignals); if (!found) return NULL; (void) fallback_out; *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, size_t nargs, size_t nsyms) { struct libsyscalls_syscall_display_info *ret; size_t i, size, dataoff, paramoff; size = sizeof(*ret); if (size & (data_align - 1)) { size |= data_align - 1; size += 1; } dataoff = size; size += nsyms * data_size; if (size & (alignof(struct libsyscalls_syscall_type_info) - 1)) { size |= alignof(struct libsyscalls_syscall_type_info) - 1; size += 1; } paramoff = size; size += (nargs + 1U) * 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, const 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; }