/* See LICENSE file for copyright and license details. */
#include "common.h"
#include <stdalign.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#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;
}