Esempio n. 1
0
/*
 * "sp" is a kernel VA.
 */
static int
print_stack(uintptr_t sp, uintptr_t pc, uintptr_t addr,
    int argc, const mdb_arg_t *argv, int free_state)
{
	int showargs = 0, count, err;

	count = mdb_getopts(argc, argv,
	    'v', MDB_OPT_SETBITS, TRUE, &showargs, NULL);
	argc -= count;
	argv += count;

	if (argc > 1 || (argc == 1 && argv->a_type != MDB_TYPE_STRING))
		return (DCMD_USAGE);

	mdb_printf("stack pointer for thread %p%s: %p\n",
	    addr, (free_state ? " (TS_FREE)" : ""), sp);
	if (pc != 0)
		mdb_printf("[ %0?lr %a() ]\n", sp, pc);

	mdb_inc_indent(2);
	mdb_set_dot(sp);

	if (argc == 1)
		err = mdb_eval(argv->a_un.a_str);
	else if (showargs)
		err = mdb_eval("<.$C");
	else
		err = mdb_eval("<.$C0");

	mdb_dec_indent(2);

	return ((err == -1) ? DCMD_ABORT : DCMD_OK);
}
Esempio n. 2
0
/* ARGSUSED */
static int
xhci_mdb_print_device(uintptr_t addr, uint_t flags, int argc,
    const mdb_arg_t *argv)
{
	int count;
	xhci_device_t xd;
	usba_device_t ud;
	char product[256], mfg[256];

	if (!(flags & DCMD_ADDRSPEC)) {
		return (mdb_eval("::walk xhci`xhci | ::walk xhci`xhci_device | "
		    "::xhci_device"));
	}

	if (mdb_vread(&xd, sizeof (xd), addr) != sizeof (xd)) {
		mdb_warn("failed to read xhci_device_t at 0x%x", addr);
		return (DCMD_ERR);
	}

	if (mdb_vread(&ud, sizeof (ud), (uintptr_t)xd.xd_usbdev) !=
	    sizeof (ud)) {
		mdb_warn("failed to read usba_device_t at %p\n", xd.xd_usbdev);
		return (DCMD_ERR);
	}

	if (ud.usb_mfg_str == NULL || mdb_readstr(mfg, sizeof (mfg),
	    (uintptr_t)ud.usb_mfg_str) <= 0) {
		(void) strlcpy(mfg, "Unknown Manufacturer", sizeof (mfg));
	}

	if (ud.usb_product_str == NULL || mdb_readstr(product, sizeof (product),
	    (uintptr_t)ud.usb_product_str) <= 0) {
		(void) strlcpy(product, "Unknown Product", sizeof (product));
	}

	mdb_printf("%<b>%s - %s%</b>\n", mfg, product);

	count = 0;
	if (mdb_pwalk("xhci`xhci_endpoint", xhci_mdb_endpoint_count, &count,
	    addr) == -1) {
		mdb_warn("failed to walk xhci_endpoint rooted at 0x%x", addr);
		return (DCMD_ERR);
	}

	mdb_printf("Port %02d | Slot %02d | # Endpoints %02d\n", xd.xd_port,
	    xd.xd_slot, count);
	mdb_printf("%<u>%-4s %-10s %-10s %-6s %-6s%</u>\n", "EP", "Type",
	    "State", "Head", "Tail");

	if (mdb_pwalk("xhci`xhci_endpoint", xhci_mdb_print_endpoint_summary,
	    &xd, addr) == -1) {
		mdb_warn("failed to walk xhci_endpoint rooted at 0x%x", addr);
		return (DCMD_ERR);
	}


	mdb_printf("\n");

	return (DCMD_OK);
}
Esempio n. 3
0
/*ARGSUSED*/
int
stacks(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{
	size_t idx;

	char *seen = NULL;

	const char *caller_str = NULL;
	const char *excl_caller_str = NULL;
	uintptr_t caller = 0, excl_caller = 0;
	const char *module_str = NULL;
	const char *excl_module_str = NULL;
	stacks_module_t module, excl_module;
	const char *sobj = NULL;
	const char *excl_sobj = NULL;
	uintptr_t sobj_ops = 0, excl_sobj_ops = 0;
	const char *tstate_str = NULL;
	const char *excl_tstate_str = NULL;
	uint_t tstate = -1U;
	uint_t excl_tstate = -1U;
	uint_t printed = 0;

	uint_t all = 0;
	uint_t force = 0;
	uint_t interesting = 0;
	uint_t verbose = 0;

	/*
	 * We have a slight behavior difference between having piped
	 * input and 'addr::stacks'.  Without a pipe, we assume the
	 * thread pointer given is a representative thread, and so
	 * we include all similar threads in the system in our output.
	 *
	 * With a pipe, we filter down to just the threads in our
	 * input.
	 */
	uint_t addrspec = (flags & DCMD_ADDRSPEC);
	uint_t only_matching = addrspec && (flags & DCMD_PIPE);

	mdb_pipe_t p;

	bzero(&module, sizeof (module));
	bzero(&excl_module, sizeof (excl_module));

	if (mdb_getopts(argc, argv,
	    'a', MDB_OPT_SETBITS, TRUE, &all,
	    'f', MDB_OPT_SETBITS, TRUE, &force,
	    'i', MDB_OPT_SETBITS, TRUE, &interesting,
	    'v', MDB_OPT_SETBITS, TRUE, &verbose,
	    'c', MDB_OPT_STR, &caller_str,
	    'C', MDB_OPT_STR, &excl_caller_str,
	    'm', MDB_OPT_STR, &module_str,
	    'M', MDB_OPT_STR, &excl_module_str,
	    's', MDB_OPT_STR, &sobj,
	    'S', MDB_OPT_STR, &excl_sobj,
	    't', MDB_OPT_STR, &tstate_str,
	    'T', MDB_OPT_STR, &excl_tstate_str,
	    NULL) != argc)
		return (DCMD_USAGE);

	if (interesting) {
		if (sobj != NULL || excl_sobj != NULL ||
		    tstate_str != NULL || excl_tstate_str != NULL) {
			mdb_warn(
			    "stacks: -i is incompatible with -[sStT]\n");
			return (DCMD_USAGE);
		}
		excl_sobj = "CV";
		excl_tstate_str = "FREE";
	}

	if (caller_str != NULL) {
		mdb_set_dot(0);
		if (mdb_eval(caller_str) != 0) {
			mdb_warn("stacks: evaluation of \"%s\" failed",
			    caller_str);
			return (DCMD_ABORT);
		}
		caller = mdb_get_dot();
	}

	if (excl_caller_str != NULL) {
		mdb_set_dot(0);
		if (mdb_eval(excl_caller_str) != 0) {
			mdb_warn("stacks: evaluation of \"%s\" failed",
			    excl_caller_str);
			return (DCMD_ABORT);
		}
		excl_caller = mdb_get_dot();
	}
	mdb_set_dot(addr);

	if (module_str != NULL && stacks_module_find(module_str, &module) != 0)
		return (DCMD_ABORT);

	if (excl_module_str != NULL &&
	    stacks_module_find(excl_module_str, &excl_module) != 0)
		return (DCMD_ABORT);

	if (sobj != NULL && text_to_sobj(sobj, &sobj_ops) != 0)
		return (DCMD_USAGE);

	if (excl_sobj != NULL && text_to_sobj(excl_sobj, &excl_sobj_ops) != 0)
		return (DCMD_USAGE);

	if (sobj_ops != 0 && excl_sobj_ops != 0) {
		mdb_warn("stacks: only one of -s and -S can be specified\n");
		return (DCMD_USAGE);
	}

	if (tstate_str != NULL && text_to_tstate(tstate_str, &tstate) != 0)
		return (DCMD_USAGE);

	if (excl_tstate_str != NULL &&
	    text_to_tstate(excl_tstate_str, &excl_tstate) != 0)
		return (DCMD_USAGE);

	if (tstate != -1U && excl_tstate != -1U) {
		mdb_warn("stacks: only one of -t and -T can be specified\n");
		return (DCMD_USAGE);
	}

	/*
	 * If there's an address specified, we're going to further filter
	 * to only entries which have an address in the input.  To reduce
	 * overhead (and make the sorted output come out right), we
	 * use mdb_get_pipe() to grab the entire pipeline of input, then
	 * use qsort() and bsearch() to speed up the search.
	 */
	if (addrspec) {
		mdb_get_pipe(&p);
		if (p.pipe_data == NULL || p.pipe_len == 0) {
			p.pipe_data = &addr;
			p.pipe_len = 1;
		}
		qsort(p.pipe_data, p.pipe_len, sizeof (uintptr_t),
		    uintptrcomp);

		/* remove any duplicates in the data */
		idx = 0;
		while (idx < p.pipe_len - 1) {
			uintptr_t *data = &p.pipe_data[idx];
			size_t len = p.pipe_len - idx;

			if (data[0] == data[1]) {
				memmove(data, data + 1,
				    (len - 1) * sizeof (*data));
				p.pipe_len--;
				continue; /* repeat without incrementing idx */
			}
			idx++;
		}

		seen = mdb_zalloc(p.pipe_len, UM_SLEEP | UM_GC);
	}

	/*
	 * Force a cleanup if we're connected to a live system. Never
	 * do a cleanup after the first invocation around the loop.
	 */
	force |= (mdb_get_state() == MDB_STATE_RUNNING);
	if (force && (flags & (DCMD_LOOPFIRST|DCMD_LOOP)) == DCMD_LOOP)
		force = 0;

	stacks_cleanup(force);

	if (stacks_state == STACKS_STATE_CLEAN) {
		int res = stacks_run(verbose, addrspec ? &p : NULL);
		if (res != DCMD_OK)
			return (res);
	}

	for (idx = 0; idx < stacks_array_size; idx++) {
		stacks_entry_t *sep = stacks_array[idx];
		stacks_entry_t *cur = sep;
		int frame;
		size_t count = sep->se_count;

		if (addrspec) {
			stacks_entry_t *head = NULL, *tail = NULL, *sp;
			size_t foundcount = 0;
			/*
			 * We use the now-unused hash chain field se_next to
			 * link together the dups which match our list.
			 */
			for (sp = sep; sp != NULL; sp = sp->se_dup) {
				uintptr_t *entry = bsearch(&sp->se_thread,
				    p.pipe_data, p.pipe_len, sizeof (uintptr_t),
				    uintptrcomp);
				if (entry != NULL) {
					foundcount++;
					seen[entry - p.pipe_data]++;
					if (head == NULL)
						head = sp;
					else
						tail->se_next = sp;
					tail = sp;
					sp->se_next = NULL;
				}
			}
			if (head == NULL)
				continue;	/* no match, skip entry */

			if (only_matching) {
				cur = sep = head;
				count = foundcount;
			}
		}

		if (caller != 0 && !stacks_has_caller(sep, caller))
			continue;

		if (excl_caller != 0 && stacks_has_caller(sep, excl_caller))
			continue;

		if (module.sm_size != 0 && !stacks_has_module(sep, &module))
			continue;

		if (excl_module.sm_size != 0 &&
		    stacks_has_module(sep, &excl_module))
			continue;

		if (tstate != -1U) {
			if (tstate == TSTATE_PANIC) {
				if (!sep->se_panic)
					continue;
			} else if (sep->se_panic || sep->se_tstate != tstate)
				continue;
		}
		if (excl_tstate != -1U) {
			if (excl_tstate == TSTATE_PANIC) {
				if (sep->se_panic)
					continue;
			} else if (!sep->se_panic &&
			    sep->se_tstate == excl_tstate)
				continue;
		}

		if (sobj_ops == SOBJ_ALL) {
			if (sep->se_sobj_ops == 0)
				continue;
		} else if (sobj_ops != 0) {
			if (sobj_ops != sep->se_sobj_ops)
				continue;
		}

		if (!(interesting && sep->se_panic)) {
			if (excl_sobj_ops == SOBJ_ALL) {
				if (sep->se_sobj_ops != 0)
					continue;
			} else if (excl_sobj_ops != 0) {
				if (excl_sobj_ops == sep->se_sobj_ops)
					continue;
			}
		}

		if (flags & DCMD_PIPE_OUT) {
			while (sep != NULL) {
				mdb_printf("%lr\n", sep->se_thread);
				sep = only_matching ?
				    sep->se_next : sep->se_dup;
			}
			continue;
		}

		if (all || !printed) {
			mdb_printf("%<u>%-?s %-8s %-?s %8s%</u>\n",
			    "THREAD", "STATE", "SOBJ", "COUNT");
			printed = 1;
		}

		do {
			char state[20];
			char sobj[100];

			tstate_to_text(cur->se_tstate, cur->se_panic,
			    state, sizeof (state));
			sobj_to_text(cur->se_sobj_ops,
			    sobj, sizeof (sobj));

			if (cur == sep)
				mdb_printf("%-?p %-8s %-?s %8d\n",
				    cur->se_thread, state, sobj, count);
			else
				mdb_printf("%-?p %-8s %-?s %8s\n",
				    cur->se_thread, state, sobj, "-");

			cur = only_matching ? cur->se_next : cur->se_dup;
		} while (all && cur != NULL);

		if (sep->se_failed != 0) {
			char *reason;
			switch (sep->se_failed) {
			case FSI_FAIL_NOTINMEMORY:
				reason = "thread not in memory";
				break;
			case FSI_FAIL_THREADCORRUPT:
				reason = "thread structure stack info corrupt";
				break;
			case FSI_FAIL_STACKNOTFOUND:
				reason = "no consistent stack found";
				break;
			default:
				reason = "unknown failure";
				break;
			}
			mdb_printf("%?s <%s>\n", "", reason);
		}

		for (frame = 0; frame < sep->se_depth; frame++)
			mdb_printf("%?s %a\n", "", sep->se_stack[frame]);
		if (sep->se_overflow)
			mdb_printf("%?s ... truncated ...\n", "");
		mdb_printf("\n");
	}

	if (flags & DCMD_ADDRSPEC) {
		for (idx = 0; idx < p.pipe_len; idx++)
			if (seen[idx] == 0)
				mdb_warn("stacks: %p not in thread list\n",
				    p.pipe_data[idx]);
	}
	return (DCMD_OK);
}
Esempio n. 4
0
/*ARGSUSED*/
void
cmd_event(mdb_tgt_t *t, int vid, void *s)
{
	if (s != NULL && mdb_eval(s) == -1)
		mdb_warn("failed to eval [ %d ] command \"%s\"", vid, s);
}