One Level Up
Top Level
runtime/kp_vm.c - ktap
Global variables defined
Functions defined
Macros defined
Source code
- #include <linux/slab.h>
- #include <linux/ftrace_event.h>
- #include <linux/signal.h>
- #include <linux/sched.h>
- #include <linux/uaccess.h>
- #include "../include/ktap_types.h"
- #include "../include/ktap_bc.h"
- #include "../include/ktap_ffi.h"
- #include "ktap.h"
- #include "kp_obj.h"
- #include "kp_str.h"
- #include "kp_mempool.h"
- #include "kp_tab.h"
- #include "kp_transport.h"
- #include "kp_vm.h"
- #include "kp_events.h"
- #define KTAP_MIN_RESERVED_STACK_SIZE 20
- #define KTAP_STACK_SIZE 120
- #define KTAP_STACK_SIZE_BYTES (KTAP_STACK_SIZE * sizeof(ktap_val_t))
- #define KTAP_PERCPU_BUFFER_SIZE (3 * PAGE_SIZE)
- static ktap_cfunction gfunc_get(ktap_state_t *ks, int idx);
- static int gfunc_getidx(ktap_global_state_t *g, ktap_cfunction cfunc);
- static ktap_str_t *str_concat(ktap_state_t *ks, StkId top, int start, int end)
- {
- int i, len = 0;
- ktap_str_t *ts;
- char *ptr, *buffer;
- for (i = start; i <= end; i++) {
- if (!is_string(top + i)) {
- kp_error(ks, "cannot concat non-string\n");
- return NULL;
- }
- len += rawtsvalue(top + i)->len;
- }
- if (len >= KTAP_PERCPU_BUFFER_SIZE) {
- kp_error(ks, "Error: too long string concatenation\n");
- return NULL;
- }
- preempt_disable_notrace();
- buffer = kp_this_cpu_print_buffer(ks);
- ptr = buffer;
- for (i = start; i <= end; i++) {
- int len = rawtsvalue(top + i)->len;
- strncpy(ptr, svalue(top + i), len);
- ptr += len;
- }
- ts = kp_str_new(ks, buffer, len);
- preempt_enable_notrace();
- return ts;
- }
- static ktap_upval_t *findupval(ktap_state_t *ks, StkId slot)
- {
- ktap_global_state_t *g = G(ks);
- ktap_upval_t **pp = &ks->openupval;
- ktap_upval_t *p;
- ktap_upval_t *uv;
- while (*pp != NULL && (p = *pp)->v >= slot) {
- if (p->v == slot) {
- return p;
- }
- pp = (ktap_upval_t **)&p->nextgc;
- }
-
- uv = (ktap_upval_t *)kp_malloc(ks, sizeof(ktap_upval_t));
- if (!uv)
- return NULL;
- uv->gct = ~KTAP_TUPVAL;
- uv->closed = 0;
- uv->v = slot;
-
- uv->nextgc = (ktap_obj_t *)*pp;
- *pp = uv;
- uv->prev = &g->uvhead;
- uv->next = g->uvhead.next;
- uv->next->prev = uv;
- g->uvhead.next = uv;
- return uv;
- }
- static void unlinkupval(ktap_upval_t *uv)
- {
- uv->next->prev = uv->prev;
- uv->prev->next = uv->next;
- }
- void kp_freeupval(ktap_state_t *ks, ktap_upval_t *uv)
- {
- if (!uv->closed)
- unlinkupval(uv);
- kp_free(ks, uv);
- }
- static void func_closeuv(ktap_state_t *ks, StkId level)
- {
- ktap_upval_t *uv;
- ktap_global_state_t *g = G(ks);
- while (ks->openupval != NULL &&
- (uv = ks->openupval)->v >= level) {
- ktap_obj_t *o = obj2gco(uv);
-
- ks->openupval = (ktap_upval_t *)uv->nextgc;
- unlinkupval(uv);
- set_obj(&uv->tv, uv->v);
- uv->v = &uv->tv;
- uv->closed = 1;
- gch(o)->nextgc = g->allgc;
- g->allgc = o;
- }
- }
- #define SIZE_KTAP_FUNC(n) (sizeof(ktap_func_t) - sizeof(ktap_obj_t *) + \
- sizeof(ktap_obj_t *) * (n))
- static ktap_func_t *func_new_empty(ktap_state_t *ks, ktap_proto_t *pt)
- {
- ktap_func_t *fn;
-
- if (ks != G(ks)->mainthread) {
- kp_error(ks, "only mainthread can create function\n");
- return NULL;
- }
- fn = (ktap_func_t *)kp_obj_new(ks, SIZE_KTAP_FUNC(pt->sizeuv));
- if (!fn)
- return NULL;
- fn->gct = ~KTAP_TFUNC;
- fn->nupvalues = 0;
- fn->pc = proto_bc(pt);
- fn->p = pt;
- return fn;
- }
- static ktap_func_t *func_new(ktap_state_t *ks, ktap_proto_t *pt,
- ktap_func_t *parent, ktap_val_t *base)
- {
- ktap_func_t *fn;
- int nuv = pt->sizeuv, i;
- fn = func_new_empty(ks, pt);
- if (!fn)
- return NULL;
- fn->nupvalues = nuv;
- for (i = 0; i < nuv; i++) {
- uint32_t v = proto_uv(pt)[i];
- ktap_upval_t *uv;
- if (v & PROTO_UV_LOCAL) {
- uv = findupval(ks, base + (v & 0xff));
- if (!uv)
- return NULL;
- uv->immutable = ((v /PROTO_UV_IMMUTABLE) & 1);
- } else {
- uv = parent->upvals[v];
- }
- fn->upvals[i] = uv;
- }
- return fn;
- }
- static inline int checkstack(ktap_state_t *ks, int n)
- {
- if (unlikely(ks->stack_last - ks->top <= n)) {
- kp_error(ks, "stack overflow, please enlarge stack size\n");
- return -1;
- }
- return 0;
- }
- static StkId adjust_varargs(ktap_state_t *ks, ktap_proto_t *p, int actual)
- {
- int i;
- int nfixargs = p->numparams;
- StkId base, fixed;
-
- fixed = ks->top - actual;
- base = ks->top;
- for (i=0; i < nfixargs; i++) {
- set_obj(ks->top++, fixed + i);
- set_nil(fixed + i);
- }
- return base;
- }
- static void poscall(ktap_state_t *ks, StkId func, StkId first_result,
- int wanted)
- {
- int i;
- for (i = wanted; i != 0 && first_result < ks->top; i--)
- set_obj(func++, first_result++);
- while(i-- > 0)
- set_nil(func++);
- }
- void kp_vm_call_proto(ktap_state_t *ks, ktap_proto_t *pt)
- {
- ktap_func_t *fn;
- fn = func_new_empty(ks, pt);
- if (!fn)
- return;
- set_func(ks->top++, fn);
- kp_vm_call(ks, ks->top - 1, 0);
- }
- static __always_inline int check_hot_loop(ktap_state_t *ks, int loop_count)
- {
- if (unlikely(loop_count == kp_max_loop_count)) {
- kp_error(ks, "loop execute count exceed max limit(%d)\n",
- kp_max_loop_count);
- return -1;
- }
- return 0;
- }
- #define dojump(i, e) { pc += (int)bc_d(i) - BCBIAS_J + e; }
- #define donextjump { instr = *pc; dojump(instr, 1); }
- #define NUMADD(a, b) ((a) + (b))
- #define NUMSUB(a, b) ((a) - (b))
- #define NUMMUL(a, b) ((a) * (b))
- #define NUMDIV(a, b) ((a) / (b))
- #define NUMUNM(a) (-(a))
- #define NUMEQ(a, b) ((a) == (b))
- #define NUMLT(a, b) ((a) < (b))
- #define NUMLE(a, b) ((a) <= (b))
- #define NUMMOD(a, b) ((a) % (b))
- #define arith_VV(ks, op) { \
- ktap_val_t *rb = RB; \
- ktap_val_t *rc = RC; \
- if (is_number(rb) && is_number(rc)) { \
- ktap_number nb = nvalue(rb), nc = nvalue(rc); \
- set_number(RA, op(nb, nc)); \
- } else { \
- kp_puts(ks, "Error: Cannot make arith operation\n"); \
- return; \
- } }
- #define arith_VN(ks, op) { \
- ktap_val_t *rb = RB; \
- if (is_number(rb)) { \
- ktap_number nb = nvalue(rb);\
- ktap_number nc = nvalue((ktap_val_t *)kbase + bc_c(instr));\
- set_number(RA, op(nb, nc)); \
- } else { \
- kp_puts(ks, "Error: Cannot make arith operation\n"); \
- return; \
- } }
- #define arith_NV(ks, op) { \
- ktap_val_t *rb = RB; \
- if (is_number(rb)) { \
- ktap_number nb = nvalue(rb);\
- ktap_number nc = nvalue((ktap_val_t *)kbase + bc_c(instr));\
- set_number(RA, op(nc, nb)); \
- } else { \
- kp_puts(ks, "Error: Cannot make arith operation\n"); \
- return; \
- } }
- static const char * const bc_names[] = {
- #define BCNAME(name, ma, mb, mc, mt) #name,
- BCDEF(BCNAME)
- #undef BCNAME
- NULL
- };
- void kp_vm_call(ktap_state_t *ks, StkId func, int nresults)
- {
- int loop_count = 0;
- ktap_func_t *fn;
- ktap_proto_t *pt;
- ktap_obj_t **kbase;
- unsigned int instr, op;
- const unsigned int *pc;
- StkId base;
- int multres = 0;
- ktap_tab_t *gtab = G(ks)->gtab;
-
- static void *dispatch_table[] = {
- #define BCNAME(name, ma, mb, mc, mt) &&DO_BC_##name,
- BCDEF(BCNAME)
- #undef BCNAME
- };
- #define DISPATCH() \
- do { \
- instr = *(pc++); \
- op = bc_op(instr); \
- goto *dispatch_table[op]; \
- } while (0)
- #define RA (base + bc_a(instr))
- #define RB (base + bc_b(instr))
- #define RC (base + bc_c(instr))
- #define RD (base + bc_d(instr))
- #define RKD ((ktap_val_t *)kbase + bc_d(instr))
- TODO
- fn = clvalue(func);
- pt = fn->p;
- kbase = fn->p->k;
- base = func + 1;
- pc = proto_bc(pt) + 1;
- ks->top = base + pt->framesize;
- func->pcr = 0;
-
- DISPATCH();
- while (1) {
- DO_BC_ISLT:
- if (!is_number(RA) || !is_number(RD)) {
- kp_error(ks, "compare with non-number\n");
- return;
- }
- if (nvalue(RA) >= nvalue(RD))
- pc++;
- else
- donextjump;
- DISPATCH();
- DO_BC_ISGE:
- if (!is_number(RA) || !is_number(RD)) {
- kp_error(ks, "compare with non-number\n");
- return;
- }
- if (nvalue(RA) < nvalue(RD))
- pc++;
- else
- donextjump;
- DISPATCH();
- DO_BC_ISLE:
- if (!is_number(RA) || !is_number(RD)) {
- kp_error(ks, "compare with non-number\n");
- return;
- }
- if (nvalue(RA) > nvalue(RD))
- pc++;
- else
- donextjump;
- DISPATCH();
- DO_BC_ISGT:
- if (!is_number(RA) || !is_number(RD)) {
- kp_error(ks, "compare with non-number\n");
- return;
- }
- if (nvalue(RA) <= nvalue(RD))
- pc++;
- else
- donextjump;
- DISPATCH();
- DO_BC_ISEQV:
- if (!kp_obj_equal(RA, RD))
- pc++;
- else
- donextjump;
- DISPATCH();
- DO_BC_ISNEV:
- if (kp_obj_equal(RA, RD))
- pc++;
- else
- donextjump;
- DISPATCH();
- DO_BC_ISEQS: {
- int idx = ~bc_d(instr);
- if (!is_string(RA) ||
- rawtsvalue(RA) != (ktap_str_t *)kbase[idx])
- pc++;
- else
- donextjump;
- DISPATCH();
- }
- DO_BC_ISNES: {
- int idx = ~bc_d(instr);
- if (is_string(RA) &&
- rawtsvalue(RA) == (ktap_str_t *)kbase[idx])
- pc++;
- else
- donextjump;
- DISPATCH();
- }
- DO_BC_ISEQN:
- if (!is_number(RA) || nvalue(RA) != nvalue(RKD))
- pc++;
- else
- donextjump;
- DISPATCH();
- DO_BC_ISNEN:
- if (is_number(RA) && nvalue(RA) == nvalue(RKD))
- pc++;
- else
- donextjump;
- DISPATCH();
- DO_BC_ISEQP:
- if (itype(RA) != ~bc_d(instr))
- pc++;
- else
- donextjump;
- DISPATCH();
- DO_BC_ISNEP:
- if (itype(RA) == ~bc_d(instr))
- pc++;
- else
- donextjump;
- DISPATCH();
- DO_BC_ISTC:
- if (itype(RD) == KTAP_TNIL || itype(RD) == KTAP_TFALSE)
- pc++;
- else {
- set_obj(RA, RD);
- donextjump;
- }
- DISPATCH();
- DO_BC_ISFC:
- if (itype(RD) != KTAP_TNIL && itype(RD) != KTAP_TFALSE)
- pc++;
- else {
- set_obj(RA, RD);
- donextjump;
- }
- DISPATCH();
- DO_BC_IST:
- if (itype(RD) == KTAP_TNIL || itype(RD) == KTAP_TFALSE)
- pc++;
- else
- donextjump;
- DISPATCH();
- DO_BC_ISF:
-
- if (itype(RD) != KTAP_TNIL && itype(RD) != KTAP_TFALSE)
- pc++;
- else
- donextjump;
- DISPATCH();
- DO_BC_ISTYPE:
- DO_BC_ISNUM:
- return;
- DO_BC_MOV:
- set_obj(RA, RD);
- DISPATCH();
- DO_BC_NOT:
- if (itype(RD) == KTAP_TNIL || itype(RD) == KTAP_TFALSE)
- setitype(RA, KTAP_TTRUE);
- else
- setitype(RA, KTAP_TFALSE);
- DISPATCH();
- DO_BC_UNM:
- if (!is_number(RD)) {
- kp_error(ks, "use '-' operator on non-number\n");
- return;
- }
- set_number(RA, -nvalue(RD));
- DISPATCH();
- DO_BC_ADDVN:
- arith_VN(ks, NUMADD);
- DISPATCH();
- DO_BC_SUBVN:
- arith_VN(ks, NUMSUB);
- DISPATCH();
- DO_BC_MULVN:
- arith_VN(ks, NUMMUL);
- DISPATCH();
- DO_BC_DIVVN:
-
- if (!nvalue((ktap_val_t *)kbase + bc_c(instr))) {
- kp_error(ks, "divide 0 arith operation\n");
- return;
- }
- arith_VN(ks, NUMDIV);
- DISPATCH();
- DO_BC_MODVN:
-
- if (!nvalue((ktap_val_t *)kbase + bc_c(instr))) {
- kp_error(ks, "mod 0 arith operation\n");
- return;
- }
- arith_VN(ks, NUMMOD);
- DISPATCH();
- DO_BC_ADDNV:
- arith_NV(ks, NUMADD);
- DISPATCH();
- DO_BC_SUBNV:
- arith_NV(ks, NUMSUB);
- DISPATCH();
- DO_BC_MULNV:
- arith_NV(ks, NUMMUL);
- DISPATCH();
- DO_BC_DIVNV:
-
- if (!nvalue(RB)){
- kp_error(ks, "divide 0 arith operation\n");
- return;
- }
- arith_NV(ks, NUMDIV);
- DISPATCH();
- DO_BC_MODNV:
-
- if (!nvalue(RB)){
- kp_error(ks, "mod 0 arith operation\n");
- return;
- }
- arith_NV(ks, NUMMOD);
- DISPATCH();
- DO_BC_ADDVV:
- arith_VV(ks, NUMADD);
- DISPATCH();
- DO_BC_SUBVV:
- arith_VV(ks, NUMSUB);
- DISPATCH();
- DO_BC_MULVV:
- arith_VV(ks, NUMMUL);
- DISPATCH();
- DO_BC_DIVVV:
- arith_VV(ks, NUMDIV);
- DISPATCH();
- DO_BC_MODVV:
- arith_VV(ks, NUMMOD);
- DISPATCH();
- DO_BC_POW:
- return;
- DO_BC_CAT: {
-
- ktap_str_t *ts = str_concat(ks, base, bc_b(instr),
- bc_c(instr));
- if (!ts)
- return;
- set_string(RA, ts);
- DISPATCH();
- }
- DO_BC_KSTR: {
- int idx = ~bc_d(instr);
- set_string(RA, (ktap_str_t *)kbase[idx]);
- DISPATCH();
- }
- DO_BC_KCDATA:
- DISPATCH();
- DO_BC_KSHORT:
- set_number(RA, bc_d(instr));
- DISPATCH();
- DO_BC_KNUM:
- set_number(RA, nvalue(RKD));
- DISPATCH();
- DO_BC_KPRI:
- setitype(RA, ~bc_d(instr));
- DISPATCH();
- DO_BC_KNIL: {
- int i;
- for (i = 0; i <= bc_d(instr) - bc_a(instr); i++) {
- set_nil(RA + i);
- }
- DISPATCH();
- }
- DO_BC_UGET:
- set_obj(RA, fn->upvals[bc_d(instr)]->v);
- DISPATCH();
- DO_BC_USETV:
- set_obj(fn->upvals[bc_a(instr)]->v, RD);
- DISPATCH();
- DO_BC_UINCV: {
- ktap_val_t *v = fn->upvals[bc_a(instr)]->v;
- if (unlikely(!is_number(RD) || !is_number(v))) {
- kp_error(ks, "use '+=' on non-number\n");
- return;
- }
- set_number(v, nvalue(v) + nvalue(RD));
- DISPATCH();
- }
- DO_BC_USETS: {
- int idx = ~bc_d(instr);
- set_string(fn->upvals[bc_a(instr)]->v,
- (ktap_str_t *)kbase[idx]);
- DISPATCH();
- }
- DO_BC_USETN:
- set_number(fn->upvals[bc_a(instr)]->v, nvalue(RKD));
- DISPATCH();
- DO_BC_UINCN: {
- ktap_val_t *v = fn->upvals[bc_a(instr)]->v;
- if (unlikely(!is_number(v))) {
- kp_error(ks, "use '+=' on non-number\n");
- return;
- }
- set_number(v, nvalue(v) + nvalue(RKD));
- DISPATCH();
- }
- DO_BC_USETP:
- setitype(fn->upvals[bc_a(instr)]->v, ~bc_d(instr));
- DISPATCH();
- DO_BC_UCLO:
- if (ks->openupval != NULL)
- func_closeuv(ks, RA);
- dojump(instr, 0);
- DISPATCH();
- DO_BC_FNEW: {
-
- int idx = ~bc_d(instr);
- ktap_func_t *subfn = func_new(ks, (ktap_proto_t *)kbase[idx],
- fn, base);
- if (unlikely(!subfn))
- return;
- set_func(RA, subfn);
- DISPATCH();
- }
- DO_BC_TNEW: {
-
- ktap_tab_t *t = kp_tab_new_ah(ks, 0, 0);
- if (unlikely(!t))
- return;
- set_table(RA, t);
- DISPATCH();
- }
- DO_BC_TDUP: {
- int idx = ~bc_d(instr);
- ktap_tab_t *t = kp_tab_dup(ks, (ktap_tab_t *)kbase[idx]);
- if (!t)
- return;
- set_table(RA, t);
- DISPATCH();
- }
- DO_BC_GGET: {
- int idx = ~bc_d(instr);
- kp_tab_getstr(gtab, (ktap_str_t *)kbase[idx], RA);
- DISPATCH();
- }
- DO_BC_GSET:
- DO_BC_GINC:
- return;
- DO_BC_TGETV:
- if (unlikely(!is_table(RB))) {
- kp_error(ks, "get key from non-table\n");
- return;
- }
- kp_tab_get(ks, hvalue(RB), RC, RA);
- DISPATCH();
- DO_BC_TGETS: {
- int idx = ~bc_c(instr);
- if (unlikely(!is_table(RB))) {
- kp_error(ks, "get key from non-table\n");
- return;
- }
- kp_tab_getstr(hvalue(RB), (ktap_str_t *)kbase[idx], RA);
- DISPATCH();
- }
- DO_BC_TGETB: {
-
- uint8_t idx = bc_c(instr);
- if (unlikely(!is_table(RB))) {
- kp_error(ks, "set key to non-table\n");
- return;
- }
- kp_tab_getint(hvalue(RB), idx, RA);
- DISPATCH();
- }
- DO_BC_TGETR:
- return;
- DO_BC_TSETV:
- if (unlikely(!is_table(RB))) {
- kp_error(ks, "set key to non-table\n");
- return;
- }
- kp_tab_set(ks, hvalue(RB), RC, RA);
- DISPATCH();
- DO_BC_TINCV:
- if (unlikely(!is_table(RB))) {
- kp_error(ks, "set key to non-table\n");
- return;
- }
- if (unlikely(!is_number(RA))) {
- kp_error(ks, "use '+=' on non-number\n");
- return;
- }
- kp_tab_incr(ks, hvalue(RB), RC, nvalue(RA));
- DISPATCH();
- DO_BC_TSETS: {
- int idx = ~bc_c(instr);
- if (unlikely(!is_table(RB))) {
- kp_error(ks, "set key to non-table\n");
- return;
- }
- kp_tab_setstr(ks, hvalue(RB), (ktap_str_t *)kbase[idx], RA);
- DISPATCH();
- }
- DO_BC_TINCS: {
- int idx = ~bc_c(instr);
- if (unlikely(!is_table(RB))) {
- kp_error(ks, "set key to non-table\n");
- return;
- }
- if (unlikely(!is_number(RA))) {
- kp_error(ks, "use '+=' on non-number\n");
- return;
- }
- kp_tab_incrstr(ks, hvalue(RB), (ktap_str_t *)kbase[idx],
- nvalue(RA));
- DISPATCH();
- }
- DO_BC_TSETB: {
-
- uint8_t idx = bc_c(instr);
- if (unlikely(!is_table(RB))) {
- kp_error(ks, "set key to non-table\n");
- return;
- }
- kp_tab_setint(ks, hvalue(RB), idx, RA);
- DISPATCH();
- }
- DO_BC_TINCB: {
- uint8_t idx = bc_c(instr);
- if (unlikely(!is_table(RB))) {
- kp_error(ks, "set key to non-table\n");
- return;
- }
- if (unlikely(!is_number(RA))) {
- kp_error(ks, "use '+=' on non-number\n");
- return;
- }
- kp_tab_incrint(ks, hvalue(RB), idx, nvalue(RA));
- DISPATCH();
- }
- DO_BC_TSETM:
- return;
- DO_BC_TSETR:
- return;
- DO_BC_CALLM:
- DO_BC_CALL: {
- int c = bc_c(instr);
- int nresults = bc_b(instr) - 1;
- StkId oldtop = ks->top;
- StkId newfunc = RA;
- if (op == BC_CALL && c != 0)
- ks->top = RA + c;
- else if (op == BC_CALLM)
- ks->top = RA + c + multres;
- if (itype(newfunc) == KTAP_TCFUNC) {
- ktap_cfunction f = fvalue(newfunc);
- int n;
- if (unlikely(checkstack(ks,
- KTAP_MIN_RESERVED_STACK_SIZE)))
- return;
- ks->func = newfunc;
- n = (*f)(ks);
- if (unlikely(n < 0))
- return;
- poscall(ks, newfunc, ks->top - n, nresults);
- ks->top = oldtop;
- multres = n + 1;
- DISPATCH();
- } else if (itype(newfunc) == KTAP_TFUNC) {
- int n;
- func = newfunc;
- pt = clvalue(func)->p;
- if (unlikely(checkstack(ks, pt->framesize)))
- return;
-
- n = (int)(ks->top - func) - 1;
-
- for (; n < pt->numparams; n++)
- set_nil(ks->top++);
- base = (!(pt->flags & PROTO_VARARG)) ? func + 1 :
- adjust_varargs(ks, pt, n);
- fn = clvalue(func);
- pt = fn->p;
- kbase = pt->k;
- func->pcr = pc - 1;
- ks->top = base + pt->framesize;
- pc = proto_bc(pt) + 1;
- DISPATCH();
- } else {
- kp_error(ks, "attempt to call nil function\n");
- return;
- }
- }
- DO_BC_CALLMT:
- return;
- DO_BC_CALLT: {
- StkId nfunc = RA;
- if (itype(nfunc) == KTAP_TCFUNC) {
- kp_error(ks, "don't support callt for C function");
- return;
- } else if (itype(nfunc) == KTAP_TFUNC) {
- int aux;
-
- StkId ofunc = func;
-
- StkId lim = nfunc + 1 + clvalue(nfunc)->p->numparams;
- fn = clvalue(nfunc);
- ofunc->val = nfunc->val;
-
- for (aux = 1; nfunc + aux < lim; aux++)
- set_obj(ofunc + aux, nfunc + aux);
- pt = fn->p;
- kbase = pt->k;
- ks->top = base + pt->framesize;
- pc = proto_bc(pt) + 1;
- DISPATCH();
- } else {
- kp_error(ks, "attempt to call nil function\n");
- return;
- }
- }
- DO_BC_ITERC:
- return;
- DO_BC_ITERN:
-
- if (unlikely(check_hot_loop(ks, loop_count++) < 0))
- return;
- if (kp_tab_next(ks, hvalue(RA - 2), RA)) {
- donextjump;
- } else {
- pc++;
- }
- DISPATCH();
- DO_BC_VARG:
- return;
- DO_BC_ISNEXT:
- if (!is_cfunc(RA - 3) || !is_table(RA - 2) || !is_nil(RA - 1)
- || fvalue(RA - 3) != (ktap_cfunction)kp_tab_next) {
-
- setbc_op(pc - 1, BC_JMP);
- dojump(instr, 0);
- setbc_op(pc, BC_ITERC);
- } else {
- dojump(instr, 0);
- set_nil(RA);
- }
- DISPATCH();
- DO_BC_RETM:
- DO_BC_RET:
- return;
- DO_BC_RET0:
-
- if (!func->pcr)
- return;
- pc = func->pcr;
- multres = bc_d(instr);
- set_nil(func);
- base = func - bc_a(*pc);
- func = base - 1;
- fn = clvalue(func);
- kbase = fn->p->k;
- ks->top = base + pt->framesize;
- pc++;
- DISPATCH();
- DO_BC_RET1:
-
- if (!func->pcr)
- return;
- pc = func->pcr;
- multres = bc_d(instr);
- set_obj(base - 1, RA);
- base = func - bc_a(*pc);
- func = base - 1;
- fn = clvalue(func);
- kbase = fn->p->k;
- ks->top = base + pt->framesize;
- pc++;
- DISPATCH();
- DO_BC_FORI: {
- ktap_number idx;
- ktap_number limit;
- ktap_number step;
- if (unlikely(!is_number(RA) || !is_number(RA + 1) ||
- !is_number(RA + 2))) {
- kp_error(ks, KTAP_QL("for")
- " init/limit/step value must be a number\n");
- return;
- }
- idx = nvalue(RA);
- limit = nvalue(RA + 1);
- step = nvalue(RA + 2);
- if (NUMLT(0, step) ? NUMLE(idx, limit) : NUMLE(limit, idx)) {
- set_number(RA + 3, nvalue(RA));
- } else {
- dojump(instr, 0);
- }
- DISPATCH();
- }
- DO_BC_JFORI:
- return;
- DO_BC_FORL: {
- ktap_number step = nvalue(RA + 2);
-
- ktap_number idx = NUMADD(nvalue(RA), step);
- ktap_number limit = nvalue(RA + 1);
- if (NUMLT(0, step) ? NUMLE(idx, limit) : NUMLE(limit, idx)) {
- dojump(instr, 0);
- set_number(RA, idx);
- set_number(RA + 3, idx);
- }
- if (unlikely(check_hot_loop(ks, loop_count++) < 0))
- return;
- DISPATCH();
- }
- DO_BC_IFORL:
- DO_BC_JFORL:
- DO_BC_ITERL:
- DO_BC_IITERL:
- DO_BC_JITERL:
- return;
- DO_BC_LOOP:
-
- if (unlikely(check_hot_loop(ks, loop_count++) < 0))
- return;
- DISPATCH();
- DO_BC_ILOOP:
- DO_BC_JLOOP:
- return;
- DO_BC_JMP:
- dojump(instr, 0);
- DISPATCH();
- DO_BC_FUNCF:
- DO_BC_IFUNCF:
- DO_BC_JFUNCF:
- DO_BC_FUNCV:
- DO_BC_IFUNCV:
- DO_BC_JFUNCV:
- DO_BC_FUNCC:
- DO_BC_FUNCCW:
- return;
- DO_BC_VARGN:
- if (unlikely(!ks->current_event)) {
- kp_error(ks, "invalid event context\n");
- return;
- }
- kp_event_getarg(ks, RA, bc_d(instr));
- DISPATCH();
- DO_BC_VARGSTR: {
-
- struct ktap_event_data *e = ks->current_event;
- if (unlikely(!e)) {
- kp_error(ks, "invalid event context\n");
- return;
- }
- if (e->argstr)
- set_string(RA, e->argstr);
- else
- set_eventstr(RA);
- DISPATCH();
- }
- DO_BC_VPROBENAME: {
- struct ktap_event_data *e = ks->current_event;
- if (unlikely(!e)) {
- kp_error(ks, "invalid event context\n");
- return;
- }
- set_string(RA, e->event->name);
- DISPATCH();
- }
- DO_BC_VPID:
- set_number(RA, (int)current->pid);
- DISPATCH();
- DO_BC_VTID:
- set_number(RA, (int)task_pid_vnr(current));
- DISPATCH();
- DO_BC_VUID: {
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
- uid_t uid = from_kuid_munged(current_user_ns(), current_uid());
- #else
- uid_t uid = current_uid();
- #endif
- set_number(RA, (int)uid);
- DISPATCH();
- }
- DO_BC_VCPU:
- set_number(RA, smp_processor_id());
- DISPATCH();
- DO_BC_VEXECNAME: {
- ktap_str_t *ts = kp_str_newz(ks, current->comm);
- if (unlikely(!ts))
- return;
- set_string(RA, ts);
- DISPATCH();
- }
- DO_BC_GFUNC: {
- ktap_cfunction cfunc = gfunc_get(ks, bc_d(instr));
- set_cfunc(RA, cfunc);
- DISPATCH();
- }
- }
- }
- TODO
- int kp_vm_validate_code(ktap_state_t *ks, ktap_proto_t *pt, ktap_val_t *base)
- {
- const unsigned int *pc = proto_bc(pt) + 1;
- unsigned int instr, op;
- ktap_obj_t **kbase = pt->k;
- ktap_tab_t *gtab = G(ks)->gtab;
- int i;
- #define RA (base + bc_a(instr))
- #define RB (base + bc_b(instr))
- #define RC (base + bc_c(instr))
- #define RD (base + bc_d(instr))
- if (pt->framesize > KP_MAX_SLOTS) {
- kp_error(ks, "exceed max frame size %d\n", pt->framesize);
- return -1;
- }
- if (base + pt->framesize > ks->stack_last) {
- kp_error(ks, "stack overflow\n");
- return -1;
- }
- for (i = 0; i < pt->sizebc - 1; i++) {
- instr = *pc++;
- op = bc_op(instr);
- if (op >= BC__MAX) {
- kp_error(ks, "unknown byte code %d\n", op);
- return -1;
- }
- switch (op) {
- case BC_FNEW: {
- int idx = ~bc_d(instr);
- ktap_proto_t *newpt = (ktap_proto_t *)kbase[idx];
- if (kp_vm_validate_code(ks, newpt, RA + 1))
- return -1;
- break;
- }
- case BC_RETM: case BC_RET:
- kp_error(ks, "don't support return multiple values\n");
- return -1;
- case BC_GSET: case BC_GINC: {
- int idx = ~bc_d(instr);
- ktap_str_t *ts = (ktap_str_t *)kbase[idx];
- kp_error(ks, "cannot set global variable '%s'\n",
- getstr(ts));
- return -1;
- }
- case BC_GGET: {
- int idx = ~bc_d(instr);
- ktap_str_t *ts = (ktap_str_t *)kbase[idx];
- ktap_val_t val;
- kp_tab_getstr(gtab, ts, &val);
- if (is_nil(&val)) {
- kp_error(ks, "undefined global variable"
- " '%s'\n", getstr(ts));
- return -1;
- } else if (is_cfunc(&val)) {
- int idx = gfunc_getidx(G(ks), fvalue(&val));
- if (idx >= 0) {
-
- setbc_op(pc - 1, BC_GFUNC);
- setbc_d(pc - 1, idx);
- }
- }
- break;
- }
- case BC_ITERC:
- kp_error(ks, "ktap only support pairs iteraor\n");
- return -1;
- case BC_POW:
- kp_error(ks, "ktap don't support pow arith\n");
- return -1;
- }
- }
- return 0;
- }
- static ktap_cfunction gfunc_get(ktap_state_t *ks, int idx)
- {
- return G(ks)->gfunc_tbl[idx];
- }
- static int gfunc_getidx(ktap_global_state_t *g, ktap_cfunction cfunc)
- {
- int nr = g->nr_builtin_cfunction;
- ktap_cfunction *gfunc_tbl = g->gfunc_tbl;
- int i;
- for (i = 0; i < nr; i++) {
- if (gfunc_tbl[i] == cfunc)
- return i;
- }
- return -1;
- }
- static void gfunc_add(ktap_state_t *ks, ktap_cfunction cfunc)
- {
- int nr = G(ks)->nr_builtin_cfunction;
- if (nr == KP_MAX_CACHED_CFUNCTION) {
- kp_error(ks, "please enlarge KP_MAX_CACHED_CFUNCTION %d\n",
- KP_MAX_CACHED_CFUNCTION);
- return;
- }
- G(ks)->gfunc_tbl[nr] = cfunc;
- G(ks)->nr_builtin_cfunction++;
- }
- int kp_vm_register_lib(ktap_state_t *ks, const char *libname,
- const ktap_libfunc_t *funcs)
- {
- ktap_tab_t *gtab = G(ks)->gtab;
- ktap_tab_t *target_tbl;
- int i;
-
- if (libname == NULL)
- target_tbl = gtab;
- else {
- ktap_val_t key, val;
- ktap_str_t *ts = kp_str_newz(ks, libname);
- if (!ts)
- return -ENOMEM;
-
- for (i = 0; funcs[i].name != NULL; i++) {
- }
- target_tbl = kp_tab_new_ah(ks, 0, i + 1);
- if (!target_tbl)
- return -ENOMEM;
- set_string(&key, ts);
- set_table(&val, target_tbl);
- kp_tab_set(ks, gtab, &key, &val);
- }
- TODO
- for (i = 0; funcs[i].name != NULL; i++) {
- ktap_str_t *func_name = kp_str_newz(ks, funcs[i].name);
- ktap_val_t fn;
- if (unlikely(!func_name))
- return -ENOMEM;
- set_cfunc(&fn, funcs[i].func);
- kp_tab_setstr(ks, target_tbl, func_name, &fn);
- gfunc_add(ks, funcs[i].func);
- }
- return 0;
- }
- static int init_registry(ktap_state_t *ks)
- {
- ktap_tab_t *registry = kp_tab_new_ah(ks, 2, 0);
- ktap_val_t gtbl;
- ktap_tab_t *t;
- if (!registry)
- return -1;
- set_table(&G(ks)->registry, registry);
-
- t = kp_tab_new_ah(ks, 0, 1024);
- if (!t)
- return -1;
- set_table(>bl, t);
- kp_tab_setint(ks, registry, KTAP_RIDX_GLOBALS, >bl);
- G(ks)->gtab = t;
- return 0;
- }
- static int init_arguments(ktap_state_t *ks, int argc, char __user **user_argv)
- {
- ktap_tab_t *gtbl = G(ks)->gtab;
- ktap_tab_t *arg_tbl = kp_tab_new_ah(ks, argc, 1);
- ktap_val_t arg_tblval;
- ktap_val_t arg_tsval;
- ktap_str_t *argts = kp_str_newz(ks, "arg");
- char **argv;
- int i, ret;
- if (!arg_tbl)
- return -1;
- if (unlikely(!argts))
- return -ENOMEM;
- set_string(&arg_tsval, argts);
- set_table(&arg_tblval, arg_tbl);
- kp_tab_set(ks, gtbl, &arg_tsval, &arg_tblval);
- if (!argc)
- return 0;
- if (argc > 1024)
- return -EINVAL;
- argv = kzalloc(argc * sizeof(char *), GFP_KERNEL);
- if (!argv)
- return -ENOMEM;
- ret = copy_from_user(argv, user_argv, argc * sizeof(char *));
- if (ret < 0) {
- kfree(argv);
- return -EFAULT;
- }
- ret = 0;
- for (i = 0; i < argc; i++) {
- ktap_val_t val;
- char __user *ustr = argv[i];
- char *kstr;
- int len;
- int res;
- len = strlen_user(ustr);
- if (len > 0x1000) {
- ret = -EINVAL;
- break;
- }
- kstr = kmalloc(len + 1, GFP_KERNEL);
- if (!kstr) {
- ret = -ENOMEM;
- break;
- }
- if (strncpy_from_user(kstr, ustr, len) < 0) {
- kfree(kstr);
- ret = -EFAULT;
- break;
- }
- kstr[len] = '\0';
- if (!kstrtoint(kstr, 10, &res)) {
- set_number(&val, res);
- } else {
- ktap_str_t *ts = kp_str_newz(ks, kstr);
- if (unlikely(!ts)) {
- kfree(kstr);
- ret = -ENOMEM;
- break;
- }
- set_string(&val, ts);
- }
- kp_tab_setint(ks, arg_tbl, i, &val);
- kfree(kstr);
- }
- kfree(argv);
- return ret;
- }
- static void free_preserved_data(ktap_state_t *ks)
- {
- int cpu, i, j;
-
- for_each_possible_cpu(cpu) {
- for (j = 0; j < PERF_NR_CONTEXTS; j++) {
- void *percpu_state = G(ks)->percpu_state[j];
- ktap_state_t *pks;
- if (!percpu_state)
- break;
- pks = per_cpu_ptr(percpu_state, cpu);
- if (!ks)
- break;
- kfree(pks->stack);
- }
- }
-
- for (i = 0; i < PERF_NR_CONTEXTS; i++) {
- if (G(ks)->percpu_state[i])
- free_percpu(G(ks)->percpu_state[i]);
- }
-
- for (i = 0; i < PERF_NR_CONTEXTS; i++) {
- if (G(ks)->percpu_print_buffer[i])
- free_percpu(G(ks)->percpu_print_buffer[i]);
- }
-
- for (i = 0; i < PERF_NR_CONTEXTS; i++) {
- if (G(ks)->percpu_temp_buffer[i])
- free_percpu(G(ks)->percpu_temp_buffer[i]);
- }
-
- for (i = 0; i < PERF_NR_CONTEXTS; i++)
- if (G(ks)->recursion_context[i])
- free_percpu(G(ks)->recursion_context[i]);
- }
- #define ALLOC_PERCPU(size) __alloc_percpu(size, __alignof__(char))
- static int init_preserved_data(ktap_state_t *ks)
- {
- void __percpu *data;
- int cpu, i, j;
-
- for (i = 0; i < PERF_NR_CONTEXTS; i++) {
- data = ALLOC_PERCPU(sizeof(ktap_state_t));
- if (!data)
- goto fail;
- G(ks)->percpu_state[i] = data;
- }
-
- for_each_possible_cpu(cpu) {
- for (j = 0; j < PERF_NR_CONTEXTS; j++) {
- void *percpu_state = G(ks)->percpu_state[j];
- ktap_state_t *pks;
- if (!percpu_state)
- break;
- pks = per_cpu_ptr(percpu_state, cpu);
- if (!ks)
- break;
- pks->stack = kzalloc(KTAP_STACK_SIZE_BYTES, GFP_KERNEL);
- if (!pks->stack)
- goto fail;
- pks->stack_last = pks->stack + KTAP_STACK_SIZE;
- G(pks) = G(ks);
- }
- }
-
- for (i = 0; i < PERF_NR_CONTEXTS; i++) {
- data = ALLOC_PERCPU(KTAP_PERCPU_BUFFER_SIZE);
- if (!data)
- goto fail;
- G(ks)->percpu_print_buffer[i] = data;
- }
-
- for (i = 0; i < PERF_NR_CONTEXTS; i++) {
- data = ALLOC_PERCPU(KTAP_PERCPU_BUFFER_SIZE);
- if (!data)
- goto fail;
- G(ks)->percpu_temp_buffer[i] = data;
- }
-
- for (i = 0; i < PERF_NR_CONTEXTS; i++) {
- data = alloc_percpu(int);
- if (!data)
- goto fail;
- G(ks)->recursion_context[i] = data;
- }
- return 0;
- fail:
- free_preserved_data(ks);
- return -ENOMEM;
- }
- static void wait_user_completion(ktap_state_t *ks)
- {
- struct task_struct *tsk = G(ks)->task;
- G(ks)->wait_user = 1;
- while (1) {
- set_current_state(TASK_INTERRUPTIBLE);
-
- schedule_timeout(HZ / 10);
- if (get_nr_threads(tsk) == 1)
- break;
- }
- }
- static void sleep_loop(ktap_state_t *ks,
- int (*actor)(ktap_state_t *ks, void *arg), void *arg)
- {
- while (!ks->stop) {
- set_current_state(TASK_INTERRUPTIBLE);
-
- schedule_timeout(HZ / 10);
- if (actor(ks, arg))
- return;
- }
- }
- static int sl_wait_task_pause_actor(ktap_state_t *ks, void *arg)
- {
- struct task_struct *task = (struct task_struct *)arg;
- if (task->state)
- return 1;
- else
- return 0;
- }
- static int sl_wait_task_exit_actor(ktap_state_t *ks, void *arg)
- {
- struct task_struct *task = (struct task_struct *)arg;
- if (signal_pending(current)) {
- flush_signals(current);
-
- kp_puts(ks, "\n");
- return 1;
- }
-
- if (task && task->state == TASK_DEAD)
- return 1;
- return 0;
- }
- static void wait_user_interrupt(ktap_state_t *ks)
- {
- struct task_struct *task = G(ks)->trace_task;
- if (G(ks)->state == KTAP_EXIT || G(ks)->state == KTAP_ERROR)
- return;
-
- ks->stop = 0;
- if (G(ks)->parm->workload) {
-
- sleep_loop(ks, sl_wait_task_pause_actor, task);
-
- send_sig(SIGINT, G(ks)->trace_task, 0);
- }
- if (!G(ks)->parm->quiet)
- kp_printf(ks, "Tracing... Hit Ctrl-C to end.\n");
- sleep_loop(ks, sl_wait_task_exit_actor, task);
- }
- void kp_vm_exit(ktap_state_t *ks)
- {
- if (!list_empty(&G(ks)->events_head) ||
- !list_empty(&G(ks)->timers))
- wait_user_interrupt(ks);
- kp_exit_timers(ks);
- kp_events_exit(ks);
-
- #ifdef CONFIG_KTAP_FFI
- ffi_free_symbols(ks);
- #endif
- kp_str_freeall(ks);
- kp_mempool_destroy(ks);
- func_closeuv(ks, 0);
- kp_obj_freeall(ks);
- kp_vm_exit_thread(ks);
- kp_free(ks, ks->stack);
- free_preserved_data(ks);
- free_cpumask_var(G(ks)->cpumask);
- wait_user_completion(ks);
-
- if (G(ks)->trace_task)
- put_task_struct(G(ks)->trace_task);
- kp_transport_exit(ks);
- kp_free(ks, ks);
- }
- ktap_state_t *kp_vm_new_state(ktap_option_t *parm, struct dentry *dir)
- {
- ktap_state_t *ks;
- ktap_global_state_t *g;
- pid_t pid;
- int cpu;
- ks = kzalloc(sizeof(ktap_state_t) + sizeof(ktap_global_state_t),
- GFP_KERNEL);
- if (!ks)
- return NULL;
- G(ks) = (ktap_global_state_t *)(ks + 1);
- g = G(ks);
- g->mainthread = ks;
- g->task = current;
- g->parm = parm;
- g->str_lock = (arch_spinlock_t)__ARCH_SPIN_LOCK_UNLOCKED;
- g->strmask = ~(int)0;
- g->uvhead.prev = &g->uvhead;
- g->uvhead.next = &g->uvhead;
- g->state = KTAP_RUNNING;
- INIT_LIST_HEAD(&(g->timers));
- INIT_LIST_HEAD(&(g->events_head));
- if (kp_transport_init(ks, dir))
- goto out;
- ks->stack = kp_malloc(ks, KTAP_STACK_SIZE_BYTES);
- if (!ks->stack)
- goto out;
- ks->stack_last = ks->stack + KTAP_STACK_SIZE;
- ks->top = ks->stack;
- pid = (pid_t)parm->trace_pid;
- if (pid != -1) {
- struct task_struct *task;
- rcu_read_lock();
- task = pid_task(find_vpid(pid), PIDTYPE_PID);
- if (!task) {
- kp_error(ks, "cannot find pid %d\n", pid);
- rcu_read_unlock();
- goto out;
- }
- g->trace_task = task;
- get_task_struct(task);
- rcu_read_unlock();
- }
- if( !alloc_cpumask_var(&g->cpumask, GFP_KERNEL))
- goto out;
- cpumask_copy(g->cpumask, cpu_online_mask);
- cpu = parm->trace_cpu;
- if (cpu != -1) {
- if (!cpu_online(cpu)) {
- kp_error(ks, "ktap: cpu %d is not online\n", cpu);
- goto out;
- }
- cpumask_clear(g->cpumask);
- cpumask_set_cpu(cpu, g->cpumask);
- }
- if (kp_mempool_init(ks, KP_MAX_MEMPOOL_SIZE))
- goto out;
- if (kp_str_resize(ks, 1024 - 1))
- goto out;
- if (init_registry(ks))
- goto out;
- if (init_arguments(ks, parm->argc, parm->argv))
- goto out;
-
- if (kp_lib_init_base(ks))
- goto out;
- if (kp_lib_init_kdebug(ks))
- goto out;
- if (kp_lib_init_timer(ks))
- goto out;
- if (kp_lib_init_ansi(ks))
- goto out;
- #ifdef CONFIG_KTAP_FFI
- if (kp_lib_init_ffi(ks))
- goto out;
- #endif
- if (kp_lib_init_table(ks))
- goto out;
- if (kp_lib_init_net(ks))
- goto out;
- if (init_preserved_data(ks))
- goto out;
- if (kp_events_init(ks))
- goto out;
- return ks;
- out:
- g->state = KTAP_ERROR;
- kp_vm_exit(ks);
- return NULL;
- }
One Level Up
Top Level