Example #1
0
/*
 * Convert an address to a symbolic string or a numeric string. If nolocks
 * is set, we return an error code if this symbol appears to be a mutex- or
 * rwlock-related symbol in libc so the caller has a chance to find a more
 * helpful symbol.
 */
static int
getsym(struct ps_prochandle *P, uintptr_t addr, char *buf, size_t size,
    int nolocks)
{
	char name[256];
	GElf_Sym sym;
	prsyminfo_t info;
	size_t len;

	if (P == NULL || Pxlookup_by_addr(P, addr, name, sizeof (name),
	    &sym, &info) != 0) {
		(void) snprintf(buf, size, "%#lx", addr);
		return (0);
	}
	if (info.prs_object == NULL)
		info.prs_object = "<unknown>";

	if (info.prs_lmid != LM_ID_BASE) {
		len = snprintf(buf, size, "LM%lu`", info.prs_lmid);
		buf += len;
		size -= len;
	}

	len = snprintf(buf, size, "%s`%s", info.prs_object, info.prs_name);
	buf += len;
	size -= len;

	if (sym.st_value != addr)
		len = snprintf(buf, size, "+%#lx", addr - sym.st_value);

	if (nolocks && strcmp("libc.so.1", info.prs_object) == 0 &&
	    (strstr("mutex", info.prs_name) == 0 ||
	    strstr("rw", info.prs_name) == 0))
		return (-1);

	return (0);
}
Example #2
0
/*
 * Read arguments from the frame indicated by regs into args, return the
 * number of arguments successfully read
 */
static int
read_args(struct ps_prochandle *P, uintptr_t fp, uintptr_t pc, prgreg_t *args,
    size_t argsize)
{
	GElf_Sym sym;
	ctf_file_t *ctfp = NULL;
	ctf_funcinfo_t finfo;
	prsyminfo_t si = {0};
	uint8_t ins[SAVEARGS_INSN_SEQ_LEN];
	size_t insnsize;
	int argc = 0;
	int rettype = 0;
	int start_index = 0;
	int args_style = 0;
	int i;
	ctf_id_t args_types[5];

	if (Pxlookup_by_addr(P, pc, NULL, 0, &sym, &si) != 0)
		return (0);

	if ((ctfp = Paddr_to_ctf(P, pc)) == NULL)
		return (0);

	if (ctf_func_info(ctfp, si.prs_id, &finfo) == CTF_ERR)
		return (0);

	argc = finfo.ctc_argc;

	if (argc == 0)
		return (0);

	rettype = ctf_type_kind(ctfp, finfo.ctc_return);

	/*
	 * If the function returns a structure or union greater than 16 bytes
	 * in size %rdi contains the address in which to store the return
	 * value rather than for an argument.
	 */
	if (((rettype == CTF_K_STRUCT) || (rettype == CTF_K_UNION)) &&
	    ctf_type_size(ctfp, finfo.ctc_return) > 16)
		start_index = 1;
	else
		start_index = 0;

	/*
	 * If any of the first 5 arguments are a structure less than 16 bytes
	 * in size, it will be passed spread across two argument registers,
	 * and we will not cope.
	 */
	if (ctf_func_args(ctfp, si.prs_id, 5, args_types) == CTF_ERR)
		return (0);

	for (i = 0; i < MIN(5, finfo.ctc_argc); i++) {
		int t = ctf_type_kind(ctfp, args_types[i]);

		if (((t == CTF_K_STRUCT) || (t == CTF_K_UNION)) &&
		    ctf_type_size(ctfp, args_types[i]) <= 16)
			return (0);
	}

	/*
	 * The number of instructions to search for argument saving is limited
	 * such that only instructions prior to %pc are considered and we
	 * never read arguments from a function where the saving code has not
	 * in fact yet executed.
	 */
	insnsize = MIN(MIN(sym.st_size, SAVEARGS_INSN_SEQ_LEN),
	    pc - sym.st_value);

	if (Pread(P, ins, insnsize, sym.st_value) != insnsize)
		return (0);

	if ((argc != 0) &&
	    ((args_style = saveargs_has_args(ins, insnsize, argc,
	    start_index)) != SAVEARGS_NO_ARGS)) {
		int regargs = MIN((6 - start_index), argc);
		size_t size = regargs * sizeof (long);
		int i;

		/*
		 * If Studio pushed a structure return address as an argument,
		 * we need to read one more argument than actually exists (the
		 * addr) to make everything line up.
		 */
		if (args_style == SAVEARGS_STRUCT_ARGS)
			size += sizeof (long);

		if (Pread(P, args, size, (fp - size)) != size)
			return (0);

		for (i = 0; i < (regargs / 2); i++) {
			prgreg_t t = args[i];

			args[i] = args[regargs - i - 1];
			args[regargs - i - 1] = t;
		}

		if (argc > regargs) {
			size = MIN((argc - regargs) * sizeof (long),
			    argsize - (regargs * sizeof (long)));

			if (Pread(P, &args[regargs], size, fp +
			    (sizeof (uintptr_t) * 2)) != size)
				return (6);
		}

		return (argc);
	} else {
		return (0);
	}
}