mdb_iwalker_t * mdb_walker_lookup(const char *s) { const char *p = strchr(s, '`'); mdb_var_t *v; if (p != NULL) { size_t nbytes = MIN((size_t)(p - s), MDB_NV_NAMELEN - 1); char mname[MDB_NV_NAMELEN]; mdb_module_t *mod; (void) strncpy(mname, s, nbytes); mname[nbytes] = '\0'; if ((v = mdb_nv_lookup(&mdb.m_modules, mname)) == NULL) { (void) set_errno(EMDB_NOMOD); return (NULL); } mod = mdb_nv_get_cookie(v); if ((v = mdb_nv_lookup(&mod->mod_walkers, ++p)) != NULL) return (mdb_nv_get_cookie(v)); } else if ((v = mdb_nv_lookup(&mdb.m_walkers, s)) != NULL) return (mdb_nv_get_cookie(mdb_nv_get_cookie(v))); (void) set_errno(EMDB_NOWALK); return (NULL); }
void kt_deactivate(mdb_tgt_t *t) { kt_data_t *kt = t->t_data; const mdb_tgt_regdesc_t *rdp; const mdb_dcmd_t *dcp; for (rdp = kt->k_rds; rdp->rd_name != NULL; rdp++) { mdb_var_t *v; if (!(rdp->rd_flags & MDB_TGT_R_EXPORT)) continue; /* Didn't export register as a variable */ if ((v = mdb_nv_lookup(&mdb.m_nv, rdp->rd_name)) != NULL) { v->v_flags &= ~MDB_NV_PERSIST; mdb_nv_remove(&mdb.m_nv, v); } } for (dcp = &kt_dcmds[0]; dcp->dc_name != NULL; dcp++) { if (mdb_module_remove_dcmd(t->t_module, dcp->dc_name) == -1) warn("failed to remove dcmd %s", dcp->dc_name); } mdb_prop_postmortem = FALSE; mdb_prop_kernel = FALSE; mdb_prop_datamodel = MDB_TGT_MODEL_UNKNOWN; }
/* * Sends a request to the driver to load the module. If/when the load has * completed successfully, kmdb_module_loaded is called. */ int mdb_module_load(const char *fname, int mode) { const char *modname = strbasename(fname); kmdb_wr_load_t *dlr; kmdb_modctl_t *kmc = NULL; const char *wformat = NULL; mdb_var_t *v; if (!mdb_module_validate_name(modname, &wformat)) goto module_load_err; if ((v = mdb_nv_lookup(&mdb.m_dmodctl, modname)) != NULL) { kmc = MDB_NV_COOKIE(v); if (kmc->kmc_state == KMDB_MC_STATE_LOADING) wformat = "module %s is already being loaded\n"; else wformat = "module %s is being unloaded\n"; goto module_load_err; } kmc = mdb_zalloc(sizeof (kmdb_modctl_t), UM_SLEEP); kmc->kmc_loadmode = mode; kmc->kmc_modname = strdup(modname); kmc->kmc_state = KMDB_MC_STATE_LOADING; if (mdb_nv_insert(&mdb.m_dmodctl, modname, NULL, (uintptr_t)kmc, 0) == NULL) { wformat = "module %s can't be registered for load\n"; kmc_free(kmc); goto module_load_err; } dlr = mdb_zalloc(sizeof (kmdb_wr_load_t), UM_SLEEP); dlr->dlr_node.wn_task = WNTASK_DMOD_LOAD; dlr->dlr_fname = strdup(fname); kmdb_wr_driver_notify(dlr); if (!(mode & MDB_MOD_DEFER) && mdb_tgt_continue(mdb.m_target, NULL) == 0) return (0); if (!(mode & MDB_MOD_SILENT)) mdb_printf("%s load pending (:c to complete)\n", modname); return (0); module_load_err: if (!(mode & MDB_MOD_SILENT)) warn(wformat, modname); return (-1); }
/* * Determine whether the specified name is a valid tab completion for * the given command. If the name is a valid tab completion then * it will be saved in the mdb_tab_cookie_t. */ void mdb_tab_insert(mdb_tab_cookie_t *mcp, const char *name) { size_t len, matches, index; uint_t flags; mdb_var_t *v; char *n; const char *nvn; /* * If we have a match set, then we want to verify that we actually match * it. */ if (mcp->mtc_base != NULL && strncmp(name, mcp->mtc_base, strlen(mcp->mtc_base)) != 0) return; v = mdb_nv_lookup(&mcp->mtc_nv, name); if (v != NULL) return; /* * Names that we get passed in may be longer than MDB_NV_NAMELEN which * is currently 31 including the null terminator. If that is the case, * then we're going to take care of allocating a string and holding it * for our caller. Note that we don't need to free it, because we're * allocating this with UM_GC. */ flags = 0; len = strlen(name); if (len > MDB_NV_NAMELEN - 1) { n = mdb_alloc(len + 1, UM_SLEEP | UM_GC); (void) strcpy(n, name); nvn = n; flags |= MDB_NV_EXTNAME; } else { nvn = name; } flags |= MDB_NV_RDONLY; (void) mdb_nv_insert(&mcp->mtc_nv, nvn, NULL, 0, flags); matches = mdb_tab_size(mcp); if (matches == 1) { (void) strlcpy(mcp->mtc_match, nvn, MDB_SYM_NAMLEN); } else { index = 0; while (mcp->mtc_match[index] && mcp->mtc_match[index] == nvn[index]) index++; mcp->mtc_match[index] = '\0'; } }
int kt_lookup_by_name(mdb_tgt_t *t, const char *obj, const char *name, GElf_Sym *symp, mdb_syminfo_t *sip) { kt_data_t *kt = t->t_data; kt_module_t *km, kmod; mdb_var_t *v; int n; /* * To simplify the implementation, we create a fake module on the stack * which is "prepended" to k_modlist and whose symtab is kt->k_symtab. */ kmod.km_symtab = kt->k_symtab; kmod.km_list.ml_next = mdb_list_next(&kt->k_modlist); switch ((uintptr_t)obj) { case (uintptr_t)MDB_TGT_OBJ_EXEC: km = &kmod; n = 1; break; case (uintptr_t)MDB_TGT_OBJ_EVERY: km = &kmod; n = mdb_nv_size(&kt->k_modules) + 1; break; case (uintptr_t)MDB_TGT_OBJ_RTLD: obj = KT_RTLD_NAME; /*FALLTHRU*/ default: if ((v = mdb_nv_lookup(&kt->k_modules, obj)) == NULL) return (set_errno(EMDB_NOOBJ)); km = mdb_nv_get_cookie(v); n = 1; if (km->km_symtab == NULL) kt_load_module(kt, t, km); } for (; n > 0; n--, km = mdb_list_next(km)) { if (mdb_gelf_symtab_lookup_by_name(km->km_symtab, name, symp, &sip->sym_id) == 0) { sip->sym_table = MDB_TGT_SYMTAB; return (0); } } return (set_errno(EMDB_NOSYM)); }
int kmdb_module_unloaded(kmdb_wr_unload_t *dur) { mdb_var_t *v; if ((v = mdb_nv_lookup(&mdb.m_dmodctl, dur->dur_modname)) == NULL) { mdb_warn("unload for unrequested module %s\n", dur->dur_modname); return (0); } if (dur->dur_errno != 0) { mdb_warn("dmod %s failed to unload", dur->dur_modname); return (0); } kmc_free(MDB_NV_COOKIE(v)); mdb_nv_remove(&mdb.m_dmodctl, v); return (1); }
int kt_vtop(mdb_tgt_t *t, mdb_tgt_as_t as, uintptr_t va, physaddr_t *pap) { kt_data_t *kt = t->t_data; struct as *asp; physaddr_t pa; mdb_module_t *mod; mdb_var_t *v; int (*fptr)(uintptr_t, struct as *, physaddr_t *); switch ((uintptr_t)as) { case (uintptr_t)MDB_TGT_AS_PHYS: case (uintptr_t)MDB_TGT_AS_FILE: case (uintptr_t)MDB_TGT_AS_IO: return (set_errno(EINVAL)); case (uintptr_t)MDB_TGT_AS_VIRT: asp = kt->k_as; break; default: asp = (struct as *)as; } if ((pa = kvm_physaddr(kt->k_cookie, asp, va)) != -1ULL) { *pap = pa; return (0); } if ((v = mdb_nv_lookup(&mdb.m_modules, "unix")) != NULL && (mod = mdb_nv_get_cookie(v)) != NULL) { fptr = (int (*)(uintptr_t, struct as *, physaddr_t *)) dlsym(mod->mod_hdl, "platform_vtop"); if ((fptr != NULL) && ((*fptr)(va, asp, pap) == 0)) return (0); } return (set_errno(EMDB_NOMAP)); }
/*ARGSUSED*/ int mdb_module_unload(const char *name, int mode) { kmdb_modctl_t *kmc = NULL; const char *basename; mdb_var_t *v; /* * We may have been called with the name from the module itself * if the caller is iterating through the module list, so we need * to make a copy of the name. If we don't, we can't use it after * the call to unload_common(), which frees the module. */ name = strdup(name); basename = strbasename(name); /* * Make sure the module is in the proper state for unloading. Modules * may only be unloaded if they have properly completed loading. */ if ((v = mdb_nv_lookup(&mdb.m_dmodctl, basename)) != NULL) { kmc = MDB_NV_COOKIE(v); switch (kmc->kmc_state) { case KMDB_MC_STATE_LOADING: warn("%s is in the process of loading\n", basename); return (set_errno(EMDB_NOMOD)); case KMDB_MC_STATE_UNLOADING: warn("%s is already being unloaded\n", basename); return (set_errno(EMDB_NOMOD)); default: ASSERT(kmc->kmc_state == KMDB_MC_STATE_LOADED); } if (kmc->kmc_flags & KMDB_MC_FL_NOUNLOAD) return (set_errno(EMDB_KMODNOUNLOAD)); } if (mdb_module_unload_common(name) < 0) { if (!(mode & MDB_MOD_SILENT)) { mdb_dprintf(MDB_DBG_MODULE, "unload of %s failed\n", name); } return (-1); /* errno is set for us */ } /* * Any modules legitimately not listed in dmodctl (builtins, for * example) will be handled by mdb_module_unload_common. If any of * them get here, we've got a problem. */ if (v == NULL) { warn("unload of unregistered module %s\n", basename); return (set_errno(EMDB_NOMOD)); } ASSERT(kmc->kmc_dlrefcnt == 0); mdb_gelf_symtab_destroy(kmc->kmc_symtab); kmdb_module_request_unload(kmc, basename, mode); return (0); }
int kmdb_module_loaded(kmdb_wr_load_t *dlr) { struct modctl *modp = dlr->dlr_modctl; const char *modname = strbasename(dlr->dlr_fname); struct module *mp; kmdb_modctl_t *kmc; mdb_var_t *v; v = mdb_nv_lookup(&mdb.m_dmodctl, modname); if (dlr->dlr_errno != 0) { /* * We're somewhat limited in the diagnostics that we can * provide in the event of a failed load. In most load-failure * cases, the driver can only send up a generic errno. We use * EMDB_ENOMOD to signal generic errors, and supply our own * message. This twists the meaning of EMDB_NOMOD somewhat, but * it's better than defining a new one. */ if (dlr->dlr_errno == EMDB_NOMOD) { mdb_warn("%s does not appear to be a kmdb dmod\n", modname); } else { (void) set_errno(dlr->dlr_errno); mdb_warn("dmod %s failed to load", modname); } if (v != NULL) mdb_nv_remove(&mdb.m_dmodctl, v); return (0); } if ((mp = modp->mod_mp) == NULL || mp->symhdr == NULL || mp->strhdr == NULL || mp->symtbl == NULL || mp->strings == NULL) { mdb_warn("dmod %s did not load properly\n"); goto module_loaded_err; } if ((v = mdb_nv_lookup(&mdb.m_dmodctl, modname)) == NULL) { kmc = mdb_zalloc(sizeof (kmdb_modctl_t), UM_SLEEP); kmc->kmc_loadmode = MDB_MOD_LOCAL; kmc->kmc_modname = strdup(modname); kmc->kmc_state = KMDB_MC_STATE_LOADING; (void) mdb_nv_insert(&mdb.m_dmodctl, modname, NULL, (uintptr_t)kmc, 0); } else { kmc = MDB_NV_COOKIE(v); ASSERT(kmc->kmc_symtab == NULL); } kmc->kmc_modctl = modp; kmc->kmc_exported = (mp->flags & KOBJ_EXPORTED) != 0; mdb_gelf_ehdr_to_gehdr(&mp->hdr, &kmc->kmc_ehdr); kmc->kmc_symtab = mdb_gelf_symtab_create_raw(&kmc->kmc_ehdr, mp->symhdr, mp->symtbl, mp->strhdr, mp->strings, MDB_TGT_SYMTAB); if (mp->flags & KOBJ_PRIM) kmc->kmc_flags |= KMDB_MC_FL_NOUNLOAD; if (mdb_module_create(modname, modp->mod_filename, kmc->kmc_loadmode, &kmc->kmc_mod) < 0) goto module_loaded_err; kmc->kmc_state = KMDB_MC_STATE_LOADED; return (1); module_loaded_err: if (kmc->kmc_symtab != NULL) mdb_gelf_symtab_destroy(kmc->kmc_symtab); kmdb_module_request_unload(kmc, kmc->kmc_modname, MDB_MOD_DEFER); return (0); }
int kt_symbol_iter(mdb_tgt_t *t, const char *obj, uint_t which, uint_t type, mdb_tgt_sym_f *cb, void *data) { kt_data_t *kt = t->t_data; kt_module_t *km; mdb_gelf_symtab_t *symtab = NULL; mdb_var_t *v; switch ((uintptr_t)obj) { case (uintptr_t)MDB_TGT_OBJ_EXEC: if (which == MDB_TGT_SYMTAB) symtab = kt->k_symtab; else symtab = kt->k_dynsym; break; case (uintptr_t)MDB_TGT_OBJ_EVERY: if (which == MDB_TGT_DYNSYM) { symtab = kt->k_dynsym; obj = MDB_TGT_OBJ_EXEC; break; } mdb_nv_rewind(&kt->k_modules); while ((v = mdb_nv_advance(&kt->k_modules)) != NULL) { km = mdb_nv_get_cookie(v); if (km->km_symtab == NULL) kt_load_module(kt, t, km); if (km->km_symtab != NULL) kt_symtab_iter(km->km_symtab, type, km->km_name, cb, data); } break; case (uintptr_t)MDB_TGT_OBJ_RTLD: obj = KT_RTLD_NAME; /*FALLTHRU*/ default: v = mdb_nv_lookup(&kt->k_modules, obj); if (v == NULL) return (set_errno(EMDB_NOOBJ)); km = mdb_nv_get_cookie(v); if (km->km_symtab == NULL) kt_load_module(kt, t, km); symtab = km->km_symtab; } if (symtab) kt_symtab_iter(symtab, type, obj, cb, data); return (0); }
static void kt_load_modules(kt_data_t *kt, mdb_tgt_t *t) { char name[MAXNAMELEN]; uintptr_t addr, head; struct module kmod; struct modctl ctl; Shdr symhdr, strhdr; GElf_Sym sym; kt_module_t *km; if (mdb_tgt_lookup_by_name(t, MDB_TGT_OBJ_EXEC, "modules", &sym, NULL) == -1) { warn("failed to get 'modules' symbol"); return; } if (mdb_tgt_readsym(t, MDB_TGT_AS_VIRT, &ctl, sizeof (ctl), MDB_TGT_OBJ_EXEC, "modules") != sizeof (ctl)) { warn("failed to read 'modules' struct"); return; } addr = head = (uintptr_t)sym.st_value; do { if (addr == NULL) break; /* Avoid spurious NULL pointers in list */ if (mdb_tgt_vread(t, &ctl, sizeof (ctl), addr) == -1) { warn("failed to read modctl at %p", (void *)addr); return; } if (ctl.mod_mp == NULL) continue; /* No associated krtld structure */ if (mdb_tgt_readstr(t, MDB_TGT_AS_VIRT, name, MAXNAMELEN, (uintptr_t)ctl.mod_modname) <= 0) { warn("failed to read module name at %p", (void *)ctl.mod_modname); continue; } mdb_dprintf(MDB_DBG_KMOD, "reading mod %s (%p)\n", name, (void *)addr); if (mdb_nv_lookup(&kt->k_modules, name) != NULL) { warn("skipping duplicate module '%s', id=%d\n", name, ctl.mod_id); continue; } if (mdb_tgt_vread(t, &kmod, sizeof (kmod), (uintptr_t)ctl.mod_mp) == -1) { warn("failed to read module at %p\n", (void *)ctl.mod_mp); continue; } if (kmod.symspace == NULL || kmod.symhdr == NULL || kmod.strhdr == NULL) { /* * If no buffer for the symbols has been allocated, * or the shdrs for .symtab and .strtab are missing, * then we're out of luck. */ continue; } if (mdb_tgt_vread(t, &symhdr, sizeof (Shdr), (uintptr_t)kmod.symhdr) == -1) { warn("failed to read .symtab header for '%s', id=%d", name, ctl.mod_id); continue; } if (mdb_tgt_vread(t, &strhdr, sizeof (Shdr), (uintptr_t)kmod.strhdr) == -1) { warn("failed to read .strtab header for '%s', id=%d", name, ctl.mod_id); continue; } /* * Now get clever: f(*^ing krtld didn't used to bother updating * its own kmod.symsize value. We know that prior to this bug * being fixed, symspace was a contiguous buffer containing * .symtab, .strtab, and the symbol hash table in that order. * So if symsize is zero, recompute it as the size of .symtab * plus the size of .strtab. We don't need to load the hash * table anyway since we re-hash all the symbols internally. */ if (kmod.symsize == 0) kmod.symsize = symhdr.sh_size + strhdr.sh_size; /* * Similar logic can be used to make educated guesses * at the values of kmod.symtbl and kmod.strings. */ if (kmod.symtbl == NULL) kmod.symtbl = kmod.symspace; if (kmod.strings == NULL) kmod.strings = kmod.symspace + symhdr.sh_size; /* * Make sure things seem reasonable before we proceed * to actually read and decipher the symspace. */ if (KT_BAD_BUF(kmod.symtbl, kmod.symspace, kmod.symsize) || KT_BAD_BUF(kmod.strings, kmod.symspace, kmod.symsize)) { warn("skipping module '%s', id=%d (corrupt symspace)\n", name, ctl.mod_id); continue; } km = mdb_zalloc(sizeof (kt_module_t), UM_SLEEP); km->km_name = strdup(name); (void) mdb_nv_insert(&kt->k_modules, km->km_name, NULL, (uintptr_t)km, MDB_NV_EXTNAME); km->km_datasz = kmod.symsize; km->km_symspace_va = (uintptr_t)kmod.symspace; km->km_symtab_va = (uintptr_t)kmod.symtbl; km->km_strtab_va = (uintptr_t)kmod.strings; km->km_symtab_hdr = symhdr; km->km_strtab_hdr = strhdr; km->km_text_va = (uintptr_t)kmod.text; km->km_text_size = kmod.text_size; km->km_data_va = (uintptr_t)kmod.data; km->km_data_size = kmod.data_size; km->km_bss_va = (uintptr_t)kmod.bss; km->km_bss_size = kmod.bss_size; if (kt->k_ctfvalid) { km->km_ctf_va = (uintptr_t)kmod.ctfdata; km->km_ctf_size = kmod.ctfsize; } /* * Add the module to the end of the list of modules in load- * dependency order. This is needed to load the corresponding * debugger modules in the same order for layering purposes. */ mdb_list_append(&kt->k_modlist, km); if (t->t_flags & MDB_TGT_F_PRELOAD) { mdb_iob_printf(mdb.m_out, " %s", name); mdb_iob_flush(mdb.m_out); kt_load_module(kt, t, km); } } while ((addr = (uintptr_t)ctl.mod_next) != head); }