summaryrefslogblamecommitdiffstats
path: root/linux/symbols.c
blob: 7a3c8e59572f988bae4f3b428a6ad1b792d7d2a6 (plain) (tree)

































                                                                                                                             




                                                         














                                                                                                                           
                                                             
                
                                                             
                
                                                             
                
                                                             








































                                                                                                                            
                                                            
                
                                                            
                
                                                            



























                                                    



                             

































                                                                                                                                
                                        







                                                                                             

                                                                                                               
































































































                                                                                                                            




                                                         







                                                                                                         
                                                                     




















                                                                 





                                                                                

                                                                          



                             
















                                                                                                             



                             
/* See LICENSE file for copyright and license details. */

/* This file is included from ../libsyscalls_get_syscall_display_info.c */

/* TODO (see syscalls.h) */
#define extract_linux_symbol_madvise extract_linux_symbol_noflags
#define extract_linux_symbol_msync extract_linux_symbol_noflags
#define extract_linux_symbol_mlock extract_linux_symbol_noflags
#define extract_linux_symbol_mcl extract_linux_symbol_noflags
#define extract_linux_symbol_epoll extract_linux_symbol_noflags
#define extract_linux_symbol_sock_fd extract_linux_symbol_noflags
#define extract_linux_symbol_dup3 extract_linux_symbol_noflags
#define extract_linux_symbol_pipe extract_linux_symbol_noflags
#define extract_linux_symbol_inotify_fd extract_linux_symbol_noflags
#define extract_linux_symbol_fan_event_f extract_linux_symbol_noflags
#define extract_linux_symbol_mq_open extract_linux_symbol_noflags
#define extract_linux_symbol_swapon extract_linux_symbol_noflags
#define extract_linux_symbol_inotify_mask extract_linux_symbol_noflags
#define extract_linux_symbol_shmget extract_linux_symbol_noflags
#define extract_linux_symbol_fan_class extract_linux_symbol_noflags
#define extract_linux_symbol_fan_mark extract_linux_symbol_noflags
#define extract_linux_symbol_fan extract_linux_symbol_noflags
#define extract_linux_symbol_socket extract_linux_symbol_noflags
#define extract_linux_symbol_reboot extract_linux_symbol_noflags


static const char *
extract_linux_symbol_signal(struct libsyscalls_symbol_printer_data *data, unsigned long long int *valuep, char *fallback_out)
{
	return extract_signal(LIBSYSCALLS_OS_LINUX, data->arch, valuep, fallback_out,
	                      0 /* doesn't matter, unsigned is probably faster */);
}


#if defined(__clang__)
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wunsafe-buffer-usage"
#endif

static const char *
extract_linux_symbol_mode(struct libsyscalls_symbol_printer_data *data, unsigned long long int *valuep, char *fallback_out)
{
	unsigned long long int value;
	size_t i;
	*fallback_out = 'o';
	*valuep ^= value = *valuep & 07777ULL;
	i = 0;
	data->buf[i++] = '0';
	if (value & 07000) goto digits4;
	if (value &  0700) goto digits3;
	if (value &   070) goto digits2;
	if (value &    07) goto digits1;
	if (0) {
	digits4:
		data->buf[i++] = '0' | ((value / 01000) & 7);
	digits3:
		data->buf[i++] = '0' | ((value /  0100) & 7);
	digits2:
		data->buf[i++] = '0' | ((value /   010) & 7);
	digits1:
		data->buf[i++] = '0' | ((value /    01) & 7);
	}
	data->buf[i++]         = ' ';
	data->buf[i++]         = '(';
	data->buf[i++]         = (value & 0400) ? 'r' : '-';
	data->buf[i++]         = (value & 0200) ? 'w' : '-';
	if (value & 04000)
		data->buf[i++] = (value & 0100) ? 's' : 'S';
	else
		data->buf[i++] = (value & 0100) ? 'x' : '-';
	data->buf[i++]         = (value &  040) ? 'r' : '-';
	data->buf[i++]         = (value &  020) ? 'w' : '-';
	if (value & 02000)
		data->buf[i++] = (value &  010) ? 's' : 'S';
	else
		data->buf[i++] = (value &  010) ? 'x' : '-';
	data->buf[i++]         = (value &   04) ? 'r' : '-';
	data->buf[i++]         = (value &   02) ? 'w' : '-';
	if (value & 01000)
		data->buf[i++] = (value &   01) ? 't' : 'T';
	else
		data->buf[i++] = (value &   01) ? 'x' : '-';
	data->buf[i++]         = ')';
	data->buf[i] = '\0';
	return data->buf;
}


