On Sat, Nov 30, 2013 at 4:47 AM, Qingping Hou <dave2008713@xxxxxxxxx> wrote: > From: Yicheng Qin <qycqycqycqycqyc@xxxxxxxxx> > > ffi type is the basic type used in ffi module, which has fixed size and > alignment. > > csymbol means symbol for c type, which is designed to represent all > possible c types in its format. It doesn't contain any real value or > data. > > ktap_cdata is the uniform cdata type in ktap. It is an instance of > csymbol, which binds a csymbol with the real data. It mainly exists in > the vm stack. > > Signed-off-by: Yicheng Qin <qycqycqycqycqyc@xxxxxxxxx> > Signed-off-by: Qingping Hou <qingping.hou@xxxxxxxxx> > --- > include/ktap_types.h | 42 +++++++- > interpreter/ffi/ffi_type.c | 50 +++++++++ > interpreter/kp_ffi.h | 259 > +++++++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 350 insertions(+), 1 deletion(-) > create mode 100644 interpreter/ffi/ffi_type.c > create mode 100644 interpreter/kp_ffi.h > > diff --git a/include/ktap_types.h b/include/ktap_types.h > index 68ec23c..f92eaf5 100644 > --- a/include/ktap_types.h > +++ b/include/ktap_types.h > @@ -8,6 +8,7 @@ typedef char u8; > #include <stdlib.h> > #include <stdio.h> > #include <string.h> > +#include <stdint.h> > #endif > > typedef struct ktap_parm { > @@ -246,6 +247,29 @@ typedef struct ktap_stringtable { > int size; > } ktap_stringtable; > > +#ifdef CONFIG_KTAP_FFI > +typedef int csymbol_id; > +typedef struct csymbol csymbol; > + > +/* global ffi state maintained in each ktap vm instance */ > +typedef struct ffi_state { > + ktap_tab *ctable; > + int csym_nr; > + csymbol *csym_arr; > +} ffi_state; > + > +/* instance of csymbol */ > +typedef struct ktap_cdata { > + CommonHeader; > + csymbol_id id; > + union { > + uint64_t i; > + void *p; /* pointer address */ > + void *st; /* struct member data */ > + } u; > +} ktap_cdata; > +#endif > + > typedef struct ktap_stats { > int mem_allocated; > int nr_mem_allocate; > @@ -300,6 +324,9 @@ typedef struct ktap_global_state { > int wait_user; > ktap_closure *trace_end_closure; > struct ktap_stats __percpu *stats; > +#ifdef CONFIG_KTAP_FFI > + ffi_state ffis; > +#endif > #endif > int error; > } ktap_global_state; > @@ -342,6 +369,9 @@ union ktap_gcobject { > struct ktap_upval uv; > struct ktap_state th; /* thread */ > struct ktap_btrace bt; /* backtrace object */ > +#ifdef CONFIG_KTAP_FFI > + struct ktap_cdata cd; > +#endif > }; > > #define gch(o) (&(o)->gch) > @@ -376,11 +406,11 @@ union ktap_gcobject { > #define KTAP_TTHREAD 7 > #define KTAP_TPROTO 8 > #define KTAP_TUPVAL 9 > - > #define KTAP_TEVENT 10 > #define KTAP_TBTRACE 11 > #define KTAP_TPTABLE 12 > #define KTAP_TSTATDATA 13 > +#define KTAP_TCDATA 14 > /* > * type number is ok so far, but it may collide later between > * 16+ and | (1 << 4), so be careful on this. > @@ -417,6 +447,7 @@ union ktap_gcobject { > #define fvalue(o) (val_(o).f) > #define evalue(o) (val_(o).p) > #define btvalue(o) (&val_(o).gc->bt) > +#define cdvalue(o) (&val_(o).gc->cd) > > #define is_nil(o) ((o)->type == KTAP_TNIL) > #define is_boolean(o) ((o)->type == KTAP_TBOOLEAN) > @@ -430,6 +461,9 @@ union ktap_gcobject { > #define is_event(o) ((o)->type == KTAP_TEVENT) > #define is_btrace(o) ((o)->type == KTAP_TBTRACE) > #define is_needclone(o) is_btrace(o) > +#ifdef CONFIG_KTAP_FFI > +#define is_cdata(o) ((o)->type == KTAP_TCDATA) > +#endif > > > #define set_nil(obj) \ > @@ -476,6 +510,12 @@ union ktap_gcobject { > { ktap_value *io = (obj); \ > val_(io).gc = (ktap_gcobject *)(x); settype(io, KTAP_TBTRACE); } > > +#ifdef CONFIG_KTAP_FFI > +#define set_cdata(obj, x) \ > + { ktap_value *io=(obj); \ > + val_(io).gc = (ktap_gcobject *)(x); settype(io, KTAP_TCDATA); } > +#endif > + > #define set_obj(obj1, obj2) \ > { const ktap_value *io2 = (obj2); ktap_value *io1 = (obj1); \ > io1->val = io2->val; io1->type = io2->type; } > diff --git a/interpreter/ffi/ffi_type.c b/interpreter/ffi/ffi_type.c > new file mode 100644 > index 0000000..608756b > --- /dev/null > +++ b/interpreter/ffi/ffi_type.c > @@ -0,0 +1,50 @@ > +#include "../kp_ffi.h" > +#ifdef __KERNEL__ > +#include <linux/types.h> > +#else > +#include <stdint.h> > +#endif > + > +#define CTYPE_MODE_HELPER(name, type) \ > +struct _##name##_align { \ > + type t1; \ > + char c; \ > + type t2; \ > +}; > + > +#define CTYPE_MODE(name) \ > +{ \ > + offsetof(struct _##name##_align, c), \ > + offsetof(struct _##name##_align, t2) - \ > + offsetof(struct _##name##_align, c), \ > + #name \ > +} > + > +#define CTYPE_MODE_NAME(name) _##name##_mode > + > +/* ffi_ctype_mode should be corresponded to ffi_ctype */ > +CTYPE_MODE_HELPER(uint8, uint8_t); > +CTYPE_MODE_HELPER(int8, int8_t); > +CTYPE_MODE_HELPER(uint16, uint16_t); > +CTYPE_MODE_HELPER(int16, int16_t); > +CTYPE_MODE_HELPER(uint32, uint32_t); > +CTYPE_MODE_HELPER(int32, int32_t); > +CTYPE_MODE_HELPER(uint64, uint64_t); > +CTYPE_MODE_HELPER(int64, int64_t); > +CTYPE_MODE_HELPER(pointer, void*); > + > +const ffi_mode ffi_type_modes[NUM_FFI_TYPE+1] = { > + {0, 1, "void"}, > + CTYPE_MODE(uint8), > + CTYPE_MODE(int8), > + CTYPE_MODE(uint16), > + CTYPE_MODE(int16), > + CTYPE_MODE(uint32), > + CTYPE_MODE(int32), > + CTYPE_MODE(uint64), > + CTYPE_MODE(int64), > + CTYPE_MODE(pointer), > + {0, 1, "function"}, > + {0, 1, "struct"}, > + {0, 1, "unknown"}, > +}; > diff --git a/interpreter/kp_ffi.h b/interpreter/kp_ffi.h > new file mode 100644 > index 0000000..6a3cb9c > --- /dev/null > +++ b/interpreter/kp_ffi.h Please move kp_ffi.h into include/ktap_ffi.h That ffi header file is used by compiler and interpreter, so it's better place at include/ directory. Also it's better to add more comments into structure definitions, and inline access functions, to explain what it does. > @@ -0,0 +1,259 @@ > +#ifndef __KTAP_FFI_H__ > +#define __KTAP_FFI_H__ > + > +#ifdef CONFIG_KTAP_FFI > + > +#include <stddef.h> stddef.h is included by interpreter? > +#include "../include/ktap_types.h" > + > + > +typedef enum { > + /* 0 - 4 */ > + FFI_VOID, > + FFI_UINT8, > + FFI_INT8, > + FFI_UINT16, > + FFI_INT16, > + /* 5 - 9 */ > + FFI_UINT32, > + FFI_INT32, > + FFI_UINT64, > + FFI_INT64, > + FFI_PTR, > + /* 10 - 12 */ > + FFI_FUNC, > + FFI_STRUCT, > + FFI_UNKNOWN, > +} ffi_type; > + > +#define NUM_FFI_TYPE ((int)FFI_UNKNOWN) > + > +typedef struct { > + size_t size; > + size_t align; > + const char *name; > +} ffi_mode; > +extern const ffi_mode const ffi_type_modes[]; > + > +#define ffi_type_size(t) (ffi_type_modes[t].size) > +#define ffi_type_align(t) (ffi_type_modes[t].align) > +#define ffi_type_name(t) (ffi_type_modes[t].name) > + > + > +#define CSYM_NAME_MAX_LEN 64 > + > +typedef struct csymbol_func { > + void *addr; > + csymbol_id ret_id; > + int arg_nr; > + csymbol_id *arg_ids; > +} csymbol_func; > + I tried below ffi script: cdef("int printk(const char *fmt, ...)") C.printk("This is ffi printk\n") [root@localhost ktap]# ./ktap printk.kp cparser error: unexpected end Current cpraser doesn't support function variable argument? does luaffi support it? I think this is a basic functionality of ffi, and it will be common used in ktap ffi. (that's the first ffi script I would try :-) ) > +typedef struct struct_member { > + char name[CSYM_NAME_MAX_LEN]; > + csymbol_id id; > +} struct_member; > + > +typedef struct csymbol_struct { > + int memb_nr; > + struct_member *members; > + size_t size; /* bytes used to store struct */ > + /* alignment of the struct, 0 indicates uninitialization */ > + size_t align; > +} csymbol_struct; > + > + > +/* > + * used for symbol array; > + */ > + > +typedef struct csymbol { > + char name[CSYM_NAME_MAX_LEN]; > + ffi_type type; > + /* only used for non scalar C types */ > + union { > + csymbol_id p; /* for pointer */ > + csymbol_func f; > + csymbol_struct st; > + csymbol_id td; /* for typedef */ > + } u; > +} csymbol; > + > +inline csymbol *ffi_get_csym_by_id(ktap_state *ks, csymbol_id id); > + > +static inline csymbol *id_to_csym(ktap_state *ks, csymbol_id id) > +{ > + return ffi_get_csym_by_id(ks, id); > +} > + > +#define csym_type(cs) ((cs)->type) > + > +static inline char *csym_name(csymbol *cs) > +{ > + return cs->name; > +} > + > +/* > + * start of pointer symbol helper functions > + */ > +static inline csymbol_id csym_ptr_deref_id(csymbol *cs) > +{ > + return cs->u.p; > +} > + > +static inline csymbol *csym_ptr_deref(ktap_state *ks, csymbol *cs) > +{ > + return id_to_csym(ks, csym_ptr_deref_id(cs)); > +} > + > +static inline void csym_set_ptr_deref(csymbol *cs, csymbol_id id) > +{ > + cs->u.p = id; > +} > + > +/* > + * start of function symbol helper functions > + */ > +static inline csymbol_func *csym_func(csymbol *cs) > +{ > + return &cs->u.f; > +} > + > +static inline csymbol *csymf_arg(ktap_state *ks, csymbol_func *csf, int idx) > +{ > + return id_to_csym(ks, csf->arg_ids[idx]); > +} > + > +static inline csymbol *csymf_ret(ktap_state *ks, csymbol_func *csf) > +{ > + return id_to_csym(ks, csf->ret_id); > +} > + > +static inline csymbol *csym_func_arg(ktap_state *ks, csymbol *cs, int idx) > +{ > + return csymf_arg(ks, csym_func(cs), idx); > +} > + > +static inline csymbol_id *csymf_arg_ids(csymbol_func *csf) > +{ > + return csf->arg_ids; > +} > + > +static inline int csymf_arg_nr(csymbol_func *csf) > +{ > + return csf->arg_nr; > +} > + > +static inline int *csym_func_arg_ids(csymbol *cs) > +{ > + return csymf_arg_ids(csym_func(cs)); > +} > + > +static inline csymbol_id csymf_ret_id(csymbol_func *csf) > +{ > + return csf->ret_id; > +} > + > +static inline void *csymf_addr(csymbol_func *csf) > +{ > + return csf->addr; > +} > + > +static inline void *csym_func_addr(csymbol *cs) > +{ > + return csymf_addr(csym_func(cs)); > +} > + > +/* > + * start of struct symbol helper functions > + */ > +static inline csymbol_struct *csym_struct(csymbol *cs) > +{ > + return &cs->u.st; > +} > + > +static inline csymbol *csymst_mb(ktap_state *ks, csymbol_struct *csst, int > idx) > +{ > + return id_to_csym(ks, csst->members[idx].id); > +} > + > +static inline csymbol *csym_struct_mb(ktap_state *ks, csymbol *cs, int idx) > +{ > + return csymst_mb(ks, csym_struct(cs), idx); > +} > + > +static inline int csymst_mb_nr(csymbol_struct *csst) > +{ > + return csst->memb_nr; > +} > + Now I think csym* inline access function is not good at readability now, ;) because there have too many "csym" prefix word in code, like structure name and field access functions. I suggest to use CSYM* macro for structure field access, do you like it? > +/* > + * following are used in ktap_cdata type > + */ > + > +typedef struct ktap_cdata ktap_cdata; > + > +#define cd_csym_id(cd) ((cd)->id) > +#define cd_set_csym_id(cd, id) (cd_csym_id(cd) = (id)) > +#define cd_csym(ks, cd) (id_to_csym(ks, cd_csym_id(cd))) > +#define cd_type(ks, cd) (cd_csym(ks, cd)->type) > + > +#define cd_int(cd) ((cd)->u.i) > +#define cd_ptr(cd) ((cd)->u.p) > +#define cd_struct(cd) ((cd)->u.st) > + > + > +#ifdef __KERNEL__ > + > +struct ktap_state; > +size_t csym_size(ktap_state *ks, csymbol *sym); > +size_t csym_align(ktap_state *ks, csymbol *sym); > +size_t csym_struct_offset(ktap_state *ks, csymbol_struct *csst, int idx); > +void init_csym_struct(ktap_state *ks, csymbol_struct *csst); > + > +#ifdef __x86_64 > + > +enum arg_status { > + IN_REGISTER, > + IN_MEMORY, > + IN_STACK, > +}; > + > +#define ALIGN_STACK(v, a) ((void *)(ALIGN(((uint64_t)v), a))) > +#define STACK_ALIGNMENT 8 > +#define REDZONE_SIZE 128 > +#define GPR_SIZE (sizeof(uint64_t)) > +#define MAX_GPR 6 > +#define MAX_GPR_SIZE (MAX_GPR * GPR_SIZE) > + > +#define ffi_call(ks, cf, rvalue) ffi_call_x86_64(ks, cf, rvalue) > + > +#else /* non-supported platform */ > + > +#define ffi_call(ks, cf, rvalue) ffi_call_unsupported(ks, cf, rvalue) > + > +#endif /* end for platform-specific setting */ > + > +void ffi_set_csym_arr(ktap_state *ks, int cs_nr, csymbol *new_arr); > +void kp_ffi_free_symbol(ktap_state *ks); > +csymbol_id ffi_get_csym_id(ktap_state *ks, char *name); > +void setup_kp_ffi_symbol_table(ktap_state *ks); > + > +ktap_cdata *kp_cdata_new(ktap_state *ks); > +void kp_cdata_dump(ktap_state *ks, ktap_cdata *cd); > +ktap_cdata *kp_cdata_new_ptr(ktap_state *ks, void *addr, csymbol_id id); > +ktap_cdata *kp_cdata_new_struct(ktap_state *ks, void *val, csymbol_id id); > + > +int kp_ffi_call(ktap_state *ks, csymbol_func *cf); > +#endif /* for __KERNEL__ */ > + > +#else > + > +static void __maybe_unused kp_ffi_free_symbol(ktap_state *ks) > +{ > + return; > +} > + > +#endif /* CONFIG_KTAP_FFI */ > + > +#endif /* __KTAP_FFI_H__ */ > -- > 1.8.1.2 >