summaryrefslogblamecommitdiffstats
path: root/libsyscalls_get_syscall_display_info.c
blob: f18834c928ccfb9b00994a2f75a1ce285c919355 (plain) (tree)
1
2
3

                                                         
 















                                                             

      




                                                    
 
                                                                                                
 



                            
 





                                     

      


 
                   

                                                                  


                                                               
                      
 
                                                                               

                            
                                                                                     


                            
                            
 







                                                                           

                                                                         

                                                     
                                          







                                       
                                  
 

                                                                          


                          
                                                    













                                                                   

                                                                                                  






                                                          

                                                                                          












                                                                                        
                                                                                     
























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