/* 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;
}