#pragma once

#include <linux/kernel.h>

#define KHOOK_F_NOREF		(1UL << 0)	// don't do auto ref-count

/*
 * 内核钩子结构体
 * fn：钩子函数
 * name：符号名字
 * addr：符号地址
 * addr_map：符号地址被映射的虚拟地址
 * orig：原函数
 */

typedef struct {
	void			*fn;		// handler fn address
	struct {
		const char	*name;		// target symbol name
		char		*addr;		// target symbol addr (see khook_lookup_name)
		char		*addr_map;	// writable mapping of target symbol
	} target;
	void			*orig;		// original fn call wrapper
	unsigned long		flags;		// hook engine options (flags)
} khook_t;

/*
 * 格式规定：假设原函数名字为fun，则自定义的fun的钩子函数名字必须为khook_fun
 * 编译器选项：
 * __attribute__((unused)表示可能不会用到
 * __attribute__((aligned(1)))表示一字节对齐
 * __attribute__((section(".data.khook")))表示这个结构需要被分配到.data.khook节中
 */
#define KHOOK_(t, f)							\
	static inline typeof(t) khook_##t; /* forward decl */		\
	khook_t								\
	__attribute__((unused))						\
	__attribute__((aligned(1)))					\
	__attribute__((section(".data.khook")))				\
	KHOOK_##t = {							\
		.fn = khook_##t,					\
		.target.name = #t,					\
		.flags = f,						\
	}

#define KHOOK(t)							\
	KHOOK_(t, 0)
#define KHOOK_EXT(r, t, ...)						\
	extern r t(__VA_ARGS__);					\
	KHOOK_(t, 0)

#define KHOOK_NOREF(t)							\
	KHOOK_(t, KHOOK_F_NOREF)
#define KHOOK_NOREF_EXT(r, t, ...)					\
	extern r t(__VA_ARGS__);					\
	KHOOK_(t, KHOOK_F_NOREF)

#define KHOOK_ORIGIN(t, ...)						\
	((typeof(t) *)KHOOK_##t.orig)(__VA_ARGS__)

extern int khook_init(void);
extern void khook_cleanup(void);