static const char *
extract_linux_symbol_umask(struct libsyscalls_symbol_printer_data *data, unsigned long long int *valuep, char *fallback_out)
{
	unsigned long long int value;
	size_t i;
	*fallback_out = 'o';
	*valuep ^= value = *valuep & 0777ULL;
	i = 0;
	data->buf[i++] = '0';
	if (value & 0700) goto digits3;
	if (value &  070) goto digits2;
	if (value &   07) goto digits1;
	if (0) {
	digits3:
		data->buf[i++] = '0' | ((value / 0700) & 7);
	digits2:
		data->buf[i++] = '0' | ((value /  070) & 7);
	digits1:
		data->buf[i++] = '0' | ((value /   07) & 7);
	}
	data->buf[i++] = ' ';
	data->buf[i++] = '(';
	data->buf[i++] = 'u';
	data->buf[i++] = ':';
	data->buf[i++] = ':';
	data->buf[i++] = (value & 0400) ? '-' : 'r';
	data->buf[i++] = (value & 0200) ? '-' : 'w';
	data->buf[i++] = (value & 0100) ? '-' : 'x';
	data->buf[i++] = ',';
	data->buf[i++] = 'g';
	data->buf[i++] = ':';
	data->buf[i++] = ':';
	data->buf[i++] = (value &  040) ? '-' : 'r';
	data->buf[i++] = (value &  020) ? '-' : 'w';
	data->buf[i++] = (value &  010) ? '-' : 'x';
	data->buf[i++] = ',';
	data->buf[i++] = 'o';
	data->buf[i++] = ':';
	data->buf[i++] = ':';
	data->buf[i++] = (value &   04) ? '-' : 'r';
	data->buf[i++] = (value &   02) ? '-' : 'w';
	data->buf[i++] = (value &   01) ? '-' : 'x';
	data->buf[i++] = ')';
	data->buf[i] = '\0';
	return data->buf;
}

#if defined(__clang__)
# pragma clang diagnostic pop
#endif


static const char *
extract_linux_symbol_dev(struct libsyscalls_symbol_printer_data *data, unsigned long long int *valuep, char *fallback_out)
{
	unsigned long long int value;
	unsigned long long int major, major1, major2;
	unsigned long long int minor, minor1, minor2;

	*fallback_out = 'x';

	major1 = 0xFFFFF00000000000ULL;
	minor1 = 0x00000FFFFFF00000ULL;
	major2 = 0x00000000000FFF00ULL;
	minor2 = 0x00000000000000FFULL;

	*valuep ^= value = *valuep & (major1 | minor1 | major2 | minor2);

	major1 = (value & major1) / LOWEST_BIT(major1) * POST_HIGHEST_OF_CONSECUTIVELY_BITS(major2);
	major2 = (value & major2) / LOWEST_BIT(major2);

	minor1 = (value & minor1) / LOWEST_BIT(minor1) * POST_HIGHEST_OF_CONSECUTIVELY_BITS(minor2);
	minor2 = (value & minor2) / LOWEST_BIT(minor2);

	major = major1 | major2;
	minor = minor1 | minor1;

	sprintf(data->buf, "%llu (%llu:%llu)", value, major, minor);
	return data->buf;
}


static const char *
extract_linux_symbol_clockid_t(struct libsyscalls_symbol_printer_data *data, unsigned long long int *valuep, char *fallback_out)
{
	if ((long long int)*valuep >= 0)
		return NULL;
	else if ((*valuep & 7) == 2)
		sprintf(data->buf, "%lli (pid: %llu)", (long long int)*valuep, ~*valuep / 8);
	else if ((*valuep & 7) == 3)
		sprintf(data->buf, "%lli (fd: %llu)", (long long int)*valuep, ~*valuep / 8);
	else if ((*valuep & 7) == 6)
		sprintf(data->buf, "%lli (tid: %llu)", (long long int)*valuep, ~*valuep / 8);
	else
		sprintf(data->buf, "%lli (~%llu*8 + %llu)", (long long int)*valuep, ~*valuep / 8, *valuep & 7);
	(void) fallback_out;
	*valuep = 0;
	return data->buf;
}


#define SYMBOL_PRINTERS_ONLY
#include "syscalls.h"
#undef SYMBOL_PRINTERS_ONLY

#include "../generated/linux-symbol-extractors.h"


static int
get_linux_symbol_extractor_by_sym_nr(LIBSYSCALLS_SYMBOL_PRINTER printer, libsyscalls_symbol_printer_function **function_out,
                                     enum libsyscalls_arch arch, const struct libsyscalls_syscall_abi *syscall, int nr,
                                     struct libsyscalls_symbol_printer_data *data_out)
{
	int ret;

#define CASE(E, F, N)\
	case E:\
		*function_out = &F;\
		ret = N;\
		break

