DUK_EXTERNAL duk_bool_t duk_put_prop(duk_context *ctx, duk_idx_t obj_index) { duk_hthread *thr = (duk_hthread *) ctx; duk_tval *tv_obj; duk_tval *tv_key; duk_tval *tv_val; duk_small_int_t throw_flag; duk_bool_t rc; DUK_ASSERT_CTX_VALID(ctx); /* Note: copying tv_obj and tv_key to locals to shield against a valstack * resize is not necessary for a property put right now (putprop protects * against it internally). */ tv_obj = duk_require_tval(ctx, obj_index); tv_key = duk_require_tval(ctx, -2); tv_val = duk_require_tval(ctx, -1); throw_flag = duk_is_strict_call(ctx); rc = duk_hobject_putprop(thr, tv_obj, tv_key, tv_val, throw_flag); DUK_ASSERT(rc == 0 || rc == 1); duk_pop_2(ctx); /* remove key and value */ return rc; /* 1 if property found, 0 otherwise */ }
int duk_bi_buffer_prototype_tostring_shared(duk_context *ctx) { duk_tval *tv; int to_string = duk_get_magic(ctx); duk_push_this(ctx); tv = duk_require_tval(ctx, -1); DUK_ASSERT(tv != NULL); if (DUK_TVAL_IS_BUFFER(tv)) { /* nop */ } else if (DUK_TVAL_IS_OBJECT(tv)) { duk_hobject *h = DUK_TVAL_GET_OBJECT(tv); DUK_ASSERT(h != NULL); /* Must be a "buffer object", i.e. class "Buffer" */ if (DUK_HOBJECT_GET_CLASS_NUMBER(h) != DUK_HOBJECT_CLASS_BUFFER) { goto type_error; } duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_VALUE); } else { goto type_error; } if (to_string) { duk_to_string(ctx, -1); } return 1; type_error: return DUK_RET_TYPE_ERROR; }
DUK_EXTERNAL duk_int_t duk_get_magic(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_tval *tv; duk_hobject *h; DUK_ASSERT_CTX_VALID(ctx); tv = duk_require_tval(ctx, idx); if (DUK_TVAL_IS_OBJECT(tv)) { h = DUK_TVAL_GET_OBJECT(tv); DUK_ASSERT(h != NULL); if (!DUK_HOBJECT_HAS_NATFUNC(h)) { goto type_error; } return (duk_int_t) ((duk_hnatfunc *) h)->magic; } else if (DUK_TVAL_IS_LIGHTFUNC(tv)) { duk_small_uint_t lf_flags = DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv); return (duk_int_t) DUK_LFUNC_FLAGS_GET_MAGIC(lf_flags); } /* fall through */ type_error: DUK_ERROR_TYPE(thr, DUK_STR_UNEXPECTED_TYPE); return 0; }
DUK_INTERNAL duk_ret_t duk_bi_string_prototype_to_string(duk_context *ctx) { duk_tval *tv; duk_push_this(ctx); tv = duk_require_tval(ctx, -1); DUK_ASSERT(tv != NULL); if (DUK_TVAL_IS_STRING(tv)) { /* return as is */ return 1; } else if (DUK_TVAL_IS_OBJECT(tv)) { duk_hobject *h = DUK_TVAL_GET_OBJECT(tv); DUK_ASSERT(h != NULL); /* Must be a "string object", i.e. class "String" */ if (DUK_HOBJECT_GET_CLASS_NUMBER(h) != DUK_HOBJECT_CLASS_STRING) { goto type_error; } duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_VALUE); DUK_ASSERT(duk_is_string(ctx, -1)); return 1; } else { goto type_error; } /* never here, but fall through */ type_error: return DUK_RET_TYPE_ERROR; }
DUK_EXTERNAL duk_bool_t duk_has_prop(duk_context *ctx, duk_idx_t obj_index) { duk_hthread *thr = (duk_hthread *) ctx; duk_tval *tv_obj; duk_tval *tv_key; duk_bool_t rc; DUK_ASSERT_CTX_VALID(ctx); /* Note: copying tv_obj and tv_key to locals to shield against a valstack * resize is not necessary for a property existence check right now. */ tv_obj = duk_require_tval(ctx, obj_index); tv_key = duk_require_tval(ctx, -1); rc = duk_hobject_hasprop(thr, tv_obj, tv_key); DUK_ASSERT(rc == 0 || rc == 1); duk_pop(ctx); /* remove key */ return rc; /* 1 if property found, 0 otherwise */ }
DUK_EXTERNAL duk_bool_t duk_del_prop(duk_context *ctx, duk_idx_t obj_index) { duk_hthread *thr = (duk_hthread *) ctx; duk_tval *tv_obj; duk_tval *tv_key; duk_small_int_t throw_flag; duk_bool_t rc; DUK_ASSERT_CTX_VALID(ctx); /* Note: copying tv_obj and tv_key to locals to shield against a valstack * resize is not necessary for a property delete right now. */ tv_obj = duk_require_tval(ctx, obj_index); tv_key = duk_require_tval(ctx, -1); throw_flag = duk_is_strict_call(ctx); rc = duk_hobject_delprop(thr, tv_obj, tv_key, throw_flag); DUK_ASSERT(rc == 0 || rc == 1); duk_pop(ctx); /* remove key */ return rc; }
/* Define own property without inheritance looks and such. This differs from * [[DefineOwnProperty]] because special behaviors (like Array 'length') are * not invoked by this method. The caller must be careful to invoke any such * behaviors if necessary. */ DUK_INTERNAL void duk_xdef_prop(duk_context *ctx, duk_idx_t obj_index, duk_small_uint_t desc_flags) { duk_hthread *thr = (duk_hthread *) ctx; duk_hobject *obj; duk_hstring *key; DUK_ASSERT_CTX_VALID(ctx); obj = duk_require_hobject(ctx, obj_index); DUK_ASSERT(obj != NULL); key = duk_to_hstring(ctx, -2); DUK_ASSERT(key != NULL); DUK_ASSERT(duk_require_tval(ctx, -1) != NULL); duk_hobject_define_property_internal(thr, obj, key, desc_flags); duk_pop(ctx); /* pop key */ }
DUK_INTERNAL void duk_xdef_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx, duk_small_uint_t desc_flags) { duk_hthread *thr = (duk_hthread *) ctx; duk_hobject *obj; duk_hstring *key; DUK_ASSERT_CTX_VALID(ctx); DUK_ASSERT_DISABLE(stridx >= 0); DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS); obj = duk_require_hobject(ctx, obj_index); DUK_ASSERT(obj != NULL); key = DUK_HTHREAD_GET_STRING(thr, stridx); DUK_ASSERT(key != NULL); DUK_ASSERT(duk_require_tval(ctx, -1) != NULL); duk_hobject_define_property_internal(thr, obj, key, desc_flags); /* value popped by call */ }
static int duk_disasm(RAsm *a, RAsmOp *op, const ut8 *buf, int len) { int res = 0, res2 = 0; const char *opstr = NULL; ut8 *b = a->cur->user; duk_push_global_stash (ctx); duk_dup (ctx, 0); /* timer callback */ duk_get_prop_string (ctx, -2, "disfun"); b = a->cur->user = duk_require_tval (ctx, -1); // pushBuffer (buf, len); if (duk_is_callable(ctx, -1)) { int i; // duk_push_string (ctx, "TODO 2"); pushBuffer (buf, len); duk_call (ctx, 1); // [ size, str ] for (i = 0; i<3; i++) { duk_dup_top (ctx); duk_get_prop_index (ctx, -1, i); if (duk_is_number (ctx, -1)) { if (res) res2 = duk_to_number (ctx, -1); else res2 = res = duk_to_number (ctx, -1); } else if (duk_is_string (ctx, -1)) { if (!opstr) { opstr = duk_to_string (ctx, -1); } } duk_pop (ctx); } } else { eprintf ("[:(] Is not a function %02x %02x\n", b[0],b[1]); } // fill op struct op->size = res; if (!opstr) opstr = "invalid"; strncpy (op->buf_asm, opstr, sizeof (op->buf_asm)); r_hex_bin2str (buf, op->size, op->buf_hex); return res2; }
static int duk_assemble(RAsm *a, RAsmOp *op, const char *str) { int i, res = 0; // call myasm function if available duk_push_global_stash (ctx); duk_dup (ctx, 0); /* timer callback */ duk_get_prop_string (ctx, -2, "asmfun"); a->cur->user = duk_require_tval (ctx, -1); if (duk_is_callable(ctx, -1)) { duk_push_string (ctx, str); duk_call (ctx, 1); // [ array of bytes ] //duk_dup_top (ctx); res = duk_get_length (ctx, -1); op->size = res; for (i=0; i<res; i++) { duk_dup_top (ctx); duk_get_prop_index (ctx, -2, i); op->buf[i] = duk_to_int (ctx, -1); } } if (res<1) res = -1; return res; }
DUK_INTERNAL duk_double_t duk_js_tonumber(duk_hthread *thr, duk_tval *tv) { duk_context *ctx = (duk_hthread *) thr; DUK_ASSERT(thr != NULL); DUK_ASSERT(tv != NULL); switch (DUK_TVAL_GET_TAG(tv)) { case DUK_TAG_UNDEFINED: { /* return a specific NaN (although not strictly necessary) */ duk_double_union du; DUK_DBLUNION_SET_NAN(&du); DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du)); return du.d; } case DUK_TAG_NULL: { /* +0.0 */ return 0.0; } case DUK_TAG_BOOLEAN: { if (DUK_TVAL_IS_BOOLEAN_TRUE(tv)) { return 1.0; } return 0.0; } case DUK_TAG_STRING: { duk_hstring *h = DUK_TVAL_GET_STRING(tv); duk_push_hstring(ctx, h); return duk__tonumber_string_raw(thr); } case DUK_TAG_OBJECT: { /* Note: ToPrimitive(object,hint) == [[DefaultValue]](object,hint), * so use [[DefaultValue]] directly. */ duk_double_t d; duk_push_tval(ctx, tv); duk_to_defaultvalue(ctx, -1, DUK_HINT_NUMBER); /* 'tv' becomes invalid */ /* recursive call for a primitive value (guaranteed not to cause second * recursion). */ d = duk_js_tonumber(thr, duk_require_tval(ctx, -1)); duk_pop(ctx); return d; } case DUK_TAG_BUFFER: { /* Coerce like a string. This makes sense because addition also treats * buffers like strings. */ duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv); duk_push_hbuffer(ctx, h); duk_to_string(ctx, -1); /* XXX: expensive, but numconv now expects to see a string */ return duk__tonumber_string_raw(thr); } case DUK_TAG_POINTER: { /* Coerce like boolean */ void *p = DUK_TVAL_GET_POINTER(tv); return (p != NULL ? 1.0 : 0.0); } case DUK_TAG_LIGHTFUNC: { /* +(function(){}) -> NaN */ return DUK_DOUBLE_NAN; } #if defined(DUK_USE_FASTINT) case DUK_TAG_FASTINT: return (duk_double_t) DUK_TVAL_GET_FASTINT(tv); #endif default: { /* number */ DUK_ASSERT(DUK_TVAL_IS_DOUBLE(tv)); return DUK_TVAL_GET_DOUBLE(tv); } } DUK_UNREACHABLE(); }
static int r2plugin(duk_context *ctx) { RLibStruct *lib_struct; int ret = R_TRUE; // args: type, function const char *type = duk_require_string (ctx, 0); if (strcmp (type, "asm")) { eprintf ("TODO: duk.r2plugin only supports 'asm' plugins atm\n"); return R_FALSE; } // call function of 2nd parameter, or get object if (duk_is_function (ctx, 1)) { duk_push_string (ctx, "TODO"); // TODO: this must be the RAsm object to get bits, offset, .. duk_call (ctx, 1); duk_to_object (ctx, 1); } if (!duk_is_object (ctx, 1)) { eprintf ("Expected object or function\n"); return R_FALSE; } duk_to_object (ctx, 1); #define ap asm_plugin ap = R_NEW0 (RAsmPlugin); #define GETSTR(x,y,or) \ duk_dup_top (ctx); \ duk_get_prop_string (ctx, 1, y); \ if (or) { \ const char *str = duk_to_string (ctx, -1); \ x = mystrdup (str? str: or); \ } else { \ x = mystrdup (duk_require_string (ctx, -1)); \ } \ duk_pop (ctx); #define GETINT(x,y,or) \ duk_dup_top (ctx); \ duk_get_prop_string (ctx, 1, y); \ if (or) { \ x = duk_is_number (ctx, -1)? \ duk_to_int (ctx, -1): or; \ } else { \ x = duk_require_int (ctx, -1); \ } \ duk_pop (ctx); #define GETFUN(x,y) \ duk_dup_top (ctx); \ duk_get_prop_string (ctx, 1, y); \ x = duk_require_tval (ctx, 1); \ duk_pop (ctx); // mandatory GETSTR (ap->name, "name", NULL); GETSTR (ap->arch, "arch", NULL); // optional GETSTR (ap->license, "license", "unlicensed"); GETSTR (ap->desc, "description", "JS Disasm Plugin"); GETINT (ap->bits, "bits", 32); // mandatory unless we handle asm+disasm ap->user = duk_require_tval (ctx, -1); //ap->user = duk_dup_top (ctx); // clone object inside user //GETFUN (ap->user, "disassemble"); duk_push_global_stash(ctx); duk_get_prop_string (ctx, 1, "disassemble"); duk_put_prop_string(ctx, -2, "disfun"); // TODO: prefix plugin name somehow ap->disassemble = duk_disasm; duk_push_global_stash(ctx); duk_get_prop_string (ctx, 1, "assemble"); duk_put_prop_string(ctx, -2, "asmfun"); // TODO: prefix plugin name somehow ap->assemble = duk_assemble; #if 0 duk_get_prop_string (ctx, 1, "disassemble"); duk_push_string (ctx, "WINRAR"); duk_call (ctx, 1); #endif #if 0 duk_get_prop_string (ctx, 1, "disassemble"); void *a = duk_require_tval (ctx, -1); if (duk_is_callable (ctx, -1)) { ut8 *b = a; eprintf ("IS FUNCTION %02x %02x \n", b[0], b[1]); } else eprintf ("NOT CALLABLE\n"); ap->user = a; eprintf ("---- %p\n", a); duk_push_string (ctx, "F**K YOU"); //duk_dup_top(ctx); //duk_call_method (ctx, 0); duk_call (ctx, 1); duk_push_tval (ctx, ap->user); // push fun duk_push_string (ctx, "WINRAR"); duk_call (ctx, 1); duk_pop (ctx); #endif // TODO: add support to assemble from js too //ap->assemble = duk_disasm; #define lp lib_struct lp = R_NEW0 (RLibStruct); lp->type = R_LIB_TYPE_ASM; // TODO resolve from handler lp->data = ap; r_lib_open_ptr (Gcore->lib, "duktape.js", NULL, lp); duk_push_boolean (ctx, ret); return 1; }