void kp_cdata_ptr_set(ktap_state_t *ks, ktap_cdata_t *cd, ktap_val_t *key, ktap_val_t *val) { ktap_number idx; csymbol *cs; size_t size; char *addr; if (!is_number(key)) { kp_error(ks, "array index should be number\n"); return; } idx = nvalue(key); if (unlikely(idx < 0 || (cd_ptr_nmemb(cd) >= 0 && idx >= cd_ptr_nmemb(cd)))) { kp_error(ks, "array index out of bound\n"); return; } cs = csym_ptr_deref(ks, cd_csym(ks, cd)); if (kp_cdata_type_match(ks, cs, val)) { kp_error(ks, "array member should be %s type\n", csym_name(cs)); return; } size = csym_size(ks, cs); addr = cd_ptr(cd); addr += size * idx; kp_cdata_unpack(ks, addr, cs, val); }
void kp_cdata_ptr_get(ktap_state_t *ks, ktap_cdata_t *cd, ktap_val_t *key, ktap_val_t *val) { ktap_number idx; csymbol *cs; size_t size; char *addr; csymbol_id cs_id; if (!is_number(key)) { kp_error(ks, "array index should be number\n"); return; } idx = nvalue(key); if (unlikely(idx < 0 || (cd_ptr_nmemb(cd) >= 0 && idx >= cd_ptr_nmemb(cd)))) { kp_error(ks, "array index out of bound\n"); return; } cs_id = csym_ptr_deref_id(cd_csym(ks, cd)); cs = id_to_csym(ks, cs_id); size = csym_size(ks, cs); addr = cd_ptr(cd); addr += size * idx; kp_cdata_init(ks, val, addr, -1, cs_id); kp_cdata_pack(ks, val, addr, cs); }
static void kp_cdata_value(ktap_state_t *ks, ktap_val_t *val, void **out_addr, size_t *out_size, void **temp) { ktap_cdata_t *cd; csymbol *cs; ffi_type type; switch (ttypenv(val)) { case KTAP_TYPE_BOOLEAN: *out_addr = &bvalue(val); *out_size = sizeof(int); return; case KTAP_TYPE_LIGHTUSERDATA: *out_addr = pvalue(val); *out_size = sizeof(void *); return; case KTAP_TYPE_NUMBER: *out_addr = &nvalue(val); *out_size = sizeof(ktap_number); return; case KTAP_TYPE_STRING: *temp = (void *)svalue(val); *out_addr = temp; *out_size = sizeof(void *); return; } cd = cdvalue(val); cs = cd_csym(ks, cd); type = csym_type(cs); *out_size = csym_size(ks, cs); switch (type) { case FFI_VOID: kp_error(ks, "Error: Cannot copy data from void type\n"); return; case FFI_UINT8: case FFI_INT8: case FFI_UINT16: case FFI_INT16: case FFI_UINT32: case FFI_INT32: case FFI_UINT64: case FFI_INT64: *out_addr = &cd_int(cd); return; case FFI_PTR: *out_addr = &cd_ptr(cd); return; case FFI_STRUCT: case FFI_UNION: *out_addr = cd_record(cd); return; case FFI_FUNC: case FFI_UNKNOWN: kp_error(ks, "Error: internal error for csymbol %s\n", csym_name(cs)); return; } }
/* Check whether or not type is matched before packing */ void kp_cdata_pack(ktap_state_t *ks, ktap_val_t *val, char *src, csymbol *cs) { size_t size = csym_size(ks, cs), val_size; void *val_addr, *temp; kp_cdata_value(ks, val, &val_addr, &val_size, &temp); if (size > val_size) size = val_size; memmove(val_addr, src, size); memset(val_addr + size, 0, val_size - size); }
/* Check whether or not type is matched before unpacking */ void kp_cdata_unpack(ktap_state_t *ks, char *dst, csymbol *cs, ktap_val_t *val) { size_t size = csym_size(ks, cs), val_size; void *val_addr, *temp; kp_cdata_value(ks, val, &val_addr, &val_size, &temp); if (val_size > size) val_size = size; memmove(dst, val_addr, val_size); memset(dst + val_size, 0, size - val_size); }
static void ffi_unpack(ktap_state_t *ks, char *dst, csymbol_func *csf, int idx, int align) { StkId arg = kp_arg(ks, idx + 1); csymbol *cs = ffi_get_arg_csym(ks, csf, idx); size_t size = csym_size(ks, cs); /* initialize the destination section */ memset(dst, 0, ALIGN(size, align)); kp_cdata_unpack(ks, dst, cs, arg); }
ktap_cdata_t *kp_cdata_new_record(ktap_state_t *ks, void *val, csymbol_id id) { ktap_cdata_t *cd; size_t size; cd = kp_cdata_new(ks, id); /* if val == NULL, allocate new empty space */ if (val == NULL) { size = csym_size(ks, id_to_csym(ks, id)); cd_record(cd) = kp_rawobj_alloc(ks, size); } else cd_record(cd) = val; return cd; }
/* argument nmemb here indicates the length of array that is pointed to, * -1 for unknown */ ktap_cdata_t *kp_cdata_new_ptr(ktap_state_t *ks, void *addr, int nmemb, csymbol_id id, int to_allocate) { ktap_cdata_t *cd; size_t memb_size; csymbol_id deref_id; cd = kp_cdata_new(ks, id); if (to_allocate) { /* allocate new empty space */ deref_id = csym_ptr_deref_id(id_to_csym(ks, id)); memb_size = csym_size(ks, id_to_csym(ks, deref_id)); cd_ptr(cd) = kp_rawobj_alloc(ks, memb_size * nmemb); } else { cd_ptr(cd) = addr; } cd_ptr_nmemb(cd) = nmemb; return cd; }
static void ffi_call_x86_64(ktap_state_t *ks, csymbol_func *csf, void *rvalue) { int i; int gpr_nr; int arg_bytes; /* total bytes needed for exceeded args in stack */ int mem_bytes; /* total bytes needed for memory storage */ char *stack, *stack_p, *gpr_p, *arg_p, *mem_p, *tmp_p; int arg_nr; csymbol *rsym; ffi_type rtype; size_t rsize; bool ret_in_memory; /* New stack to call C function */ char space[NEWSTACK_SIZE]; arg_nr = kp_arg_nr(ks); rsym = csymf_ret(ks, csf); rtype = csym_type(rsym); rsize = csym_size(ks, rsym); ret_in_memory = false; if (rtype == FFI_STRUCT || rtype == FFI_UNION) { if (rsize > 16) { rvalue = kp_malloc(ks, rsize); rtype = FFI_VOID; ret_in_memory = true; } else { /* much easier to always copy 16 bytes from registers */ rvalue = kp_malloc(ks, 16); } } gpr_nr = 0; arg_bytes = mem_bytes = 0; if (ret_in_memory) gpr_nr++; /* calculate bytes needed for stack */ for (i = 0; i < arg_nr; i++) { csymbol *cs = ffi_get_arg_csym(ks, csf, i); size_t size = csym_size(ks, cs); size_t align = csym_align(ks, cs); enum arg_status st = IN_REGISTER; int n_gpr_nr = 0; if (size > 32) { st = IN_MEMORY; n_gpr_nr = 1; } else if (size > 16) st = IN_STACK; else n_gpr_nr = ALIGN(size, GPR_SIZE) / GPR_SIZE; if (gpr_nr + n_gpr_nr > MAX_GPR) { if (st == IN_MEMORY) arg_bytes += GPR_SIZE; else st = IN_STACK; } else gpr_nr += n_gpr_nr; if (st == IN_STACK) { arg_bytes = ALIGN(arg_bytes, align); arg_bytes += size; arg_bytes = ALIGN(arg_bytes, STACK_ALIGNMENT); } if (st == IN_MEMORY) { mem_bytes = ALIGN(mem_bytes, align); mem_bytes += size; mem_bytes = ALIGN(mem_bytes, STACK_ALIGNMENT); } } /* apply space to fake stack for C function call */ if (16 + REDZONE_SIZE + MAX_GPR_SIZE + arg_bytes + mem_bytes + 6 * 8 >= NEWSTACK_SIZE) { kp_error(ks, "Unable to handle that many arguments by now\n"); return; } stack = space; /* 128 bytes below %rsp is red zone */ /* stack should be 16-bytes aligned */ stack_p = ALIGN_STACK(stack + REDZONE_SIZE, 16); /* save general purpose registers here */ gpr_p = stack_p; memset(gpr_p, 0, MAX_GPR_SIZE); /* save arguments in stack here */ arg_p = gpr_p + MAX_GPR_SIZE; /* save arguments in memory here */ mem_p = arg_p + arg_bytes; /* set additional space as temporary space */ tmp_p = mem_p + mem_bytes; /* copy arguments here */ gpr_nr = 0; if (ret_in_memory) { memcpy(gpr_p, &rvalue, GPR_SIZE); gpr_p += GPR_SIZE; gpr_nr++; } for (i = 0; i < arg_nr; i++) { csymbol *cs = ffi_get_arg_csym(ks, csf, i); size_t size = csym_size(ks, cs); size_t align = csym_align(ks, cs); enum arg_status st = IN_REGISTER; int n_gpr_nr = 0; if (size > 32) { st = IN_MEMORY; n_gpr_nr = 1; } else if (size > 16) st = IN_STACK; else n_gpr_nr = ALIGN(size, GPR_SIZE) / GPR_SIZE; if (st == IN_MEMORY) mem_p = ALIGN_STACK(mem_p, align); /* Tricky way about storing it above mem_p. It won't overflow * because temp region can be temporarily used if necesseary. */ ffi_unpack(ks, mem_p, csf, i, GPR_SIZE); if (gpr_nr + n_gpr_nr > MAX_GPR) { if (st == IN_MEMORY) { memcpy(arg_p, &mem_p, GPR_SIZE); arg_p += GPR_SIZE; } else st = IN_STACK; } else { memcpy(gpr_p, mem_p, n_gpr_nr * GPR_SIZE); gpr_p += n_gpr_nr * GPR_SIZE; gpr_nr += n_gpr_nr; } if (st == IN_STACK) { arg_p = ALIGN_STACK(arg_p, align); memcpy(arg_p, mem_p, size); arg_p += size; arg_p = ALIGN_STACK(arg_p, STACK_ALIGNMENT); } if (st == IN_MEMORY) { mem_p += size; mem_p = ALIGN_STACK(mem_p, STACK_ALIGNMENT); } } kp_verbose_printf(ks, "Stack location: %p -redzone- %p -general purpose " "register used- %p -zero- %p -stack for argument- %p" " -memory for argument- %p -temp stack-\n", stack, stack_p, gpr_p, stack_p + MAX_GPR_SIZE, arg_p, mem_p); kp_verbose_printf(ks, "GPR number: %d; arg in stack: %d; " "arg in mem: %d\n", gpr_nr, arg_bytes, mem_bytes); kp_verbose_printf(ks, "Return: address %p type %d\n", rvalue, rtype); kp_verbose_printf(ks, "Number of register used: %d\n", gpr_nr); kp_verbose_printf(ks, "Start FFI call on %p\n", csf->addr); ffi_call_assem_x86_64(stack_p, tmp_p, csf->addr, rvalue, rtype); }