summaryrefslogblamecommitdiffstats
path: root/linux/structs.c
blob: d9ac2d73120c53dccd4800d3da664b418387d0fb (plain) (tree)























































































































































































































































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

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


/* Don't forget to add new ones to ../libsyscalls.h */
#define LIST_LINUX_STRUCTS(X, D)\
	X(STRUCT, AIO_SIGSET, 0 /* TODO bitmask */,\
		FIELD("sigmask", ULONG_ARRAY, IN, INPTR),\
		FIELD("sigsetsize", SIZE, IN)) D\
	X(STRUCT, COMPAT_AIO_SIGSET, 0 /* TODO bitmask */,\
		FIELD("sigmask", UINT32, IN, OUT),\
		FIELD("sigsetsize", UINT32, IN, OUT)) D\
	X(STRUCT, CACHESTAT, 0,\
		FIELD("nr_cache", UINT64, IN, OUT),\
		FIELD("nr_dirty", UINT64, IN, OUT),\
		FIELD("nr_writeback", UINT64, IN, OUT),\
		FIELD("nr_evicted", UINT64, IN, OUT),\
		FIELD("nr_recently_evicted", UINT64, IN, OUT)) D\
	X(STRUCT, CACHESTAT_RANGE, 0,\
		FIELD("off", UINT64, IN, OUT),\
		FIELD("len", UINT64, IN, OUT)) D\
	X(STRUCT, CLONE_ARGS, 0, /* TODO which fields are IN and OUT? */\
		FIELD("flags", UINT64, IN) /* TODO bitmask */,\
		FIELD("pidfd", UINT64, IN) /* TODO actually (int *) */,\
		FIELD("child_tid", UINT64, IN) /* TODO actually (pid_t *) */,\
		FIELD("parent_tid", UINT64, IN) /* TODO actually (pid_t *) */,\
		FIELD("exit_signal", UINT64, IN) /* TODO actually INT_SIGNAL */,\
		FIELD("stack", UINT64, IN),\
		FIELD("stack_size", UINT64, IN),\
		FIELD("tls", UINT64, IN), /* TODO actually MEMORY_ADDRESS */\
		/* Since Linux 5.5: */\
		FIELD("set_tid", UINT64, IN), /* TODO acually (pid_t *) with count in next field */\
		FIELD("set_tid_size", UINT64, IN),\
		FIELD("cgroup", UINT64, IN)) /* TODO actually INT_FD */ D\
	X(STRUCT, EPOLL_EVENT, 0, /* TODO different in libc */\
		FIELD("events", UINT, IN, OUT) /* TODO bitmask */,\
		FIELD("data", UINT64, PARTIAL, IN, OUT)) D\
	X(STRUCT, OABI_EPOLL_EVENT, 0, /* TODO different in libc */\
		FIELD("events", UINT, IN, OUT) /* TODO bitmask */,\
		FIELD("data", UINT64_FRONT_32, PARTIAL, IN, OUT),\
		FIELD("data", UINT64_BACK_32, PARTIAL, IN, OUT)) D\
	X(STRUCT, FILE_HANDLE, 0) D /* TODO */\
	X(STRUCT, FUTEX_WAITV, 0,\
		FIELD("val", UINT64, IN, OUT),\
		FIELD("uaddr", UINT64, IN, OUT), /* TODO actually (void *) */\
		FIELD("flags", UINT32, IN, OUT), /* TODO bitmask */\
		FIELD(NULL, UINT32, IN, OUT)) D\
	X(STRUCT, IOB, 0) D /* TODO */\
	X(STRUCT, IOVEC, 0) D /* TODO */\
	X(STRUCT, IO_EVENT, 0,\
		FIELD("data", UINT64, IN, OUT),\
		FIELD("obj", UINT64, IN, OUT),\
		FIELD("res", INT64, IN, OUT),\
		FIELD("res2", INT64, IN, OUT)) D\
	X(STRUCT, IO_URING_PARAMS, 0) D /* TODO */\
	X(STRUCT, ITIMERSPEC, 0,\
		FIELD("it_interval", STRUCT_TIMESPEC, IN, OUT),\
		FIELD("it_value", STRUCT_TIMESPEC, IN, OUT)) D\
	X(STRUCT, ITIMERSPEC64, 0,\
		FIELD("it_interval", STRUCT_TIMESPEC64, IN, OUT),\
		FIELD("it_value", STRUCT_TIMESPEC64, IN, OUT)) D\
	X(STRUCT, KEXEC_SEGMENT, 0) D /* TODO */\
	X(STRUCT, COMPAT_KEXEC_SEGMENT, 0) D /* TODO */\
	X(STRUCT, LANDLOCK_RULESET_ATTR, 0) D /* TODO */\
	X(STRUCT, LINUX_DIRENT, 0) D /* TODO */\
	X(STRUCT, LINUX_DIRENT64, 0) D /* TODO */\
	X(STRUCT, MMAP_ARG_STRUCT, 0) D /* TODO */\
	X(STRUCT, MMSGHDR, 0) D /* TODO */\
	X(STRUCT, MOUNT_ATTR, 0) D /* TODO */\
	X(STRUCT, MQ_ATTR, 0) D /* TODO */\
	X(STRUCT, MSGBUF, 0) D /* TODO */\
	X(STRUCT, MSGHDR, 0) D /* TODO */\
	X(STRUCT, MSQID_DS, 0) D /* TODO */\
	X(STRUCT, NEW_UTSNAME, 0,\
		FIELD("sysname", BUFFER_65, OUT),\
		FIELD("nodename", BUFFER_65, OUT),\
		FIELD("release", BUFFER_65, OUT),\
		FIELD("version", BUFFER_65, OUT),\
		FIELD("machine", BUFFER_65, OUT),\
		FIELD("domainname", BUFFER_65, OUT)) D\
	X(STRUCT, OLDOLD_UTSNAME, 0,\
		FIELD("sysname", BUFFER_9, OUT),\
		FIELD("nodename", BUFFER_9, OUT),\
		FIELD("release", BUFFER_9, OUT),\
		FIELD("version", BUFFER_9, OUT),\
		FIELD("machine", BUFFER_9, OUT)) D\
	X(STRUCT, OLD_ITIMERSPEC32, 0,\
		FIELD("it_interval", STRUCT_OLD_TIMESPEC32, IN, OUT),\
		FIELD("it_value", STRUCT_OLD_TIMESPEC32, IN, OUT)) D\
	X(STRUCT, ITIMERVAL, 0,\
		FIELD("it_interval", STRUCT_TIMEVAL, IN, OUT),\
		FIELD("it_value", STRUCT_TIMEVAL, IN, OUT)) D\
	X(STRUCT, OLD_ITIMERVAL, 0,\
		FIELD("it_interval", STRUCT_OLD_TIMEVAL, IN, OUT),\
		FIELD("it_value", STRUCT_OLD_TIMEVAL, IN, OUT)) D\
	X(STRUCT, OLD_LINUX_DIRENT, 0) D /* TODO */\
	X(STRUCT, OLD_SIGACTION, 0) D /* TODO */\
	X(STRUCT, OLD_STAT, 0) D /* TODO */\
	X(STRUCT, OLD_TIMESPEC32, 0) D /* TODO */\
	X(STRUCT, OLD_TIMEVAL, 0) D /* TODO */\
	X(STRUCT, OLD_TIMEVAL32, 0) D /* TODO */\
	X(STRUCT, OLD_TIMEX32, 0) D /* TODO */\
	X(STRUCT, OLD_UTIMBUF32, 0) D /* TODO */\
	X(STRUCT, OLD_UTSNAME, 0,\
		FIELD("sysname", BUFFER_65, OUT),\
		FIELD("nodename", BUFFER_65, OUT),\
		FIELD("release", BUFFER_65, OUT),\
		FIELD("version", BUFFER_65, OUT),\
		FIELD("machine", BUFFER_65, OUT)) D\
	X(STRUCT, OPEN_HOW, 0) D /* TODO */\
	X(STRUCT, PERF_EVENT_ATTR, 0) D /* TODO */\
	X(STRUCT, POLLFD, 0,\
		FIELD("pollfd", INT_FD, IN),\
		FIELD("events", SHORT, IN), /* TODO bitmask */\
		FIELD("revents", SHORT, OUT)) D /* TODO bitmask */\
	X(STRUCT, RLIMIT, 0,\
		FIELD("rlim_cur", ULONG, IN, OUT),\
		FIELD("rlim_max", ULONG, IN, OUT)) D\
	X(STRUCT, RLIMIT64, 0,\
		FIELD("rlim_cur", UINT64, IN, OUT),\
		FIELD("rlim_max", UINT64, IN, OUT)) D\
	X(STRUCT, COMPAT_RLIMIT, 0,\
		FIELD("rlim_cur", UINT32, IN, OUT),\
		FIELD("rlim_max", UINT32, IN, OUT)) D\
	X(STRUCT, ROBUST_LIST_HEAD, 0) D /* TODO */\
	X(STRUCT, RSEQ, 0) D /* TODO */\
	X(STRUCT, RUSAGE, 0) D /* TODO */\
	X(STRUCT, SCHED_ATTR, 0,\
		FIELD("size", UINT32, IN, OUT),\
		FIELD("sched_policy", UINT32, IN, OUT),\
		FIELD("sched_flags", UINT64, IN, OUT),\
		FIELD("sched_nice", INT32, IN, OUT),\
		FIELD("sched_priority", UINT32, IN, OUT),\
		FIELD("sched_runtime", UINT64, IN, OUT),\
		FIELD("sched_deadline", UINT32, IN, OUT),\
		FIELD("sched_period", UINT32, IN, OUT)) D\
	X(STRUCT, SCHED_PARAM, 0,\
		FIELD("sched_priority", INT, IN, OUT)) D\
	X(STRUCT, SEL_ARG_STRUCT, 0) D /* TODO */\
	X(STRUCT, SEMBUF, 0,\
		FIELD("sem_num", USHORT, IN, OUT),\
		FIELD("sem_op", SHORT, IN, OUT), /* TODO enum */\
		FIELD("sem_flg", SHORT, IN, OUT)) D /* TODO bitmask */\
	X(STRUCT, SEMID_DS, 0) D /* TODO */\
	X(STRUCT, SHMID_DS, 0) D /* TODO */\
	X(STRUCT, SIGACTION, 0) D /* TODO */\
	X(STRUCT, SIGALTSTACK, 0) D /* TODO */\
	X(STRUCT, SIGEVENT, 0) D /* TODO */\
	X(STRUCT, SIGINFO, 0) D /* TODO */\
	X(STRUCT, SOCKADDR, 0) D /* TODO */\
	X(STRUCT, STAT, 0) D /* TODO */\
	X(STRUCT, STAT64, 0) D /* TODO */\
	X(STRUCT, STATFS, 0) D /* TODO */\
	X(STRUCT, STATFS64, 0) D /* TODO */\
	X(STRUCT, STATX, 0) D /* TODO */\
	X(STRUCT, SYSINFO, 0) D /* TODO */\
	X(STRUCT, TIMESPEC, 0) D /* TODO */\
	X(STRUCT, TIMESPEC64, 0) D /* TODO */\
	X(STRUCT, TIMEVAL, 0) D /* TODO */\
	X(STRUCT, TIMEX, 0) D /* TODO */\
	X(STRUCT, TIMEZONE, 0) D /* TODO */\
	X(STRUCT, TMS, 0) D /* TODO */\
	X(STRUCT, USTAT, 0) D /* TODO */\
	X(STRUCT, UTIMBUF, 0) D /* TODO */\
	X(UNION, BPF_ATTR, 0) /* TODO */


