Пример #1
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);
}
Пример #2
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';
	}
}
Пример #3
0
void
mdb_create(const char *execname, const char *arg0)
{
	static const mdb_nv_disc_t psym_disc = { psym_disc_set, psym_disc_get };
	static const mdb_nv_disc_t roff_disc = { roff_disc_set, roff_disc_get };
	static const mdb_nv_disc_t thr_disc = { NULL, thr_disc_get };

	static char rootdir[MAXPATHLEN];

	const mdb_dcmd_t *dcp;
	int i;

	bzero(&mdb, sizeof (mdb_t));

	mdb.m_flags = MDB_FL_PSYM | MDB_FL_PAGER | MDB_FL_BPTNOSYMSTOP |
	    MDB_FL_READBACK;
	mdb.m_radix = MDB_DEF_RADIX;
	mdb.m_nargs = MDB_DEF_NARGS;
	mdb.m_histlen = MDB_DEF_HISTLEN;
	mdb.m_armemlim = MDB_DEF_ARRMEM;
	mdb.m_arstrlim = MDB_DEF_ARRSTR;

	mdb.m_pname = strbasename(arg0);
	if (strcmp(mdb.m_pname, "adb") == 0) {
		mdb.m_flags |= MDB_FL_NOMODS | MDB_FL_ADB | MDB_FL_REPLAST;
		mdb.m_flags &= ~MDB_FL_PAGER;
	}

	mdb.m_ipathstr = mdb_zalloc(MAXPATHLEN, UM_SLEEP);
	mdb.m_lpathstr = mdb_zalloc(MAXPATHLEN, UM_SLEEP);

	(void) strncpy(rootdir, execname, sizeof (rootdir));
	rootdir[sizeof (rootdir) - 1] = '\0';
	(void) strdirname(rootdir);

	if (strcmp(strbasename(rootdir), "sparcv9") == 0 ||
	    strcmp(strbasename(rootdir), "sparcv7") == 0 ||
	    strcmp(strbasename(rootdir), "amd64") == 0 ||
	    strcmp(strbasename(rootdir), "i86") == 0)
		(void) strdirname(rootdir);

	if (strcmp(strbasename(rootdir), "bin") == 0) {
		(void) strdirname(rootdir);
		if (strcmp(strbasename(rootdir), "usr") == 0)
			(void) strdirname(rootdir);
	} else
		(void) strcpy(rootdir, "/");

	mdb.m_root = rootdir;

	mdb.m_rminfo.mi_dvers = MDB_API_VERSION;
	mdb.m_rminfo.mi_dcmds = mdb_dcmd_builtins;
	mdb.m_rminfo.mi_walkers = NULL;

	(void) mdb_nv_create(&mdb.m_rmod.mod_walkers, UM_SLEEP);
	(void) mdb_nv_create(&mdb.m_rmod.mod_dcmds, UM_SLEEP);

	mdb.m_rmod.mod_name = mdb.m_pname;
	mdb.m_rmod.mod_info = &mdb.m_rminfo;

	(void) mdb_nv_create(&mdb.m_disasms, UM_SLEEP);
	(void) mdb_nv_create(&mdb.m_modules, UM_SLEEP);
	(void) mdb_nv_create(&mdb.m_dcmds, UM_SLEEP);
	(void) mdb_nv_create(&mdb.m_walkers, UM_SLEEP);
	(void) mdb_nv_create(&mdb.m_nv, UM_SLEEP);

	mdb.m_dot = mdb_nv_insert(&mdb.m_nv, ".", NULL, 0, MDB_NV_PERSIST);
	mdb.m_rvalue = mdb_nv_insert(&mdb.m_nv, "0", NULL, 0, MDB_NV_PERSIST);

	mdb.m_roffset =
	    mdb_nv_insert(&mdb.m_nv, "1", &roff_disc, 0, MDB_NV_PERSIST);

	mdb.m_proffset = mdb_nv_insert(&mdb.m_nv, "2", NULL, 0, MDB_NV_PERSIST);
	mdb.m_rcount = mdb_nv_insert(&mdb.m_nv, "9", NULL, 0, MDB_NV_PERSIST);

	(void) mdb_nv_insert(&mdb.m_nv, "b", NULL, 0, MDB_NV_PERSIST);
	(void) mdb_nv_insert(&mdb.m_nv, "d", NULL, 0, MDB_NV_PERSIST);
	(void) mdb_nv_insert(&mdb.m_nv, "e", NULL, 0, MDB_NV_PERSIST);
	(void) mdb_nv_insert(&mdb.m_nv, "m", NULL, 0, MDB_NV_PERSIST);
	(void) mdb_nv_insert(&mdb.m_nv, "t", NULL, 0, MDB_NV_PERSIST);
	(void) mdb_nv_insert(&mdb.m_nv, "_", &psym_disc, 0, MDB_NV_PERSIST);
	(void) mdb_nv_insert(&mdb.m_nv, "hits", NULL, 0, MDB_NV_PERSIST);

	(void) mdb_nv_insert(&mdb.m_nv, "thread", &thr_disc, 0,
	    MDB_NV_PERSIST | MDB_NV_RDONLY);

	mdb.m_prsym = mdb_gelf_symtab_create_mutable();

	(void) mdb_nv_insert(&mdb.m_modules, mdb.m_pname, NULL,
	    (uintptr_t)&mdb.m_rmod, MDB_NV_RDONLY);

	for (dcp = &mdb_dcmd_builtins[0]; dcp->dc_name != NULL; dcp++)
		(void) mdb_module_add_dcmd(&mdb.m_rmod, dcp, 0);

	for (i = 0; mdb_dis_builtins[i] != NULL; i++)
		(void) mdb_dis_create(mdb_dis_builtins[i]);

	mdb_macalias_create();

	mdb_create_builtin_tgts();

	(void) mdb_callb_add(NULL, MDB_CALLB_PROMPT, (mdb_callb_f)prompt_update,
	    NULL);

#ifdef _KMDB
	(void) mdb_nv_create(&mdb.m_dmodctl, UM_SLEEP);
#endif
	mdb_lex_state_create(&frame0);

	mdb_list_append(&mdb.m_flist, &frame0);
	mdb.m_frame = &frame0;
}
Пример #4
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);
}
Пример #5
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);
}
Пример #6
0
static int
kmdb_dbgnotify_cb(kmdb_wr_t *wn, void *arg)
{
	work_results_t *res = arg;

	switch (WR_TASK(wn)) {
	case WNTASK_DMOD_LOAD: {
		/*
		 * If this is an ack, the driver finished processing a load we
		 * requested.  We process it and free the message.  If this
		 * isn't an ack, then it's a driver-initiated load.  We process
		 * the message, and send it back as an ack so the driver can
		 * free it.
		 */
		kmdb_wr_load_t *dlr = (kmdb_wr_load_t *)wn;

		mdb_dprintf(MDB_DBG_DPI, "received module load message\n");

		if (kmdb_module_loaded(dlr) && res != NULL) {
			(void) mdb_nv_insert(&res->res_loads,
			    strbasename(dlr->dlr_fname), NULL, 0, 0);
		}

		if (WR_ISACK(dlr)) {
			kmdb_module_load_ack(dlr);
			return (0);
		}

		/* Send it back as an ack */
		mdb_dprintf(MDB_DBG_DPI, "Sending load request for %s back "
		    "as an ack\n", dlr->dlr_fname);
		WR_ACK(wn);
		kmdb_wr_driver_notify(wn);
		return (0);
	}

	case WNTASK_DMOD_LOAD_ALL:
		/*
		 * We initiated the load-all, so this must be an ack.  The
		 * individual module load messages will arrive separately -
		 * there's no need to do anything further with this message.
		 */
		ASSERT(WR_ISACK(wn));

		mdb_dprintf(MDB_DBG_DPI, "received module load all ack\n");

		kmdb_module_load_all_ack(wn);
		return (0);

	case WNTASK_DMOD_UNLOAD: {
		/*
		 * The debugger received an unload message.  The driver isn't
		 * supposed to initiate unloads, so we shouldn't see anything
		 * but acks.  We tell the dmod subsystem that the module has
		 * been unloaded, and we free the message.
		 */
		kmdb_wr_unload_t *dur = (kmdb_wr_unload_t *)wn;

		ASSERT(WR_ISACK(dur));

		mdb_dprintf(MDB_DBG_DPI, "received module unload ack\n");

		if (kmdb_module_unloaded(dur) && res != NULL) {
			(void) mdb_nv_insert(&res->res_unloads,
			    dur->dur_modname, NULL, 0, 0);
		}

		/* Done with message */
		kmdb_module_unload_ack(dur);
		return (0);
	}

	case WNTASK_DMOD_PATH_CHANGE: {
		/*
		 * The debugger received a path change message.  The driver
		 * can't initiate these, so it must be an acknowledgement.
		 * There's no processing to be done, so just free the message.
		 */
		kmdb_wr_path_t *dpth = (kmdb_wr_path_t *)wn;

		ASSERT(WR_ISACK(dpth));

		mdb_dprintf(MDB_DBG_DPI, "received path change ack\n");

		kmdb_module_path_ack(dpth);
		return (0);
	}

	default:
		mdb_warn("Received unknown message type %d from driver\n",
		    wn->wn_task);
		/* Ignore it */
		return (0);
	}
}