#ifndef KCT_H_
# define KCT_H_
# include <linux/netlink.h>
/*
* warning: structures and constants in this header must match the
* ones in libc/kernel/common/linux/kct.h, so that information can
* be exchange between kernel and userspace throught netlink socket.
*/
/* flags to optionally filter events on android property activation */
#define EV_FLAGS_PRIORITY_LOW (1<<0)
# ifndef MAX_SB_N
# define MAX_SB_N 32
# endif
# ifndef MAX_EV_N
# define MAX_EV_N 32
# endif
# define NETLINK_CRASHTOOL 27
# define ATTCHMT_ALIGN 4U
/* Type of events supported by crashtool */
enum ct_ev_type {
CT_EV_STAT,
CT_EV_INFO,
CT_EV_ERROR,
CT_EV_CRASH,
CT_EV_LAST
};
enum ct_attchmt_type {
CT_ATTCHMT_DATA0,
CT_ATTCHMT_DATA1,
CT_ATTCHMT_DATA2,
CT_ATTCHMT_DATA3,
CT_ATTCHMT_DATA4,
CT_ATTCHMT_DATA5,
/* Always add new types after DATA5 */
CT_ATTCHMT_BINARY,
CT_ATTCHMT_FILELIST
};
struct ct_attchmt {
__u32 size; /* sizeof(data) */
enum ct_attchmt_type type;
char data[];
} __aligned(4);
struct ct_event {
__u64 timestamp;
char submitter_name[MAX_SB_N];
char ev_name[MAX_EV_N];
enum ct_ev_type type;
__u32 attchmt_size; /* sizeof(all_attachments inc. padding) */
__u32 flags;
struct ct_attchmt attachments[];
} __aligned(4);
enum kct_nlmsg_type {
/* kernel -> userland */
KCT_EVENT,
/* userland -> kernel */
KCT_SET_PID = 4200,
};
struct kct_packet {
struct nlmsghdr nlh;
struct ct_event event;
};
# define ATTCHMT_ALIGNMENT 4
# ifndef KCT_ALIGN
# define __KCT_ALIGN_MASK(x, mask) (((x) + (mask)) & ~(mask))
# define __KCT_ALIGN(x, a) __KCT_ALIGN_MASK(x, (typeof(x))(a) - 1)
# define KCT_ALIGN(x, a) __KCT_ALIGN((x), (a))
# endif /* !KCT_ALIGN */
# define foreach_attchmt(Event, Attchmt) \
if ((Event)->attchmt_size) \
for ((Attchmt) = (Event)->attachments; \
(Attchmt) < (typeof(Attchmt))(((char *) \
(Event)->attachments) + \
(Event)->attchmt_size); \
(Attchmt) = (typeof(Attchmt))KCT_ALIGN(((size_t)(Attchmt)) \
+ sizeof(*(Attchmt)) + \
(Attchmt)->size, ATTCHMT_ALIGNMENT))
/*
* User should use the macros below rather than those extern functions
* directly. Laters' declaration are only to set them __weak so
* that the macros works fine.
*/
/* Raw API (deprecated) */
extern struct ct_event *kct_alloc_event(const char *submitter_name,
const char *ev_name,
enum ct_ev_type ev_type,
gfp_t flags, uint eflags) __weak;
extern int kct_add_attchmt(struct ct_event **ev,
enum ct_attchmt_type at_type,
unsigned int size,
char *data, gfp_t flags) __weak;
extern void kct_free_event(struct ct_event *ev) __weak;
extern int kct_log_event(struct ct_event *ev, gfp_t flags) __weak;
/* API */
#define MKFN(fn, ...) MKFN_N(fn, ##__VA_ARGS__, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)(__VA_ARGS__)
#define MKFN_N(fn, n0, n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n, ...) fn##n
#define kct_log(...) MKFN(__kct_log_, ##__VA_ARGS__)
#define __kct_log_4(Type, Submitter_name, Ev_name, flags) \
do { if (kct_alloc_event) { \
struct ct_event *__ev = \
kct_alloc_event(Submitter_name, Ev_name, Type, \
GFP_ATOMIC, flags); \
if (__ev) { \
kct_log_event(__ev, GFP_ATOMIC); \
} \
} } while (0)
#define __kct_log_5(Type, Submitter_name, Ev_name, flags, Data0) \
do { if (kct_alloc_event) { \
struct ct_event *__ev = \
kct_alloc_event(Submitter_name, Ev_name, Type, \
GFP_ATOMIC, flags); \
if (__ev) { \
if (Data0) \
kct_add_attchmt(&__ev, CT_ATTCHMT_DATA0, \
strlen(Data0) + 1, Data0, GFP_ATOMIC); \
kct_log_event(__ev, GFP_ATOMIC); \
} \
} } while (0)
#define __kct_log_6(Type, Submitter_name, Ev_name, flags, Data0, Data1) \
do { if (kct_alloc_event) { \
struct ct_event *__ev = \
kct_alloc_event(Submitter_name, Ev_name, Type, \
GFP_ATOMIC, flags); \
if (__ev) { \
if (Data0) \
kct_add_attchmt(&__ev, CT_ATTCHMT_DATA0, \
strlen(Data0) + 1, Data0, GFP_ATOMIC); \
if (Data1) \
kct_add_attchmt(&__ev, CT_ATTCHMT_DATA1, \
strlen(Data1) + 1, Data1, GFP_ATOMIC); \
kct_log_event(__ev, GFP_ATOMIC); \
} \
} } while (0)
#define __kct_log_7(Type, Submitter_name, Ev_name, flags, Data0, Data1, Data2) \
do { if (kct_alloc_event) { \
struct ct_event *__ev = \
kct_alloc_event(Submitter_name, Ev_name, Type, \
GFP_ATOMIC, flags); \
if (__ev) { \
if (Data0) \
kct_add_attchmt(&__ev, CT_ATTCHMT_DATA0, \
strlen(Data0) + 1, Data0, GFP_ATOMIC); \
if (Data1) \
kct_add_attchmt(&__ev, CT_ATTCHMT_DATA1, \
strlen(Data1) + 1, Data1, GFP_ATOMIC); \
if (Data2) \
kct_add_attchmt(&__ev, CT_ATTCHMT_DATA2, \
strlen(Data2) + 1, Data2, GFP_ATOMIC); \
kct_log_event(__ev, GFP_ATOMIC); \
} \
} } while (0)
#define __kct_log_8(Type, Submitter_name, Ev_name, flags, Data0, Data1, Data2, \
Data3) \
do { if (kct_alloc_event) { \
struct ct_event *__ev = \
kct_alloc_event(Submitter_name, Ev_name, Type, \
GFP_ATOMIC, flags); \
if (__ev) { \
if (Data0) \
kct_add_attchmt(&__ev, CT_ATTCHMT_DATA0, \
strlen(Data0) + 1, Data0, GFP_ATOMIC); \
if (Data1) \
kct_add_attchmt(&__ev, CT_ATTCHMT_DATA1, \
strlen(Data1) + 1, Data1, GFP_ATOMIC); \
if (Data2) \
kct_add_attchmt(&__ev, CT_ATTCHMT_DATA2, \
strlen(Data2) + 1, Data2, GFP_ATOMIC); \
if (Data3) \
kct_add_attchmt(&__ev, CT_ATTCHMT_DATA3, \
strlen(Data3) + 1, Data3, GFP_ATOMIC); \
kct_log_event(__ev, GFP_ATOMIC); \
} \
} } while (0)
#define __kct_log_9(Type, Submitter_name, Ev_name, flags, Data0, Data1, Data2, \
Data3, Data4) \
do { if (kct_alloc_event) { \
struct ct_event *__ev = \
kct_alloc_event(Submitter_name, Ev_name, Type, \
GFP_ATOMIC, flags); \
if (__ev) { \
if (Data0) \
kct_add_attchmt(&__ev, CT_ATTCHMT_DATA0, \
strlen(Data0) + 1, Data0, GFP_ATOMIC); \
if (Data1) \
kct_add_attchmt(&__ev, CT_ATTCHMT_DATA1, \
strlen(Data1) + 1, Data1, GFP_ATOMIC); \
if (Data2) \
kct_add_attchmt(&__ev, CT_ATTCHMT_DATA2, \
strlen(Data2) + 1, Data2, GFP_ATOMIC); \
if (Data3) \
kct_add_attchmt(&__ev, CT_ATTCHMT_DATA3, \
strlen(Data3) + 1, Data3, GFP_ATOMIC); \
if (Data4) \
kct_add_attchmt(&__ev, CT_ATTCHMT_DATA4, \
strlen(Data4) + 1, Data4, GFP_ATOMIC); \
kct_log_event(__ev, GFP_ATOMIC); \
} \
} } while (0)
#define __kct_log_10(Type, Submitter_name, Ev_name, flags, Data0, Data1, Data2, \
Data3, Data4, Data5) \
do { if (kct_alloc_event) { \
struct ct_event *__ev = \
kct_alloc_event(Submitter_name, Ev_name, Type, \
GFP_ATOMIC, flags); \
if (__ev) { \
if (Data0) \
kct_add_attchmt(&__ev, CT_ATTCHMT_DATA0, \
strlen(Data0) + 1, Data0, GFP_ATOMIC); \
if (Data1) \
kct_add_attchmt(&__ev, CT_ATTCHMT_DATA1, \
strlen(Data1) + 1, Data1, GFP_ATOMIC); \
if (Data2) \
kct_add_attchmt(&__ev, CT_ATTCHMT_DATA2, \
strlen(Data2) + 1, Data2, GFP_ATOMIC); \
if (Data3) \
kct_add_attchmt(&__ev, CT_ATTCHMT_DATA3, \
strlen(Data3) + 1, Data3, GFP_ATOMIC); \
if (Data4) \
kct_add_attchmt(&__ev, CT_ATTCHMT_DATA4, \
strlen(Data4) + 1, Data4, GFP_ATOMIC); \
if (Data5) \
kct_add_attchmt(&__ev, CT_ATTCHMT_DATA5, \
strlen(Data5) + 1, Data5, GFP_ATOMIC); \
kct_log_event(__ev, GFP_ATOMIC); \
} \
} } while (0)
#define __kct_log_11(Type, Submitter_name, Ev_name, flags, Data0, Data1, Data2, \
Data3, Data4, Data5, filelist) \
do { if (kct_alloc_event) { \
struct ct_event *__ev = \
kct_alloc_event(Submitter_name, Ev_name, Type, \
GFP_ATOMIC, flags); \
if (__ev) { \
if (Data0) \
kct_add_attchmt(&__ev, CT_ATTCHMT_DATA0, \
strlen(Data0) + 1, Data0, GFP_ATOMIC); \
if (Data1) \
kct_add_attchmt(&__ev, CT_ATTCHMT_DATA1, \
strlen(Data1) + 1, Data1, GFP_ATOMIC); \
if (Data2) \
kct_add_attchmt(&__ev, CT_ATTCHMT_DATA2, \
strlen(Data2) + 1, Data2, GFP_ATOMIC); \
if (Data3) \
kct_add_attchmt(&__ev, CT_ATTCHMT_DATA3, \
strlen(Data3) + 1, Data3, GFP_ATOMIC); \
if (Data4) \
kct_add_attchmt(&__ev, CT_ATTCHMT_DATA4, \
strlen(Data4) + 1, Data4, GFP_ATOMIC); \
if (Data5) \
kct_add_attchmt(&__ev, CT_ATTCHMT_DATA5, \
strlen(Data5) + 1, Data5, GFP_ATOMIC); \
if (filelist) \
kct_add_attchmt(&__ev, CT_ATTCHMT_FILELIST, \
strlen(filelist) + 1, filelist, GFP_ATOMIC); \
kct_log_event(__ev, GFP_ATOMIC); \
} \
} } while (0)
#endif /* !KCT_H_ */