int erts_is_native_break(BeamInstr *pc) { #ifdef HIPE ASSERT(pc[-5] == (BeamInstr) BeamOp(op_i_func_info_IaaI)); return pc[0] == (BeamInstr) BeamOp(op_hipe_trap_call) || pc[0] == (BeamInstr) BeamOp(op_hipe_trap_call_closure); #else return 0; #endif }
void erts_install_breakpoints(BpFunctions* f) { Uint i; Uint n = f->matched; BeamInstr br = (BeamInstr) BeamOp(op_i_generic_breakpoint); for (i = 0; i < n; i++) { BeamInstr* pc = f->matching[i].pc; GenericBp* g = (GenericBp *) pc[-4]; if (*pc != br && g) { Module* modp = f->matching[i].mod; /* * The breakpoint must be disabled in the active data * (it will enabled later by switching bp indices), * and enabled in the staging data. */ ASSERT(g->data[erts_active_bp_ix()].flags == 0); ASSERT(g->data[erts_staging_bp_ix()].flags != 0); /* * The following write is not protected by any lock. We * assume that the hardware guarantees that a write of an * aligned word-size (or half-word) writes is atomic * (i.e. that other processes executing this code will not * see a half pointer). */ *pc = br; modp->curr.num_breakpoints++; } } }
/* Empty loop body */ } for (i = specified; i < 3; i++) { if (mfa[i] != am_Underscore) { goto error; } } if (is_small(mfa[2])) { mfa[2] = signed_val(mfa[2]); } if (!erts_try_seize_code_write_permission(BIF_P)) { ERTS_BIF_YIELD2(bif_export[BIF_erts_debug_breakpoint_2], BIF_P, BIF_ARG_1, BIF_ARG_2); } erts_smp_proc_unlock(p, ERTS_PROC_LOCK_MAIN); erts_smp_thr_progress_block(); erts_bp_match_functions(&f, mfa, specified); if (boolean == am_true) { erts_set_debug_break(&f); erts_install_breakpoints(&f); erts_commit_staged_bp(); } else { erts_clear_debug_break(&f); erts_commit_staged_bp(); erts_uninstall_breakpoints(&f); } erts_consolidate_bp_data(&f, 1); res = make_small(f.matched); erts_bp_free_matched_functions(&f); erts_smp_thr_progress_unblock(); erts_smp_proc_lock(p, ERTS_PROC_LOCK_MAIN); erts_release_code_write_permission(); return res; error: BIF_ERROR(p, BADARG); } #if 0 /* Kept for conveninence when hard debugging. */ void debug_dump_code(BeamInstr *I, int num) { BeamInstr *code_ptr = I; BeamInstr *end = code_ptr + num; erts_dsprintf_buf_t *dsbufp; BeamInstr instr; int i; dsbufp = erts_create_tmp_dsbuf(0); while (code_ptr < end) { erts_print(ERTS_PRINT_DSBUF, (void *) dsbufp, HEXF ": ", code_ptr); instr = (BeamInstr) code_ptr[0]; for (i = 0; i < NUM_SPECIFIC_OPS; i++) { if (instr == (BeamInstr) BeamOp(i) && opc[i].name[0] != '\0') { code_ptr += print_op(ERTS_PRINT_DSBUF, (void *) dsbufp, i, opc[i].sz-1, code_ptr+1) + 1; break; } } if (i >= NUM_SPECIFIC_OPS) { erts_print(ERTS_PRINT_DSBUF, (void *) dsbufp, "unknown " HEXF "\n", instr); code_ptr++; } } dsbufp->str[dsbufp->str_len] = 0; erts_fprintf(stderr,"%s", dsbufp->str); erts_destroy_tmp_dsbuf(dsbufp); }
/* * SMP NOTE: Process p may have become exiting on return! */ BeamInstr erts_trace_break(Process *p, BeamInstr *pc, Eterm *args, Uint32 *ret_flags, Eterm *tracer_pid) { Eterm tpid1, tpid2; BpData **bds = (BpData **) (pc)[-4]; BpDataTrace *bdt = NULL; ASSERT(bds); ASSERT(pc[-5] == (BeamInstr) BeamOp(op_i_func_info_IaaI)); bdt = (BpDataTrace *) bds[bp_sched2ix_proc(p)]; ASSERT(bdt); bdt = (BpDataTrace *) bdt->next; ASSERT(bdt); ASSERT(ret_flags); ASSERT(tracer_pid); ErtsSmpBPLock(bdt); tpid1 = tpid2 = bdt->tracer_pid; ErtsSmpBPUnlock(bdt); *ret_flags = erts_call_trace(p, pc-3/*mfa*/, bdt->match_spec, args, 1, &tpid2); *tracer_pid = tpid2; if (tpid1 != tpid2) { ErtsSmpBPLock(bdt); bdt->tracer_pid = tpid2; ErtsSmpBPUnlock(bdt); } bds[bp_sched2ix_proc(p)] = (BpData *) bdt; return bdt->orig_instr; }
static int set_module_break(Module *modp, Eterm mfa[3], int specified, Binary *match_spec, Uint break_op, enum erts_break_op count_op, Eterm tracer_pid) { Uint** code_base; Uint* code_ptr; int num_processed = 0; Uint i,n; ASSERT(break_op); ASSERT(modp); code_base = (Uint **) modp->code; if (code_base == NULL) { return 0; } n = (Uint) code_base[MI_NUM_FUNCTIONS]; for (i = 0; i < n; ++i) { code_ptr = code_base[MI_FUNCTIONS+i]; ASSERT(code_ptr[0] == (Uint) BeamOp(op_i_func_info_IaaI)); if ((specified < 2 || mfa[1] == ((Eterm) code_ptr[3])) && (specified < 3 || ((int) mfa[2]) == ((int) code_ptr[4]))) { Uint *pc = code_ptr+5; num_processed += set_function_break(modp, pc, match_spec, break_op, count_op, tracer_pid); } } return num_processed; }
/* ** Searches (linear forward) the breakpoint ring for a specified opcode ** and returns a pointer to the breakpoint data structure or NULL if ** not found. If the specified opcode is 0, the last breakpoint is ** returned. The program counter must point to the first executable ** (breakpoint) instruction of the function. */ static BpData *is_break(Uint *pc, Uint break_op) { ASSERT(pc[-5] == (Uint) BeamOp(op_i_func_info_IaaI)); if (! erts_is_native_break(pc)) { BpData *bd = (BpData *) pc[-4]; if (break_op == 0) { return bd; } if (*pc == break_op) { ASSERT(bd); return bd->next; } if (! bd){ return NULL; } bd = bd->next; while (bd != (BpData *) pc[-4]) { ASSERT(bd); if (bd->orig_instr == break_op) { bd = bd->next; ASSERT(bd); return bd; } else { bd = bd->next; } } } return NULL; }
/* * SMP NOTE: Process p may have become exiting on return! */ Uint erts_trace_break(Process *p, Uint *pc, Eterm *args, Uint32 *ret_flags, Eterm *tracer_pid) { Eterm tpid1, tpid2; BpDataTrace *bdt = (BpDataTrace *) pc[-4]; ASSERT(pc[-5] == (Uint) BeamOp(op_i_func_info_IaaI)); ASSERT(bdt); bdt = (BpDataTrace *) bdt->next; ASSERT(bdt); ASSERT(ret_flags); ASSERT(tracer_pid); ErtsSmpBPLock(bdt); tpid1 = tpid2 = bdt->tracer_pid; ErtsSmpBPUnlock(bdt); *ret_flags = erts_call_trace(p, pc-3/*mfa*/, bdt->match_spec, args, 1, &tpid2); *tracer_pid = tpid2; if (tpid1 != tpid2) { ErtsSmpBPLock(bdt); bdt->tracer_pid = tpid2; ErtsSmpBPUnlock(bdt); } pc[-4] = (Uint) bdt; return bdt->orig_instr; }
int erts_set_mtrace_break(Eterm mfa[3], int specified, Binary *match_spec, Eterm tracer_pid) { ERTS_SMP_LC_ASSERT(erts_smp_is_system_blocked(0)); return set_break(mfa, specified, match_spec, (Uint) BeamOp(op_i_mtrace_breakpoint), 0, tracer_pid); }
int erts_set_mtrace_break(Eterm mfa[3], int specified, Binary *match_spec, Eterm tracer_pid) { ERTS_SMP_LC_ASSERT(erts_smp_thr_progress_is_blocking()); return set_break(mfa, specified, match_spec, (BeamInstr) BeamOp(op_i_mtrace_breakpoint), 0, tracer_pid); }
int erts_is_time_break(Process *p, BeamInstr *pc, Eterm *retval) { Uint i, ix; bp_time_hash_t hash; Uint size; Eterm *hp, t; bp_data_time_item_t *item = NULL; BpDataTime *bdt = (BpDataTime *) is_break(pc, (BeamInstr) BeamOp(op_i_time_breakpoint)); if (bdt) { if (retval) { /* collect all hashes to one hash */ bp_hash_init(&hash, 64); /* foreach threadspecific hash */ for (i = 0; i < bdt->n; i++) { bp_data_time_item_t *sitem; /* foreach hash bucket not NIL*/ for(ix = 0; ix < bdt->hash[i].n; ix++) { item = &(bdt->hash[i].item[ix]); if (item->pid != NIL) { sitem = bp_hash_get(&hash, item); if (sitem) { BP_TIME_ADD(sitem, item); } else { bp_hash_put(&hash, item); } } } } /* *retval should be NIL or term from previous bif in export entry */ if (hash.used > 0) { size = (5 + 2)*hash.used; hp = HAlloc(p, size); for(ix = 0; ix < hash.n; ix++) { item = &(hash.item[ix]); if (item->pid != NIL) { t = TUPLE4(hp, item->pid, make_small(item->count), make_small(item->s_time), make_small(item->us_time)); hp += 5; *retval = CONS(hp, t, *retval); hp += 2; } } } bp_hash_delete(&hash); } return !0; } return 0; }
int erts_is_count_break(BeamInstr *pc, Sint *count_ret) { BpDataCount *bdc = (BpDataCount *) is_break(pc, (BeamInstr) BeamOp(op_i_count_breakpoint)); if (bdc) { if (count_ret) { *count_ret = (Sint) erts_smp_atomic_read_nob(&bdc->acount); } return !0; } return 0; }
Export* erts_find_function(Eterm m, Eterm f, unsigned int a, ErtsCodeIndex code_ix) { struct export_templ templ; struct export_entry* ee; ee = hash_get_ext(&export_tables[code_ix].htable, init_template(&templ, m, f, a), &fun); if (ee == NULL || (ee->ep->addressv[code_ix] == ee->ep->code+3 && ee->ep->code[3] != (BeamInstr) BeamOp(op_i_generic_breakpoint))) { return NULL; } return ee->ep; }
int erts_is_count_break(Uint *pc, Sint *count_ret) { BpDataCount *bdc = (BpDataCount *) is_break(pc, (Uint) BeamOp(op_i_count_breakpoint)); if (bdc) { if (count_ret) { ErtsSmpBPLock(bdc); *count_ret = bdc->count; ErtsSmpBPUnlock(bdc); } return !0; } return 0; }
void erts_bp_match_export(BpFunctions* f, ErtsCodeMFA *mfa, int specified) { ErtsCodeIndex code_ix = erts_active_code_ix(); int i; int num_exps = export_list_size(code_ix); int ne; f->matching = (BpFunction *) Alloc(num_exps*sizeof(BpFunction)); ne = 0; for (i = 0; i < num_exps; i++) { Export* ep = export_list(i, code_ix); BeamInstr* pc; switch (specified) { case 3: if (mfa->arity != ep->info.mfa.arity) continue; case 2: if (mfa->function != ep->info.mfa.function) continue; case 1: if (mfa->module != ep->info.mfa.module) continue; case 0: break; default: ASSERT(0); } pc = ep->beam; if (ep->addressv[code_ix] == pc) { if ((*pc == (BeamInstr) em_apply_bif || *pc == (BeamInstr) em_call_error_handler)) { continue; } ASSERT(*pc == (BeamInstr) BeamOp(op_i_generic_breakpoint)); } else if (erts_is_function_native(erts_code_to_codeinfo(ep->addressv[code_ix]))) { continue; } f->matching[ne].ci = &ep->info; f->matching[ne].mod = erts_get_module(ep->info.mfa.module, code_ix); ne++; } f->matched = ne; }
static void uninstall_breakpoint(BeamInstr* pc) { if (*pc == (BeamInstr) BeamOp(op_i_generic_breakpoint)) { GenericBp* g = (GenericBp *) pc[-4]; if (g->data[erts_active_bp_ix()].flags == 0) { /* * The following write is not protected by any lock. We * assume that the hardware guarantees that a write of an * aligned word-size (or half-word) writes is atomic * (i.e. that other processes executing this code will not * see a half pointer). */ *pc = g->orig_instr; } } }
int erts_is_mtrace_break(BeamInstr *pc, Binary **match_spec_ret, Eterm *tracer_pid_ret) { BpDataTrace *bdt = (BpDataTrace *) is_break(pc, (BeamInstr) BeamOp(op_i_mtrace_breakpoint)); if (bdt) { if (match_spec_ret) { *match_spec_ret = bdt->match_spec; } if (tracer_pid_ret) { ErtsSmpBPLock(bdt); *tracer_pid_ret = bdt->tracer_pid; ErtsSmpBPUnlock(bdt); } return !0; } return 0; }
void erts_bp_match_export(BpFunctions* f, Eterm mfa[3], int specified) { ErtsCodeIndex code_ix = erts_active_code_ix(); int i; int num_exps = export_list_size(code_ix); int ne; f->matching = (BpFunction *) Alloc(num_exps*sizeof(BpFunction)); ne = 0; for (i = 0; i < num_exps; i++) { Export* ep = export_list(i, code_ix); BeamInstr* pc; int j; for (j = 0; j < specified && mfa[j] == ep->code[j]; j++) { /* Empty loop body */ } if (j < specified) { continue; } pc = ep->code+3; if (ep->addressv[code_ix] == pc) { if ((*pc == (BeamInstr) em_apply_bif || *pc == (BeamInstr) em_call_error_handler)) { continue; } ASSERT(*pc == (BeamInstr) BeamOp(op_i_generic_breakpoint)); } else if (erts_is_native_break(ep->addressv[code_ix])) { continue; } f->matching[ne].pc = pc; f->matching[ne].mod = erts_get_module(ep->code[0], code_ix); ne++; } f->matched = ne; }
static void delete_code(Module* modp) { ErtsCodeIndex code_ix = erts_staging_code_ix(); Eterm module = make_atom(modp->module); int i; for (i = 0; i < export_list_size(code_ix); i++) { Export *ep = export_list(i, code_ix); if (ep != NULL && (ep->info.mfa.module == module)) { if (ep->addressv[code_ix] == ep->beam) { if (ep->beam[0] == (BeamInstr) em_apply_bif) { continue; } else if (ep->beam[0] == (BeamInstr) BeamOp(op_i_generic_breakpoint)) { ERTS_SMP_LC_ASSERT(erts_smp_thr_progress_is_blocking()); ASSERT(modp->curr.num_traced_exports > 0); DBG_TRACE_MFA_P(&ep->info.mfa, "export trace cleared, code_ix=%d", code_ix); erts_clear_export_break(modp, &ep->info); } else ASSERT(ep->beam[0] == (BeamInstr) em_call_error_handler || !erts_initialized); } ep->addressv[code_ix] = ep->beam; ep->beam[0] = (BeamInstr) em_call_error_handler; ep->beam[1] = 0; DBG_TRACE_MFA_P(&ep->info.mfa, "export invalidation, code_ix=%d", code_ix); } } ASSERT(modp->curr.num_breakpoints == 0); ASSERT(modp->curr.num_traced_exports == 0); modp->old = modp->curr; erts_module_instance_init(&modp->curr); }
static void delete_code(Module* modp) { ErtsCodeIndex code_ix = erts_staging_code_ix(); Eterm module = make_atom(modp->module); int i; for (i = 0; i < export_list_size(code_ix); i++) { Export *ep = export_list(i, code_ix); if (ep != NULL && (ep->code[0] == module)) { if (ep->addressv[code_ix] == ep->code+3) { if (ep->code[3] == (BeamInstr) em_apply_bif) { continue; } else if (ep->code[3] == (BeamInstr) BeamOp(op_i_generic_breakpoint)) { ERTS_SMP_LC_ASSERT(erts_smp_thr_progress_is_blocking()); ASSERT(modp->curr.num_traced_exports > 0); erts_clear_export_break(modp, ep->code+3); } else ASSERT(ep->code[3] == (BeamInstr) em_call_error_handler || !erts_initialized); } ep->addressv[code_ix] = ep->code+3; ep->code[3] = (BeamInstr) em_call_error_handler; ep->code[4] = 0; } } ASSERT(modp->curr.num_breakpoints == 0); ASSERT(modp->curr.num_traced_exports == 0); modp->old = modp->curr; modp->curr.code_hdr = NULL; modp->curr.code_length = 0; modp->curr.catches = BEAM_CATCHES_NIL; modp->curr.nif = NULL; }
BeamInstr * erts_find_local_func(Eterm mfa[3]) { Module *modp; BeamInstr** code_base; BeamInstr* code_ptr; Uint i,n; if ((modp = erts_get_module(mfa[0])) == NULL) return NULL; if ((code_base = (BeamInstr **) modp->code) == NULL) return NULL; n = (BeamInstr) code_base[MI_NUM_FUNCTIONS]; for (i = 0; i < n; ++i) { code_ptr = code_base[MI_FUNCTIONS+i]; ASSERT(((BeamInstr) BeamOp(op_i_func_info_IaaI)) == code_ptr[0]); ASSERT(mfa[0] == ((Eterm) code_ptr[2])); if (mfa[1] == ((Eterm) code_ptr[3]) && ((BeamInstr) mfa[2]) == code_ptr[4]) { return code_ptr + 5; } } return NULL; }
int erts_clear_time_break(Eterm mfa[3], int specified) { ERTS_SMP_LC_ASSERT(erts_smp_thr_progress_is_blocking()); return clear_break(mfa, specified, (BeamInstr) BeamOp(op_i_time_breakpoint)); }
BIF_RETTYPE load_nif_2(BIF_ALIST_2) { static const char bad_lib[] = "bad_lib"; static const char reload[] = "reload"; static const char upgrade[] = "upgrade"; char* lib_name = NULL; void* handle = NULL; void* init_func; ErlNifEntry* entry = NULL; ErlNifEnv env; int len, i, err; Module* mod; Eterm mod_atom; Eterm f_atom; BeamInstr* caller; ErtsSysDdllError errdesc = ERTS_SYS_DDLL_ERROR_INIT; Eterm ret = am_ok; int veto; struct erl_module_nif* lib = NULL; len = list_length(BIF_ARG_1); if (len < 0) { BIF_ERROR(BIF_P, BADARG); } lib_name = (char *) erts_alloc(ERTS_ALC_T_TMP, len + 1); if (intlist_to_buf(BIF_ARG_1, lib_name, len) != len) { erts_free(ERTS_ALC_T_TMP, lib_name); BIF_ERROR(BIF_P, BADARG); } lib_name[len] = '\0'; /* Block system (is this the right place to do it?) */ erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); erts_smp_thr_progress_block(); /* Find calling module */ ASSERT(BIF_P->current != NULL); ASSERT(BIF_P->current[0] == am_erlang && BIF_P->current[1] == am_load_nif && BIF_P->current[2] == 2); caller = find_function_from_pc(BIF_P->cp); ASSERT(caller != NULL); mod_atom = caller[0]; ASSERT(is_atom(mod_atom)); mod=erts_get_module(mod_atom); ASSERT(mod != NULL); if (!in_area(caller, mod->code, mod->code_length)) { ASSERT(in_area(caller, mod->old_code, mod->old_code_length)); ret = load_nif_error(BIF_P, "old_code", "Calling load_nif from old " "module '%T' not allowed", mod_atom); } else if ((err=erts_sys_ddll_open2(lib_name, &handle, &errdesc)) != ERL_DE_NO_ERROR) { const char slogan[] = "Failed to load NIF library"; if (strstr(errdesc.str, lib_name) != NULL) { ret = load_nif_error(BIF_P, "load_failed", "%s: '%s'", slogan, errdesc.str); } else { ret = load_nif_error(BIF_P, "load_failed", "%s %s: '%s'", slogan, lib_name, errdesc.str); } } else if (erts_sys_ddll_load_nif_init(handle, &init_func, &errdesc) != ERL_DE_NO_ERROR) { ret = load_nif_error(BIF_P, bad_lib, "Failed to find library init" " function: '%s'", errdesc.str); } else if ((add_taint(mod_atom), (entry = erts_sys_ddll_call_nif_init(init_func)) == NULL)) { ret = load_nif_error(BIF_P, bad_lib, "Library init-call unsuccessful"); } else if (entry->major != ERL_NIF_MAJOR_VERSION || entry->minor > ERL_NIF_MINOR_VERSION) { ret = load_nif_error(BIF_P, bad_lib, "Library version (%d.%d) not compatible (with %d.%d).", entry->major, entry->minor, ERL_NIF_MAJOR_VERSION, ERL_NIF_MINOR_VERSION); } else if (entry->minor >= 1 && sys_strcmp(entry->vm_variant, ERL_NIF_VM_VARIANT) != 0) { ret = load_nif_error(BIF_P, bad_lib, "Library (%s) not compiled for " "this vm variant (%s).", entry->vm_variant, ERL_NIF_VM_VARIANT); } else if (!erts_is_atom_str((char*)entry->name, mod_atom)) { ret = load_nif_error(BIF_P, bad_lib, "Library module name '%s' does not" " match calling module '%T'", entry->name, mod_atom); } else { /*erts_fprintf(stderr, "Found module %T\r\n", mod_atom);*/ for (i=0; i < entry->num_of_funcs && ret==am_ok; i++) { BeamInstr** code_pp; ErlNifFunc* f = &entry->funcs[i]; if (!erts_atom_get(f->name, sys_strlen(f->name), &f_atom) || (code_pp = get_func_pp(mod->code, f_atom, f->arity))==NULL) { ret = load_nif_error(BIF_P,bad_lib,"Function not found %T:%s/%u", mod_atom, f->name, f->arity); } else if (code_pp[1] - code_pp[0] < (5+3)) { ret = load_nif_error(BIF_P,bad_lib,"No explicit call to load_nif" " in module (%T:%s/%u to small)", mod_atom, entry->funcs[i].name, entry->funcs[i].arity); } /*erts_fprintf(stderr, "Found NIF %T:%s/%u\r\n", mod_atom, entry->funcs[i].name, entry->funcs[i].arity);*/ } } if (ret != am_ok) { goto error; } /* Call load, reload or upgrade: */ lib = erts_alloc(ERTS_ALC_T_NIF, sizeof(struct erl_module_nif)); lib->handle = handle; lib->entry = entry; erts_refc_init(&lib->rt_cnt, 0); erts_refc_init(&lib->rt_dtor_cnt, 0); lib->mod = mod; env.mod_nif = lib; if (mod->nif != NULL) { /* Reload */ int k; lib->priv_data = mod->nif->priv_data; ASSERT(mod->nif->entry != NULL); if (entry->reload == NULL) { ret = load_nif_error(BIF_P,reload,"Reload not supported by this NIF library."); goto error; } /* Check that no NIF is removed */ for (k=0; k < mod->nif->entry->num_of_funcs; k++) { ErlNifFunc* old_func = &mod->nif->entry->funcs[k]; for (i=0; i < entry->num_of_funcs; i++) { if (old_func->arity == entry->funcs[i].arity && sys_strcmp(old_func->name, entry->funcs[i].name) == 0) { break; } } if (i == entry->num_of_funcs) { ret = load_nif_error(BIF_P,reload,"Reloaded library missing " "function %T:%s/%u\r\n", mod_atom, old_func->name, old_func->arity); goto error; } } erts_pre_nif(&env, BIF_P, lib); veto = entry->reload(&env, &lib->priv_data, BIF_ARG_2); erts_post_nif(&env); if (veto) { ret = load_nif_error(BIF_P, reload, "Library reload-call unsuccessful."); } else { mod->nif->entry = NULL; /* to prevent 'unload' callback */ erts_unload_nif(mod->nif); } } else { lib->priv_data = NULL; if (mod->old_nif != NULL) { /* Upgrade */ void* prev_old_data = mod->old_nif->priv_data; if (entry->upgrade == NULL) { ret = load_nif_error(BIF_P, upgrade, "Upgrade not supported by this NIF library."); goto error; } erts_pre_nif(&env, BIF_P, lib); veto = entry->upgrade(&env, &lib->priv_data, &mod->old_nif->priv_data, BIF_ARG_2); erts_post_nif(&env); if (veto) { mod->old_nif->priv_data = prev_old_data; ret = load_nif_error(BIF_P, upgrade, "Library upgrade-call unsuccessful."); } /*else if (mod->old_nif->priv_data != prev_old_data) { refresh_cached_nif_data(mod->old_code, mod->old_nif); }*/ } else if (entry->load != NULL) { /* Initial load */ erts_pre_nif(&env, BIF_P, lib); veto = entry->load(&env, &lib->priv_data, BIF_ARG_2); erts_post_nif(&env); if (veto) { ret = load_nif_error(BIF_P, "load", "Library load-call unsuccessful."); } } } if (ret == am_ok) { /* ** Everything ok, patch the beam code with op_call_nif */ mod->nif = lib; for (i=0; i < entry->num_of_funcs; i++) { BeamInstr* code_ptr; erts_atom_get(entry->funcs[i].name, sys_strlen(entry->funcs[i].name), &f_atom); code_ptr = *get_func_pp(mod->code, f_atom, entry->funcs[i].arity); if (code_ptr[1] == 0) { code_ptr[5+0] = (BeamInstr) BeamOp(op_call_nif); } else { /* Function traced, patch the original instruction word */ BpData** bps = (BpData**) code_ptr[1]; BpData* bp = (BpData*) bps[erts_bp_sched2ix()]; bp->orig_instr = (BeamInstr) BeamOp(op_call_nif); } code_ptr[5+1] = (BeamInstr) entry->funcs[i].fptr; code_ptr[5+2] = (BeamInstr) lib; } } else { error: ASSERT(ret != am_ok); if (lib != NULL) { erts_free(ERTS_ALC_T_NIF, lib); } if (handle != NULL) { erts_sys_ddll_close(handle); } erts_sys_ddll_free_error(&errdesc); } erts_smp_thr_progress_unblock(); erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); erts_free(ERTS_ALC_T_TMP, lib_name); BIF_RET(ret); }
BeamInstr erts_generic_breakpoint(Process* c_p, BeamInstr* I, Eterm* reg) { GenericBp* g; GenericBpData* bp; Uint bp_flags; ErtsBpIndex ix = erts_active_bp_ix(); g = (GenericBp *) I[-4]; bp = &g->data[ix]; bp_flags = bp->flags; ASSERT((bp_flags & ~ERTS_BPF_ALL) == 0); if (bp_flags & (ERTS_BPF_LOCAL_TRACE| ERTS_BPF_GLOBAL_TRACE| ERTS_BPF_TIME_TRACE_ACTIVE) && !IS_TRACED_FL(c_p, F_TRACE_CALLS)) { bp_flags &= ~(ERTS_BPF_LOCAL_TRACE| ERTS_BPF_GLOBAL_TRACE| ERTS_BPF_TIME_TRACE| ERTS_BPF_TIME_TRACE_ACTIVE); if (bp_flags == 0) { /* Quick exit */ return g->orig_instr; } } if (bp_flags & ERTS_BPF_LOCAL_TRACE) { ASSERT((bp_flags & ERTS_BPF_GLOBAL_TRACE) == 0); (void) do_call_trace(c_p, I, reg, 1, bp->local_ms, erts_tracer_true); } else if (bp_flags & ERTS_BPF_GLOBAL_TRACE) { (void) do_call_trace(c_p, I, reg, 0, bp->local_ms, erts_tracer_true); } if (bp_flags & ERTS_BPF_META_TRACE) { ErtsTracer old_tracer, new_tracer; old_tracer = erts_smp_atomic_read_nob(&bp->meta_tracer->tracer); new_tracer = do_call_trace(c_p, I, reg, 1, bp->meta_ms, old_tracer); if (!ERTS_TRACER_COMPARE(new_tracer, old_tracer)) { if (old_tracer == erts_smp_atomic_cmpxchg_acqb( &bp->meta_tracer->tracer, (erts_aint_t)new_tracer, (erts_aint_t)old_tracer)) { ERTS_TRACER_CLEAR(&old_tracer); } else { ERTS_TRACER_CLEAR(&new_tracer); } } } if (bp_flags & ERTS_BPF_COUNT_ACTIVE) { erts_smp_atomic_inc_nob(&bp->count->acount); } if (bp_flags & ERTS_BPF_TIME_TRACE_ACTIVE) { Eterm w; erts_trace_time_call(c_p, I, bp->time); w = (BeamInstr) *c_p->cp; if (! (w == (BeamInstr) BeamOp(op_i_return_time_trace) || w == (BeamInstr) BeamOp(op_return_trace) || w == (BeamInstr) BeamOp(op_i_return_to_trace)) ) { Eterm* E = c_p->stop; ASSERT(c_p->htop <= E && E <= c_p->hend); if (E - 2 < c_p->htop) { (void) erts_garbage_collect(c_p, 2, reg, I[-1]); ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p); } E = c_p->stop; ASSERT(c_p->htop <= E && E <= c_p->hend); E -= 2; E[0] = make_cp(I); E[1] = make_cp(c_p->cp); /* original return address */ c_p->cp = beam_return_time_trace; c_p->stop = E; } } if (bp_flags & ERTS_BPF_DEBUG) { return (BeamInstr) BeamOp(op_i_debug_breakpoint); } else { return g->orig_instr; } }
void erts_set_mtrace_bif(BeamInstr *pc, Binary *match_spec, Eterm tracer_pid) { ERTS_SMP_LC_ASSERT(erts_smp_thr_progress_is_blocking()); set_function_break(NULL, pc, BREAK_IS_BIF, match_spec, (BeamInstr) BeamOp(op_i_mtrace_breakpoint), 0, tracer_pid); }
void erts_set_time_trace_bif(BeamInstr *pc, enum erts_break_op count_op) { set_function_break(NULL, pc, BREAK_IS_BIF, NULL, (BeamInstr) BeamOp(op_i_time_breakpoint), count_op, NIL); }
static void consolidate_bp_data(Module* modp, BeamInstr* pc, int local) { GenericBp* g = (GenericBp *) pc[-4]; GenericBpData* src; GenericBpData* dst; Uint flags; if (g == 0) { return; } src = &g->data[erts_active_bp_ix()]; dst = &g->data[erts_staging_bp_ix()]; /* * The contents of the staging area may be out of date. * Decrement all reference pointers. */ flags = dst->flags; if (flags & (ERTS_BPF_LOCAL_TRACE|ERTS_BPF_GLOBAL_TRACE)) { MatchSetUnref(dst->local_ms); } if (flags & ERTS_BPF_META_TRACE) { bp_meta_unref(dst->meta_tracer); MatchSetUnref(dst->meta_ms); } if (flags & ERTS_BPF_COUNT) { bp_count_unref(dst->count); } if (flags & ERTS_BPF_TIME_TRACE) { bp_time_unref(dst->time); } /* * If all flags are zero, deallocate all breakpoint data. */ flags = dst->flags = src->flags; if (flags == 0) { if (modp) { if (local) { modp->curr.num_breakpoints--; } else { modp->curr.num_traced_exports--; } ASSERT(modp->curr.num_breakpoints >= 0); ASSERT(modp->curr.num_traced_exports >= 0); ASSERT(*pc != (BeamInstr) BeamOp(op_i_generic_breakpoint)); } pc[-4] = 0; Free(g); return; } /* * Copy the active data to the staging area (making it ready * for the next time it will be used). */ if (flags & (ERTS_BPF_LOCAL_TRACE|ERTS_BPF_GLOBAL_TRACE)) { dst->local_ms = src->local_ms; MatchSetRef(dst->local_ms); } if (flags & ERTS_BPF_META_TRACE) { dst->meta_tracer = src->meta_tracer; erts_refc_inc(&dst->meta_tracer->refc, 1); dst->meta_ms = src->meta_ms; MatchSetRef(dst->meta_ms); } if (flags & ERTS_BPF_COUNT) { dst->count = src->count; erts_refc_inc(&dst->count->refc, 1); } if (flags & ERTS_BPF_TIME_TRACE) { dst->time = src->time; erts_refc_inc(&dst->time->refc, 1); ASSERT(dst->time->hash); } }
int erts_set_debug_break(Eterm mfa[3], int specified) { ERTS_SMP_LC_ASSERT(erts_smp_thr_progress_is_blocking()); return set_break(mfa, specified, NULL, (BeamInstr) BeamOp(op_i_debug_breakpoint), 0, NIL); }
void erts_bp_match_functions(BpFunctions* f, Eterm mfa[3], int specified) { ErtsCodeIndex code_ix = erts_active_code_ix(); Uint max_funcs = 0; int current; int max_modules = module_code_size(code_ix); int num_modules = 0; Module* modp; Module** module; Uint i; module = (Module **) Alloc(max_modules*sizeof(Module *)); num_modules = 0; for (current = 0; current < max_modules; current++) { modp = module_code(current, code_ix); if (modp->curr.code_hdr) { max_funcs += modp->curr.code_hdr->num_functions; module[num_modules++] = modp; } } f->matching = (BpFunction *) Alloc(max_funcs*sizeof(BpFunction)); i = 0; for (current = 0; current < num_modules; current++) { BeamCodeHeader* code_hdr = module[current]->curr.code_hdr; BeamInstr* code; Uint num_functions = (Uint)(UWord) code_hdr->num_functions; Uint fi; if (specified > 0) { if (mfa[0] != make_atom(module[current]->module)) { /* Wrong module name */ continue; } } for (fi = 0; fi < num_functions; fi++) { BeamInstr* pc; int wi; code = code_hdr->functions[fi]; ASSERT(code[0] == (BeamInstr) BeamOp(op_i_func_info_IaaI)); pc = code+5; if (erts_is_native_break(pc)) { continue; } if (is_nil(code[3])) { /* Ignore BIF stub */ continue; } for (wi = 0; wi < specified && (Eterm) code[2+wi] == mfa[wi]; wi++) { /* Empty loop body */ } if (wi == specified) { /* Store match */ f->matching[i].pc = pc; f->matching[i].mod = module[current]; i++; } } } f->matched = i; Free(module); }
int erts_set_time_break(Eterm mfa[3], int specified, enum erts_break_op count_op) { ERTS_SMP_LC_ASSERT(erts_smp_thr_progress_is_blocking()); return set_break(mfa, specified, NULL, (BeamInstr) BeamOp(op_i_time_breakpoint), count_op, NIL); }
void erts_clear_mtrace_bif(BeamInstr *pc) { clear_function_break(NULL, pc, BREAK_IS_BIF, (BeamInstr) BeamOp(op_i_mtrace_breakpoint)); }