#define X(TYPE, NAME, ...)\
	static struct libsyscalls_structure_description linux_##TYPE##_##NAME##_prototype = TYPE(__VA_ARGS__)
	LIST_LINUX_STRUCTS(X, ;);
#undef X


static enum libsyscalls_error
fix_linux_struct_description(enum libsyscalls_arch arch, enum libsyscalls_datatype datatype, unsigned class,
                             const void *data, size_t data_size, struct libsyscalls_structure_description *description)
{
	switch ((int)datatype) {
	case LIBSYSCALLS_TYPE_STRUCT_SOCKADDR:
		if (class != LIBSYSCALLS_TYPEBITS_SCALAR)
			return LIBSYSCALLS_E_NOSUCHTYPE;
		description->size = 0;
		description->relative_position_of_size = +1;
		description->absolute_position_of_size = -1;
		/* TODO that is the alignment of `struct sockaddr`? */
		break;

	case LIBSYSCALLS_TYPE_STRUCT_CLONE_ARGS:
		description->alignment = 64;
		break;

	case LIBSYSCALLS_TYPE_STRUCT_RSEQ:
		description->alignment = 4 * 64;
		break;

	default:
		break;
	}

	(void) arch;
	(void) data;
	(void) data_size;
	return LIBSYSCALLS_E_OK;
}


