On Wed, Apr 08, 2020 at 04:25:31PM -0700, Yonghong Song wrote: > > +BPF_CALL_5(bpf_seq_printf, struct seq_file *, m, char *, fmt, u32, fmt_size, u64, arg1, > + u64, arg2) > +{ > + bool buf_used = false; > + int i, copy_size; > + int mod[2] = {}; > + int fmt_cnt = 0; > + u64 unsafe_addr; > + char buf[64]; > + > + /* > + * bpf_check()->check_func_arg()->check_stack_boundary() > + * guarantees that fmt points to bpf program stack, > + * fmt_size bytes of it were initialized and fmt_size > 0 > + */ > + if (fmt[--fmt_size] != 0) > + return -EINVAL; ... > +/* Horrid workaround for getting va_list handling working with different > + * argument type combinations generically for 32 and 64 bit archs. > + */ > +#define __BPF_SP_EMIT() __BPF_ARG2_SP() > +#define __BPF_SP(...) \ > + seq_printf(m, fmt, ##__VA_ARGS__) > + > +#define __BPF_ARG1_SP(...) \ > + ((mod[0] == 2 || (mod[0] == 1 && __BITS_PER_LONG == 64)) \ > + ? __BPF_SP(arg1, ##__VA_ARGS__) \ > + : ((mod[0] == 1 || (mod[0] == 0 && __BITS_PER_LONG == 32)) \ > + ? __BPF_SP((long)arg1, ##__VA_ARGS__) \ > + : __BPF_SP((u32)arg1, ##__VA_ARGS__))) > + > +#define __BPF_ARG2_SP(...) \ > + ((mod[1] == 2 || (mod[1] == 1 && __BITS_PER_LONG == 64)) \ > + ? __BPF_ARG1_SP(arg2, ##__VA_ARGS__) \ > + : ((mod[1] == 1 || (mod[1] == 0 && __BITS_PER_LONG == 32)) \ > + ? __BPF_ARG1_SP((long)arg2, ##__VA_ARGS__) \ > + : __BPF_ARG1_SP((u32)arg2, ##__VA_ARGS__))) > + > + __BPF_SP_EMIT(); > + return seq_has_overflowed(m); > +} This function is mostly a copy-paste of bpf_trace_printk() with difference of printing via seq_printf vs __trace_printk. Please find a way to share the code.