	switch (printer) {
	LIST_LINUX_EXTRACTORS(CASE, ;);

	case LINUX_SYMBOL_PRINTER_SIGNAL:
		*function_out = &extract_linux_symbol_signal;
		ret = 1;
		break;

	default:
		abort();
	}

#undef CASE

	data_out->arch = arch;
	data_out->nr = nr;

	(void) syscall;
	return ret;
}


static libsyscalls_symbol_printer_function *
get_linux_symbol_extractor_by_arg_nr(enum libsyscalls_arch arch, const struct libsyscalls_syscall_abi *syscall,
                                     int arg, struct libsyscalls_symbol_printer_data *data_out)
{
	int nr, n;
	unsigned mask;
	LIBSYSCALLS_SYMBOL_PRINTER first, second;
	libsyscalls_symbol_printer_function *function;

	if (!syscall->symbol_printer || arg >= NPARAMS) {
		return NULL;
	} else if (arg < 0) {
		if (syscall->symbolic_return)
			nr = 0;
		else
			return NULL;
	} else if ((syscall->symbolic_mask >> arg) & 1) {
		mask = (unsigned)syscall->symbolic_mask;
		nr = (int)syscall->symbolic_return;
		for (mask &= (1U << arg) - 1; mask; mask >>= 1)
			nr += (int)mask & 1;
	} else {
		return NULL;
	}

	first  = (syscall->symbol_printer & 0x00FF) >> 0;
	second = (syscall->symbol_printer & 0xFF00) >> 8;
	if (second && !first)
		second = syscall->symbol_printer;

	if (first) {
		n = get_linux_symbol_extractor_by_sym_nr(first, &function, arch, syscall, nr, data_out);
		if (nr < n)
			goto have_fun;
		nr -= n;
	}

	if (second) {
		n = get_linux_symbol_extractor_by_sym_nr(second, &function, arch, syscall, nr, data_out);
		if (nr < n)
			goto have_fun;
	}

	abort();

have_fun:
	return function;
}


#if defined(__clang__)
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wunsafe-buffer-usage"
#endif

static struct libsyscalls_syscall_display_info *
get_linux_syscall_display_info(enum libsyscalls_arch arch, const struct libsyscalls_syscall_abi *syscall,
                               long long int syscall_number, unsigned long long int *syscall_argument)
{
	LIBSYSCALLS_SYMBOL_PRINTER_DATA *data;
	libsyscalls_symbol_printer_function **funcs;
	int i, nargs, nsyms;
	size_t data_size = offsetof(LIBSYSCALLS_SYMBOL_PRINTER_DATA, buf);
	size_t data_align = alignof(LIBSYSCALLS_SYMBOL_PRINTER_DATA);
	size_t bufspace, bufspace1, bufspace2;
	LIBSYSCALLS_SYMBOL_PRINTER first, second;

	nargs = (int)syscall->max_argument_count;
	nargs = nargs < 0 ? 0 : nargs;

	first  = (syscall->symbol_printer & 0x00FF) >> 0;
	second = (syscall->symbol_printer & 0xFF00) >> 8;
	if (second && !first)
		second = syscall->symbol_printer;

	bufspace1 = LINUX_REQUIRE_SYMBOL_BUFFER(first);
	bufspace2 = LINUX_REQUIRE_SYMBOL_BUFFER(second);
	bufspace = bufspace1 > bufspace2 ? bufspace1 : bufspace2;
	data_size += bufspace;
	if (bufspace & (data_align - 1)) {
		data_size |= data_align - 1;
		data_size += 1;
	}

	{
#if defined(__clang__)
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wvla"
#endif

		char data_vla_buf[(size_t)(nargs + 1) * data_size + data_align];
		libsyscalls_symbol_printer_function *funcs_vla[nargs + 1];

#if defined(__clang__)
# pragma clang diagnostic pop
#endif

		data  = (void *)ALIGN_BUF(data_vla_buf, data_align);
		funcs = funcs_vla;

		nsyms = 0;
		for (i = 0; i < nargs; i++) {
			funcs[i] = get_linux_symbol_extractor_by_arg_nr(arch, syscall, i, &data[i]);
			nsyms += !!funcs[i];
		}
		funcs[i] = get_linux_symbol_extractor_by_arg_nr(arch, syscall, -1, &data[i]);
		nsyms += !!funcs[i];

		(void) syscall_argument;
		(void) syscall_number;

		return build_syscall_display_info(data, data_size, data_align, funcs, syscall, nargs, nsyms);
	}
}

#if defined(__clang__)
# pragma clang diagnostic pop
#endif