runtime/ffi/cdata.c - ktap

Functions defined

Source code

  1. /*
  2. * cdata.c - support functions for ktap_cdata_t
  3. *
  4. * This file is part of ktap by Jovi Zhangwei
  5. *
  6. * Copyright (C) 2012-2013 Jovi Zhangwei <jovi.zhangwei@gmail.com>.
  7. *
  8. * ktap is free software; you can redistribute it and/or modify it
  9. * under the terms and conditions of the GNU General Public License,
  10. * version 2, as published by the Free Software Foundation.
  11. *
  12. * ktap is distributed in the hope it will be useful, but WITHOUT
  13. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  14. * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  15. * more details.
  16. *
  17. * You should have received a copy of the GNU General Public License along with
  18. * this program; if not, write to the Free Software Foundation, Inc.,
  19. * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
  20. */


  21. #include "../../include/ktap_types.h"
  22. #include "../../include/ktap_ffi.h"
  23. #include "../kp_obj.h"

  24. ktap_cdata_t *kp_cdata_new(ktap_state_t *ks, csymbol_id id)
  25. {
  26.     ktap_cdata_t *cd;

  27.     cd = &kp_obj_newobject(ks, KTAP_TYPE_CDATA, sizeof(ktap_cdata_t), NULL)->cd;
  28.     cd_set_csym_id(cd, id);

  29.     return cd;
  30. }

  31. ktap_cdata_t *kp_cdata_new_number(ktap_state_t *ks, void *val, csymbol_id id)
  32. {
  33.     ktap_cdata_t *cd;

  34.     cd = kp_cdata_new(ks, id);
  35.     cd_int(cd) = (cdata_number)val;

  36.     return cd;
  37. }

  38. /* argument nmemb here indicates the length of array that is pointed to,
  39. * -1 for unknown */
  40. ktap_cdata_t *kp_cdata_new_ptr(ktap_state_t *ks, void *addr,
  41.                  int nmemb, csymbol_id id, int to_allocate)
  42. {
  43.     ktap_cdata_t *cd;
  44.     size_t memb_size;
  45.     csymbol_id deref_id;

  46.     cd = kp_cdata_new(ks, id);

  47.     if (to_allocate) {
  48.         /* allocate new empty space */
  49.         deref_id = csym_ptr_deref_id(id_to_csym(ks, id));
  50.         memb_size = csym_size(ks, id_to_csym(ks, deref_id));
  51.         cd_ptr(cd) = kp_rawobj_alloc(ks, memb_size * nmemb);
  52.     } else {
  53.         cd_ptr(cd) = addr;
  54.     }

  55.     cd_ptr_nmemb(cd) = nmemb;

  56.     return cd;
  57. }

  58. ktap_cdata_t *kp_cdata_new_record(ktap_state_t *ks, void *val, csymbol_id id)
  59. {
  60.     ktap_cdata_t *cd;
  61.     size_t size;

  62.     cd = kp_cdata_new(ks, id);

  63.     /* if val == NULL, allocate new empty space */
  64.     if (val == NULL) {
  65.         size = csym_size(ks, id_to_csym(ks, id));
  66.         cd_record(cd) = kp_rawobj_alloc(ks, size);
  67.     } else
  68.         cd_record(cd) = val;

  69.     return cd;
  70. }

  71. ktap_cdata_t *kp_cdata_new_by_id(ktap_state_t *ks, void *val, csymbol_id id)
  72. {
  73.     csymbol *cs = id_to_csym(ks, id);

  74.     switch (csym_type(cs)) {
  75.     case FFI_VOID:
  76.         kp_error(ks, "Error: Cannot new a void type\n");
  77.         return NULL;
  78.     case FFI_UINT8:
  79.     case FFI_INT8:
  80.     case FFI_UINT16:
  81.     case FFI_INT16:
  82.     case FFI_UINT32:
  83.     case FFI_INT32:
  84.     case FFI_UINT64:
  85.     case FFI_INT64:
  86.         return kp_cdata_new_number(ks, val, id);
  87.     case FFI_PTR:
  88.         return kp_cdata_new_ptr(ks, val, 0, id, 0);
  89.     case FFI_STRUCT:
  90.     case FFI_UNION:
  91.         return kp_cdata_new_record(ks, val, id);
  92.     case FFI_FUNC:
  93.         kp_error(ks, "Error: Cannot new a function type\n");
  94.         return NULL;
  95.     case FFI_UNKNOWN:
  96.     default:
  97.         kp_error(ks, "Error: unknown csymbol type %s\n", csym_name(cs));
  98.         return NULL;
  99.     }
  100. }

  101. void kp_cdata_dump(ktap_state_t *ks, ktap_cdata_t *cd)
  102. {
  103.     switch (cd_type(ks, cd)) {
  104.     case FFI_UINT8:    case FFI_INT8:
  105.         kp_printf(ks, "c int(0x%01x)", cd_int(cd));
  106.         break;
  107.     case FFI_UINT16:    case FFI_INT16:
  108.         kp_printf(ks, "c int(0x%02x)", cd_int(cd));
  109.         break;
  110.     case FFI_UINT32:    case FFI_INT32:
  111.         kp_printf(ks, "c int(0x%04x)", cd_int(cd));
  112.         break;
  113.     case FFI_UINT64:    case FFI_INT64:
  114.         kp_printf(ks, "c int(0x%08x)", cd_int(cd));
  115.         break;
  116.     case FFI_PTR:
  117.         kp_printf(ks, "c pointer(0x%p)", cd_ptr(cd));
  118.         break;
  119.     case FFI_STRUCT:
  120.         kp_printf(ks, "c struct(0x%p)", cd_struct(cd));
  121.         break;
  122.     case FFI_UNION:
  123.         kp_printf(ks, "c union(0x%p)", cd_union(cd));
  124.         break;
  125.     default:
  126.         kp_printf(ks, "unsupported cdata type %d!\n", cd_type(ks, cd));
  127.     }
  128. }

  129. /* Notice: Even if the types are matched, there may exist the lost of
  130. * data in the unpack process due to precision */
  131. int kp_cdata_type_match(ktap_state_t *ks, csymbol *cs, ktap_val_t *val)
  132. {
  133.     ffi_type type;

  134.     type = csym_type(cs);
  135.     if (type == FFI_FUNC)
  136.         goto error;

  137.     switch (ttypenv(val)) {
  138.     case KTAP_TYPE_LIGHTUSERDATA:
  139.         if (type != FFI_PTR) goto error;
  140.         break;
  141.     case KTAP_TYPE_BOOLEAN:
  142.     case KTAP_TYPE_NUMBER:
  143.         if (type != FFI_UINT8 && type != FFI_INT8
  144.         && type != FFI_UINT16 && type != FFI_INT16
  145.         && type != FFI_UINT32 && type != FFI_INT32
  146.         && type != FFI_UINT64 && type != FFI_INT64)
  147.             goto error;
  148.         break;
  149.     case KTAP_TYPE_STRING:
  150.         if (type != FFI_PTR && type != FFI_UINT8 && type != FFI_INT8)
  151.             goto error;
  152.         break;
  153.     case KTAP_TYPE_CDATA:
  154.         if (cs != cd_csym(ks, cdvalue(val)))
  155.             goto error;
  156.         break;
  157.     default:
  158.         goto error;
  159.     }
  160.     return 0;

  161. error:
  162.     return -1;
  163. }

  164. static void kp_cdata_value(ktap_state_t *ks, ktap_val_t *val, void **out_addr,
  165.                size_t *out_size, void **temp)
  166. {
  167.     ktap_cdata_t *cd;
  168.     csymbol *cs;
  169.     ffi_type type;

  170.     switch (ttypenv(val)) {
  171.     case KTAP_TYPE_BOOLEAN:
  172.         *out_addr = &bvalue(val);
  173.         *out_size = sizeof(int);
  174.         return;
  175.     case KTAP_TYPE_LIGHTUSERDATA:
  176.         *out_addr = pvalue(val);
  177.         *out_size = sizeof(void *);
  178.         return;
  179.     case KTAP_TYPE_NUMBER:
  180.         *out_addr = &nvalue(val);
  181.         *out_size = sizeof(ktap_number);
  182.         return;
  183.     case KTAP_TYPE_STRING:
  184.         *temp = (void *)svalue(val);
  185.         *out_addr = temp;
  186.         *out_size = sizeof(void *);
  187.         return;
  188.     }

  189.     cd = cdvalue(val);
  190.     cs = cd_csym(ks, cd);
  191.     type = csym_type(cs);
  192.     *out_size = csym_size(ks, cs);
  193.     switch (type) {
  194.     case FFI_VOID:
  195.         kp_error(ks, "Error: Cannot copy data from void type\n");
  196.         return;
  197.     case FFI_UINT8:
  198.     case FFI_INT8:
  199.     case FFI_UINT16:
  200.     case FFI_INT16:
  201.     case FFI_UINT32:
  202.     case FFI_INT32:
  203.     case FFI_UINT64:
  204.     case FFI_INT64:
  205.         *out_addr = &cd_int(cd);
  206.         return;
  207.     case FFI_PTR:
  208.         *out_addr = &cd_ptr(cd);
  209.         return;
  210.     case FFI_STRUCT:
  211.     case FFI_UNION:
  212.         *out_addr = cd_record(cd);
  213.         return;
  214.     case FFI_FUNC:
  215.     case FFI_UNKNOWN:
  216.         kp_error(ks, "Error: internal error for csymbol %s\n",
  217.                 csym_name(cs));
  218.         return;
  219.     }
  220. }

  221. /* Check whether or not type is matched before unpacking */
  222. void kp_cdata_unpack(ktap_state_t *ks, char *dst, csymbol *cs, ktap_val_t *val)
  223. {
  224.     size_t size = csym_size(ks, cs), val_size;
  225.     void *val_addr, *temp;

  226.     kp_cdata_value(ks, val, &val_addr, &val_size, &temp);
  227.     if (val_size > size)
  228.         val_size = size;
  229.     memmove(dst, val_addr, val_size);
  230.     memset(dst + val_size, 0, size - val_size);
  231. }

  232. /* Check whether or not type is matched before packing */
  233. void kp_cdata_pack(ktap_state_t *ks, ktap_val_t *val, char *src, csymbol *cs)
  234. {
  235.     size_t size = csym_size(ks, cs), val_size;
  236.     void *val_addr, *temp;

  237.     kp_cdata_value(ks, val, &val_addr, &val_size, &temp);
  238.     if (size > val_size)
  239.         size = val_size;
  240.     memmove(val_addr, src, size);
  241.     memset(val_addr + size, 0, val_size - size);
  242. }

  243. /* Init its cdata type, but not its actual value */
  244. static void kp_cdata_init(ktap_state_t *ks, ktap_val_t *val, void *addr, int len,
  245.               csymbol_id id)
  246. {
  247.     ffi_type type = csym_type(id_to_csym(ks, id));

  248.     switch (type) {
  249.     case FFI_PTR:
  250.         set_cdata(val, kp_cdata_new_ptr(ks, addr, len, id, 0));
  251.         break;
  252.     case FFI_STRUCT:
  253.     case FFI_UNION:
  254.         set_cdata(val, kp_cdata_new_record(ks, addr, id));
  255.         break;
  256.     case FFI_UINT8:
  257.     case FFI_INT8:
  258.     case FFI_UINT16:
  259.     case FFI_INT16:
  260.     case FFI_UINT32:
  261.     case FFI_INT32:
  262.     case FFI_UINT64:
  263.     case FFI_INT64:
  264.         /* set all these value into ktap_number(long) */
  265.         set_number(val, 0);
  266.         break;
  267.     default:
  268.         set_cdata(val, kp_cdata_new(ks, id));
  269.         break;
  270.     }
  271. }

  272. void kp_cdata_ptr_set(ktap_state_t *ks, ktap_cdata_t *cd,
  273.               ktap_val_t *key, ktap_val_t *val)
  274. {
  275.     ktap_number idx;
  276.     csymbol *cs;
  277.     size_t size;
  278.     char *addr;

  279.     if (!is_number(key)) {
  280.         kp_error(ks, "array index should be number\n");
  281.         return;
  282.     }
  283.     idx = nvalue(key);
  284.     if (unlikely(idx < 0 || (cd_ptr_nmemb(cd) >= 0
  285.                     && idx >= cd_ptr_nmemb(cd)))) {
  286.         kp_error(ks, "array index out of bound\n");
  287.         return;
  288.     }

  289.     cs = csym_ptr_deref(ks, cd_csym(ks, cd));
  290.     if (kp_cdata_type_match(ks, cs, val)) {
  291.         kp_error(ks, "array member should be %s type\n", csym_name(cs));
  292.         return;
  293.     }
  294.     size = csym_size(ks, cs);
  295.     addr = cd_ptr(cd);
  296.     addr += size * idx;
  297.     kp_cdata_unpack(ks, addr, cs, val);
  298. }

  299. void kp_cdata_ptr_get(ktap_state_t *ks, ktap_cdata_t *cd,
  300.               ktap_val_t *key, ktap_val_t *val)
  301. {
  302.     ktap_number idx;
  303.     csymbol *cs;
  304.     size_t size;
  305.     char *addr;
  306.     csymbol_id cs_id;

  307.     if (!is_number(key)) {
  308.         kp_error(ks, "array index should be number\n");
  309.         return;
  310.     }
  311.     idx = nvalue(key);
  312.     if (unlikely(idx < 0 || (cd_ptr_nmemb(cd) >= 0
  313.                     && idx >= cd_ptr_nmemb(cd)))) {
  314.         kp_error(ks, "array index out of bound\n");
  315.         return;
  316.     }

  317.     cs_id = csym_ptr_deref_id(cd_csym(ks, cd));
  318.     cs = id_to_csym(ks, cs_id);
  319.     size = csym_size(ks, cs);
  320.     addr = cd_ptr(cd);
  321.     addr += size * idx;

  322.     kp_cdata_init(ks, val, addr, -1, cs_id);
  323.     kp_cdata_pack(ks, val, addr, cs);
  324. }

  325. void kp_cdata_record_set(ktap_state_t *ks, ktap_cdata_t *cd,
  326.              ktap_val_t *key, ktap_val_t *val)
  327. {
  328.     const char *mb_name;
  329.     csymbol *cs, *mb_cs;
  330.     csymbol_struct *csst;
  331.     struct_member *mb;
  332.     char *addr;

  333.     if (!is_shrstring(key)) {
  334.         kp_error(ks, "struct member name should be string\n");
  335.         return;
  336.     }
  337.     mb_name = svalue(key);
  338.     cs = cd_csym(ks, cd);
  339.     csst = csym_struct(cs);
  340.     mb = csymst_mb_by_name(ks, csst, mb_name);
  341.     if (mb == NULL) {
  342.         kp_error(ks, "struct member %s doesn't exist\n", mb_name);
  343.         return;
  344.     }

  345.     mb_cs = id_to_csym(ks, mb->id);
  346.     if (kp_cdata_type_match(ks, mb_cs, val)) {
  347.         kp_error(ks, "struct member should be %s type\n",
  348.                  csym_name(mb_cs));
  349.         return;
  350.     }

  351.     addr = cd_record(cd);
  352.     addr += csym_record_mb_offset_by_name(ks, cs, mb_name);
  353.     kp_cdata_unpack(ks, addr, mb_cs, val);
  354. }

  355. void kp_cdata_record_get(ktap_state_t *ks, ktap_cdata_t *cd,
  356.              ktap_val_t *key, ktap_val_t *val)
  357. {
  358.     const char *mb_name;
  359.     csymbol *cs, *mb_cs;
  360.     csymbol_struct *csst;
  361.     struct_member *mb;
  362.     char *addr;
  363.     csymbol_id mb_cs_id;

  364.     if (!is_shrstring(key)) {
  365.         kp_error(ks, "struct member name should be string\n");
  366.         return;
  367.     }

  368.     mb_name = svalue(key);
  369.     cs = cd_csym(ks, cd);
  370.     csst = csym_struct(cs);
  371.     mb = csymst_mb_by_name(ks, csst, mb_name);
  372.     if (mb == NULL) {
  373.         kp_error(ks, "struct member %s doesn't exist\n", mb_name);
  374.         return;
  375.     }

  376.     mb_cs_id = mb->id;
  377.     mb_cs = id_to_csym(ks, mb_cs_id);
  378.     addr = cd_record(cd);
  379.     addr += csym_record_mb_offset_by_name(ks, cs, mb_name);

  380.     kp_cdata_init(ks, val, addr, mb->len, mb_cs_id);
  381.     if (mb->len < 0)
  382.         kp_cdata_pack(ks, val, addr, mb_cs);
  383. }