예제 #1
0
int
mdb_lookup_by_addr(uintptr_t addr, uint_t flags, char *buf,
	size_t nbytes, GElf_Sym *sym)
{
	return (mdb_tgt_lookup_by_addr(mdb.m_target, addr, flags,
	    buf, nbytes, sym, NULL));
}
예제 #2
0
/*
 * Determine the return address for the current frame.  Typically this is the
 * fr_savpc value from the current frame, but we also perform some special
 * handling to see if we are stopped on one of the first two instructions of a
 * typical function prologue, in which case %ebp will not be set up yet.
 */
int
mdb_ia32_step_out(mdb_tgt_t *t, uintptr_t *p, kreg_t pc, kreg_t fp, kreg_t sp,
    mdb_instr_t curinstr)
{
	struct frame fr;
	GElf_Sym s;
	char buf[1];

	enum {
		M_PUSHL_EBP	= 0x55, /* pushl %ebp */
		M_MOVL_EBP	= 0x8b  /* movl %esp, %ebp */
	};

	if (mdb_tgt_lookup_by_addr(t, pc, MDB_TGT_SYM_FUZZY,
	    buf, 0, &s, NULL) == 0) {
		if (pc == s.st_value && curinstr == M_PUSHL_EBP)
			fp = sp - 4;
		else if (pc == s.st_value + 1 && curinstr == M_MOVL_EBP)
			fp = sp;
	}

	if (mdb_tgt_vread(t, &fr, sizeof (fr), fp) == sizeof (fr)) {
		*p = fr.fr_savpc;
		return (0);
	}

	return (-1); /* errno is set for us */
}
예제 #3
0
/*ARGSUSED*/
int
mdb_ctf_func_info(const GElf_Sym *symp, const mdb_syminfo_t *sip,
    mdb_ctf_funcinfo_t *mfp)
{
	ctf_file_t *fp = NULL;
	ctf_funcinfo_t f;
	mdb_tgt_t *t = mdb.m_target;
	char name[MDB_SYM_NAMLEN];
	const mdb_map_t *mp;
	mdb_syminfo_t si;
	int err;

	if (symp == NULL || mfp == NULL)
		return (set_errno(EINVAL));

	/*
	 * In case the input symbol came from a merged or private symbol table,
	 * re-lookup the address as a symbol, and then perform a fully scoped
	 * lookup of that symbol name to get the mdb_syminfo_t for its CTF.
	 */
	if ((fp = mdb_tgt_addr_to_ctf(t, symp->st_value)) == NULL ||
	    (mp = mdb_tgt_addr_to_map(t, symp->st_value)) == NULL ||
	    mdb_tgt_lookup_by_addr(t, symp->st_value, MDB_TGT_SYM_FUZZY,
	    name, sizeof (name), NULL, NULL) != 0)
		return (-1); /* errno is set for us */

	if (strchr(name, '`') != NULL)
		err = mdb_tgt_lookup_by_scope(t, name, NULL, &si);
	else
		err = mdb_tgt_lookup_by_name(t, mp->map_name, name, NULL, &si);

	if (err != 0)
		return (-1); /* errno is set for us */

	if (ctf_func_info(fp, si.sym_id, &f) == CTF_ERR)
		return (set_errno(ctf_to_errno(ctf_errno(fp))));

	set_ctf_id(&mfp->mtf_return, fp, f.ctc_return);
	mfp->mtf_argc = f.ctc_argc;
	mfp->mtf_flags = f.ctc_flags;
	mfp->mtf_symidx = si.sym_id;

	return (0);
}
예제 #4
0
int
mdb_ctf_lookup_by_addr(uintptr_t addr, mdb_ctf_id_t *p)
{
	GElf_Sym sym;
	mdb_syminfo_t si;
	char name[MDB_SYM_NAMLEN];
	const mdb_map_t *mp;
	mdb_tgt_t *t = mdb.m_target;
	const char *obj, *c;

	if (p == NULL)
		return (set_errno(EINVAL));

	if (mdb_tgt_lookup_by_addr(t, addr, MDB_TGT_SYM_EXACT, name,
	    sizeof (name), NULL, NULL) == -1) {
		mdb_ctf_type_invalidate(p);
		return (-1); /* errno is set for us */
	}

	if ((c = strrsplit(name, '`')) != NULL) {
		obj = name;
	} else {
		if ((mp = mdb_tgt_addr_to_map(t, addr)) == NULL) {
			mdb_ctf_type_invalidate(p);
			return (-1); /* errno is set for us */
		}

		obj = mp->map_name;
		c = name;
	}

	if (mdb_tgt_lookup_by_name(t, obj, c, &sym, &si) == -1) {
		mdb_ctf_type_invalidate(p);
		return (-1); /* errno is set for us */
	}

	return (mdb_ctf_lookup_by_symbol(&sym, &si, p));
}
예제 #5
0
/*ARGSUSED*/
int
cmd_nm(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{
	enum {
		NM_DYNSYM	= 0x0001,	/* -D (use dynsym) */
		NM_DEC		= 0x0002,	/* -d (decimal output) */
		NM_GLOBAL	= 0x0004,	/* -g (globals only) */
		NM_NOHDRS	= 0x0008,	/* -h (suppress header) */
		NM_OCT		= 0x0010,	/* -o (octal output) */
		NM_UNDEF	= 0x0020,	/* -u (undefs only) */
		NM_HEX		= 0x0040,	/* -x (hex output) */
		NM_SORT_NAME	= 0x0080,	/* -n (sort by name) */
		NM_SORT_VALUE	= 0x0100,	/* -v (sort by value) */
		NM_PRVSYM	= 0x0200,	/* -P (use private symtab) */
		NM_PRTASGN	= 0x0400	/* -p (print in asgn syntax) */
	};

	mdb_subopt_t opt_fmt_opts[] = {
		{ NM_FMT_INDEX, "ndx" },
		{ NM_FMT_VALUE, "val" },
		{ NM_FMT_SIZE, "sz" },
		{ NM_FMT_TYPE, "type" },
		{ NM_FMT_BIND, "bind" },
		{ NM_FMT_OTHER, "oth" },
		{ NM_FMT_SHNDX, "shndx" },
		{ NM_FMT_NAME, "name" },
		{ NM_FMT_CTYPE, "ctype" },
		{ NM_FMT_OBJECT, "obj" },
		{ NM_FMT_CTFID, "ctfid" },
		{ 0, NULL }
	};

	mdb_subopt_t opt_type_opts[] = {
		{ NM_TYPE_NOTY, "noty" },
		{ NM_TYPE_OBJT, "objt" },
		{ NM_TYPE_FUNC, "func" },
		{ NM_TYPE_SECT, "sect" },
		{ NM_TYPE_FILE, "file" },
		{ NM_TYPE_COMM, "comm" },
		{ NM_TYPE_TLS, "tls" },
		{ NM_TYPE_REGI, "regi" },
		{ 0, NULL }
	};

	uint_t optf = 0;
	uint_t opt_fmt;
	uint_t opt_types;
	int i;

	mdb_tgt_sym_f *callback;
	uint_t which, type;

	char *object = (char *)MDB_TGT_OBJ_EVERY;
	int hwidth;
	size_t nsyms = 0;

	nm_sym_t *syms, *symp;

	nm_iter_info_t nii;

	/* default output columns */
	opt_fmt = NM_FMT_VALUE | NM_FMT_SIZE | NM_FMT_TYPE | NM_FMT_BIND |
	    NM_FMT_OTHER | NM_FMT_SHNDX | NM_FMT_NAME;

	/* default output types */
	opt_types = NM_TYPE_NOTY | NM_TYPE_OBJT | NM_TYPE_FUNC | NM_TYPE_SECT |
	    NM_TYPE_FILE | NM_TYPE_COMM | NM_TYPE_TLS | NM_TYPE_REGI;

	i = mdb_getopts(argc, argv,
	    'D', MDB_OPT_SETBITS, NM_DYNSYM, &optf,
	    'P', MDB_OPT_SETBITS, NM_PRVSYM, &optf,
	    'd', MDB_OPT_SETBITS, NM_DEC, &optf,
	    'g', MDB_OPT_SETBITS, NM_GLOBAL, &optf,
	    'h', MDB_OPT_SETBITS, NM_NOHDRS, &optf,
	    'n', MDB_OPT_SETBITS, NM_SORT_NAME, &optf,
	    'o', MDB_OPT_SETBITS, NM_OCT, &optf,
	    'p', MDB_OPT_SETBITS, NM_PRTASGN | NM_NOHDRS, &optf,
	    'u', MDB_OPT_SETBITS, NM_UNDEF, &optf,
	    'v', MDB_OPT_SETBITS, NM_SORT_VALUE, &optf,
	    'x', MDB_OPT_SETBITS, NM_HEX, &optf,
	    'f', MDB_OPT_SUBOPTS, opt_fmt_opts, &opt_fmt,
	    't', MDB_OPT_SUBOPTS, opt_type_opts, &opt_types,
	    NULL);

	if (i != argc) {
		if (flags & DCMD_ADDRSPEC)
			return (DCMD_USAGE);

		if (argc != 0 && (argc - i) == 1) {
			if (argv[i].a_type != MDB_TYPE_STRING ||
			    argv[i].a_un.a_str[0] == '-')
				return (DCMD_USAGE);
			else
				object = (char *)argv[i].a_un.a_str;
		} else
			return (DCMD_USAGE);
	}

	if ((optf & (NM_DEC | NM_HEX | NM_OCT)) == 0) {
		switch (mdb.m_radix) {
		case 8:
			optf |= NM_OCT;
			break;
		case 10:
			optf |= NM_DEC;
			break;
		default:
			optf |= NM_HEX;
		}
	}

	switch (optf & (NM_DEC | NM_HEX | NM_OCT)) {
	case NM_DEC:
#ifdef _LP64
		nii.nii_pfmt = "%-20llu";
		nii.nii_ofmt = "%-5u";
		hwidth = 20;
#else
		nii.nii_pfmt = "%-10llu";
		nii.nii_ofmt = "%-5u";
		hwidth = 10;
#endif
		break;
	case NM_HEX:
#ifdef _LP64
		nii.nii_pfmt = "0x%016llx";
		nii.nii_ofmt = "0x%-3x";
		hwidth = 18;
#else
		nii.nii_pfmt = "0x%08llx";
		nii.nii_ofmt = "0x%-3x";
		hwidth = 10;
#endif
		break;
	case NM_OCT:
#ifdef _LP64
		nii.nii_pfmt = "%-22llo";
		nii.nii_ofmt = "%-5o";
		hwidth = 22;
#else
		nii.nii_pfmt = "%-11llo";
		nii.nii_ofmt = "%-5o";
		hwidth = 11;
#endif
		break;
	default:
		mdb_warn("-d/-o/-x options are mutually exclusive\n");
		return (DCMD_USAGE);
	}

	if (object != MDB_TGT_OBJ_EVERY && (optf & NM_PRVSYM)) {
		mdb_warn("-P/object options are mutually exclusive\n");
		return (DCMD_USAGE);
	}

	if ((flags & DCMD_ADDRSPEC) && (optf & NM_PRVSYM)) {
		mdb_warn("-P/address options are mutually exclusive\n");
		return (DCMD_USAGE);
	}

	if (!(optf & NM_NOHDRS)) {
		mdb_printf("%<u>");
		mdb_table_print(opt_fmt, " ",
		    MDB_TBL_PRNT, NM_FMT_INDEX, "Index",
		    MDB_TBL_PRNT, NM_FMT_OBJECT, "%-15s", "Object",
		    MDB_TBL_PRNT, NM_FMT_VALUE, "%-*s", hwidth, "Value",
		    MDB_TBL_PRNT, NM_FMT_SIZE, "%-*s", hwidth, "Size",
		    MDB_TBL_PRNT, NM_FMT_TYPE, "%-5s", "Type",
		    MDB_TBL_PRNT, NM_FMT_BIND, "%-5s", "Bind",
		    MDB_TBL_PRNT, NM_FMT_OTHER, "%-5s", "Other",
		    MDB_TBL_PRNT, NM_FMT_SHNDX, "%-8s", "Shndx",
		    MDB_TBL_PRNT, NM_FMT_CTFID, "%-9s", "CTF ID",
		    MDB_TBL_PRNT, NM_FMT_CTYPE, "%-50s", "C Type",
		    MDB_TBL_PRNT, NM_FMT_NAME, "%s", "Name",
		    MDB_TBL_DONE);

		mdb_printf("%</u>\n");
	}

	nii.nii_flags = opt_fmt;
	nii.nii_types = opt_types;

	if (optf & NM_DYNSYM)
		which = MDB_TGT_DYNSYM;
	else
		which = MDB_TGT_SYMTAB;

	if (optf & NM_GLOBAL)
		type = MDB_TGT_BIND_GLOBAL | MDB_TGT_TYPE_ANY;
	else
		type = MDB_TGT_BIND_ANY | MDB_TGT_TYPE_ANY;

	if (flags & DCMD_ADDRSPEC)
		optf |= NM_SORT_NAME; /* use sorting path if only one symbol */

	if (optf & (NM_SORT_NAME | NM_SORT_VALUE)) {
		char name[MDB_SYM_NAMLEN];
		GElf_Sym sym;
		mdb_syminfo_t si;

		if (optf & NM_UNDEF)
			callback = nm_cnt_undef;
		else
			callback = nm_cnt_any;

		if (flags & DCMD_ADDRSPEC) {
			const mdb_map_t *mp;
			/* gather relevant data for the specified addr */

			nii.nii_fp = mdb_tgt_addr_to_ctf(mdb.m_target, addr);

			if (mdb_tgt_lookup_by_addr(mdb.m_target, addr,
			    MDB_SYM_FUZZY, name, sizeof (name), &sym,
			    &si) == -1) {
				mdb_warn("%lr", addr);
				return (DCMD_ERR);
			}

			if ((mp = mdb_tgt_addr_to_map(mdb.m_target, addr))
			    != NULL) {
				object = mdb_alloc(strlen(mp->map_name) + 1,
				    UM_SLEEP | UM_GC);

				(void) strcpy(object, mp->map_name);

				/*
				 * Try to find a better match for the syminfo.
				 */
				(void) mdb_tgt_lookup_by_name(mdb.m_target,
				    object, name, &sym, &si);
			}

			(void) callback(&nsyms, &sym, name, &si, object);

		} else if (optf & NM_PRVSYM) {
			nsyms = mdb_gelf_symtab_size(mdb.m_prsym);
		} else {
			(void) mdb_tgt_symbol_iter(mdb.m_target, object,
			    which, type, callback, &nsyms);
		}

		if (nsyms == 0)
			return (DCMD_OK);

		syms = symp = mdb_alloc(sizeof (nm_sym_t) * nsyms,
		    UM_SLEEP | UM_GC);

		nii.nii_sympp = &symp;

		if (optf & NM_UNDEF)
			callback = nm_get_undef;
		else
			callback = nm_get_any;

		if (flags & DCMD_ADDRSPEC) {
			(void) callback(&nii, &sym, name, &si, object);
		} else if (optf & NM_PRVSYM) {
			nm_gelf_symtab_iter(mdb.m_prsym, object, MDB_TGT_PRVSYM,
			    callback, &nii);
		} else if (nm_symbol_iter(object, which, type, callback,
		    &nii) == -1) {
			mdb_warn("failed to iterate over symbols");
			return (DCMD_ERR);
		}

		if (optf & NM_SORT_NAME)
			qsort(syms, nsyms, sizeof (nm_sym_t), nm_compare_name);
		else
			qsort(syms, nsyms, sizeof (nm_sym_t), nm_compare_val);
	}

	if ((optf & (NM_PRVSYM | NM_PRTASGN)) == (NM_PRVSYM | NM_PRTASGN))
		callback = nm_asgn;
	else if (optf & NM_UNDEF)
		callback = nm_undef;
	else
		callback = nm_any;

	if (optf & (NM_SORT_NAME | NM_SORT_VALUE)) {
		for (symp = syms; nsyms-- != 0; symp++) {
			nii.nii_fp = symp->nm_fp;

			callback(&nii, &symp->nm_sym, symp->nm_name,
			    &symp->nm_si, symp->nm_object);
		}

	} else {
		if (optf & NM_PRVSYM) {
			nm_gelf_symtab_iter(mdb.m_prsym, object, MDB_TGT_PRVSYM,
			    callback, &nii);

		} else if (nm_symbol_iter(object, which, type, callback, &nii)
		    == -1) {
			mdb_warn("failed to iterate over symbols");
			return (DCMD_ERR);
		}
	}

	return (DCMD_OK);
}