예제 #1
0
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);
}
예제 #2
0
파일: mdb_kvm.c 프로젝트: andreiw/polaris
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;
}
예제 #3
0
/*
 * 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);
}
예제 #4
0
/*
 * 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';
	}
}
예제 #5
0
파일: mdb_kvm.c 프로젝트: andreiw/polaris
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));
}
예제 #6
0
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);
}
예제 #7
0
파일: mdb_kvm.c 프로젝트: andreiw/polaris
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));
}
예제 #8
0
/*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);
}
예제 #9
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);
}
예제 #10
0
파일: mdb_kvm.c 프로젝트: andreiw/polaris
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);
}
예제 #11
0
파일: mdb_kvm.c 프로젝트: andreiw/polaris
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);
}