static enum libsyscalls_error
get_linux_struct_description(enum libsyscalls_arch arch, enum libsyscalls_datatype datatype, unsigned class,
                             const void *data, size_t data_size, struct libsyscalls_structure_description **description_out,
                             int *dont_align_fields_out)
{
	struct libsyscalls_structure_description *description;

	switch ((int)datatype) {
	case LIBSYSCALLS_TYPE_STRUCT_EPOLL_EVENT:
		if (arch == LIBSYSCALLS_ARCH_AMD64 || arch == LIBSYSCALLS_ARCH_AMD64_X32)
			datatype = LIBSYSCALLS_TYPE_STRUCT_OABI_EPOLL_EVENT;
		break;

	default:
		break;
	}

#define CASE(TYPE, NAME, ...)\
	case LIBSYSCALLS_TYPE_##TYPE##_##NAME:\
		description = copy_struct(&linux_##TYPE##_##NAME##_prototype);\
		break

	switch ((int)datatype) {
	LIST_LINUX_STRUCTS(CASE, ;);
	default:
		return LIBSYSCALLS_E_NOSUCHTYPE;
	}

#undef CASE

	if (!description)
		return LIBSYSCALLS_E_NOMEM;

	(void) class;
	(void) data;
	(void) data_size;

	*description_out = description;
	*dont_align_fields_out = 0;
	return LIBSYSCALLS_E_OK;
}