linux内核系统调用学习5:SYSCALL_DEFINE<0-6>
系统调用最大参数是6,由下面这个宏定义,位于文件include\linux\syscalls.h
#define SYSCALL_DEFINE_MAXARGS 6
SYSCALL_DEFINE0(fork)
fork:系统调用名。
SYSCALL_DEFINE1(set_tid_address, int __user *, tidptr)
set_tid_address:系统调用名
int __user *:第一个参数类型
tidptr:第一个参数。
注意参数类型和参数名之间是用逗号隔开的。后面的2-6也是如此。
COMPAT_SYSCALL_DEFINE2(stat64, const char __user *, filename,struct compat_stat64 __user *, statbuf)
SYSCALL_DEFINE3(cacheflush,void __user *, addr,unsigned long, bytes,int, cache)
/** The following function implements the controller interface for* the eventpoll file that enables the insertion/removal/change of* file descriptors inside the interest set.*/
SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd,struct epoll_event __user *, event)
SYSCALL_DEFINE5(fsconfig,int, fd,unsigned int, cmd,const char __user *, _key,const void __user *, _value,int, aux)
SYSCALL_DEFINE6(mmap, unsigned long, addr, unsigned long, len,unsigned long, prot, unsigned long, flags,unsigned long, fd, unsigned long, off)
#define SYSCALL_DEFINE0(sname) \SYSCALL_METADATA(_##sname, 0); \asmlinkage long sys_##sname(void); \ALLOW_ERROR_INJECTION(sys_##sname, ERRNO); \asmlinkage long sys_##sname(void)
#define SYSCALL_DEFINE1(name, ...) SYSCALL_DEFINEx(1, _##name, __VA_ARGS__)
#define SYSCALL_DEFINE2(name, ...) SYSCALL_DEFINEx(2, _##name, __VA_ARGS__)
#define SYSCALL_DEFINE3(name, ...) SYSCALL_DEFINEx(3, _##name, __VA_ARGS__)
#define SYSCALL_DEFINE4(name, ...) SYSCALL_DEFINEx(4, _##name, __VA_ARGS__)
#define SYSCALL_DEFINE5(name, ...) SYSCALL_DEFINEx(5, _##name, __VA_ARGS__)
#define SYSCALL_DEFINE6(name, ...) SYSCALL_DEFINEx(6, _##name, __VA_ARGS__)
#define SYSCALL_DEFINEx(x, sname, ...) \SYSCALL_METADATA(sname, x, __VA_ARGS__) \__SYSCALL_DEFINEx(x, sname, __VA_ARGS__)
#define __SYSCALL_DEFINEx(x, name, ...) \__diag_push(); \__diag_ignore(GCC, 8, "-Wattribute-alias", \"Type aliasing is used to sanitize syscall arguments");\asmlinkage long sys##name(__MAP(x,__SC_DECL,__VA_ARGS__)) \__attribute__((alias(__stringify(__se_sys##name)))); \ALLOW_ERROR_INJECTION(sys##name, ERRNO); \static inline long __do_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__));\asmlinkage long __se_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__)); \asmlinkage long __se_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__)) \{ \long ret = __do_sys##name(__MAP(x,__SC_CAST,__VA_ARGS__));\__MAP(x,__SC_TEST,__VA_ARGS__); \__PROTECT(x, ret,__MAP(x,__SC_ARGS,__VA_ARGS__)); \return ret; \} \__diag_pop(); \static inline long __do_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__))
然后看看__MAP宏系列宏
/** __MAP - apply a macro to syscall arguments* __MAP(n, m, t1, a1, t2, a2, ..., tn, an) will expand to* m(t1, a1), m(t2, a2), ..., m(tn, an)* The first argument must be equal to the amount of type/name* pairs given. Note that this list of pairs (i.e. the arguments* of __MAP starting at the third one) is in the same format as* for SYSCALL_DEFINE<n>/COMPAT_SYSCALL_DEFINE<n>*/
#define __MAP0(m,...)
#define __MAP1(m,t,a,...) m(t,a)
#define __MAP2(m,t,a,...) m(t,a), __MAP1(m,__VA_ARGS__)
#define __MAP3(m,t,a,...) m(t,a), __MAP2(m,__VA_ARGS__)
#define __MAP4(m,t,a,...) m(t,a), __MAP3(m,__VA_ARGS__)
#define __MAP5(m,t,a,...) m(t,a), __MAP4(m,__VA_ARGS__)
#define __MAP6(m,t,a,...) m(t,a), __MAP5(m,__VA_ARGS__)
#define __MAP(n,...) __MAP##n(__VA_ARGS__)
__PROTECT宏
#define __PROTECT(...) asmlinkage_protect(__VA_ARGS__)
asmlinkage_protect宏位于文件include\linux\linkage.h
#ifndef __ASSEMBLY__
#ifndef asmlinkage_protect
# define asmlinkage_protect(n, ret, args...) do { } while (0)
#endif
#endif
SYSCALL_METADATA宏
这个宏由CONFIG_FTRACE_SYSCALLS决定,定义如下
#ifdef CONFIG_FTRACE_SYSCALLS
#define __SC_STR_ADECL(t, a) #a
#define __SC_STR_TDECL(t, a) #textern struct trace_event_class event_class_syscall_enter;
extern struct trace_event_class event_class_syscall_exit;
extern struct trace_event_functions enter_syscall_print_funcs;
extern struct trace_event_functions exit_syscall_print_funcs;#define SYSCALL_TRACE_ENTER_EVENT(sname) \static struct syscall_metadata __syscall_meta_##sname; \static struct trace_event_call __used \event_enter_##sname = { \.class = &event_class_syscall_enter, \{ \.name = "sys_enter"#sname, \}, \.event.funcs = &enter_syscall_print_funcs, \.data = (void *)&__syscall_meta_##sname,\.flags = TRACE_EVENT_FL_CAP_ANY, \}; \static struct trace_event_call __used \__attribute__((section("_ftrace_events"))) \*__event_enter_##sname = &event_enter_##sname;#define SYSCALL_TRACE_EXIT_EVENT(sname) \static struct syscall_metadata __syscall_meta_##sname; \static struct trace_event_call __used \event_exit_##sname = { \.class = &event_class_syscall_exit, \{ \.name = "sys_exit"#sname, \}, \.event.funcs = &exit_syscall_print_funcs, \.data = (void *)&__syscall_meta_##sname,\.flags = TRACE_EVENT_FL_CAP_ANY, \}; \static struct trace_event_call __used \__attribute__((section("_ftrace_events"))) \*__event_exit_##sname = &event_exit_##sname;#define SYSCALL_METADATA(sname, nb, ...) \static const char *types_##sname[] = { \__MAP(nb,__SC_STR_TDECL,__VA_ARGS__) \}; \static const char *args_##sname[] = { \__MAP(nb,__SC_STR_ADECL,__VA_ARGS__) \}; \SYSCALL_TRACE_ENTER_EVENT(sname); \SYSCALL_TRACE_EXIT_EVENT(sname); \static struct syscall_metadata __used \__syscall_meta_##sname = { \.name = "sys"#sname, \.syscall_nr = -1, /* Filled in at boot */ \.nb_args = nb, \.types = nb ? types_##sname : NULL, \.args = nb ? args_##sname : NULL, \.enter_event = &event_enter_##sname, \.exit_event = &event_exit_##sname, \.enter_fields = LIST_HEAD_INIT(__syscall_meta_##sname.enter_fields), \}; \static struct syscall_metadata __used \__attribute__((section("__syscalls_metadata"))) \*__p_syscall_meta_##sname = &__syscall_meta_##sname;static inline int is_syscall_trace_event(struct trace_event_call *tp_event)
{return tp_event->class == &event_class_syscall_enter ||tp_event->class == &event_class_syscall_exit;
}#else
#define SYSCALL_METADATA(sname, nb, ...)static inline int is_syscall_trace_event(struct trace_event_call *tp_event)
{return 0;
}
#endif
CONFIG_FTRACE_SYSCALLS从名字上看应该是和trace命令相关的功能。
查看它对应的配置: