[ktap] [PATCHv3 2/8] Cparser to parse C declareation

  • From: Qingping Hou <dave2008713@xxxxxxxxx>
  • To: ktap@xxxxxxxxxxxxx
  • Date: Fri, 29 Nov 2013 15:47:16 -0500

From: Yicheng Qin <qycqycqycqycqyc@xxxxxxxxx>

Cparser is able to interpret C declareation, including basic types,
aggregate types, type definition and so on.

C declareations are converted into csymbol type, which provides type
information for cdata in ktap vm.

Cparser is partially ported from LuaFFI's c parser.
Thanks for their great work!

Signed-off-by: Yicheng Qin <qycqycqycqycqyc@xxxxxxxxx>
Signed-off-by: Qingping Hou <qingping.hou@xxxxxxxxx>
---
 userspace/cparser.h     |  201 +++++
 userspace/ffi/cparser.c | 1894 +++++++++++++++++++++++++++++++++++++++++++++++
 userspace/ffi/ctype.c   |  541 ++++++++++++++
 3 files changed, 2636 insertions(+)
 create mode 100644 userspace/cparser.h
 create mode 100644 userspace/ffi/cparser.c
 create mode 100644 userspace/ffi/ctype.c

diff --git a/userspace/cparser.h b/userspace/cparser.h
new file mode 100644
index 0000000..e6ce448
--- /dev/null
+++ b/userspace/cparser.h
@@ -0,0 +1,201 @@
+#ifndef __KTAP_CPARSER_H__
+#define __KTAP_CPARSER_H__
+
+/*
+ * Copyright (c) 2011 James R. McKaskill
+ *
+ * This software is licensed under the stock MIT license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------------
+ */
+
+/*
+ * Adapted from luaffi commit: abc638c9341025580099dcf77795c4b320ba0e63
+ *
+ * Copyright (c) 2013 Yicheng Qin, Qingping Hou
+ */
+
+#ifdef CONFIG_KTAP_FFI
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdbool.h>
+
+#include "../interpreter/kp_ffi.h"
+
+#define PTR_ALIGN_MASK (sizeof(void*) - 1)
+#define FUNCTION_ALIGN_MASK (sizeof(void (*)()) - 1)
+#define DEFAULT_ALIGN_MASK 7
+
+struct parser {
+       int line;
+       const char *next;
+       const char *prev;
+       unsigned align_mask;
+};
+
+enum {
+       C_CALL,
+       STD_CALL,
+       FAST_CALL,
+};
+
+
+#define MAX_TYPE_NAME_LEN CSYM_NAME_MAX_LEN
+
+enum {
+       /* 0 - 4 */
+       INVALID_TYPE,
+       VOID_TYPE,
+       BOOL_TYPE,
+       INT8_TYPE,
+       INT16_TYPE,
+       /* 5 - 9 */
+       INT32_TYPE,
+       INT64_TYPE,
+       INTPTR_TYPE,
+       ENUM_TYPE,
+       UNION_TYPE,
+       /* 10 - 12 */
+       STRUCT_TYPE,
+       FUNCTION_TYPE,
+       FUNCTION_PTR_TYPE,
+};
+
+
+#define IS_CHAR_UNSIGNED (((char) -1) > 0)
+
+#define POINTER_BITS 2
+#define POINTER_MAX ((1 << POINTER_BITS) - 1)
+
+#define ALIGNOF(S) ((int) ((char*) &S.v - (char*) &S - 1))
+
+
+/* Note: if adding a new member that is associated with a struct/union
+ * definition then it needs to be copied over in ctype.c:set_defined for when
+ * we create types based off of the declaration alone.
+ *
+ * Since this is used as a header for every ctype and cdata, and we create a
+ * ton of them on the stack, we try and minimise its size.
+ */
+struct cp_ctype {
+       size_t base_size; /* size of the base type in bytes */
+       int ffi_cs_id; /* index for csymbol from ktap vm */
+       union {
+               /* valid if is_bitfield */
+               struct {
+                       /* size of bitfield in bits */
+                       unsigned bit_size : 7;
+                       /* offset within the current byte between 0-63 */
+                       unsigned bit_offset : 6;
+               };
+               /* Valid if is_array */
+               size_t array_size;
+               /* Valid for is_variable_struct or is_variable_array. If
+                * variable_size_known (only used for is_variable_struct)
+                * then this is the total increment otherwise this is the
+                * per element increment.
+                */
+               size_t variable_increment;
+       };
+       size_t offset;
+       /* as (align bytes - 1) eg 7 gives 8 byte alignment */
+       unsigned align_mask : 4;
+       /* number of dereferences to get to the base type
+        * including +1 for arrays */
+       unsigned pointers : POINTER_BITS;
+       /* const pointer mask, LSB is current pointer, +1 for the whether
+        * the base type is const */
+       unsigned const_mask : POINTER_MAX + 1;
+       unsigned type : 5; /* value given by type enum above */
+       unsigned is_reference : 1;
+       unsigned is_array : 1;
+       unsigned is_defined : 1;
+       unsigned is_null : 1;
+       unsigned has_member_name : 1;
+       unsigned calling_convention : 2;
+       unsigned has_var_arg : 1;
+       /* set for variable array types where we don't know
+        * the variable size yet */
+       unsigned is_variable_array : 1;
+       unsigned is_variable_struct : 1;
+       /* used for variable structs after we know the variable size */
+       unsigned variable_size_known : 1;
+       unsigned is_bitfield : 1;
+       unsigned has_bitfield : 1;
+       unsigned is_jitted : 1;
+       unsigned is_packed : 1;
+       unsigned is_unsigned : 1;
+};
+
+#define ALIGNED_DEFAULT (__alignof__(void* __attribute__((aligned))) - 1)
+
+csymbol *cp_id_to_csym(int id);
+#define ct_ffi_cs(ct) (cp_id_to_csym((ct)->ffi_cs_id))
+
+size_t ctype_size(const struct cp_ctype* ct);
+int cp_ctype_init();
+int cp_ctype_free();
+struct cp_ctype *ctype_lookup_type(char *name);
+void cp_ctype_dump_stack();
+void cp_error(const char *err_msg_fmt, ...);
+struct cp_ctype *cp_ctype_reg_type(char *name, struct cp_ctype *ct);
+
+void cp_push_ctype_with_name(struct cp_ctype *ct, const char *name, int nlen);
+void cp_push_ctype(struct cp_ctype *ct);
+void cp_set_defined(struct cp_ctype *ct);
+
+int cp_symbol_build_func(const char *fname, int fn_size);
+int cp_symbol_build_struct(const char *stname);
+int cp_symbol_build_pointer(struct cp_ctype *ct);
+
+int ffi_cdef(char *s);
+void ffi_cparser_init(void);
+void ffi_cparser_free(void);
+
+
+static inline csymbol *cp_csymf_ret(csymbol_func *csf)
+{
+       return cp_id_to_csym(csf->ret_id);
+}
+
+static inline csymbol *cp_csymf_arg(csymbol_func *csf, int idx)
+{
+       return cp_id_to_csym(csf->arg_ids[idx]);
+}
+
+
+#else
+static void __maybe_unused ffi_cparser_init(void)
+{
+       return;
+}
+static void __maybe_unused ffi_cparser_free(void)
+{
+       return;
+}
+#endif /* CONFIG_KTAP_FFI */
+
+
+#endif /* __KTAP_CPARSER_H__ */
diff --git a/userspace/ffi/cparser.c b/userspace/ffi/cparser.c
new file mode 100644
index 0000000..00597c8
--- /dev/null
+++ b/userspace/ffi/cparser.c
@@ -0,0 +1,1894 @@
+#include <stdarg.h>
+#include "../cparser.h"
+
+#define IS_CONST(tok) (IS_LITERAL(tok, "const") || IS_LITERAL(tok, "__const") \
+                       || IS_LITERAL(tok, "__const__"))
+#define IS_VOLATILE(tok) (IS_LITERAL(tok, "volatile") || \
+                               IS_LITERAL(tok, "__volatile") || \
+                               IS_LITERAL(tok, "__volatile__"))
+#define IS_RESTRICT(tok) (IS_LITERAL(tok, "restrict") || \
+                               IS_LITERAL(tok, "__restrict") || \
+                               IS_LITERAL(tok, "__restrict__"))
+
+#define max(a,b) ((a) < (b) ? (b) : (a))
+#define min(a,b) ((a) < (b) ? (a) : (b))
+
+
+enum etoken {
+       /* 0 - 3 */
+       TOK_NIL,
+       TOK_NUMBER,
+       TOK_STRING,
+       TOK_TOKEN,
+
+       /* the order of these values must match the token strings in lex.c */
+
+       /* 4 - 5 */
+       TOK_3_BEGIN,
+       TOK_VA_ARG,
+
+       /* 6 - 14 */
+       TOK_2_BEGIN,
+       TOK_LEFT_SHIFT, TOK_RIGHT_SHIFT, TOK_LOGICAL_AND, TOK_LOGICAL_OR,
+       TOK_LESS_EQUAL, TOK_GREATER_EQUAL, TOK_EQUAL, TOK_NOT_EQUAL,
+
+       /* 15 - 20 */
+       TOK_1_BEGIN,
+       TOK_OPEN_CURLY, TOK_CLOSE_CURLY, TOK_SEMICOLON, TOK_COMMA, TOK_COLON,
+       /* 21 - 30 */
+       TOK_ASSIGN, TOK_OPEN_PAREN, TOK_CLOSE_PAREN, TOK_OPEN_SQUARE, 
TOK_CLOSE_SQUARE,
+       TOK_DOT, TOK_AMPERSAND, TOK_LOGICAL_NOT, TOK_BITWISE_NOT, TOK_MINUS,
+       /* 31 - 40 */
+       TOK_PLUS, TOK_STAR, TOK_DIVIDE, TOK_MODULUS, TOK_LESS,
+       TOK_GREATER, TOK_BITWISE_XOR, TOK_BITWISE_OR, TOK_QUESTION, TOK_POUND,
+
+       /* 41 - 43 */
+       TOK_REFERENCE = TOK_AMPERSAND,
+       TOK_MULTIPLY = TOK_STAR,
+       TOK_BITWISE_AND = TOK_AMPERSAND,
+};
+
+struct token {
+       enum etoken type;
+       int64_t integer;
+       const char *str;
+       size_t size;
+};
+
+#define IS_LITERAL(TOK, STR) \
+       (((TOK).size == sizeof(STR) - 1) && \
+               0 == memcmp((TOK).str, STR, sizeof(STR) - 1))
+
+
+static int parse_type_name(struct parser *P, char *type_name);
+static void parse_argument(struct parser *P, struct cp_ctype *ct,
+               struct token *pname, struct parser *asmname);
+static int parse_attribute(struct parser *P, struct token *tok,
+               struct cp_ctype *ct, struct parser *asmname);
+static int parse_record(struct parser *P, struct cp_ctype *ct);
+static void instantiate_typedef(struct parser *P, struct cp_ctype *tt,
+               const struct cp_ctype *ft);
+
+
+/* the order of tokens _must_ match the order of the enum etoken enum */
+
+static char tok3[][4] = {
+       "...", /* unused ">>=", "<<=", */
+};
+
+static char tok2[][3] = {
+       "<<", ">>", "&&", "||", "<=",
+       ">=", "==", "!=",
+       /* unused "+=", "-=", "*=", "/=", "%=", "&=", "^=",
+        * "|=", "++", "--", "->", "::", */
+};
+
+static char tok1[] = {
+       '{', '}', ';', ',', ':',
+       '=', '(', ')', '[', ']',
+       '.', '&', '!', '~', '-',
+       '+', '*', '/', '%', '<',
+       '>', '^', '|', '?', '#'
+};
+
+
+/* this function never returns, but it's an idiom to use it in C functions
+ * as return cp_error */
+void cp_error(const char *err_msg_fmt, ...)
+{
+       va_list ap;
+
+       fprintf(stderr, "cparser error:\n");
+
+       va_start(ap, err_msg_fmt);
+       vfprintf(stderr, err_msg_fmt, ap);
+       va_end(ap);
+
+       exit(EXIT_FAILURE);
+}
+
+static int set_struct_type_name(char *dst, const char *src, int len)
+{
+       int prefix_len = sizeof("struct ");
+
+       if (len + prefix_len > MAX_TYPE_NAME_LEN)
+               return -1;
+
+       memset(dst, 0, MAX_TYPE_NAME_LEN);
+       strcpy(dst, "struct ");
+       strncat(dst, src, len);
+
+       return 0;
+}
+
+static void increase_ptr_deref_level(struct parser *P, struct cp_ctype *ct)
+{
+       if (ct->pointers == POINTER_MAX) {
+               cp_error("maximum number of pointer derefs reached - use a "
+                       "struct to break up the pointers on line %d", P->line);
+       } else {
+               ct->pointers++;
+               ct->const_mask <<= 1;
+       }
+}
+
+static int next_token(struct parser *P, struct token *tok)
+{
+       size_t i;
+       const char *s = P->next;
+
+       /* UTF8 BOM */
+       if (s[0] == '\xEF' && s[1] == '\xBB' && s[2] == '\xBF') {
+               s += 3;
+       }
+
+       /* consume whitespace and comments */
+       for (;;) {
+               /* consume whitespace */
+               while (*s == '\t' || *s == '\n' || *s == ' '
+                               || *s == '\v' || *s == '\r') {
+                       if (*s == '\n') {
+                               P->line++;
+                       }
+                       s++;
+               }
+
+               /* consume comments */
+               if (*s == '/' && *(s+1) == '/') {
+
+                       s = strchr(s, '\n');
+                       if (!s) {
+                               cp_error("non-terminated comment");
+                       }
+
+               } else if (*s == '/' && *(s+1) == '*') {
+                       s += 2;
+
+                       for (;;) {
+                               if (s[0] == '\0') {
+                                       cp_error("non-terminated comment");
+                               } else if (s[0] == '*' && s[1] == '/') {
+                                       s += 2;
+                                       break;
+                               } else if (s[0] == '\n') {
+                                       P->line++;
+                               }
+                               s++;
+                       }
+
+               } else if (*s == '\0') {
+                       tok->type = TOK_NIL;
+                       return 0;
+
+               } else {
+                       break;
+               }
+       }
+
+       P->prev = s;
+
+       for (i = 0; i < sizeof(tok3) / sizeof(tok3[0]); i++) {
+               if (s[0] == tok3[i][0] && s[1] == tok3[i][1] && s[2] == 
tok3[i][2]) {
+                       tok->type = (enum etoken) (TOK_3_BEGIN + 1 + i);
+                       P->next = s + 3;
+                       goto end;
+               }
+       }
+
+       for (i = 0; i < sizeof(tok2) / sizeof(tok2[0]); i++) {
+               if (s[0] == tok2[i][0] && s[1] == tok2[i][1]) {
+                       tok->type = (enum etoken) (TOK_2_BEGIN + 1 + i);
+                       P->next = s + 2;
+                       goto end;
+               }
+       }
+
+       for (i = 0; i < sizeof(tok1) / sizeof(tok1[0]); i++) {
+               if (s[0] == tok1[i]) {
+                       tok->type = (enum etoken) (TOK_1_BEGIN + 1 + i);
+                       P->next = s + 1;
+                       goto end;
+               }
+       }
+
+       if (*s == '.' || *s == '-' || ('0' <= *s && *s <= '9')) {
+               /* number */
+               tok->type = TOK_NUMBER;
+
+               /* split out the negative case so we get the full range of
+                * bits for unsigned (eg to support 0xFFFFFFFF where
+                * sizeof(long) == 4 */
+               if (*s == '-') {
+                       tok->integer = strtol(s, (char**) &s, 0);
+               } else {
+                       tok->integer = strtoul(s, (char**) &s, 0);
+               }
+
+               while (*s == 'u' || *s == 'U' || *s == 'l' || *s == 'L') {
+                       s++;
+               }
+
+               P->next = s;
+               goto end;
+
+       } else if (*s == '\'' || *s == '\"') {
+               /* "..." or '...' */
+               char quote = *s;
+               s++; /* jump over " */
+
+               tok->type = TOK_STRING;
+               tok->str = s;
+
+               while (*s != quote) {
+
+                       if (*s == '\0' || (*s == '\\' && *(s+1) == '\0')) {
+                               cp_error("string not finished");
+                       }
+
+                       if (*s == '\\') {
+                               s++;
+                       }
+
+                       s++;
+               }
+
+               tok->size = s - tok->str;
+               s++; /* jump over " */
+               P->next = s;
+               goto end;
+
+       } else if (('a' <= *s && *s <= 'z') || ('A' <= *s && *s <= 'Z')
+                       || *s == '_') {
+               /* tokens */
+               tok->type = TOK_TOKEN;
+               tok->str = s;
+
+               while (('a' <= *s && *s <= 'z') || ('A' <= *s && *s <= 'Z')
+                               || *s == '_' || ('0' <= *s && *s <= '9')) {
+                       s++;
+               }
+
+               tok->size = s - tok->str;
+               P->next = s;
+               goto end;
+       } else {
+               cp_error("invalid character %d", P->line);
+       }
+
+end:
+       return 1;
+}
+
+static void require_token(struct parser *P, struct token *tok)
+{
+       if (!next_token(P, tok)) {
+               cp_error("unexpected end");
+       }
+}
+
+static void check_token(struct parser *P, int type, const char *str,
+                               const char *err, ...)
+{
+       va_list ap;
+       struct token tok;
+       if (!next_token(P, &tok) || tok.type != type
+                       || (tok.type == TOK_TOKEN && (tok.size != strlen(str)
+                               || memcmp(tok.str, str, tok.size) != 0))) {
+
+               va_start(ap, err);
+               vfprintf(stderr, err, ap);
+               va_end(ap);
+
+               exit(EXIT_FAILURE);
+       }
+}
+
+static void put_back(struct parser *P) {
+       P->next = P->prev;
+}
+
+int64_t calculate_constant(struct parser *P);
+
+/* parses out the base type of a type expression in a function declaration,
+ * struct definition, typedef etc
+ *
+ * leaves the usr value of the type on the stack
+ */
+int parse_type(struct parser *P, struct cp_ctype *ct)
+{
+       struct token tok;
+
+       memset(ct, 0, sizeof(*ct));
+
+       require_token(P, &tok);
+
+       /* get function attributes before the return type */
+       while (parse_attribute(P, &tok, ct, NULL)) {
+               require_token(P, &tok);
+       }
+
+       /* get const/volatile before the base type */
+       for (;;) {
+               if (tok.type != TOK_TOKEN) {
+                       cp_error("unexpected value before type name on line %d",
+                                       P->line);
+                       return 0;
+               } else if (IS_CONST(tok)) {
+                       ct->const_mask = 1;
+                       require_token(P, &tok);
+               } else if (IS_VOLATILE(tok) || IS_RESTRICT(tok)) {
+                       /* ignored for now */
+                       require_token(P, &tok);
+               } else {
+                       break;
+               }
+       }
+
+       /* get base type */
+       if (tok.type != TOK_TOKEN) {
+               cp_error("unexpected value before type name on line %d", 
P->line);
+               return 0;
+       } else if (IS_LITERAL(tok, "struct")) {
+               ct->type = STRUCT_TYPE;
+               parse_record(P, ct);
+       } else if (IS_LITERAL(tok, "union")) {
+               ct->type = UNION_TYPE;
+               parse_record(P, ct);
+       } else if (IS_LITERAL(tok, "enum")) {
+               ct->type = ENUM_TYPE;
+               parse_record(P, ct);
+       } else {
+               put_back(P);
+
+               /* lookup type */
+               struct cp_ctype *lct;
+               char cur_type_name[MAX_TYPE_NAME_LEN];
+
+               memset(cur_type_name, 0, MAX_TYPE_NAME_LEN);
+               parse_type_name(P, cur_type_name);
+               lct = ctype_lookup_type(cur_type_name);
+               if (!lct)
+                       cp_error("unknow type: \"%s\"\n", cur_type_name);
+
+               instantiate_typedef(P, ct, lct);
+       }
+
+       while (next_token(P, &tok)) {
+               if (tok.type != TOK_TOKEN) {
+                       put_back(P);
+                       break;
+               } else if (IS_CONST(tok) || IS_VOLATILE(tok)) {
+                       /* ignore for now */
+               } else {
+                       put_back(P);
+                       break;
+               }
+       }
+
+       return 0;
+}
+
+enum test {TEST};
+
+/* Parses an enum definition from after the open curly through to the close
+ * curly. Expects the user table to be on the top of the stack
+ */
+static int parse_enum(struct parser *P, struct cp_ctype *type)
+{
+       struct token tok;
+       int value = -1;
+
+       /*@TODO clean up this function when enum support is added*/
+       cp_error("TODO: enum not supported!\n");
+
+       for (;;) {
+               require_token(P, &tok);
+
+               if (tok.type == TOK_CLOSE_CURLY) {
+                       break;
+               } else if (tok.type != TOK_TOKEN) {
+                       cp_error("unexpected token in enum at line %d", 
P->line);
+                       return 0;
+               }
+
+#if 0
+               lua_pushlstring(L, tok.str, tok.size);
+#endif
+
+               require_token(P, &tok);
+
+               if (tok.type == TOK_COMMA || tok.type == TOK_CLOSE_CURLY) {
+                       /* we have an auto calculated enum value */
+                       value++;
+               } else if (tok.type == TOK_ASSIGN) {
+                       /* we have an explicit enum value */
+                       value = (int) calculate_constant(P);
+                       require_token(P, &tok);
+               } else {
+                       cp_error("unexpected token in enum at line %d", 
P->line);
+                       return 0;
+               }
+
+#if 0
+               assert(lua_gettop(L) == ct_usr + 1);
+
+               /* add the enum value to the constants table */
+               push_upval(L, &constants_key);
+               lua_pushvalue(L, -2);
+               lua_pushnumber(L, value);
+               lua_rawset(L, -3);
+               lua_pop(L, 1);
+
+               assert(lua_gettop(L) == ct_usr + 1);
+
+               /* add the enum value to the enum usr value table */
+               lua_pushnumber(L, value);
+               lua_rawset(L, ct_usr);
+#endif
+
+               if (tok.type == TOK_CLOSE_CURLY) {
+                       break;
+               } else if (tok.type != TOK_COMMA) {
+                       cp_error("unexpected token in enum at line %d", 
P->line);
+                       return 0;
+               }
+       }
+
+       type->base_size = sizeof(enum test);
+       type->align_mask = sizeof(enum test) - 1;
+
+       return 0;
+}
+
+/* Parses a struct from after the open curly through to the close curly. */
+static int parse_struct(struct parser *P, const struct cp_ctype *ct)
+{
+       struct token tok;
+
+       /* parse members */
+       for (;;) {
+               struct cp_ctype mbase;
+
+               /* see if we're at the end of the struct */
+               require_token(P, &tok);
+               if (tok.type == TOK_CLOSE_CURLY) {
+                       break;
+               } else if (ct->is_variable_struct) {
+                       cp_error("can't have members after a variable sized "
+                                       "member on line %d", P->line);
+                       return -1;
+               } else {
+                       put_back(P);
+               }
+
+               /* members are of the form
+                * <base type> <arg>, <arg>, <arg>;
+                * eg struct foo bar, *bar2[2];
+                * mbase is 'struct foo'
+                * mtype is '' then '*[2]'
+                * mname is 'bar' then 'bar2'
+                */
+
+               parse_type(P, &mbase);
+
+               for (;;) {
+                       struct token mname;
+                       struct cp_ctype mt = mbase;
+
+                       memset(&mname, 0, sizeof(mname));
+
+                       if (ct->is_variable_struct) {
+                               cp_error("can't have members after a variable "
+                                       "sized member on line %d", P->line);
+                               return -1;
+                       }
+
+                       parse_argument(P, &mt, &mname, NULL);
+
+                       if (!mt.is_defined && (mt.pointers - mt.is_array) == 0) 
{
+                               cp_error("member type is undefined on line %d",
+                                               P->line);
+                               return -1;
+                       }
+
+                       if (mt.type == VOID_TYPE
+                                       && (mt.pointers - mt.is_array) == 0) {
+                               cp_error("member type can not be void on line 
%d",
+                                               P->line);
+                               return -1;
+                       }
+
+                       mt.has_member_name = (mname.size > 0);
+                       if (mt.has_member_name) {
+                               cp_push_ctype_with_name(&mt,
+                                               mname.str, mname.size);
+                       } else {
+                               /* @TODO handle unnamed member (houqp) */
+                               cp_error("TODO: unnamed member not supported.");
+                               cp_push_ctype(&mt);
+                       }
+
+                       require_token(P, &tok);
+                       if (tok.type == TOK_SEMICOLON) {
+                               break;
+                       } else if (tok.type != TOK_COMMA) {
+                               cp_error("unexpected token in struct "
+                                       "definition on line %d", P->line);
+                       }
+               }
+       }
+
+       return 0;
+}
+
+/* copy over attributes that could be specified before the typedef eg
+ * __attribute__(packed) const type_t */
+static void instantiate_typedef(struct parser *P, struct cp_ctype *tt,
+               const struct cp_ctype *ft)
+{
+       struct cp_ctype pt = *tt;
+       *tt = *ft;
+
+       tt->const_mask |= pt.const_mask;
+       tt->is_packed = pt.is_packed;
+
+       if (tt->is_packed) {
+               tt->align_mask = 0;
+       } else {
+               /* Instantiate the typedef in the current packing. This may be
+                * further updated if a pointer is added or another alignment
+                * attribute is applied. If pt.align_mask is already non-zero
+                * than an increased alignment via __declspec(aligned(#)) has
+                * been set. */
+               tt->align_mask = max(min(P->align_mask, tt->align_mask),
+                                       pt.align_mask);
+       }
+}
+
+/* this parses a struct or union starting with the optional
+ * name before the opening brace
+ * leaves the type usr value on the stack */
+static int parse_record(struct parser *P, struct cp_ctype *ct)
+{
+       struct token tok;
+       char cur_type_name[MAX_TYPE_NAME_LEN];
+
+       require_token(P, &tok);
+
+       /* name is optional */
+       if (tok.type == TOK_TOKEN) {
+               /* declaration */
+               struct cp_ctype *lct;
+
+               memset(cur_type_name, 0, MAX_TYPE_NAME_LEN);
+               set_struct_type_name(cur_type_name, tok.str, tok.size);
+;
+               /* lookup the name to see if we've seen this type before */
+               lct = ctype_lookup_type(cur_type_name);
+
+               if (!lct) {
+                       /* new type, delay type registration to the end
+                        * of this function */
+               } else {
+                       /* get the exsting declared type */
+                       if (lct->type != ct->type) {
+                               cp_error("type '%s' previously declared as 
'%s'",
+                                       cur_type_name,
+                                       csym_name(ct_ffi_cs(lct)));
+                       }
+
+                       instantiate_typedef(P, ct, lct);
+               }
+
+               /* if a name is given then we may be at the end of the string
+                * eg for ffi.new('struct foo') */
+               if (!next_token(P, &tok)) {
+                       return 0;
+               }
+       } else {
+               /* create a new unnamed record */
+
+               /*@TODO clean this up after unnamed record support is added */
+               cp_error("TODO: support unnamed record.\n");
+#if 0
+               int num;
+               /* get the next unnamed number */
+               push_upval(L, &next_unnamed_key);
+               num = lua_tointeger(L, -1);
+               lua_pop(L, 1);
+
+               /* increment the unnamed upval */
+               lua_pushinteger(L, num + 1);
+               set_upval(L, &next_unnamed_key);
+
+               lua_newtable(L); /* the new usr table - leave on stack */
+
+               /* usr[name_key] = num */
+               lua_pushlightuserdata(L, &g_name_key);
+               lua_pushfstring(L, "%d", num);
+               lua_rawset(L, -3);
+#endif
+       }
+
+       if (tok.type != TOK_OPEN_CURLY) {
+               /* this may just be a declaration or use of the type as an
+                * argument or member */
+               put_back(P);
+               return 0;
+       }
+
+       if (ct->is_defined) {
+               cp_error("redefinition in line %d", P->line);
+               return 0;
+       }
+
+       if (ct->type == ENUM_TYPE) {
+               parse_enum(P, ct);
+       } else {
+               /* we do a two stage parse, where we parse the content first
+                * and build up the temp user table. We then iterate over that
+                * to calculate the offsets and fill out ct_usr. This is so we
+                * can handle out of order members (eg vtable) and attributes
+                * specified at the end of the struct. */
+               parse_struct(P, ct);
+               /* build symbol for vm */
+               ct->ffi_cs_id = cp_symbol_build_struct(cur_type_name);
+               /* save cp_ctype for parser */
+               cp_ctype_reg_type(cur_type_name, ct);
+#if 0
+               /*@TODO size is calcuated in vm for now, might need to do it
+                * in parser later  24.11 2013 (houqp)*/
+               calculate_struct_offsets(P, -2, ct, -1);
+#endif
+       }
+
+       cp_set_defined(ct);
+       return 0;
+}
+
+/* parses single or multi work built in types, and pushes it onto the stack */
+static int parse_type_name(struct parser *P, char *type_name)
+{
+       struct token tok;
+       int flags = 0;
+
+       enum {
+               UNSIGNED = 0x01,
+               SIGNED = 0x02,
+               LONG = 0x04,
+               SHORT = 0x08,
+               INT = 0x10,
+               CHAR = 0x20,
+               LONG_LONG = 0x40,
+               INT8 = 0x80,
+               INT16 = 0x100,
+               INT32 = 0x200,
+               INT64 = 0x400,
+       };
+
+       require_token(P, &tok);
+
+       /* we have to manually decode the builtin types since they can take up
+        * more then one token */
+       for (;;) {
+               if (tok.type != TOK_TOKEN) {
+                       break;
+               } else if (IS_LITERAL(tok, "unsigned")) {
+                       flags |= UNSIGNED;
+               } else if (IS_LITERAL(tok, "signed")) {
+                       flags |= SIGNED;
+               } else if (IS_LITERAL(tok, "short")) {
+                       flags |= SHORT;
+               } else if (IS_LITERAL(tok, "char")) {
+                       flags |= CHAR;
+               } else if (IS_LITERAL(tok, "long")) {
+                       flags |= (flags & LONG) ? LONG_LONG : LONG;
+               } else if (IS_LITERAL(tok, "int")) {
+                       flags |= INT;
+               } else if (IS_LITERAL(tok, "__int8")) {
+                       flags |= INT8;
+               } else if (IS_LITERAL(tok, "__int16")) {
+                       flags |= INT16;
+               } else if (IS_LITERAL(tok, "__int32")) {
+                       flags |= INT32;
+               } else if (IS_LITERAL(tok, "__int64")) {
+                       flags |= INT64;
+               } else if (IS_LITERAL(tok, "register")) {
+                       /* ignore */
+               } else {
+                       break;
+               }
+
+               if (!next_token(P, &tok)) {
+                       break;
+               }
+       }
+
+       if (flags) {
+               put_back(P);
+       }
+
+       if (flags & CHAR) {
+               if (flags & SIGNED) {
+                       strcpy(type_name, "int8_t");
+               } else if (flags & UNSIGNED) {
+                       strcpy(type_name, "uint8_t");
+               } else {
+                       if (((char) -1) > 0) {
+                               strcpy(type_name, "uint8_t");
+                       } else {
+                               strcpy(type_name, "int8_t");
+                       }
+               }
+       } else if (flags & INT8) {
+               strcpy(type_name, (flags & UNSIGNED) ? "uint8_t" : "int8_t");
+       } else if (flags & INT16) {
+               strcpy(type_name, (flags & UNSIGNED) ? "uint16_t" : "int16_t");
+       } else if (flags & INT32) {
+               strcpy(type_name, (flags & UNSIGNED) ? "uint32_t" : "int32_t");
+       } else if (flags & INT64) {
+               strcpy(type_name, (flags & UNSIGNED) ? "uint64_t" : "int64_t");
+       } else if (flags & LONG_LONG) {
+               strcpy(type_name, (flags & UNSIGNED) ? "uint64_t" : "int64_t");
+       } else if (flags & SHORT) {
+#define SHORT_TYPE(u) (sizeof(short) == sizeof(int64_t) ? \
+               u "int64_t" : sizeof(short) == sizeof(int32_t) ? \
+               u "int32_t" : u "int16_t")
+               if (flags & UNSIGNED) {
+                       strcpy(type_name, SHORT_TYPE("u"));
+               } else {
+                       strcpy(type_name, SHORT_TYPE(""));
+               }
+#undef SHORT_TYPE
+       } else if (flags & LONG) {
+#define LONG_TYPE(u) (sizeof(long) == sizeof(int64_t) ? \
+               u "int64_t" : u "int32_t")
+               if (flags & UNSIGNED) {
+                       strcpy(type_name, LONG_TYPE("u"));
+               } else {
+                       strcpy(type_name, LONG_TYPE(""));
+               }
+#undef LONG_TYPE
+       } else if (flags) {
+#define INT_TYPE(u) (sizeof(int) == sizeof(int64_t) ? \
+               u "int64_t" : sizeof(int) == sizeof(int32_t) ? \
+               u "int32_t" : u "int16_t")
+               if (flags & UNSIGNED) {
+                       strcpy(type_name, INT_TYPE("u"));
+               } else {
+                       strcpy(type_name, INT_TYPE(""));
+               }
+#undef INT_TYPE
+       } else {
+               strncpy(type_name, tok.str, tok.size);
+       }
+
+       return 0;
+}
+
+/* parse_attribute parses a token to see if it is an attribute. It may then
+ * parse some following tokens to decode the attribute setting the appropriate
+ * fields in ct. It will return 1 if the token was used (and possibly some
+ * more following it) or 0 if not. If the token was used, the next token must
+ * be retrieved using next_token/require_token. */
+static int parse_attribute(struct parser *P, struct token *tok,
+               struct cp_ctype *ct, struct parser *asmname)
+{
+       if (tok->type != TOK_TOKEN) {
+               return 0;
+       } else if (asmname && (IS_LITERAL(*tok, "__asm__")
+                               || IS_LITERAL(*tok, "__asm"))) {
+               check_token(P, TOK_OPEN_PAREN, NULL,
+                               "unexpected token after __asm__ on line %d",
+                               P->line);
+               *asmname = *P;
+
+               require_token(P, tok);
+               while (tok->type == TOK_STRING) {
+                       require_token(P, tok);
+               }
+
+               if (tok->type != TOK_CLOSE_PAREN) {
+                       cp_error("unexpected token after __asm__ on line %d",
+                                       P->line);
+               }
+               return 1;
+
+       } else if (IS_LITERAL(*tok, "__attribute__")
+                       || IS_LITERAL(*tok, "__declspec")) {
+               int parens = 1;
+               check_token(P, TOK_OPEN_PAREN, NULL,
+                               "expected parenthesis after __attribute__ or "
+                               "__declspec on line %d", P->line);
+
+               for (;;) {
+                       require_token(P, tok);
+                       if (tok->type == TOK_OPEN_PAREN) {
+                               parens++;
+                       } else if (tok->type == TOK_CLOSE_PAREN) {
+                               if (--parens == 0) {
+                                       break;
+                               }
+
+                       } else if (tok->type != TOK_TOKEN) {
+                               /* ignore unknown symbols within parentheses */
+
+                       } else if (IS_LITERAL(*tok, "align") ||
+                                       IS_LITERAL(*tok, "aligned") ||
+                                       IS_LITERAL(*tok, "__aligned__")) {
+                               unsigned align = 0;
+                               require_token(P, tok);
+
+                               switch (tok->type) {
+                               case TOK_CLOSE_PAREN:
+                                       align = ALIGNED_DEFAULT;
+                                       put_back(P);
+                                       break;
+
+                               case TOK_OPEN_PAREN:
+                                       require_token(P, tok);
+
+                                       if (tok->type != TOK_NUMBER) {
+                                               cp_error("expected align(#) "
+                                                       "on line %d", P->line);
+                                       }
+
+                                       switch (tok->integer) {
+                                       case 1: align = 0; break;
+                                       case 2: align = 1; break;
+                                       case 4: align = 3; break;
+                                       case 8: align = 7; break;
+                                       case 16: align = 15; break;
+                                       default:
+                                               cp_error("unsupported align "
+                                                       "size on line %d",
+                                                       P->line);
+                                       }
+
+                                       check_token(P, TOK_CLOSE_PAREN, NULL,
+                                               "expected align(#) on line %d",
+                                               P->line);
+                                       break;
+
+                               default:
+                                       cp_error("expected align(#) on line %d",
+                                                       P->line);
+                               }
+
+                               /* __attribute__(aligned(#)) is only supposed
+                                * to increase alignment */
+                               ct->align_mask = max(align, ct->align_mask);
+
+                       } else if (IS_LITERAL(*tok, "packed")
+                                       || IS_LITERAL(*tok, "__packed__")) {
+                               ct->align_mask = 0;
+                               ct->is_packed = 1;
+
+                       } else if (IS_LITERAL(*tok, "mode")
+                                       || IS_LITERAL(*tok, "__mode__")) {
+
+                               check_token(P, TOK_OPEN_PAREN, NULL,
+                                       "expected mode(MODE) on line %d",
+                                       P->line);
+
+                               require_token(P, tok);
+                               if (tok->type != TOK_TOKEN) {
+                                       cp_error("expected mode(MODE) on line 
%d",
+                                                       P->line);
+                               }
+
+
+                               struct {char ch; uint16_t v;} a16;
+                               struct {char ch; uint32_t v;} a32;
+                               struct {char ch; uint64_t v;} a64;
+
+                               if (IS_LITERAL(*tok, "QI")
+                                               || IS_LITERAL(*tok, "__QI__")
+                                               || IS_LITERAL(*tok, "byte")
+                                               || IS_LITERAL(*tok, "__byte__")
+                                  ) {
+                                       ct->type = INT8_TYPE;
+                                       ct->base_size = sizeof(uint8_t);
+                                       ct->align_mask = 0;
+
+                               } else if (IS_LITERAL(*tok, "HI")
+                                               || IS_LITERAL(*tok, "__HI__")) {
+                                       ct->type = INT16_TYPE;
+                                       ct->base_size = sizeof(uint16_t);
+                                       ct->align_mask = ALIGNOF(a16);
+
+                               } else if (IS_LITERAL(*tok, "SI")
+                                               || IS_LITERAL(*tok, "__SI__")
+#if defined ARCH_X86 || defined ARCH_ARM
+                                               || IS_LITERAL(*tok, "word")
+                                               || IS_LITERAL(*tok, "__word__")
+                                               || IS_LITERAL(*tok, "pointer")
+                                               || IS_LITERAL(*tok, 
"__pointer__")
+#endif
+                                         ) {
+                                       ct->type = INT32_TYPE;
+                                       ct->base_size = sizeof(uint32_t);
+                                       ct->align_mask = ALIGNOF(a32);
+
+                               } else if (IS_LITERAL(*tok, "DI")
+                                               || IS_LITERAL(*tok, "__DI__")
+#if defined ARCH_X64
+                                               || IS_LITERAL(*tok, "word")
+                                               || IS_LITERAL(*tok, "__word__")
+                                               || IS_LITERAL(*tok, "pointer")
+                                               || IS_LITERAL(*tok, 
"__pointer__")
+#endif
+                                         ) {
+                                       ct->type = INT64_TYPE;
+                                       ct->base_size = sizeof(uint64_t);
+                                       ct->align_mask = ALIGNOF(a64);
+
+                               } else {
+                                       cp_error("unexpected mode on line %d",
+                                                       P->line);
+                               }
+
+                               check_token(P, TOK_CLOSE_PAREN, NULL,
+                                       "expected mode(MODE) on line %d", 
P->line);
+
+                       } else if (IS_LITERAL(*tok, "cdecl")
+                                       || IS_LITERAL(*tok, "__cdecl__")) {
+                               ct->calling_convention = C_CALL;
+
+                       } else if (IS_LITERAL(*tok, "fastcall")
+                                       || IS_LITERAL(*tok, "__fastcall__")) {
+                               ct->calling_convention = FAST_CALL;
+
+                       } else if (IS_LITERAL(*tok, "stdcall")
+                                       || IS_LITERAL(*tok, "__stdcall__")) {
+                               ct->calling_convention = STD_CALL;
+                       }
+                       /* ignore unknown tokens within parentheses */
+               }
+               return 1;
+
+       } else if (IS_LITERAL(*tok, "__cdecl")) {
+               ct->calling_convention = C_CALL;
+               return 1;
+
+       } else if (IS_LITERAL(*tok, "__fastcall")) {
+               ct->calling_convention = FAST_CALL;
+               return 1;
+
+       } else if (IS_LITERAL(*tok, "__stdcall")) {
+               ct->calling_convention = STD_CALL;
+               return 1;
+
+       } else if (IS_LITERAL(*tok, "__extension__")
+                       || IS_LITERAL(*tok, "extern")) {
+               /* ignore */
+               return 1;
+       } else {
+               return 0;
+       }
+}
+
+/* parses from after the opening paranthesis to after the closing parenthesis 
*/
+static void parse_function_arguments(struct parser* P, struct cp_ctype* ct)
+{
+       struct token tok;
+       int args = 0;
+
+       for (;;) {
+               require_token(P, &tok);
+
+               if (tok.type == TOK_CLOSE_PAREN)
+                       break;
+
+               if (args) {
+                       if (tok.type != TOK_COMMA) {
+                               cp_error("unexpected token in function "
+                                               "argument %d on line %d",
+                                               args, P->line);
+                       }
+                       require_token(P, &tok);
+               }
+
+               if (tok.type == TOK_VA_ARG) {
+                       ct->has_var_arg = true;
+                       check_token(P, TOK_CLOSE_PAREN, "",
+                                       "unexpected token after ... in "
+                                       "function on line %d",
+                                       P->line);
+                       break;
+
+               } else if (tok.type == TOK_TOKEN) {
+                       struct cp_ctype at;
+
+                       put_back(P);
+                       parse_type(P, &at);
+                       parse_argument(P, &at, NULL, NULL);
+
+                       /* array arguments are just treated as their
+                        * base pointer type */
+                       at.is_array = 0;
+
+                       /* check for the c style int func(void) and error
+                        * on other uses of arguments of type void */
+                       if (at.type == VOID_TYPE && at.pointers == 0) {
+                               if (args) {
+                                       cp_error("can't have argument of type "
+                                                       "void on line %d",
+                                                       P->line);
+                               }
+
+                               check_token(P, TOK_CLOSE_PAREN, "",
+                                       "unexpected void in function on line 
%d",
+                                       P->line);
+                               break;
+                       }
+                       cp_push_ctype(&at);
+                       args++;
+               } else {
+                       cp_error("unexpected token in function argument %d "
+                                       "on line %d", args+1, P->line);
+               }
+       }
+}
+
+static int max_bitfield_size(int type)
+{
+       switch (type) {
+       case BOOL_TYPE:
+               return 1;
+       case INT8_TYPE:
+               return 8;
+       case INT16_TYPE:
+               return 16;
+       case INT32_TYPE:
+       case ENUM_TYPE:
+               return 32;
+       case INT64_TYPE:
+               return 64;
+       default:
+               return -1;
+       }
+}
+
+static struct cp_ctype *parse_argument2(struct parser *P, struct cp_ctype *ct,
+               struct token *name, struct parser *asmname);
+
+/* parses from after the first ( in a function declaration or function pointer
+ * can be one of:
+ * void foo(...) before ...
+ * void (foo)(...) before foo
+ * void (* <>)(...) before <> which is the inner type */
+static struct cp_ctype *parse_function(struct parser *P, struct cp_ctype *ct,
+                               struct token *name, struct parser *asmname)
+{
+       /* We have a function pointer or a function. The usr table will
+        * get replaced by the canonical one (if there is one) in
+        * find_canonical_usr after all the arguments and returns have
+        * been parsed. */
+       struct token tok;
+       struct cp_ctype *ret = ct;
+
+       cp_push_ctype(ct);
+
+       memset(ct, 0, sizeof(*ct));
+       ct->base_size = sizeof(void (*)());
+       ct->align_mask = min(FUNCTION_ALIGN_MASK, P->align_mask);
+       ct->type = FUNCTION_TYPE;
+       ct->is_defined = 1;
+
+       if (name->type == TOK_NIL) {
+               for (;;) {
+                       require_token(P, &tok);
+
+                       if (tok.type == TOK_STAR) {
+                               if (ct->type == FUNCTION_TYPE) {
+                                       ct->type = FUNCTION_PTR_TYPE;
+                               } else {
+                                       increase_ptr_deref_level(P, ct);
+                               }
+                       } else if (parse_attribute(P, &tok, ct, asmname)) {
+                               /* parse_attribute sets the appropriate fields 
*/
+                       } else {
+                               /* call parse_argument to handle the inner
+                                * contents e.g. the <> in "void (* <>)
+                                * (...)". Note that the inner contents can
+                                * itself be a function, a function ptr,
+                                * array, etc (e.g. "void (*signal(int sig,
+                                * void (*func)(int)))(int)" ). */
+                               cp_error("TODO: inner function not supported 
for now.");
+                               put_back(P);
+                               ct = parse_argument2(P, ct, name, asmname);
+                               break;
+                       }
+               }
+
+               check_token(P, TOK_CLOSE_PAREN, NULL,
+                       "unexpected token in function on line %d", P->line);
+               check_token(P, TOK_OPEN_PAREN, NULL,
+                       "unexpected token in function on line %d", P->line);
+       }
+
+       parse_function_arguments(P, ct);
+
+       /*@TODO support for inner function  24.11 2013 (houqp)*/
+       /* if we have an inner function then set the outer function ptr as its
+        * return type and return the inner function
+        * e.g. for void (* <signal(int, void (*)(int))> )(int) inner is
+        * surrounded by <>, return type is void (*)(int) */
+
+       return ret;
+}
+
+static struct cp_ctype *parse_argument2(struct parser *P, struct cp_ctype *ct,
+                               struct token *name, struct parser *asmname)
+{
+       struct token tok;
+
+       for (;;) {
+               if (!next_token(P, &tok)) {
+                       /* we've reached the end of the string */
+                       break;
+               } else if (tok.type == TOK_STAR) {
+                       increase_ptr_deref_level(P, ct);
+
+                       /* __declspec(align(#)) may come before the type in a
+                        * member */
+                       if (!ct->is_packed) {
+                               ct->align_mask = max(min(PTR_ALIGN_MASK, 
P->align_mask),
+                                                       ct->align_mask);
+                       }
+               } else if (tok.type == TOK_REFERENCE) {
+                       cp_error("NYI: c++ reference types");
+                       return 0;
+               } else if (parse_attribute(P, &tok, ct, asmname)) {
+                       /* parse attribute has filled out appropriate fields in 
type */
+
+               } else if (tok.type == TOK_OPEN_PAREN) {
+                       ct = parse_function(P, ct, name, asmname);
+                       /*ft_usr = lua_gettop(L);*/
+               } else if (tok.type == TOK_OPEN_SQUARE) {
+                       /* array */
+                       if (ct->pointers == POINTER_MAX) {
+                               cp_error("maximum number of pointer derefs "
+                                       "reached - use a struct to break up "
+                                       "the pointers");
+                       }
+                       ct->is_array = 1;
+                       ct->pointers++;
+                       ct->const_mask <<= 1;
+                       require_token(P, &tok);
+
+                       if (ct->pointers == 1 && !ct->is_defined) {
+                               cp_error("array of undefined type on line %d",
+                                               P->line);
+                       }
+
+                       if (ct->is_variable_struct || ct->is_variable_array) {
+                               cp_error("can't have an array of a variably "
+                                       "sized type on line %d", P->line);
+                       }
+
+                       if (tok.type == TOK_QUESTION) {
+                               ct->is_variable_array = 1;
+                               ct->variable_increment = (ct->pointers > 1) ?
+                                               sizeof(void*) : ct->base_size;
+                               check_token(P, TOK_CLOSE_SQUARE, "",
+                                       "invalid character in array on line %d",
+                                       P->line);
+
+                       } else if (tok.type == TOK_CLOSE_SQUARE) {
+                               ct->array_size = 0;
+
+                       } else if (tok.type == TOK_TOKEN && IS_RESTRICT(tok)) {
+                               /* odd gcc extension foo[__restrict] for 
arguments */
+                               ct->array_size = 0;
+                               check_token(P, TOK_CLOSE_SQUARE, "",
+                                       "invalid character in array on line %d",
+                                       P->line);
+                       } else {
+                               int64_t asize;
+                               put_back(P);
+                               asize = calculate_constant(P);
+                               if (asize < 0) {
+                                       cp_error("array size can not be "
+                                               "negative on line %d", P->line);
+                                       return 0;
+                               }
+                               ct->array_size = (size_t) asize;
+                               check_token(P, TOK_CLOSE_SQUARE, "",
+                                       "invalid character in array on line %d",
+                                       P->line);
+                       }
+
+               } else if (tok.type == TOK_COLON) {
+                       int64_t bsize = calculate_constant(P);
+
+                       if (ct->pointers || bsize < 0
+                                       || bsize > max_bitfield_size(ct->type)) 
{
+                               cp_error("invalid bitfield on line %d", 
P->line);
+                       }
+
+                       ct->is_bitfield = 1;
+                       ct->bit_size = (unsigned) bsize;
+
+               } else if (tok.type != TOK_TOKEN) {
+                       /* we've reached the end of the declaration */
+                       put_back(P);
+                       break;
+
+               } else if (IS_CONST(tok)) {
+                       ct->const_mask |= 1;
+
+               } else if (IS_VOLATILE(tok) || IS_RESTRICT(tok)) {
+                       /* ignored for now */
+
+               } else {
+                       *name = tok;
+               }
+       }
+
+       return ct;
+}
+
+
+
+/* parses after the main base type of a typedef, function argument or
+ * struct/union member
+ * eg for const void* bar[3] the base type is void with the subtype so far of
+ * const, this parses the "* bar[3]" and updates the type argument
+ *
+ * type must be as filled out by parse_type
+ *
+ * pushes the updated user value on the top of the stack
+ */
+void parse_argument(struct parser *P, struct cp_ctype *ct, struct token *pname,
+                       struct parser *asmname)
+{
+       struct token tok, name;
+
+       memset(&name, 0, sizeof(name));
+       parse_argument2(P, ct, &name, asmname);
+
+       for (;;) {
+               if (!next_token(P, &tok)) {
+                       break;
+               } else if (parse_attribute(P, &tok, ct, asmname)) {
+                       /* parse_attribute sets the appropriate fields */
+               } else {
+                       put_back(P);
+                       break;
+               }
+       }
+
+#if 0
+       if (lua_gettop(L) == top) {
+               lua_pushvalue(L, ct_usr);
+       }
+
+       find_canonical_usr(L, -1, ct);
+#endif
+
+       if (pname) {
+               *pname = name;
+       }
+}
+
+static void parse_typedef(struct parser *P)
+{
+       struct token tok;
+       struct cp_ctype base_type;
+       char typedef_name[MAX_TYPE_NAME_LEN];
+
+       parse_type(P, &base_type);
+
+       for (;;) {
+               struct cp_ctype arg_type = base_type;
+               struct token name;
+
+               memset(&name, 0, sizeof(name));
+
+               parse_argument(P, &arg_type, &name, NULL);
+
+               if (!name.size) {
+                       cp_error("Can't have a typedef without a name on line 
%d",
+                                       P->line);
+               } else if (arg_type.is_variable_array) {
+                       cp_error("Can't typedef a variable length array on line 
%d",
+                                       P->line);
+               }
+
+               memset(typedef_name, 0, sizeof(typedef_name));
+               strncpy(typedef_name, name.str, name.size);
+               /* link typedef name with ctype for parser */
+               cp_ctype_reg_type(typedef_name, &arg_type);
+
+               require_token(P, &tok);
+
+               if (tok.type == TOK_SEMICOLON) {
+                       break;
+               } else if (tok.type != TOK_COMMA) {
+                       cp_error("Unexpected character in typedef on line %d",
+                                       P->line);
+               }
+       }
+}
+
+#define END 0
+#define PRAGMA_POP 1
+
+static int parse_root(struct parser *P)
+{
+       struct token tok;
+
+       while (next_token(P, &tok)) {
+               /* we can have:
+                * struct definition
+                * enum definition
+                * union definition
+                * struct/enum/union declaration
+                * typedef
+                * function declaration
+                * pragma pack
+                */
+
+               if (tok.type == TOK_SEMICOLON) {
+                       /* empty semicolon in root continue on */
+
+               } else if (tok.type == TOK_POUND) {
+
+                       check_token(P, TOK_TOKEN, "pragma",
+                               "unexpected pre processor directive on line %d",
+                               P->line);
+                       check_token(P, TOK_TOKEN, "pack",
+                               "unexpected pre processor directive on line %d",
+                               P->line);
+                       check_token(P, TOK_OPEN_PAREN, "",
+                               "invalid pack directive on line %d",
+                               P->line);
+                       require_token(P, &tok);
+
+                       if (tok.type == TOK_NUMBER) {
+                               if (tok.integer != 1 && tok.integer != 2
+                                               && tok.integer != 4
+                                               && tok.integer != 8
+                                               && tok.integer != 16) {
+                                       cp_error("pack directive with invalid "
+                                                       "pack size on line %d",
+                                                       P->line);
+                                       return 0;
+                               }
+
+                               P->align_mask = (unsigned) (tok.integer - 1);
+                               check_token(P, TOK_CLOSE_PAREN, "",
+                                       "invalid pack directive on line %d",
+                                       P->line);
+                       } else if (tok.type == TOK_TOKEN && IS_LITERAL(tok, 
"push")) {
+                               /*int line = P->line;*/
+                               unsigned previous_alignment = P->align_mask;
+
+                               check_token(P, TOK_CLOSE_PAREN, "",
+                                       "invalid pack directive on line %d",
+                                       P->line);
+
+                               if (parse_root(P) != PRAGMA_POP) {
+                                       cp_error("reached end of string "
+                                               "without a pragma pop to "
+                                               "match the push on line %d",
+                                               P->line);
+                                       return 0;
+                               }
+
+                               P->align_mask = previous_alignment;
+
+                       } else if (tok.type == TOK_TOKEN && IS_LITERAL(tok, 
"pop")) {
+                               check_token(P, TOK_CLOSE_PAREN, "",
+                                       "invalid pack directive on line %d",
+                                               P->line);
+                               return PRAGMA_POP;
+                       } else {
+                               cp_error("invalid pack directive on line %d",
+                                               P->line);
+                               return 0;
+                       }
+               } else if (tok.type != TOK_TOKEN) {
+                       cp_error("unexpected character on line %d", P->line);
+                       return 0;
+               } else if (IS_LITERAL(tok, "__extension__")) {
+                       /* ignore */
+                       continue;
+               } else if (IS_LITERAL(tok, "extern")) {
+                       /* ignore extern as data and functions can only be
+                        * extern */
+                       continue;
+               } else if (IS_LITERAL(tok, "typedef")) {
+                       parse_typedef(P);
+               } else if (IS_LITERAL(tok, "static")) {
+                       /*@TODO we haven't tested static so far */
+                       cp_error("TODO: support static keyword.\n");
+
+#if 0
+                       struct cp_ctype at;
+                       int64_t val;
+
+                       require_token(P, &tok);
+                       if (!IS_CONST(tok)) {
+                               cp_error("expected 'static const int' on line 
%d",
+                                               P->line);
+                               return 0;
+                       }
+
+                       parse_type(P, &at);
+
+                       require_token(P, &tok);
+                       if (tok.type != TOK_TOKEN) {
+                               cp_error("expected constant name after 'static "
+                                       "const int' on line %d", P->line);
+                               return 0;
+                       }
+
+                       check_token(P, TOK_ASSIGN, "",
+                                       "expected = after 'static const int "
+                                       "<name>' on line %d", P->line);
+
+                       val = calculate_constant(P);
+
+                       check_token(P, TOK_SEMICOLON, "",
+                                       "expected ; after 'static const int' "
+                                       "definition on line %d", P->line);
+                       push_upval(L, &constants_key);
+                       lua_pushlstring(L, tok.str, tok.size);
+                       switch (at.type) {
+                               case INT8_TYPE:
+                               case INT16_TYPE:
+                               case INT32_TYPE:
+                                       if (at.is_unsigned) {
+                                               assert(0);
+                                               /*lua_pushnumber(L, (unsigned 
int) val);*/
+                                       } else {
+                                               assert(0);
+                                               /*lua_pushnumber(L, (int) 
val);*/
+                                       }
+                                       break;
+
+                               default:
+                                       cp_error("expected a valid 8-, 16-, or "
+                                               "32-bit signed or unsigned "
+                                               "integer type after 'static "
+                                               "const' on line %d", P->line);
+                       }
+                       lua_rawset(L, -3);
+                       lua_pop(L, 2); /*constants and type*/
+#endif
+               } else {
+                       /* type declaration, type definition, or function
+                        * declaration */
+                       struct cp_ctype type;
+                       struct token name;
+                       struct parser asmname;
+
+                       memset(&name, 0, sizeof(name));
+                       memset(&asmname, 0, sizeof(asmname));
+
+                       put_back(P);
+                       parse_type(P, &type);
+
+                       for (;;) {
+                               parse_argument(P, &type, &name, &asmname);
+
+                               if (name.size) {
+                                       /* global/function declaration */
+                                       cp_symbol_build_func(name.str, 
name.size);
+                                       /* @TODO asmname is not used for now
+                                        * since we are not supporting __asm__
+                                        * as this point.
+                                        * might need to bind it with function
+                                        * name later. */
+                               } else {
+                                       /* type declaration/definition -
+                                        * already been processed */
+                               }
+                               require_token(P, &tok);
+
+                               if (tok.type == TOK_SEMICOLON) {
+                                       break;
+                               } else if (tok.type != TOK_COMMA) {
+                                       cp_error("missing semicolon on line %d",
+                                                       P->line);
+                               }
+                       }
+               }
+       }
+
+       return END;
+}
+
+static int64_t calculate_constant2(struct parser *P, struct token *tok);
+
+/* () */
+static int64_t calculate_constant1(struct parser *P, struct token *tok)
+{
+       int64_t ret;
+
+       if (tok->type == TOK_NUMBER) {
+               ret = tok->integer;
+               next_token(P, tok);
+               return ret;
+
+       } else if (tok->type == TOK_TOKEN) {
+               /* look up name in constants table */
+               cp_error("TODO: support name lookup in constant table\n");
+#if 0
+               push_upval(L, &constants_key);
+               lua_pushlstring(L, tok->str, tok->size);
+               lua_rawget(L, -2);
+               lua_remove(L, -2); /* constants table */
+
+               if (!lua_isnumber(L, -1)) {
+                       lua_pushlstring(L, tok->str, tok->size);
+                       luaL_error(L, "use of undefined constant %s on line %d",
+                                       lua_tostring(L, -1), P->line);
+               }
+
+               ret = (int64_t) lua_tonumber(L, -1);
+               lua_pop(L, 1);
+#endif
+               next_token(P, tok);
+               return ret;
+
+       } else if (tok->type == TOK_OPEN_PAREN) {
+               struct parser before_cast = *P;
+               cp_error("TODO: handle open parent token in constant1\n");
+#if 0
+               int top = lua_gettop(L);
+
+               /* see if this is a numeric cast, which we ignore */
+               lua_pushcfunction(L, &try_cast);
+               lua_pushlightuserdata(L, P);
+               if (!lua_pcall(L, 1, 0, 0)) {
+                       next_token(L, P, tok);
+                       return calculate_constant2(L, P, tok);
+               }
+               lua_settop(L, top);
+#endif
+               *P = before_cast;
+               ret = calculate_constant(P);
+
+               require_token(P, tok);
+               if (tok->type != TOK_CLOSE_PAREN) {
+                       cp_error("error whilst parsing constant at line %d",
+                                       P->line);
+               }
+
+               next_token(P, tok);
+               return ret;
+       } else {
+               cp_error("unexpected token whilst parsing constant at line %d",
+                               P->line);
+               return 0;
+       }
+}
+
+/* ! and ~, unary + and -, and sizeof */
+static int64_t calculate_constant2(struct parser *P, struct token *tok)
+{
+       if (tok->type == TOK_LOGICAL_NOT) {
+               require_token(P, tok);
+               return !calculate_constant2(P, tok);
+
+       } else if (tok->type == TOK_BITWISE_NOT) {
+               require_token(P, tok);
+               return ~calculate_constant2(P, tok);
+
+       } else if (tok->type == TOK_PLUS) {
+               require_token(P, tok);
+               return calculate_constant2(P, tok);
+
+       } else if (tok->type == TOK_MINUS) {
+               require_token(P, tok);
+               return -calculate_constant2(P, tok);
+
+       } else if (tok->type == TOK_TOKEN &&
+                       (IS_LITERAL(*tok, "sizeof")
+                        || IS_LITERAL(*tok, "alignof")
+                        || IS_LITERAL(*tok, "__alignof__")
+                        || IS_LITERAL(*tok, "__alignof"))) {
+               cp_error("TODO: support sizeof\n");
+               bool issize = IS_LITERAL(*tok, "sizeof");
+               struct cp_ctype type;
+
+               require_token(P, tok);
+               if (tok->type != TOK_OPEN_PAREN) {
+                       cp_error("invalid sizeof at line %d", P->line);
+               }
+
+               parse_type(P, &type);
+               parse_argument(P, &type, NULL, NULL);
+
+               require_token(P, tok);
+               if (tok->type != TOK_CLOSE_PAREN) {
+                       cp_error("invalid sizeof at line %d", P->line);
+               }
+
+               next_token(P, tok);
+
+               return issize ? ctype_size(&type) : type.align_mask + 1;
+
+       } else {
+               return calculate_constant1(P, tok);
+       }
+}
+
+/* binary * / and % (left associative) */
+static int64_t calculate_constant3(struct parser *P, struct token *tok)
+{
+       int64_t left = calculate_constant2(P, tok);
+
+       for (;;) {
+               if (tok->type == TOK_MULTIPLY) {
+                       require_token(P, tok);
+                       left *= calculate_constant2(P, tok);
+
+               } else if (tok->type == TOK_DIVIDE) {
+                       require_token(P, tok);
+                       left /= calculate_constant2(P, tok);
+
+               } else if (tok->type == TOK_MODULUS) {
+                       require_token(P, tok);
+                       left %= calculate_constant2(P, tok);
+
+               } else {
+                       return left;
+               }
+       }
+}
+
+/* binary + and - (left associative) */
+static int64_t calculate_constant4(struct parser *P, struct token *tok)
+{
+       int64_t left = calculate_constant3(P, tok);
+
+       for (;;) {
+               if (tok->type == TOK_PLUS) {
+                       require_token(P, tok);
+                       left += calculate_constant3(P, tok);
+
+               } else if (tok->type == TOK_MINUS) {
+                       require_token(P, tok);
+                       left -= calculate_constant3(P, tok);
+
+               } else {
+                       return left;
+               }
+       }
+}
+
+/* binary << and >> (left associative) */
+static int64_t calculate_constant5(struct parser *P, struct token *tok)
+{
+       int64_t left = calculate_constant4(P, tok);
+
+       for (;;) {
+               if (tok->type == TOK_LEFT_SHIFT) {
+                       require_token(P, tok);
+                       left <<= calculate_constant4(P, tok);
+
+               } else if (tok->type == TOK_RIGHT_SHIFT) {
+                       require_token(P, tok);
+                       left >>= calculate_constant4(P, tok);
+
+               } else {
+                       return left;
+               }
+       }
+}
+
+/* binary <, <=, >, and >= (left associative) */
+static int64_t calculate_constant6(struct parser *P, struct token *tok)
+{
+       int64_t left = calculate_constant5(P, tok);
+
+       for (;;) {
+               if (tok->type == TOK_LESS) {
+                       require_token(P, tok);
+                       left = (left < calculate_constant5(P, tok));
+
+               } else if (tok->type == TOK_LESS_EQUAL) {
+                       require_token(P, tok);
+                       left = (left <= calculate_constant5(P, tok));
+
+               } else if (tok->type == TOK_GREATER) {
+                       require_token(P, tok);
+                       left = (left > calculate_constant5(P, tok));
+
+               } else if (tok->type == TOK_GREATER_EQUAL) {
+                       require_token(P, tok);
+                       left = (left >= calculate_constant5(P, tok));
+
+               } else {
+                       return left;
+               }
+       }
+}
+
+/* binary ==, != (left associative) */
+static int64_t calculate_constant7(struct parser *P, struct token *tok)
+{
+       int64_t left = calculate_constant6(P, tok);
+
+       for (;;) {
+               if (tok->type == TOK_EQUAL) {
+                       require_token(P, tok);
+                       left = (left == calculate_constant6(P, tok));
+
+               } else if (tok->type == TOK_NOT_EQUAL) {
+                       require_token(P, tok);
+                       left = (left != calculate_constant6(P, tok));
+
+               } else {
+                       return left;
+               }
+       }
+}
+
+/* binary & (left associative) */
+static int64_t calculate_constant8(struct parser *P, struct token *tok)
+{
+       int64_t left = calculate_constant7(P, tok);
+
+       for (;;) {
+               if (tok->type == TOK_BITWISE_AND) {
+                       require_token(P, tok);
+                       left = (left & calculate_constant7(P, tok));
+
+               } else {
+                       return left;
+               }
+       }
+}
+
+/* binary ^ (left associative) */
+static int64_t calculate_constant9(struct parser *P, struct token *tok)
+{
+       int64_t left = calculate_constant8(P, tok);
+
+       for (;;) {
+               if (tok->type == TOK_BITWISE_XOR) {
+                       require_token(P, tok);
+                       left = (left ^ calculate_constant8(P, tok));
+
+               } else {
+                       return left;
+               }
+       }
+}
+
+/* binary | (left associative) */
+static int64_t calculate_constant10(struct parser *P, struct token *tok)
+{
+       int64_t left = calculate_constant9(P, tok);
+
+       for (;;) {
+               if (tok->type == TOK_BITWISE_OR) {
+                       require_token(P, tok);
+                       left = (left | calculate_constant9(P, tok));
+
+               } else {
+                       return left;
+               }
+       }
+}
+
+/* binary && (left associative) */
+static int64_t calculate_constant11(struct parser *P, struct token *tok)
+{
+       int64_t left = calculate_constant10(P, tok);
+
+       for (;;) {
+               if (tok->type == TOK_LOGICAL_AND) {
+                       require_token(P, tok);
+                       left = (left && calculate_constant10(P, tok));
+
+               } else {
+                       return left;
+               }
+       }
+}
+
+/* binary || (left associative) */
+static int64_t calculate_constant12(struct parser *P, struct token *tok)
+{
+       int64_t left = calculate_constant11(P, tok);
+
+       for (;;) {
+               if (tok->type == TOK_LOGICAL_OR) {
+                       require_token(P, tok);
+                       left = (left || calculate_constant11(P, tok));
+
+               } else {
+                       return left;
+               }
+       }
+}
+
+/* ternary ?: (right associative) */
+static int64_t calculate_constant13(struct parser *P, struct token *tok)
+{
+       int64_t left = calculate_constant12(P, tok);
+
+       if (tok->type == TOK_QUESTION) {
+               int64_t middle, right;
+               require_token(P, tok);
+               middle = calculate_constant13(P, tok);
+               if (tok->type != TOK_COLON) {
+                       cp_error("invalid ternery (? :) in constant on line %d",
+                                       P->line);
+               }
+               require_token(P, tok);
+               right = calculate_constant13(P, tok);
+               return left ? middle : right;
+
+       } else {
+               return left;
+       }
+}
+
+int64_t calculate_constant(struct parser* P)
+{
+       struct token tok;
+       int64_t ret;
+       require_token(P, &tok);
+       ret = calculate_constant13(P, &tok);
+
+       if (tok.type != TOK_NIL) {
+               put_back(P);
+       }
+
+       return ret;
+}
+
+int ffi_cdef(char *s)
+{
+       struct parser P;
+
+       memset(&P, 0, sizeof(struct parser));
+       P.line = 1;
+       P.prev = P.next = s;
+       P.align_mask = DEFAULT_ALIGN_MASK;
+
+       if (parse_root(&P) == PRAGMA_POP) {
+               cp_error("pragma pop without an associated push on line %d",
+                               P.line);
+       }
+
+       return 0;
+}
+
+void ffi_cparser_init(void)
+{
+       cp_ctype_init();
+}
+
+void ffi_cparser_free(void)
+{
+       cp_ctype_free();
+}
diff --git a/userspace/ffi/ctype.c b/userspace/ffi/ctype.c
new file mode 100644
index 0000000..7509976
--- /dev/null
+++ b/userspace/ffi/ctype.c
@@ -0,0 +1,541 @@
+#include "../../include/ktap_types.h"
+#include "../../include/ktap_opcodes.h"
+#include "../ktapc.h"
+#include "../cparser.h"
+
+
+/* for ktap vm */
+cp_csymbol_state csym_state;
+
+#define cs_nr (csym_state.cs_nr)
+#define cs_arr_size (csym_state.cs_arr_size)
+#define cs_arr (csym_state.cs_arr)
+
+csymbol *cp_id_to_csym(int id)
+{
+       return &cs_arr[id];
+}
+
+
+typedef struct cp_ctype_entry {
+       char name[MAX_TYPE_NAME_LEN];
+       struct cp_ctype ct;
+} cp_ctype_entry;
+
+#define DEFAULT_CTYPE_ARR_SIZE 100
+static int cte_nr;
+static int cte_arr_size;
+static cp_ctype_entry *cte_arr;
+
+
+/* stack to help maintain state during parsing */
+typedef struct cp_ctype_stack {
+       int size;
+       int top;
+       cp_ctype_entry *stack;
+} ctype_stack;
+
+
+static ctype_stack cts;
+
+#define ct_stack(id) (&(cts.stack[id]))
+#define ct_stack_ct(id) (&(cts.stack[id].ct))
+
+
+
+int cp_ctype_reg_csymbol(csymbol *cs);
+
+
+size_t ctype_size(const struct cp_ctype *ct)
+{
+       if (ct->pointers - ct->is_array) {
+               return sizeof(void*) * (ct->is_array ? ct->array_size : 1);
+
+       } else if (!ct->is_defined || ct->type == VOID_TYPE) {
+               cp_error("can't calculate size of an undefined type");
+               return 0;
+       } else if (ct->variable_size_known) {
+               assert(ct->is_variable_struct && !ct->is_array);
+               return ct->base_size + ct->variable_increment;
+       } else if (ct->is_variable_array || ct->is_variable_struct) {
+               cp_error("internal error: calc size of variable type with "
+                               "unknown size");
+               return 0;
+       } else {
+               return ct->base_size * (ct->is_array ? ct->array_size : 1);
+       }
+}
+
+#define MAX_STACK_SIZE 100
+int ctype_stack_grow(int size)
+{
+       struct cp_ctype_entry *new_st;
+
+       assert(cts.size + size < MAX_STACK_SIZE);
+
+       new_st = realloc(cts.stack, (cts.size+size)*sizeof(cp_ctype_entry));
+       if (new_st)
+               cts.stack = new_st;
+       else
+               return -1;
+
+       cts.size += size;
+
+       return size;
+}
+
+int ctype_stack_free_space()
+{
+       return cts.size - cts.top;
+}
+
+void ctype_stack_reset()
+{
+       cts.top = 0;
+}
+
+/* push ctype to stack, create new csymbol if needed */
+void cp_push_ctype_with_name(struct cp_ctype *ct, const char *name, int nlen)
+{
+       int i;
+       struct cp_ctype *nct;
+
+       if (ctype_stack_free_space() < 1)
+               ctype_stack_grow(4);
+
+       /* we have to check pointer here because does type lookup by name
+        * before parsing '*', and for pointers, ct will always be the
+        * original type */
+       if (ct->pointers) {
+               for (i = 0; i < cte_nr; i++) {
+                       nct = &(cte_arr[i].ct);
+                       if (nct->type == ct->type &&
+                                       nct->pointers == ct->pointers) {
+                               break;
+                       }
+               }
+
+               if (i == cte_nr) {
+                       /* pointer type not found
+                        * create a new pointer symbol for this type */
+                       /* associate ctype with new csymbol */
+                       ct->ffi_cs_id = cp_symbol_build_pointer(ct);
+                       /* register wit new pointer name */
+                       cp_ctype_reg_type(csym_name(ct_ffi_cs(ct)), ct);
+               } else {
+                       /* pointer type already registered, reinstantiate ct */
+                       *ct = cte_arr[i].ct;
+               }
+       }
+       memset(ct_stack(cts.top), 0, sizeof(cp_ctype_entry));
+       ct_stack(cts.top)->ct = *ct;
+       if (name)
+               strncpy(ct_stack(cts.top)->name, name, nlen);
+       cts.top++;
+}
+
+void cp_push_ctype(struct cp_ctype *ct)
+{
+       cp_push_ctype_with_name(ct, NULL, 0);
+}
+
+void cp_set_defined(struct cp_ctype *ct)
+{
+       ct->is_defined = 1;
+
+       /* @TODO: update ctypes and cdatas that were created before the
+        * definition came in */
+}
+
+void cp_ctype_dump_stack()
+{
+       int i;
+       struct cp_ctype *ct;
+
+       printf("---------------------------\n");
+       printf("start of ctype stack (%d) dump: \n", cts.top);
+       for (i = 0; i < cts.top; i++) {
+               ct = ct_stack_ct(i);
+               printf("[%d] -> cp_ctype: %d, sym_type: %d, pointer: %d "
+                       "symbol_id: %d, name: %s\n",
+                       i, ct->type,
+                       csym_type(ct_ffi_cs(ct)), ct->pointers, ct->ffi_cs_id,
+                       ct_stack(i)->name);
+       }
+}
+
+int ctype_reg_table_grow()
+{
+       cp_ctype_entry *new_arr;
+
+       new_arr = realloc(cte_arr, sizeof(cp_ctype_entry)*cte_arr_size*2);
+       if (!new_arr)
+               cp_error("failed to allocate memory for ctype array\n");
+
+       cte_arr_size = cte_arr_size * 2;
+       return 0;
+}
+
+/* return index in csymbol array */
+int cp_ctype_reg_csymbol(csymbol *cs)
+{
+       if (cs_nr >= cs_arr_size) {
+               cs_arr_size *= 2;
+               cs_arr = realloc(cs_arr, cs_arr_size*sizeof(csymbol));
+               if (!cs_arr)
+                       cp_error("failed to extend csymbol array!\n");
+       }
+
+       cs_arr[cs_nr] = *cs;
+       cs_nr++;
+
+       return cs_nr-1;
+}
+
+void __cp_symbol_dump_struct(csymbol *cs)
+{
+       int i;
+       csymbol *ncs;
+       csymbol_struct *stcs = csym_struct(cs);
+
+       printf("=== [%s] definition ==================\n", csym_name(cs));
+       for (i = 0; i < stcs->memb_nr; i++) {
+               printf("\t(%d) ", i);
+               printf("csym_id: %d, ", stcs->members[i].id);
+               ncs = &cs_arr[stcs->members[i].id];
+               printf("name: %s, ffi_ctype: %d, %s\n",
+                       stcs->members[i].name, ncs->type, csym_name(ncs));
+       }
+}
+
+void cp_symbol_dump_struct(int id)
+{
+       __cp_symbol_dump_struct(&cs_arr[id]);
+}
+
+int cp_symbol_build_struct(const char *stname)
+{
+       int i, id, memb_size;
+       cp_ctype_entry *cte;
+       csymbol nst;
+       struct_member *st_membs;
+       csymbol_struct *stcs;
+
+       if (cts.top <= 0 || !stname) {
+               cp_error("invalid struct definition.\n");
+       }
+
+       memb_size = cts.top;
+       st_membs = malloc(memb_size*sizeof(struct_member));
+       if (!st_membs)
+               cp_error("failed to allocate memory for struct members.\n");
+       memset(st_membs, 0, memb_size*sizeof(struct_member));
+
+       nst.type = FFI_STRUCT;
+       strcpy(nst.name, stname);
+
+       stcs = csym_struct(&nst);
+       stcs->memb_nr = memb_size;
+       stcs->members = st_membs;
+
+       for (i = 0; i < memb_size; i++) {
+               assert(i < cts.top);
+               cte = ct_stack(i);
+               if (cte->name)
+                       strcpy(st_membs[i].name, cte->name);
+               st_membs[i].id = ct_stack_ct(i)->ffi_cs_id;
+       }
+
+       id = cp_ctype_reg_csymbol(&nst);
+
+       ctype_stack_reset();
+
+       return id;
+}
+
+/* build pointer symbol from given csymbol */
+int cp_symbol_build_pointer(struct cp_ctype *ct)
+{
+       int id, ret;
+       csymbol ncspt;
+       csymbol *ref_cs = ct_ffi_cs(ct);
+
+       /* TODO: Check correctness of multi-level pointer 24.11.2013(unihorn) */
+       memset(&ncspt, 0, sizeof(csymbol));
+       ncspt.type = FFI_PTR;
+       ret = sprintf(ncspt.name, "%s *", csym_name(ref_cs));
+       assert(ret < MAX_TYPE_NAME_LEN);
+
+       csym_set_ptr_deref(&ncspt, ct->ffi_cs_id);
+       id = cp_ctype_reg_csymbol(&ncspt);
+
+       return id;
+}
+
+void __cp_symbol_dump_func(csymbol *cs)
+{
+       int i;
+       csymbol *ncs;
+       csymbol_func *fcs = csym_func(cs);
+
+       printf("=== [%s] function definition =============\n", csym_name(cs));
+       ncs = cp_csymf_ret(fcs);
+       printf("address: %p\n", fcs->addr);
+       printf("return type: \n");
+       printf("\tcsym_id: %d, ffi_ctype: %d, %s\n",
+                       fcs->ret_id, ncs->type, csym_name(ncs));
+       printf("args type (%d): \n", fcs->arg_nr);
+       for (i = 0; i < csymf_arg_nr(fcs); i++) {
+           printf("\t (%d) ", i);
+           printf("csym_id: %d, ", fcs->arg_ids[i]);
+           ncs = cp_csymf_arg(fcs, i);
+           printf("ffi_ctype: %d, %s\n", ncs->type, csym_name(ncs));
+       }
+}
+
+void cp_symbol_dump_func(int id)
+{
+       __cp_symbol_dump_func(&cs_arr[id]);
+}
+
+int cp_symbol_build_func(const char *fname, int fn_size)
+{
+       int i = 1, arg_nr, id;
+       int *argsym_id_arr;
+       csymbol nfcs;
+       csymbol_func *fcs;
+
+       if (cts.top == 0 || fn_size < 0 || !fname) {
+               cp_error("invalid function definition.\n");
+       }
+
+       argsym_id_arr = NULL;
+       memset(&nfcs, 0, sizeof(csymbol));
+       csym_type(&nfcs) = FFI_FUNC;
+
+       strncpy(csym_name(&nfcs), fname, fn_size);
+
+       fcs = csym_func(&nfcs);
+       fcs->addr = (void *)find_kernel_symbol(csym_name(&nfcs));
+       if (!fcs->addr)
+               cp_error("wrong function address for %s\n", csym_name(&nfcs));
+
+       /* bottom of the stack is return type */
+       fcs->ret_id = ct_stack_ct(0)->ffi_cs_id;
+
+       /* the rest is argument type */
+       if (cts.top == 1) {
+               /* function takes no argument */
+               arg_nr = 0;
+       } else {
+               arg_nr = cts.top - 1;
+               argsym_id_arr = malloc(arg_nr * sizeof(int));
+               if (!argsym_id_arr)
+                       cp_error("failed to allocate memory for function 
args.\n");
+               for (i = 0; i < arg_nr; i++) {
+                       argsym_id_arr[i] = ct_stack_ct(i+1)->ffi_cs_id;
+               }
+       }
+       fcs->arg_nr = arg_nr;
+       fcs->arg_ids = argsym_id_arr;
+
+       id = cp_ctype_reg_csymbol(&nfcs);
+
+       /* clear stack since we have consumed all the ctypes */
+       ctype_stack_reset();
+
+       return id;
+}
+
+struct cp_ctype *cp_ctype_reg_type(char *name, struct cp_ctype *ct)
+{
+       if (cte_nr >= cte_arr_size)
+               ctype_reg_table_grow();
+
+       memset(cte_arr[cte_nr].name, 0, MAX_TYPE_NAME_LEN);
+       strcpy(cte_arr[cte_nr].name, name);
+
+       cte_arr[cte_nr].ct = *ct;
+       cte_nr++;
+
+       return &(cte_arr[cte_nr-1].ct);
+}
+
+#if 0
+/* TODO: used for size calculation */
+static ffi_type ffi_int_type(ktap_state *ks, int size, bool sign)
+{
+       switch(size) {
+       case 1:
+               if (!sign)
+                       return FFI_UINT8;
+               else
+                       return FFI_INT8;
+       case 2:
+               if (!sign)
+                       return FFI_UINT16;
+               else
+                       return FFI_INT16;
+       case 4:
+               if (!sign)
+                       return FFI_UINT32;
+               else
+                       return FFI_INT32;
+       case 8:
+               if (!sign)
+                       return FFI_UINT64;
+               else
+                       return FFI_INT64;
+       default:
+               kp_error(ks, "Error: Have not support int type of size %d\n", 
size);
+               return FFI_UNKNOWN;
+       }
+
+       /* NEVER reach here, silence compiler */
+       return -1;
+}
+#endif
+
+
+static inline void ct_set_type(struct cp_ctype *ct, int type, int is_unsigned)
+{
+       ct->type = type;
+       ct->is_unsigned = is_unsigned;
+}
+
+static void init_builtin_type(struct cp_ctype *ct, ffi_type ftype)
+{
+       csymbol cs;
+       int cs_id;
+
+       csym_type(&cs) = ftype;
+       strncpy(csym_name(&cs), ffi_type_name(ftype), CSYM_NAME_MAX_LEN);
+       cs_id = cp_ctype_reg_csymbol(&cs);
+
+       memset(ct, 0, sizeof(*ct));
+       ct->ffi_cs_id = cs_id;
+       switch (ftype) {
+       case FFI_VOID:          ct_set_type(ct, VOID_TYPE, 0); break;
+       case FFI_UINT8:         ct_set_type(ct, INT8_TYPE, 1); break;
+       case FFI_INT8:          ct_set_type(ct, INT8_TYPE, 0); break;
+       case FFI_UINT16:        ct_set_type(ct, INT16_TYPE, 1); break;
+       case FFI_INT16:         ct_set_type(ct, INT16_TYPE, 0); break;
+       case FFI_UINT32:        ct_set_type(ct, INT32_TYPE, 1); break;
+       case FFI_INT32:         ct_set_type(ct, INT32_TYPE, 0); break;
+       case FFI_UINT64:        ct_set_type(ct, INT64_TYPE, 1); break;
+       case FFI_INT64:         ct_set_type(ct, INT64_TYPE, 0); break;
+       default:                break;
+       }
+       ct->base_size = ffi_type_size(ftype);
+       ct->align_mask = ffi_type_align(ftype) - 1;
+       ct->is_defined = 1;
+}
+
+/* lookup and register builtin C type on demand */
+struct cp_ctype *ctype_lookup_builtin_type(char *name)
+{
+       struct cp_ctype ct;
+
+       if (!strncmp(name, "void", sizeof("void"))) {
+               init_builtin_type(&ct, FFI_VOID);
+               return cp_ctype_reg_type("void", &ct);
+       } else if (!strncmp(name, "int8_t", sizeof("int8_t"))) {
+               init_builtin_type(&ct, FFI_INT8);
+               return cp_ctype_reg_type("int8_t", &ct);
+       } else if (!strncmp(name, "uint8_t", sizeof("uint8_t"))) {
+               init_builtin_type(&ct, FFI_UINT8);
+               return cp_ctype_reg_type("uint8_t", &ct);
+       } else if (!strncmp(name, "int16_t", sizeof("int16_t"))) {
+               init_builtin_type(&ct, FFI_INT16);
+               return cp_ctype_reg_type("int16_t", &ct);
+       } else if (!strncmp(name, "uint16_t", sizeof("uint16_t"))) {
+               init_builtin_type(&ct, FFI_UINT16);
+               return cp_ctype_reg_type("uint16_t", &ct);
+       } else if (!strncmp(name, "int32_t", sizeof("int32_t"))) {
+               init_builtin_type(&ct, FFI_INT32);
+               return cp_ctype_reg_type("int32_t", &ct);
+       } else if (!strncmp(name, "uint32_t", sizeof("uint32_t"))) {
+               init_builtin_type(&ct, FFI_UINT32);
+               return cp_ctype_reg_type("uint32_t", &ct);
+       } else if (!strncmp(name, "int64_t", sizeof("int64_t"))) {
+               init_builtin_type(&ct, FFI_INT64);
+               return cp_ctype_reg_type("int64_t", &ct);
+       } else if (!strncmp(name, "uint64_t", sizeof("uint64_t"))) {
+               init_builtin_type(&ct, FFI_UINT64);
+               return cp_ctype_reg_type("uint64_t", &ct);
+       } else {
+               /* no builtin type matched */
+               return NULL;
+       }
+}
+
+/* start ctype reg table */
+struct cp_ctype *ctype_lookup_type(char *name)
+{
+       int i;
+       struct cp_ctype *ct;
+
+       for (i = 0; i < cte_nr; i++) {
+               ct = &cte_arr[i].ct;
+               if (!strcmp(name, cte_arr[i].name))
+                       return ct;
+       }
+
+       /* see if it's a builtin C type
+        * return NULL if still no match */
+       return ctype_lookup_builtin_type(name);
+}
+
+cp_csymbol_state *ctype_get_csym_state(void)
+{
+       return &csym_state;
+}
+
+#define DEFAULT_STACK_SIZE 20
+#define DEFAULT_SYM_ARR_SIZE 20
+int cp_ctype_init()
+{
+       cts.size = DEFAULT_STACK_SIZE;
+       cts.top = 0;
+       cts.stack = malloc(sizeof(cp_ctype_entry)*DEFAULT_STACK_SIZE);
+
+       cs_nr = 0;
+       cs_arr_size = DEFAULT_SYM_ARR_SIZE;
+       cs_arr = malloc(sizeof(csymbol)*DEFAULT_SYM_ARR_SIZE);
+       memset(cs_arr, 0, sizeof(csymbol)*DEFAULT_SYM_ARR_SIZE);
+
+       cte_nr = 0;
+       cte_arr_size = DEFAULT_CTYPE_ARR_SIZE;
+       cte_arr = malloc(sizeof(cp_ctype_entry)*DEFAULT_CTYPE_ARR_SIZE);
+
+       return 0;
+}
+
+int cp_ctype_free()
+{
+       int i;
+       csymbol *cs;
+
+       if (cts.stack)
+               free(cts.stack);
+
+       if (cs_arr) {
+               for (i = 0; i < cs_nr; i++) {
+                       cs = &cs_arr[i];
+                       if (csym_type(cs) == FFI_FUNC) {
+                               if (csym_func(cs)->arg_ids)
+                                       free(csym_func(cs)->arg_ids);
+                       } else if (csym_type(cs) == FFI_STRUCT) {
+                               if (csym_struct(cs)->members)
+                                       free(csym_struct(cs)->members);
+                       }
+               }
+               free(cs_arr);
+       }
+
+       if (cte_arr) {
+               free(cte_arr);
+       }
+
+       return 0;
+}
-- 
1.8.1.2


Other related posts:

  • » [ktap] [PATCHv3 2/8] Cparser to parse C declareation - Qingping Hou