runtime/kp_bcread.c - ktap

Data types defined

Functions defined

Macros defined

Source code

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

  25. #include "../include/ktap_types.h"
  26. #include "../include/ktap_bc.h"
  27. #include "../include/ktap_err.h"
  28. #include "ktap.h"
  29. #include "kp_obj.h"
  30. #include "kp_str.h"
  31. #include "kp_tab.h"


  32. /* Context for bytecode reader. */
  33. typedef struct BCReadCtx {
  34.     ktap_state_t *ks;
  35.     int flags;
  36.     char *start;
  37.     char *p;
  38.     char *pe;
  39.     ktap_str_t *chunkname;
  40.     ktap_val_t *savetop;
  41. } BCReadCtx;


  42. #define bcread_flags(ctx)    (ctx)->flags
  43. #define bcread_swap(ctx) \
  44.     ((bcread_flags(ctx) & BCDUMP_F_BE) != KP_BE*BCDUMP_F_BE)
  45. #define bcread_oldtop(ctx)        (ctx)->savetop
  46. #define bcread_savetop(ctx)    (ctx)->savetop = (ctx)->ks->top;

  47. static inline uint32_t bswap(uint32_t x)
  48. {
  49.     return (uint32_t)__builtin_bswap32((int32_t)x);
  50. }

  51. /* -- Input buffer handling ----------------------------------------------- */

  52. /* Throw reader error. */
  53. static void bcread_error(BCReadCtx *ctx, ErrMsg em)
  54. {
  55.     kp_error(ctx->ks, "%s\n", err2msg(em));
  56. }

  57. /* Return memory block from buffer. */
  58. static inline uint8_t *bcread_mem(BCReadCtx *ctx, int len)
  59. {
  60.     uint8_t *p = (uint8_t *)ctx->p;
  61.     ctx->p += len;
  62.     kp_assert(ctx->p <= ctx->pe);
  63.     return p;
  64. }

  65. /* Copy memory block from buffer. */
  66. static void bcread_block(BCReadCtx *ctx, void *q, int len)
  67. {
  68.     memcpy(q, bcread_mem(ctx, len), len);
  69. }

  70. /* Read byte from buffer. */
  71. static inline uint32_t bcread_byte(BCReadCtx *ctx)
  72. {
  73.     kp_assert(ctx->p < ctx->pe);
  74.     return (uint32_t)(uint8_t)*ctx->p++;
  75. }

  76. /* Read ULEB128 value from buffer. */
  77. static inline uint32_t bcread_uint32(BCReadCtx *ctx)
  78. {
  79.     uint32_t v;
  80.     bcread_block(ctx, &v, sizeof(uint32_t));
  81.     kp_assert(ctx->p <= ctx->pe);
  82.     return v;
  83. }

  84. /* -- Bytecode reader ----------------------------------------------------- */

  85. /* Read debug info of a prototype. */
  86. static void bcread_dbg(BCReadCtx *ctx, ktap_proto_t *pt, int sizedbg)
  87. {
  88.     void *lineinfo = (void *)proto_lineinfo(pt);

  89.     bcread_block(ctx, lineinfo, sizedbg);
  90.     /* Swap lineinfo if the endianess differs. */
  91.     if (bcread_swap(ctx) && pt->numline >= 256) {
  92.         int i, n = pt->sizebc-1;
  93.         if (pt->numline < 65536) {
  94.             uint16_t *p = (uint16_t *)lineinfo;
  95.             for (i = 0; i < n; i++)
  96.                 p[i] = (uint16_t)((p[i] >> 8)|(p[i] << 8));
  97.         } else {
  98.             uint32_t *p = (uint32_t *)lineinfo;
  99.             for (i = 0; i < n; i++)
  100.                 p[i] = bswap(p[i]);
  101.         }
  102.     }
  103. }

  104. /* Find pointer to varinfo. */
  105. static const void *bcread_varinfo(ktap_proto_t *pt)
  106. {
  107.     const uint8_t *p = proto_uvinfo(pt);
  108.     int n = pt->sizeuv;
  109.     if (n)
  110.         while (*p++ || --n) ;
  111.     return p;
  112. }

  113. /* Read a single constant key/value of a template table. */
  114. static int bcread_ktabk(BCReadCtx *ctx, ktap_val_t *o)
  115. {
  116.     int tp = bcread_uint32(ctx);
  117.     if (tp >= BCDUMP_KTAB_STR) {
  118.         int len = tp - BCDUMP_KTAB_STR;
  119.         const char *p = (const char *)bcread_mem(ctx, len);
  120.         ktap_str_t *ts = kp_str_new(ctx->ks, p, len);
  121.         if (unlikely(!ts))
  122.             return -ENOMEM;

  123.         set_string(o, ts);
  124.     } else if (tp == BCDUMP_KTAB_NUM) {
  125.         set_number(o, *(ktap_number *)bcread_mem(ctx,
  126.                     sizeof(ktap_number)));
  127.     } else {
  128.          kp_assert(tp <= BCDUMP_KTAB_TRUE);
  129.         setitype(o, ~tp);
  130.     }
  131.     return 0;
  132. }

  133. /* Read a template table. */
  134. static ktap_tab_t *bcread_ktab(BCReadCtx *ctx)
  135. {
  136.     int narray = bcread_uint32(ctx);
  137.     int nhash = bcread_uint32(ctx);

  138.     ktap_tab_t *t = kp_tab_new(ctx->ks, narray, hsize2hbits(nhash));
  139.     if (!t)
  140.         return NULL;

  141.     if (narray) {  /* Read array entries. */
  142.         int i;
  143.         ktap_val_t *o = t->array;
  144.         for (i = 0; i < narray; i++, o++)
  145.             if (bcread_ktabk(ctx, o))
  146.                 return NULL;
  147.     }
  148.     if (nhash) {  /* Read hash entries. */
  149.         int i;
  150.         for (i = 0; i < nhash; i++) {
  151.             ktap_val_t key;
  152.             ktap_val_t val;
  153.             if (bcread_ktabk(ctx, &key))
  154.                 return NULL;
  155.             kp_assert(!is_nil(&key));
  156.             if (bcread_ktabk(ctx, &val))
  157.                 return NULL;
  158.             kp_tab_set(ctx->ks, t, &key, &val);
  159.         }
  160.     }
  161.     return t;
  162. }

  163. /* Read GC constants(string, table, child proto) of a prototype. */
  164. static int bcread_kgc(BCReadCtx *ctx, ktap_proto_t *pt, int sizekgc)
  165. {
  166.     ktap_obj_t **kr = (ktap_obj_t **)pt->k - (ptrdiff_t)sizekgc;
  167.     int i;

  168.     for (i = 0; i < sizekgc; i++, kr++) {
  169.         int tp = bcread_uint32(ctx);
  170.         if (tp >= BCDUMP_KGC_STR) {
  171.             int len = tp - BCDUMP_KGC_STR;
  172.             const char *p = (const char *)bcread_mem(ctx, len);
  173.             *kr =(ktap_obj_t *)kp_str_new(ctx->ks, p, len);
  174.             if (unlikely(!*kr))
  175.                 return -1;
  176.         } else if (tp == BCDUMP_KGC_TAB) {
  177.             *kr = (ktap_obj_t *)bcread_ktab(ctx);
  178.             if (unlikely(!*kr))
  179.                 return -1;
  180.         } else if (tp == BCDUMP_KGC_CHILD){
  181.             ktap_state_t *ks = ctx->ks;
  182.             if (ks->top <= bcread_oldtop(ctx)) {
  183.                 bcread_error(ctx, KP_ERR_BCBAD);
  184.                 return -1;
  185.             }
  186.             ks->top--;
  187.             *kr = (ktap_obj_t *)ptvalue(ks->top);
  188.         } else {
  189.             bcread_error(ctx, KP_ERR_BCBAD);
  190.             return -1;
  191.         }
  192.     }

  193.     return 0;
  194. }

  195. /* Read number constants of a prototype. */
  196. static void bcread_knum(BCReadCtx *ctx, ktap_proto_t *pt, int sizekn)
  197. {
  198.     int i;
  199.     ktap_val_t *o = pt->k;

  200.     for (i = 0; i < sizekn; i++, o++) {
  201.         set_number(o, *(ktap_number *)bcread_mem(ctx,
  202.                     sizeof(ktap_number)));
  203.     }
  204. }

  205. /* Read bytecode instructions. */
  206. static void bcread_bytecode(BCReadCtx *ctx, ktap_proto_t *pt, int sizebc)
  207. {
  208.     BCIns *bc = proto_bc(pt);
  209.     bc[0] = BCINS_AD((pt->flags & PROTO_VARARG) ? BC_FUNCV : BC_FUNCF,
  210.               pt->framesize, 0);
  211.     bcread_block(ctx, bc+1, (sizebc-1)*(int)sizeof(BCIns));
  212.     /* Swap bytecode instructions if the endianess differs. */
  213.     if (bcread_swap(ctx)) {
  214.         int i;
  215.         for (i = 1; i < sizebc; i++) bc[i] = bswap(bc[i]);
  216.     }
  217. }

  218. /* Read upvalue refs. */
  219. static void bcread_uv(BCReadCtx *ctx, ktap_proto_t *pt, int sizeuv)
  220. {
  221.     if (sizeuv) {
  222.         uint16_t *uv = proto_uv(pt);
  223.         bcread_block(ctx, uv, sizeuv*2);
  224.         /* Swap upvalue refs if the endianess differs. */
  225.         if (bcread_swap(ctx)) {
  226.             int i;
  227.             for (i = 0; i < sizeuv; i++)
  228.                 uv[i] = (uint16_t)((uv[i] >> 8)|(uv[i] << 8));
  229.         }
  230.     }
  231. }

  232. /* Read a prototype. */
  233. static ktap_proto_t *bcread_proto(BCReadCtx *ctx)
  234. {
  235.     ktap_proto_t *pt;
  236.     int framesize, numparams, flags;
  237.     int sizeuv, sizekgc, sizekn, sizebc, sizept;
  238.     int ofsk, ofsuv, ofsdbg;
  239.     int sizedbg = 0;
  240.     BCLine firstline = 0, numline = 0;

  241.     /* Read prototype header. */
  242.     flags = bcread_byte(ctx);
  243.     numparams = bcread_byte(ctx);
  244.     framesize = bcread_byte(ctx);
  245.     sizeuv = bcread_byte(ctx);
  246.     sizekgc = bcread_uint32(ctx);
  247.     sizekn = bcread_uint32(ctx);
  248.     sizebc = bcread_uint32(ctx) + 1;
  249.     if (!(bcread_flags(ctx) & BCDUMP_F_STRIP)) {
  250.         sizedbg = bcread_uint32(ctx);
  251.         if (sizedbg) {
  252.             firstline = bcread_uint32(ctx);
  253.             numline = bcread_uint32(ctx);
  254.         }
  255.     }

  256.     /* Calculate total size of prototype including all colocated arrays. */
  257.     sizept = (int)sizeof(ktap_proto_t) + sizebc * (int)sizeof(BCIns) +
  258.             sizekgc * (int)sizeof(ktap_obj_t *);
  259.     sizept = (sizept + (int)sizeof(ktap_val_t)-1) &
  260.             ~((int)sizeof(ktap_val_t)-1);
  261.     ofsk = sizept; sizept += sizekn*(int)sizeof(ktap_val_t);
  262.     ofsuv = sizept; sizept += ((sizeuv+1)&~1)*2;
  263.     ofsdbg = sizept; sizept += sizedbg;

  264.     /* Allocate prototype object and initialize its fields. */
  265.     pt = (ktap_proto_t *)kp_obj_new(ctx->ks, (int)sizept);
  266.     pt->gct = ~KTAP_TPROTO;
  267.     pt->numparams = (uint8_t)numparams;
  268.     pt->framesize = (uint8_t)framesize;
  269.     pt->sizebc = sizebc;
  270.     pt->k = (char *)pt + ofsk;
  271.     pt->uv = (char *)pt + ofsuv;
  272.     pt->sizekgc = 0/* Set to zero until fully initialized. */
  273.     pt->sizekn = sizekn;
  274.     pt->sizept = sizept;
  275.     pt->sizeuv = (uint8_t)sizeuv;
  276.     pt->flags = (uint8_t)flags;
  277.     pt->chunkname = ctx->chunkname;

  278.     /* Close potentially uninitialized gap between bc and kgc. */
  279.     *(uint32_t *)((char *)pt + ofsk - sizeof(ktap_obj_t *)*(sizekgc+1))
  280.                                     = 0;

  281.     /* Read bytecode instructions and upvalue refs. */
  282.     bcread_bytecode(ctx, pt, sizebc);
  283.     bcread_uv(ctx, pt, sizeuv);

  284.     /* Read constants. */
  285.     if (bcread_kgc(ctx, pt, sizekgc))
  286.         return NULL;
  287.     pt->sizekgc = sizekgc;
  288.     bcread_knum(ctx, pt, sizekn);

  289.     /* Read and initialize debug info. */
  290.     pt->firstline = firstline;
  291.     pt->numline = numline;
  292.     if (sizedbg) {
  293.         int sizeli = (sizebc-1) << (numline < 256 ? 0 :
  294.                     numline < 65536 ? 1 : 2);
  295.         pt->lineinfo = (char *)pt + ofsdbg;
  296.         pt->uvinfo = (char *)pt + ofsdbg + sizeli;
  297.         bcread_dbg(ctx, pt, sizedbg);
  298.         pt->varinfo = (void *)bcread_varinfo(pt);
  299.     } else {
  300.         pt->lineinfo = NULL;
  301.         pt->uvinfo = NULL;
  302.         pt->varinfo = NULL;
  303.     }
  304.     return pt;
  305. }

  306. /* Read and check header of bytecode dump. */
  307. static int bcread_header(BCReadCtx *ctx)
  308. {
  309.     uint32_t flags;

  310.     if (bcread_byte(ctx) != BCDUMP_HEAD1 ||
  311.         bcread_byte(ctx) != BCDUMP_HEAD2 ||
  312.         bcread_byte(ctx) != BCDUMP_HEAD3 ||
  313.         bcread_byte(ctx) != BCDUMP_VERSION)
  314.         return -1;

  315.     bcread_flags(ctx) = flags = bcread_byte(ctx);

  316.     if ((flags & ~(BCDUMP_F_KNOWN)) != 0)
  317.         return -1;

  318.     if ((flags & BCDUMP_F_FFI)) {
  319.         return -1;
  320.     }

  321.     if ((flags & BCDUMP_F_STRIP)) {
  322.         ctx->chunkname = kp_str_newz(ctx->ks, "striped");
  323.     } else {
  324.         int len = bcread_uint32(ctx);
  325.         ctx->chunkname = kp_str_new(ctx->ks,
  326.                 (const char *)bcread_mem(ctx, len), len);
  327.     }

  328.     if (unlikely(!ctx->chunkname))
  329.         return -1;

  330.     return 0;
  331. }

  332. /* Read a bytecode dump. */
  333. ktap_proto_t *kp_bcread(ktap_state_t *ks, unsigned char *buff, int len)
  334. {
  335.     BCReadCtx ctx;

  336.     ctx.ks = ks;
  337.     ctx.p = buff;
  338.     ctx.pe = buff + len;

  339.     ctx.start = buff;

  340.     bcread_savetop(&ctx);
  341.     /* Check for a valid bytecode dump header. */
  342.     if (bcread_header(&ctx)) {
  343.         bcread_error(&ctx, KP_ERR_BCFMT);
  344.         return NULL;
  345.     }

  346.     for (;;) {  /* Process all prototypes in the bytecode dump. */
  347.         ktap_proto_t *pt;
  348.         int len;
  349.         const char *startp;
  350.         /* Read length. */
  351.         if (ctx.p < ctx.pe && ctx.p[0] == 0) {  /* Shortcut EOF. */
  352.             ctx.p++;
  353.             break;
  354.         }
  355.         len = bcread_uint32(&ctx);
  356.         if (!len)
  357.             break/* EOF */
  358.         startp = ctx.p;
  359.         pt = bcread_proto(&ctx);
  360.         if (!pt)
  361.             return NULL;
  362.         if (ctx.p != startp + len) {
  363.             bcread_error(&ctx, KP_ERR_BCBAD);
  364.             return NULL;
  365.         }
  366.         set_proto(ks->top, pt);
  367.         incr_top(ks);
  368.     }
  369.     if ((int32_t)(2*(uint32_t)(ctx.pe - ctx.p)) > 0 ||
  370.             ks->top-1 != bcread_oldtop(&ctx)) {
  371.         bcread_error(&ctx, KP_ERR_BCBAD);
  372.         return NULL;
  373.     }

  374.     /* Pop off last prototype. */
  375.     ks->top--;
  376.     return ptvalue(ks->top);
  377. }