Exposed function:
ktap_proto_t *kp_bcread(ktap_state_t *ks, unsigned char *buff, int len)

Function kp_bcread read bytecode from buff, and return
ktap top-level function prototype.

Signed-off-by: Jovi Zhangwei <jovi.zhang...@gmail.com>
---
 kernel/trace/ktap/kp_bcread.c | 429 ++++++++++++++++++++++++++++++++++++++++++
 kernel/trace/ktap/kp_bcread.h |   6 +
 2 files changed, 435 insertions(+)
 create mode 100644 kernel/trace/ktap/kp_bcread.c
 create mode 100644 kernel/trace/ktap/kp_bcread.h

diff --git a/kernel/trace/ktap/kp_bcread.c b/kernel/trace/ktap/kp_bcread.c
new file mode 100644
index 0000000..b51b622
--- /dev/null
+++ b/kernel/trace/ktap/kp_bcread.c
@@ -0,0 +1,429 @@
+/*
+ * Bytecode reader.
+ *
+ * This file is part of ktap by Jovi Zhangwei.
+ *
+ * Copyright (C) 2012-2014 Jovi Zhangwei <jovi.zhang...@gmail.com>.
+ *
+ * Adapted from luajit and lua interpreter.
+ * Copyright (C) 2005-2014 Mike Pall.
+ * Copyright (C) 1994-2008 Lua.org, PUC-Rio.
+ *
+ * ktap is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * ktap is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <uapi/ktap/ktap_types.h>
+#include <uapi/ktap/ktap_bc.h>
+#include <uapi/ktap/ktap_err.h>
+#include "ktap.h"
+#include "kp_obj.h"
+#include "kp_vm.h"
+#include "kp_str.h"
+#include "kp_tab.h"
+
+
+/* Context for bytecode reader. */
+typedef struct BCReadCtx {
+       ktap_state_t *ks;
+       int flags;
+       char *start;
+       char *p;
+       char *pe;
+       ktap_str_t *chunkname;
+       ktap_val_t *savetop;
+} BCReadCtx;
+
+
+#define bcread_flags(ctx)      (ctx)->flags
+#define bcread_swap(ctx) \
+       ((bcread_flags(ctx) & BCDUMP_F_BE) != KP_BE*BCDUMP_F_BE)
+#define bcread_oldtop(ctx)             (ctx)->savetop
+#define bcread_savetop(ctx)    (ctx)->savetop = (ctx)->ks->top;
+
+static inline uint32_t bswap(uint32_t x)
+{
+       return (uint32_t)__builtin_bswap32((int32_t)x);
+}
+
+/* -- Input buffer handling ----------------------------------------------- */
+
+/* Throw reader error. */
+static void bcread_error(BCReadCtx *ctx, ErrMsg em)
+{
+       kp_error(ctx->ks, "%s\n", err2msg(em));
+}
+
+/* Return memory block from buffer. */
+static inline uint8_t *bcread_mem(BCReadCtx *ctx, int len)
+{
+       uint8_t *p = (uint8_t *)ctx->p;
+       ctx->p += len;
+       kp_assert(ctx->p <= ctx->pe);
+       return p;
+}
+
+/* Copy memory block from buffer. */
+static void bcread_block(BCReadCtx *ctx, void *q, int len)
+{
+       memcpy(q, bcread_mem(ctx, len), len);
+}
+
+/* Read byte from buffer. */
+static inline uint32_t bcread_byte(BCReadCtx *ctx)
+{
+       kp_assert(ctx->p < ctx->pe);
+       return (uint32_t)(uint8_t)*ctx->p++;
+}
+
+/* Read ULEB128 value from buffer. */
+static inline uint32_t bcread_uint32(BCReadCtx *ctx)
+{
+       uint32_t v;
+       bcread_block(ctx, &v, sizeof(uint32_t));
+       kp_assert(ctx->p <= ctx->pe);
+       return v;
+}
+
+/* -- Bytecode reader ----------------------------------------------------- */
+
+/* Read debug info of a prototype. */
+static void bcread_dbg(BCReadCtx *ctx, ktap_proto_t *pt, int sizedbg)
+{
+       void *lineinfo = (void *)proto_lineinfo(pt);
+
+       bcread_block(ctx, lineinfo, sizedbg);
+       /* Swap lineinfo if the endianess differs. */
+       if (bcread_swap(ctx) && pt->numline >= 256) {
+               int i, n = pt->sizebc-1;
+               if (pt->numline < 65536) {
+                       uint16_t *p = (uint16_t *)lineinfo;
+                       for (i = 0; i < n; i++)
+                               p[i] = (uint16_t)((p[i] >> 8)|(p[i] << 8));
+               } else {
+                       uint32_t *p = (uint32_t *)lineinfo;
+                       for (i = 0; i < n; i++)
+                               p[i] = bswap(p[i]);
+               }
+       }
+}
+
+/* Find pointer to varinfo. */
+static const void *bcread_varinfo(ktap_proto_t *pt)
+{
+       const uint8_t *p = proto_uvinfo(pt);
+       int n = pt->sizeuv;
+       if (n)
+               while (*p++ || --n) ;
+       return p;
+}
+
+/* Read a single constant key/value of a template table. */
+static int bcread_ktabk(BCReadCtx *ctx, ktap_val_t *o)
+{
+       int tp = bcread_uint32(ctx);
+       if (tp >= BCDUMP_KTAB_STR) {
+               int len = tp - BCDUMP_KTAB_STR;
+               const char *p = (const char *)bcread_mem(ctx, len);
+               ktap_str_t *ts = kp_str_new(ctx->ks, p, len);
+               if (unlikely(!ts))
+                       return -ENOMEM;
+
+               set_string(o, ts);
+       } else if (tp == BCDUMP_KTAB_NUM) {
+               set_number(o, *(ktap_number *)bcread_mem(ctx,
+                                       sizeof(ktap_number)));
+       } else {
+               kp_assert(tp <= BCDUMP_KTAB_TRUE);
+               setitype(o, ~tp);
+       }
+       return 0;
+}
+
+/* Read a template table. */
+static ktap_tab_t *bcread_ktab(BCReadCtx *ctx)
+{
+       int narray = bcread_uint32(ctx);
+       int nhash = bcread_uint32(ctx);
+
+       ktap_tab_t *t = kp_tab_new(ctx->ks, narray, hsize2hbits(nhash));
+       if (!t)
+               return NULL;
+
+       if (narray) {  /* Read array entries. */
+               int i;
+               ktap_val_t *o = t->array;
+               for (i = 0; i < narray; i++, o++) 
+                       if (bcread_ktabk(ctx, o))
+                               return NULL;
+       }
+       if (nhash) {  /* Read hash entries. */
+               int i;
+               for (i = 0; i < nhash; i++) {
+                       ktap_val_t key;
+                       ktap_val_t val;
+                       if (bcread_ktabk(ctx, &key))
+                               return NULL;
+                       kp_assert(!is_nil(&key));
+                       if (bcread_ktabk(ctx, &val))
+                               return NULL;
+                       kp_tab_set(ctx->ks, t, &key, &val);
+               }
+       }
+       return t;
+}
+
+/* Read GC constants(string, table, child proto) of a prototype. */
+static int bcread_kgc(BCReadCtx *ctx, ktap_proto_t *pt, int sizekgc)
+{
+       ktap_obj_t **kr = (ktap_obj_t **)pt->k - (ptrdiff_t)sizekgc;
+       int i;
+
+       for (i = 0; i < sizekgc; i++, kr++) {
+               int tp = bcread_uint32(ctx);
+               if (tp >= BCDUMP_KGC_STR) {
+                       int len = tp - BCDUMP_KGC_STR;
+                       const char *p = (const char *)bcread_mem(ctx, len);
+                       *kr =(ktap_obj_t *)kp_str_new(ctx->ks, p, len);
+                       if (unlikely(!*kr))
+                               return -1;
+               } else if (tp == BCDUMP_KGC_TAB) {
+                       *kr = (ktap_obj_t *)bcread_ktab(ctx);
+                       if (unlikely(!*kr))
+                               return -1;
+               } else if (tp == BCDUMP_KGC_CHILD){
+                       ktap_state_t *ks = ctx->ks;
+                       if (ks->top <= bcread_oldtop(ctx)) {
+                               bcread_error(ctx, KP_ERR_BCBAD);
+                               return -1;
+                       }
+                       ks->top--;
+                       *kr = (ktap_obj_t *)ptvalue(ks->top);
+               } else {
+                       bcread_error(ctx, KP_ERR_BCBAD);
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+
+/* Read number constants of a prototype. */
+static void bcread_knum(BCReadCtx *ctx, ktap_proto_t *pt, int sizekn)
+{
+       int i;
+       ktap_val_t *o = pt->k;
+
+       for (i = 0; i < sizekn; i++, o++) {
+               set_number(o, *(ktap_number *)bcread_mem(ctx,
+                                       sizeof(ktap_number)));
+       }
+}
+
+/* Read bytecode instructions. */
+static void bcread_bytecode(BCReadCtx *ctx, ktap_proto_t *pt, int sizebc)
+{
+       BCIns *bc = proto_bc(pt);
+       bc[0] = BCINS_AD((pt->flags & PROTO_VARARG) ? BC_FUNCV : BC_FUNCF,
+                         pt->framesize, 0);
+       bcread_block(ctx, bc+1, (sizebc-1)*(int)sizeof(BCIns));
+       /* Swap bytecode instructions if the endianess differs. */
+       if (bcread_swap(ctx)) {
+               int i;
+               for (i = 1; i < sizebc; i++) bc[i] = bswap(bc[i]);
+       }
+}
+
+/* Read upvalue refs. */
+static void bcread_uv(BCReadCtx *ctx, ktap_proto_t *pt, int sizeuv)
+{
+       if (sizeuv) {
+               uint16_t *uv = proto_uv(pt);
+               bcread_block(ctx, uv, sizeuv*2);
+               /* Swap upvalue refs if the endianess differs. */
+               if (bcread_swap(ctx)) {
+                       int i;
+                       for (i = 0; i < sizeuv; i++)
+                               uv[i] = (uint16_t)((uv[i] >> 8)|(uv[i] << 8));
+               }
+       }
+}
+
+/* Read a prototype. */
+static ktap_proto_t *bcread_proto(BCReadCtx *ctx)
+{
+       ktap_proto_t *pt;
+       int framesize, numparams, flags;
+       int sizeuv, sizekgc, sizekn, sizebc, sizept;
+       int ofsk, ofsuv, ofsdbg;
+       int sizedbg = 0;
+       BCLine firstline = 0, numline = 0;
+
+       /* Read prototype header. */
+       flags = bcread_byte(ctx);
+       numparams = bcread_byte(ctx);
+       framesize = bcread_byte(ctx);
+       sizeuv = bcread_byte(ctx);
+       sizekgc = bcread_uint32(ctx);
+       sizekn = bcread_uint32(ctx);
+       sizebc = bcread_uint32(ctx) + 1;
+       if (!(bcread_flags(ctx) & BCDUMP_F_STRIP)) {
+               sizedbg = bcread_uint32(ctx);
+               if (sizedbg) {
+                       firstline = bcread_uint32(ctx);
+                       numline = bcread_uint32(ctx);
+               }
+       }
+
+       /* Calculate total size of prototype including all colocated arrays. */
+       sizept = (int)sizeof(ktap_proto_t) + sizebc * (int)sizeof(BCIns) +
+                       sizekgc * (int)sizeof(ktap_obj_t *);
+       sizept = (sizept + (int)sizeof(ktap_val_t)-1) &
+                       ~((int)sizeof(ktap_val_t)-1);
+       ofsk = sizept; sizept += sizekn*(int)sizeof(ktap_val_t);
+       ofsuv = sizept; sizept += ((sizeuv+1)&~1)*2;
+       ofsdbg = sizept; sizept += sizedbg;
+
+       /* Allocate prototype object and initialize its fields. */
+       pt = (ktap_proto_t *)kp_obj_new(ctx->ks, (int)sizept);
+       pt->gct = ~KTAP_TPROTO;
+       pt->numparams = (uint8_t)numparams;
+       pt->framesize = (uint8_t)framesize;
+       pt->sizebc = sizebc;
+       pt->k = (char *)pt + ofsk;
+       pt->uv = (char *)pt + ofsuv;
+       pt->sizekgc = 0;  /* Set to zero until fully initialized. */
+       pt->sizekn = sizekn;
+       pt->sizept = sizept;
+       pt->sizeuv = (uint8_t)sizeuv;
+       pt->flags = (uint8_t)flags;
+       pt->chunkname = ctx->chunkname;
+
+       /* Close potentially uninitialized gap between bc and kgc. */
+       *(uint32_t *)((char *)pt + ofsk - sizeof(ktap_obj_t *)*(sizekgc+1))
+                                                                       = 0;
+
+       /* Read bytecode instructions and upvalue refs. */
+       bcread_bytecode(ctx, pt, sizebc);
+       bcread_uv(ctx, pt, sizeuv);
+
+       /* Read constants. */
+       if (bcread_kgc(ctx, pt, sizekgc))
+               return NULL;
+       pt->sizekgc = sizekgc;
+       bcread_knum(ctx, pt, sizekn);
+
+       /* Read and initialize debug info. */
+       pt->firstline = firstline;
+       pt->numline = numline;
+       if (sizedbg) {
+               int sizeli = (sizebc-1) << (numline < 256 ? 0 :
+                                       numline < 65536 ? 1 : 2);
+               pt->lineinfo = (char *)pt + ofsdbg;
+               pt->uvinfo = (char *)pt + ofsdbg + sizeli;
+               bcread_dbg(ctx, pt, sizedbg);
+               pt->varinfo = (void *)bcread_varinfo(pt);
+       } else {
+               pt->lineinfo = NULL;
+               pt->uvinfo = NULL;
+               pt->varinfo = NULL;
+       }
+       return pt;
+}
+
+/* Read and check header of bytecode dump. */
+static int bcread_header(BCReadCtx *ctx)
+{
+       uint32_t flags;
+
+       if (bcread_byte(ctx) != BCDUMP_HEAD1 ||
+               bcread_byte(ctx) != BCDUMP_HEAD2 ||
+               bcread_byte(ctx) != BCDUMP_HEAD3 ||
+               bcread_byte(ctx) != BCDUMP_VERSION)
+               return -1;
+
+       bcread_flags(ctx) = flags = bcread_byte(ctx);
+
+       if ((flags & ~(BCDUMP_F_KNOWN)) != 0)
+               return -1;
+
+       if ((flags & BCDUMP_F_FFI)) {
+               return -1;
+       }
+
+       if ((flags & BCDUMP_F_STRIP)) {
+               ctx->chunkname = kp_str_newz(ctx->ks, "striped");
+       } else {
+               int len = bcread_uint32(ctx);
+               ctx->chunkname = kp_str_new(ctx->ks,
+                               (const char *)bcread_mem(ctx, len), len);
+       }
+
+       if (unlikely(!ctx->chunkname))
+               return -1;
+
+       return 0;
+}
+
+/* Read a bytecode dump. */
+ktap_proto_t *kp_bcread(ktap_state_t *ks, unsigned char *buff, int len)
+{
+       BCReadCtx ctx;
+
+       ctx.ks = ks;
+       ctx.p = buff;
+       ctx.pe = buff + len;
+
+       ctx.start = buff;
+
+       bcread_savetop(&ctx);
+       /* Check for a valid bytecode dump header. */
+       if (bcread_header(&ctx)) {
+               bcread_error(&ctx, KP_ERR_BCFMT);
+               return NULL;
+       }
+
+       for (;;) {  /* Process all prototypes in the bytecode dump. */
+               ktap_proto_t *pt;
+               int len;
+               const char *startp;
+               /* Read length. */
+               if (ctx.p < ctx.pe && ctx.p[0] == 0) {  /* Shortcut EOF. */
+                       ctx.p++;
+                       break;
+               }
+               len = bcread_uint32(&ctx);
+               if (!len)
+                       break;  /* EOF */
+               startp = ctx.p;
+               pt = bcread_proto(&ctx);
+               if (!pt)
+                       return NULL;
+               if (ctx.p != startp + len) {
+                       bcread_error(&ctx, KP_ERR_BCBAD);
+                       return NULL;
+               }
+               set_proto(ks->top, pt);
+               incr_top(ks);
+       }
+       if ((int32_t)(2*(uint32_t)(ctx.pe - ctx.p)) > 0 ||
+                       ks->top-1 != bcread_oldtop(&ctx)) {
+               bcread_error(&ctx, KP_ERR_BCBAD);
+               return NULL;
+       }
+
+       /* Pop off last prototype. */
+       ks->top--;
+       return ptvalue(ks->top);
+}
+
diff --git a/kernel/trace/ktap/kp_bcread.h b/kernel/trace/ktap/kp_bcread.h
new file mode 100644
index 0000000..ea2dde2
--- /dev/null
+++ b/kernel/trace/ktap/kp_bcread.h
@@ -0,0 +1,6 @@
+#ifndef __KTAP_BCREAD_H__
+#define __KTAP_BCREAD_H__
+
+ktap_proto_t *kp_bcread(ktap_state_t *ks, unsigned char *buff, int len);
+
+#endif /* __KTAP_BCREAD_H__ */
-- 
1.8.1.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to