void _gum_duk_process_init (GumDukProcess * self, GumDukCore * core) { GumDukScope scope = GUM_DUK_SCOPE_INIT (core); duk_context * ctx = scope.ctx; self->core = core; duk_push_c_function (ctx, gumjs_process_construct, 0); duk_push_object (ctx); duk_put_function_list (ctx, -1, gumjs_process_functions); duk_push_string (ctx, GUM_SCRIPT_ARCH); duk_put_prop_string (ctx, -2, "arch"); duk_push_string (ctx, GUM_SCRIPT_PLATFORM); duk_put_prop_string (ctx, -2, "platform"); duk_push_uint (ctx, gum_query_page_size ()); duk_put_prop_string (ctx, -2, "pageSize"); duk_push_uint (ctx, GLIB_SIZEOF_VOID_P); duk_put_prop_string (ctx, -2, "pointerSize"); duk_put_prop_string (ctx, -2, "prototype"); duk_new (ctx, 0); _gum_duk_put_data (ctx, -1, self); duk_put_global_string (ctx, "Process"); }
/* * High precission time. If an optional array is given * it returns the difference. */ static duk_ret_t time_hrtime(duk_context* ctx) { uint64_t t = sjs_time_hrtime(); uint64_t sec; uint64_t nsec; if (duk_is_array(ctx, 0)) { uint64_t t0; uint64_t sec0; uint64_t nsec0; duk_get_prop_index(ctx, 0, 0); sec0 = duk_require_uint(ctx, -1); duk_pop(ctx); duk_get_prop_index(ctx, 0, 1); nsec0 = duk_require_uint(ctx, -1); duk_pop(ctx); t0 = sec0 * NANOS_PER_SEC + nsec0; t -= t0; } sec = t / NANOS_PER_SEC; nsec = t % NANOS_PER_SEC; duk_push_array(ctx); duk_push_uint(ctx, sec); duk_put_prop_index(ctx, -2, 0); duk_push_uint(ctx, nsec); duk_put_prop_index(ctx, -2, 1); return 1; }
static int sys1_localtime(duk_context *ctx) { struct tm tm, *tmp; time_t timep = duk_to_uint(ctx, 0); tmp = localtime_r(&timep, &tm); if(!tmp) { duk_push_undefined(ctx); return 1; } duk_push_object(ctx); duk_push_uint(ctx, tm.tm_sec); duk_put_prop_string(ctx, 1, "tm_sec"); duk_push_uint(ctx, tm.tm_min); duk_put_prop_string(ctx, 1, "tm_min"); duk_push_uint(ctx, tm.tm_hour); duk_put_prop_string(ctx, 1, "tm_hour"); duk_push_uint(ctx, tm.tm_mday); duk_put_prop_string(ctx, 1, "tm_mday"); duk_push_uint(ctx, tm.tm_mon); duk_put_prop_string(ctx, 1, "tm_mon"); duk_push_uint(ctx, tm.tm_year); duk_put_prop_string(ctx, 1, "tm_year"); duk_push_uint(ctx, tm.tm_wday); duk_put_prop_string(ctx, 1, "tm_wday"); duk_push_uint(ctx, tm.tm_yday); duk_put_prop_string(ctx, 1, "tm_yday"); duk_push_uint(ctx, tm.tm_isdst); duk_put_prop_string(ctx, 1, "tm_isdst"); return 1; }
DUK_INTERNAL duk_ret_t duk_bi_duktape_object_act(duk_context *ctx) { duk_hthread *thr = (duk_hthread *) ctx; duk_activation *act; duk_uint_fast32_t pc; duk_uint_fast32_t line; duk_int_t level; /* -1 = top callstack entry, callstack[callstack_top - 1] * -callstack_top = bottom callstack entry, callstack[0] */ level = duk_to_int(ctx, 0); if (level >= 0 || -level > (duk_int_t) thr->callstack_top) { return 0; } DUK_ASSERT(level >= -((duk_int_t) thr->callstack_top) && level <= -1); act = thr->callstack + thr->callstack_top + level; duk_push_object(ctx); duk_push_tval(ctx, &act->tv_func); /* Relevant PC is just before current one because PC is * post-incremented. This should match what error augment * code does. */ pc = duk_hthread_get_act_prev_pc(thr, act); duk_push_uint(ctx, (duk_uint_t) pc); #if defined(DUK_USE_PC2LINE) line = duk_hobject_pc2line_query(ctx, -2, pc); #else line = 0; #endif duk_push_uint(ctx, (duk_uint_t) line); /* Providing access to e.g. act->lex_env would be dangerous: these * internal structures must never be accessible to the application. * Duktape relies on them having consistent data, and this consistency * is only asserted for, not checked for. */ /* [ level obj func pc line ] */ /* XXX: version specific array format instead? */ duk_xdef_prop_stridx_wec(ctx, -4, DUK_STRIDX_LINE_NUMBER); duk_xdef_prop_stridx_wec(ctx, -3, DUK_STRIDX_PC); duk_xdef_prop_stridx_wec(ctx, -2, DUK_STRIDX_LC_FUNCTION); return 1; }
static int sys1_gettimeofday(duk_context *ctx) { pid_t rc; struct timeval tv; rc = gettimeofday(&tv, (void*)0); duk_push_uint(ctx, tv.tv_sec); duk_put_prop_string(ctx, 0, "tv_sec"); duk_push_uint(ctx, tv.tv_usec); duk_put_prop_string(ctx, 0, "tv_usec"); duk_push_int(ctx, rc); return 1; }
static AJ_Status PushScalarArg(duk_context* ctx, AJ_Message* msg) { AJ_Arg arg; AJ_Status status = AJ_UnmarshalArg(msg, &arg); if (status == AJ_OK) { switch (arg.typeId) { case AJ_ARG_BYTE: duk_push_uint(ctx, (uint32_t)(*arg.val.v_byte)); break; case AJ_ARG_BOOLEAN: duk_push_boolean(ctx, *arg.val.v_bool); break; case AJ_ARG_UINT32: duk_push_uint(ctx, *arg.val.v_uint32); break; case AJ_ARG_INT32: duk_push_int(ctx, *arg.val.v_int32); break; case AJ_ARG_UINT16: duk_push_uint(ctx, *arg.val.v_uint16); break; case AJ_ARG_INT16: duk_push_int(ctx, *arg.val.v_int16); break; case AJ_ARG_DOUBLE: duk_push_number(ctx, *arg.val.v_double); break; case AJ_ARG_UINT64: /* TODO this will lose precision for numbers ~> 2^52*/ duk_push_number(ctx, (double)*arg.val.v_uint64); break; case AJ_ARG_INT64: /* TODO this will lose precision for numbers ~> 2^52*/ duk_push_number(ctx, (double)*arg.val.v_int64); break; } } return status; }
static int handle_eval(duk_context *ctx, const char *code) { int rc; int retval = -1; duk_push_pointer(ctx, (void *) code); duk_push_uint(ctx, (duk_uint_t) strlen(code)); duk_push_string(ctx, "eval"); interactive_mode = 0; /* global */ rc = duk_safe_call(ctx, wrapped_compile_execute, 3 /*nargs*/, 1 /*nret*/); #if defined(DUK_CMDLINE_AJSHEAP) ajsheap_clear_exec_timeout(); #endif if (rc != DUK_EXEC_SUCCESS) { print_pop_error(ctx, stderr); } else { duk_pop(ctx); retval = 0; } return retval; }
DUK_EXTERNAL int sjs_vm_eval_code(const sjs_vm_t* vm, const char* filename, const char* code, size_t len, FILE* foutput, FILE* ferror) { int r; assert(vm); duk_context* ctx = vm->ctx; duk_push_pointer(ctx, (void *) code); duk_push_uint(ctx, len); duk_push_string(ctx, filename); r = duk_safe_call(ctx, sjs__compile_execute, 3 /*nargs*/, 1 /*nret*/); if (r != DUK_EXEC_SUCCESS) { if (ferror) { duk_safe_call(ctx, sjs__get_error_stack, 1 /*nargs*/, 1 /*nrets*/); fprintf(ferror, "%s\n", duk_safe_to_string(ctx, -1)); fflush(ferror); } } else { if (foutput) { fprintf(foutput, "= %s\n", duk_safe_to_string(ctx, -1)); fflush(foutput); } } duk_pop(ctx); return r; }
static int es_db_last_insert_row_id(duk_context *ctx) { es_sqlite_t *es = es_resource_get(ctx, 0, &es_resource_sqlite); duk_push_uint(ctx, sqlite3_last_insert_rowid(es->es_db)); return 1; }
static duk_ret_t duk_btnp(duk_context* duk) { tic_machine* machine = getDukMachine(duk); tic_mem* memory = (tic_mem*)machine; if (duk_is_null_or_undefined(duk, 0)) { duk_push_uint(duk, memory->api.btnp(memory, -1, -1, -1)); } else if(duk_is_null_or_undefined(duk, 1) && duk_is_null_or_undefined(duk, 2)) { s32 index = duk_to_int(duk, 0) & 0x1f; duk_push_boolean(duk, memory->api.btnp(memory, index, -1, -1)); } else { s32 index = duk_to_int(duk, 0) & 0x1f; u32 hold = duk_to_int(duk, 1); u32 period = duk_to_int(duk, 2); duk_push_boolean(duk, memory->api.btnp(memory, index, hold, period)); } return 1; }
static gboolean gum_emit_malloc_range (const GumMallocRangeDetails * details, gpointer user_data) { GumDukMatchContext * mc = user_data; GumDukScope * scope = mc->scope; duk_context * ctx = scope->ctx; gboolean proceed = TRUE; duk_push_heapptr (ctx, mc->on_match); duk_push_object (ctx); _gum_duk_push_native_pointer (ctx, GSIZE_TO_POINTER (details->range->base_address), scope->core); duk_put_prop_string (ctx, -2, "base"); duk_push_uint (ctx, details->range->size); duk_put_prop_string (ctx, -2, "size"); if (_gum_duk_scope_call_sync (scope, 1)) { if (duk_is_string (ctx, -1)) proceed = strcmp (duk_require_string (ctx, -1), "stop") != 0; } else { proceed = FALSE; } duk_pop (ctx); return proceed; }
static int sys1_time(duk_context *ctx) { time_t t; t = time(0); duk_push_uint(ctx, t); return 1; }
static int handle_fh(duk_context *ctx, FILE *f, const char *filename, const char *bytecode_filename) { char *buf = NULL; int len; size_t got; int rc; int retval = -1; if (fseek(f, 0, SEEK_END) < 0) { goto error; } len = (int) ftell(f); if (fseek(f, 0, SEEK_SET) < 0) { goto error; } buf = (char *) malloc(len); if (!buf) { goto error; } got = fread((void *) buf, (size_t) 1, (size_t) len, f); duk_push_string(ctx, bytecode_filename); duk_push_pointer(ctx, (void *) buf); duk_push_uint(ctx, (duk_uint_t) got); duk_push_string(ctx, filename); interactive_mode = 0; /* global */ rc = duk_safe_call(ctx, wrapped_compile_execute, 4 /*nargs*/, 1 /*nret*/); #if defined(DUK_CMDLINE_AJSHEAP) ajsheap_clear_exec_timeout(); #endif free(buf); buf = NULL; if (rc != DUK_EXEC_SUCCESS) { print_pop_error(ctx, stderr); goto error; } else { duk_pop(ctx); retval = 0; } /* fall thru */ cleanup: if (buf) { free(buf); } return retval; error: fprintf(stderr, "error in executing file %s\n", filename); fflush(stderr); goto cleanup; }
static duk_ret_t test_putprop_shorthand_a(duk_context *ctx) { duk_eval_string(ctx, "({ foo: 123 })"); duk_push_uint(ctx, 123); duk_put_prop_string(ctx, -2, "bar" "\x00" "quux"); duk_push_uint(ctx, 234); duk_put_prop_index(ctx, -2, 2001); duk_push_uint(ctx, 345); duk_put_prop_lstring(ctx, -2, "nul" "\x00" "keyx", 7); duk_json_encode(ctx, -1); printf("%s\n", duk_to_string(ctx, -1)); printf("final top: %ld\n", (long) duk_get_top(ctx)); return 0; }
void _gum_duk_protect (duk_context * ctx, GumDukHeapPtr object) { gchar name[32]; duk_uint_t ref_count; if (object == NULL) return; sprintf (name, "protected_%p", object); duk_push_global_stash (ctx); duk_get_prop_string (ctx, -1, name); if (duk_is_undefined (ctx, -1)) { duk_pop (ctx); duk_push_object (ctx); duk_push_heapptr (ctx, object); duk_put_prop_string (ctx, -2, "o"); ref_count = 1; duk_push_uint (ctx, ref_count); duk_put_prop_string (ctx, -2, "n"); duk_put_prop_string (ctx, -2, name); } else { duk_get_prop_string (ctx, -1, "n"); ref_count = duk_get_uint (ctx, -1); duk_pop (ctx); ref_count++; duk_push_uint (ctx, ref_count); duk_put_prop_string (ctx, -2, "n"); duk_pop (ctx); } duk_pop (ctx); }
static duk_ret_t duk_mget(duk_context* duk) { s32 x = duk_is_null_or_undefined(duk, 0) ? 0 : duk_to_int(duk, 0); s32 y = duk_is_null_or_undefined(duk, 1) ? 0 : duk_to_int(duk, 1); tic_mem* memory = (tic_mem*)getDukMachine(duk); u8 value = memory->api.map_get(memory, &memory->ram.map, x, y); duk_push_uint(duk, value); return 1; }
void _gum_duk_push_range (duk_context * ctx, const GumRangeDetails * details, GumDukCore * core) { char prot_str[4] = "---"; const GumFileMapping * f = details->file; duk_push_object (ctx); _gum_duk_push_native_pointer (ctx, GSIZE_TO_POINTER (details->range->base_address), core); duk_put_prop_string (ctx, -2, "base"); duk_push_uint (ctx, details->range->size); duk_put_prop_string (ctx, -2, "size"); if ((details->prot & GUM_PAGE_READ) != 0) prot_str[0] = 'r'; if ((details->prot & GUM_PAGE_WRITE) != 0) prot_str[1] = 'w'; if ((details->prot & GUM_PAGE_EXECUTE) != 0) prot_str[2] = 'x'; duk_push_string (ctx, prot_str); duk_put_prop_string (ctx, -2, "protection"); if (f != NULL) { duk_push_object (ctx); duk_push_string (ctx, f->path); duk_put_prop_string (ctx, -2, "path"); duk_push_uint (ctx, f->offset); duk_put_prop_string (ctx, -2, "offset"); duk_put_prop_string (ctx, -2, "file"); } }
static void test_one_flags(duk_context *ctx, duk_uint_t defprop_flags) { duk_eval_string(ctx, "({})"); duk_push_string(ctx, "prop"); duk_push_uint(ctx, 123); duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_VALUE | DUK_DEFPROP_FORCE | defprop_flags); dump_prop(ctx); duk_pop(ctx); duk_eval_string(ctx, "(function () { var o = {}; Object.defineProperty(o, 'prop', {value:-123,writable:true,enumerable:true,configurable:true}); return o; })()"); duk_push_string(ctx, "prop"); duk_push_uint(ctx, 123); duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_VALUE | DUK_DEFPROP_FORCE | defprop_flags); dump_prop(ctx); duk_pop(ctx); duk_eval_string(ctx, "(function () { var o = {}; Object.defineProperty(o, 'prop', {value:-123,writable:false,enumerable:false,configurable:false}); return o; })()"); duk_push_string(ctx, "prop"); duk_push_uint(ctx, 123); duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_VALUE | DUK_DEFPROP_FORCE | defprop_flags); dump_prop(ctx); duk_pop(ctx); }
static duk_ret_t duk_peek(duk_context* duk) { s32 address = duk_to_int(duk, 0); if(address >= 0 && address < sizeof(tic_ram)) { tic_machine* machine = getDukMachine(duk); duk_push_uint(duk, *((u8*)&machine->memory.ram + address)); return 1; } return 0; }
static duk_ret_t duk_peek4(duk_context* duk) { s32 address = duk_to_int(duk, 0); if(address >= 0 && address < sizeof(tic_ram)*2) { tic_mem* memory = (tic_mem*)getDukMachine(duk); duk_push_uint(duk, tic_tool_peek4((u8*)&memory->ram, address)); return 1; } return 0; }
static duk_ret_t check_1(duk_context *ctx, void *udata) { int i; (void) udata; /* dummy filler */ for (i = 0; i < 10000; i++) { duk_require_stack(ctx, 1); duk_push_uint(ctx, 123); } duk_push_c_function(ctx, check_1_inner, 0); duk_call(ctx, 0); return 0; }
static duk_ret_t duk_btn(duk_context* duk) { tic_machine* machine = getDukMachine(duk); if (duk_is_null_or_undefined(duk, 0)) { duk_push_uint(duk, machine->memory.ram.input.gamepads.data); } else { s32 index = duk_to_int(duk, 0) & 0x1f; duk_push_boolean(duk, machine->memory.ram.input.gamepads.data & (1 << index)); } return 1; }
static void gum_push_module (duk_context * ctx, const GumModuleDetails * details, GumDukCore * core) { duk_push_object (ctx); duk_push_string (ctx, details->name); duk_put_prop_string (ctx, -2, "name"); _gum_duk_push_uint64 (ctx, details->range->base_address, core); duk_put_prop_string (ctx, -2, "base"); duk_push_uint (ctx, details->range->size); duk_put_prop_string (ctx, -2, "size"); }
static void gum_push_range (duk_context * ctx, const GumRangeDetails * details, GumDukCore * core) { duk_push_object (ctx); _gum_duk_push_uint64 (ctx, details->range->base_address, core); duk_put_prop_string (ctx, -2, "base"); duk_push_uint (ctx, details->range->size); duk_put_prop_string (ctx, -2, "size"); _gum_duk_push_page_protection (ctx, details->prot); duk_put_prop_string (ctx, -2, "protection"); }
DUK_EXTERNAL int sjs_vm_eval_code(const sjs_vm_t* vm, const char* filename, const char* code, size_t len, FILE* foutput, FILE* ferror, bool use_strict) { int r; assert(vm); duk_context* ctx = vm->ctx; duk_push_boolean(ctx, use_strict); duk_push_pointer(ctx, (void *) code); duk_push_uint(ctx, len); duk_push_string(ctx, filename); r = duk_safe_call(ctx, sjs__compile_execute, 4 /*nargs*/, 1 /*nret*/); if (r != DUK_EXEC_SUCCESS) { if (ferror) { duk_safe_call(ctx, sjs__get_error_stack, 1 /*nargs*/, 1 /*nrets*/); fprintf(ferror, "%s\n", duk_safe_to_string(ctx, -1)); fflush(ferror); } } else { if (foutput) { /* TODO: make this optional with a parameter? */ /* beautify output */ duk_eval_string(ctx, "(function (v) {\n" " try {\n" " return Duktape.enc('jx', v, null, 4);\n" " } catch (e) {\n" " return String(v);\n" " }\n" "})"); duk_insert(ctx, -2); duk_call(ctx, 1); fprintf(foutput, "= %s\n", duk_safe_to_string(ctx, -1)); fflush(foutput); } } duk_pop(ctx); return r; }
static duk_ret_t duk_print(duk_context* duk) { tic_mem* memory = (tic_mem*)getDukMachine(duk); const char* text = duk_is_null_or_undefined(duk, 0) ? "" : duk_to_string(duk, 0); s32 x = duk_is_null_or_undefined(duk, 1) ? 0 : duk_to_int(duk, 1); s32 y = duk_is_null_or_undefined(duk, 2) ? 0 : duk_to_int(duk, 2); s32 color = duk_is_null_or_undefined(duk, 3) ? (TIC_PALETTE_SIZE-1) : duk_to_int(duk, 3); bool fixed = duk_is_null_or_undefined(duk, 4) ? false : duk_to_boolean(duk, 4); s32 scale = duk_is_null_or_undefined(duk, 5) ? 1 : duk_to_int(duk, 5); s32 size = memory->api.text_ex(memory, text ? text : "nil", x, y, color, fixed, scale); duk_push_uint(duk, size); return 1; }
void _gum_duk_kernel_init (GumDukKernel * self, GumDukCore * core) { GumDukScope scope = GUM_DUK_SCOPE_INIT (core); duk_context * ctx = scope.ctx; self->core = core; duk_push_object (ctx); duk_push_uint (ctx, gum_kernel_query_page_size ()); duk_put_prop_string (ctx, -2, "pageSize"); _gum_duk_add_properties_to_class_by_heapptr (ctx, duk_require_heapptr (ctx, -1), gumjs_kernel_values); duk_put_function_list (ctx, -1, gumjs_kernel_functions); duk_put_global_string (ctx, "Kernel"); }
DUK_EXTERNAL duk_int_t duk_pnew(duk_context *ctx, duk_idx_t nargs) { duk_int_t rc; DUK_ASSERT_CTX_VALID(ctx); /* For now, just use duk_safe_call() to wrap duk_new(). We can't * simply use a protected duk_handle_call() because there's post * processing which might throw. It should be possible to ensure * the post processing never throws (except in internal errors and * out of memory etc which are always allowed) and then remove this * wrapper. */ duk_push_uint(ctx, nargs); rc = duk_safe_call(ctx, duk__pnew_helper, nargs + 2 /*nargs*/, 1 /*nrets*/); return rc; }
static int es_sqlite_step(duk_context *ctx) { es_sqlite_t *es = es_resource_get(ctx, 0, &es_resource_sqlite); if(es->es_stmt == NULL) { duk_push_null(ctx); return 1; } const int cols = sqlite3_data_count(es->es_stmt); duk_push_object(ctx); for(int i = 0; i < cols; i++) { int64_t i64; switch(sqlite3_column_type(es->es_stmt, i)) { case SQLITE_INTEGER: i64 = sqlite3_column_int64(es->es_stmt, i); if(i64 >= INT32_MIN && i64 <= INT32_MAX) duk_push_int(ctx, i64); else if(i64 >= 0 && i64 <= UINT32_MAX) duk_push_uint(ctx, i64); else duk_push_number(ctx, i64); break; case SQLITE_TEXT: duk_push_string(ctx, (const char *)sqlite3_column_text(es->es_stmt, i)); break; case SQLITE_FLOAT: duk_push_number(ctx, sqlite3_column_double(es->es_stmt, i)); break; default: continue; } duk_put_prop_string(ctx, -2, sqlite3_column_name(es->es_stmt, i)); } es_sqlite_stmt_step(ctx, es); return 1; }
static duk_ret_t test_passthrough(duk_context *ctx, void *udata) { (void) udata; duk_push_c_function(ctx, my_constructor, 1 /*nargs*/); /* target */ duk_push_object(ctx); /* handler */ duk_push_proxy(ctx, 0); duk_push_uint(ctx, 123); duk_new(ctx, 1 /*nargs*/); duk_get_prop_string(ctx, -1, "foo"); printf("ret.foo=%s\n", duk_to_string(ctx, -1)); duk_pop_2(ctx); /* 'foo', constructor result */ printf("final top: %ld\n", (long) duk_get_top(ctx)); return 0; }