Beispiel #1
0
const char *
Ppltdest(struct ps_prochandle *P, uintptr_t pltaddr)
{
	map_info_t *mp = Paddr2mptr(P, pltaddr);

	uintptr_t r_addr;
	file_info_t *fp;
	Elf32_Rela r;
	size_t i;

	if (mp == NULL || (fp = mp->map_file) == NULL ||
	    fp->file_plt_base == 0 || pltaddr < fp->file_plt_base ||
	    pltaddr >= fp->file_plt_base + fp->file_plt_size) {
		errno = EINVAL;
		return (NULL);
	}

	i = (pltaddr - fp->file_plt_base -
	    M_PLT_XNumber * M32_PLT_ENTSIZE) / M32_PLT_ENTSIZE;

	r_addr = fp->file_jmp_rel + i * sizeof (Elf32_Rela);

	if (Pread(P, &r, sizeof (r), r_addr) == sizeof (r) &&
	    (i = ELF32_R_SYM(r.r_info)) < fp->file_dynsym.sym_symn) {

		Elf_Data *data = fp->file_dynsym.sym_data_pri;
		Elf32_Sym *symp = &(((Elf32_Sym *)data->d_buf)[i]);

		return (fp->file_dynsym.sym_strs + symp->st_name);
	}

	return (NULL);
}
Beispiel #2
0
/*
 * Given a return address, determine the likely number of arguments
 * that were pushed on the stack prior to its execution.  We do this by
 * expecting that a typical call sequence consists of pushing arguments on
 * the stack, executing a call instruction, and then performing an add
 * on %esp to restore it to the value prior to pushing the arguments for
 * the call.  We attempt to detect such an add, and divide the addend
 * by the size of a word to determine the number of pushed arguments.
 *
 * If we do not find such an add, this does not necessarily imply that the
 * function took no arguments. It is not possible to reliably detect such a
 * void function because hand-coded assembler does not always perform an add
 * to %esp immediately after the "call" instruction (eg. _sys_call()).
 * Because of this, we default to returning MIN(sz, TR_ARG_MAX) instead of 0
 * in the absence of an add to %esp.
 */
static ulong_t
argcount(struct ps_prochandle *P, uint32_t pc, ssize_t sz)
{
	uchar_t instr[6];
	ulong_t count, max;

	max = MIN(sz / sizeof (uint32_t), TR_ARG_MAX);

	/*
	 * Read the instruction at the return location.
	 */
	if (Pread(P, instr, sizeof (instr), (uintptr_t)pc) != sizeof (instr))
		return (max);

	if (instr[1] != 0xc4)
		return (max);

	switch (instr[0]) {
	case 0x81:	/* count is a longword */
		count = instr[2]+(instr[3]<<8)+(instr[4]<<16)+(instr[5]<<24);
		break;
	case 0x83:	/* count is a byte */
		count = instr[2];
		break;
	default:
		return (max);
	}

	count /= sizeof (uint32_t);
	return (MIN(count, max));
}
Beispiel #3
0
static int
dt_pid_usdt_mapping(void *data, const prmap_t *pmp, const char *oname)
{
	struct ps_prochandle *P = data;
	GElf_Sym sym;
	prsyminfo_t sip;
	dof_helper_t dh;
	GElf_Half e_type;
	const char *mname;
	const char *syms[] = { "___SUNW_dof", "__SUNW_dof" };
	int i, fd = -1;

	/*
	 * The symbol ___SUNW_dof is for lazy-loaded DOF sections, and
	 * __SUNW_dof is for actively-loaded DOF sections. We try to force
	 * in both types of DOF section since the process may not yet have
	 * run the code to instantiate these providers.
	 */
	for (i = 0; i < 2; i++) {
		if (Pxlookup_by_name(P, PR_LMID_EVERY, oname, syms[i], &sym,
		    &sip) != 0) {
			continue;
		}

		if ((mname = strrchr(oname, '/')) == NULL)
			mname = oname;
		else
			mname++;

		dt_dprintf("lookup of %s succeeded for %s\n", syms[i], mname);

		if (Pread(P, &e_type, sizeof (e_type), pmp->pr_vaddr +
		    offsetof(Elf64_Ehdr, e_type)) != sizeof (e_type)) {
			dt_dprintf("read of ELF header failed");
			continue;
		}

		dh.dofhp_dof = sym.st_value;
		dh.dofhp_addr = (e_type == ET_EXEC) ? 0 : pmp->pr_vaddr;

		dt_pid_objname(dh.dofhp_mod, sizeof (dh.dofhp_mod),
		    sip.prs_lmid, mname);

		if (fd == -1 &&
		    (fd = pr_open(P, "/dev/dtrace/helper", O_RDWR, 0)) < 0) {
			dt_dprintf("pr_open of helper device failed: %s\n",
			    strerror(errno));
			return (-1); /* errno is set for us */
		}

		if (pr_ioctl(P, fd, DTRACEHIOC_ADDDOF, &dh, sizeof (dh)) < 0)
			dt_dprintf("DOF was rejected for %s\n", dh.dofhp_mod);
	}

	if (fd != -1)
		(void) pr_close(P, fd);

	return (0);
}
Beispiel #4
0
const char *
Ppltdest(struct ps_prochandle *P, uintptr_t pltaddr)
{
	map_info_t *mp = Paddr2mptr(P, pltaddr);
	file_info_t *fp;
	size_t i;
	uintptr_t r_addr;

	if (mp == NULL || (fp = mp->map_file) == NULL ||
	    fp->file_plt_base == 0 ||
	    pltaddr - fp->file_plt_base >= fp->file_plt_size) {
		errno = EINVAL;
		return (NULL);
	}

	i = (pltaddr - fp->file_plt_base) / M_PLT_ENTSIZE - M_PLT_XNumber;

	if (P->status.pr_dmodel == PR_MODEL_LP64) {
		Elf64_Rela r;

		r_addr = fp->file_jmp_rel + i * sizeof (r);

		if (Pread(P, &r, sizeof (r), r_addr) == sizeof (r) &&
		    (i = ELF64_R_SYM(r.r_info)) < fp->file_dynsym.sym_symn) {
			Elf_Data *data = fp->file_dynsym.sym_data_pri;
			Elf64_Sym *symp = &(((Elf64_Sym *)data->d_buf)[i]);

			return (fp->file_dynsym.sym_strs + symp->st_name);
		}
	} else {
		Elf32_Rel r;

		r_addr = fp->file_jmp_rel + i * sizeof (r);

		if (Pread(P, &r, sizeof (r), r_addr) == sizeof (r) &&
		    (i = ELF32_R_SYM(r.r_info)) < fp->file_dynsym.sym_symn) {
			Elf_Data *data = fp->file_dynsym.sym_data_pri;
			Elf32_Sym *symp = &(((Elf32_Sym *)data->d_buf)[i]);

			return (fp->file_dynsym.sym_strs + symp->st_name);
		}
	}

	return (NULL);
}
int
main(int argc, const char *argv[])
{
	int ifd, ofd, perr, toread, ret;
	struct ps_prochandle *p;
	GElf_Sym sym;
	prsyminfo_t si;
	char buf[1024];

	if (argc != 3) {
		fprintf(stderr, "pdump: <infile> <outfile>\n");
		return (1);
	}

	ifd = open(argv[1], O_RDONLY);
	if (ifd < 0) {
		fprintf(stderr, "failed to open: %s: %s\n",
		    argv[1], strerror(errno));
		return (1);
	}
	ofd = open(argv[2], O_RDWR | O_CREAT | O_TRUNC);
	if (ofd < 0) {
		fprintf(stderr, "failed to open: %s: %s\n",
		    argv[1], strerror(errno));
		return (1);
	}

	p = Pfgrab_core(ifd, NULL, &perr); 
	if (p == NULL) {
		fprintf(stderr, "failed to grab core file\n");
		return (1);
	}

	if (Pxlookup_by_name(p, NULL, "a.out", g_sym, &sym, &si) != 0) {
		fprintf(stderr, "failed to lookup symobl %s\n", g_sym);
		return (0);
	}

	while (sym.st_size > 0) {
		toread = MIN(sym.st_size, sizeof (buf));
		ret = Pread(p, buf, toread, sym.st_value);
		if (ret < 0) {
			fprintf(stderr, "failed to Pread...\n");
			return (1);
		}
		if (ret != 0)
			ret = write(ofd, buf, ret);
		if (ret < 0) {
			fprintf(stderr, "failed to write to output file %s\n",
			    strerror(errno));
		}
		sym.st_size -= ret;
		sym.st_value += ret;
	}

	return (0);
}
void geFilePool::Reader::PreadCRC(void *buffer, size_t size, off64_t offset) {
  Pread(buffer, size, offset);
  size_t data_len = size - sizeof(uint32);
  uint32 computed_crc = Crc32(buffer, data_len);
  uint32 file_crc;
  FromLittleEndianBuffer(&file_crc,
                         reinterpret_cast<char*>(buffer) + data_len);
  if (computed_crc != file_crc) {
    throw khSimpleException("geFilePool::Reader::PreadCRC: CRC mismatch");
  }
}
Beispiel #7
0
int
Plwp_stack(struct ps_prochandle *P, lwpid_t lwpid, stack_t *stkp)
{
	uintptr_t addr;

	if (P->state == PS_IDLE) {
		errno = ENODATA;
		return (-1);
	}

	if (P->state != PS_DEAD) {
		lwpstatus_t ls;
		if (getlwpfile(P, lwpid, "lwpstatus", &ls, sizeof (ls)) != 0)
			return (-1);
		addr = ls.pr_ustack;
	} else {
		lwp_info_t *lwp;
		if ((lwp = getlwpcore(P, lwpid)) == NULL)
			return (-1);
		addr = lwp->lwp_status.pr_ustack;
	}


	if (P->status.pr_dmodel == PR_MODEL_NATIVE) {
		if (Pread(P, stkp, sizeof (*stkp), addr) != sizeof (*stkp))
			return (-1);
#ifdef _LP64
	} else {
		stack32_t stk32;

		if (Pread(P, &stk32, sizeof (stk32), addr) != sizeof (stk32))
			return (-1);

		stack_32_to_n(&stk32, stkp);
#endif
	}

	return (0);
}
Beispiel #8
0
int
Pissyscall(struct ps_prochandle *P, uintptr_t addr)
{
	instr_t sysinstr;
	instr_t instr;

	sysinstr = SYSCALL32;

	if (Pread(P, &instr, sizeof (instr), addr) != sizeof (instr) ||
	    instr != sysinstr)
		return (0);
	else
		return (1);
}
Beispiel #9
0
int
Pissyscall(struct ps_prochandle *P, uintptr_t addr)
{
	uchar_t instr[16];

	if (P->status.pr_dmodel == PR_MODEL_LP64) {
		if (Pread(P, instr, sizeof (syscall_instr), addr) !=
		    sizeof (syscall_instr) ||
		    memcmp(instr, syscall_instr, sizeof (syscall_instr)) != 0)
			return (0);
		else
			return (1);
	}

	if (Pread(P, instr, sizeof (int_syscall_instr), addr) !=
	    sizeof (int_syscall_instr))
		return (0);

	if (memcmp(instr, int_syscall_instr, sizeof (int_syscall_instr)) == 0)
		return (1);

	return (0);
}
Beispiel #10
0
int
dt_pid_create_return_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp,
    fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, uint64_t *stret)
{

	uint32_t *text;
	int i;
	int srdepth = 0;

	dt_dprintf("%s: unimplemented\n", __func__);
	return (DT_PROC_ERR);

	if ((text = malloc(symp->st_size + 4)) == NULL) {
		dt_dprintf("mr sparkle: malloc() failed\n");
		return (DT_PROC_ERR);
	}
#ifdef DOODAD
	if (Pread(P, text, symp->st_size, symp->st_value) != symp->st_size) {
		dt_dprintf("mr sparkle: Pread() failed\n");
		free(text);
		return (DT_PROC_ERR);
	}
#endif

	/*
	 * Leave a dummy instruction in the last slot to simplify edge
	 * conditions.
	 */
	text[symp->st_size / 4] = 0;

	ftp->ftps_type = DTFTP_RETURN;
	ftp->ftps_pc = symp->st_value;
	ftp->ftps_size = symp->st_size;
	ftp->ftps_noffs = 0;


	free(text);
	if (ftp->ftps_noffs > 0) {
		if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) {
			dt_dprintf("fasttrap probe creation ioctl failed: %s\n",
			    strerror(errno));
			return (dt_set_errno(dtp, errno));
		}
	}


	return (ftp->ftps_noffs);
}
Beispiel #11
0
void
show_stat32(private_t *pri, long offset)
{
	struct stat32 statb;
	timestruc_t ts;

	if (offset != NULL &&
	    Pread(Proc, &statb, sizeof (statb), offset) == sizeof (statb)) {
		(void) printf(
		    "%s    d=0x%.8X i=%-5u m=0%.6o l=%-2u u=%-5u g=%-5u",
		    pri->pname,
		    statb.st_dev,
		    statb.st_ino,
		    statb.st_mode,
		    statb.st_nlink,
		    statb.st_uid,
		    statb.st_gid);

		switch (statb.st_mode & S_IFMT) {
		case S_IFCHR:
		case S_IFBLK:
			(void) printf(" rdev=0x%.8X\n", statb.st_rdev);
			break;
		default:
			(void) printf(" sz=%u\n", statb.st_size);
			break;
		}

		TIMESPEC32_TO_TIMESPEC(&ts, &statb.st_atim);
		prtimestruc(pri, "at = ", &ts);
		TIMESPEC32_TO_TIMESPEC(&ts, &statb.st_mtim);
		prtimestruc(pri, "mt = ", &ts);
		TIMESPEC32_TO_TIMESPEC(&ts, &statb.st_ctim);
		prtimestruc(pri, "ct = ", &ts);

		(void) printf(
		    "%s    bsz=%-5d blks=%-5d fs=%.*s\n",
		    pri->pname,
		    statb.st_blksize,
		    statb.st_blocks,
		    _ST_FSTYPSZ,
		    statb.st_fstype);
	}
}
Beispiel #12
0
void
show_o_stat(private_t *pri, long offset)
{
	struct o_stat statb;
	timestruc_t ts;

	if (offset != NULL &&
	    Pread(Proc, &statb, sizeof (statb), offset) == sizeof (statb)) {
		(void) printf(
		    "%s    d=0x%.8X i=%-5u m=0%.6o l=%-2u u=%-5u g=%-5u",
		    pri->pname,
		    statb.st_dev & 0xffff,
		    statb.st_ino,
		    statb.st_mode,
		    statb.st_nlink % 0xffff,
		    statb.st_uid,
		    statb.st_gid);

		switch (statb.st_mode & S_IFMT) {
		case S_IFCHR:
		case S_IFBLK:
			(void) printf(" rdev=0x%.4X\n", statb.st_rdev & 0xffff);
			break;
		default:
			(void) printf(" sz=%u\n", (uint32_t)statb.st_size);
			break;
		}

		ts.tv_nsec = 0;
		ts.tv_sec = statb.st_atim;
		prtimestruc(pri, "at = ", &ts);
		ts.tv_sec = statb.st_atim;
		prtimestruc(pri, "mt = ", &ts);
		ts.tv_sec = statb.st_atim;
		prtimestruc(pri, "ct = ", &ts);
	}
}
Beispiel #13
0
int
Plwp_main_stack(struct ps_prochandle *P, lwpid_t lwpid, stack_t *stkp)
{
	uintptr_t addr;
	lwpstatus_t ls;

	if (P->state == PS_IDLE) {
		errno = ENODATA;
		return (-1);
	}

	if (P->state != PS_DEAD) {
		if (getlwpfile(P, lwpid, "lwpstatus", &ls, sizeof (ls)) != 0)
			return (-1);
	} else {
		lwp_info_t *lwp;
		if ((lwp = getlwpcore(P, lwpid)) == NULL)
			return (-1);
		ls = lwp->lwp_status;
	}

	addr = ls.pr_ustack;

	/*
	 * Read out the current stack; if the SS_ONSTACK flag is set then
	 * this LWP is operating on the alternate signal stack. We can
	 * recover the original stack from pr_oldcontext.
	 */
	if (P->status.pr_dmodel == PR_MODEL_NATIVE) {
		if (Pread(P, stkp, sizeof (*stkp), addr) != sizeof (*stkp))
			return (-1);

		if (stkp->ss_flags & SS_ONSTACK)
			goto on_altstack;
#ifdef _LP64
	} else {
		stack32_t stk32;

		if (Pread(P, &stk32, sizeof (stk32), addr) != sizeof (stk32))
			return (-1);

		if (stk32.ss_flags & SS_ONSTACK)
			goto on_altstack;

		stack_32_to_n(&stk32, stkp);
#endif
	}

	return (0);

on_altstack:

	if (P->status.pr_dmodel == PR_MODEL_NATIVE) {
		ucontext_t *ctxp = (void *)ls.pr_oldcontext;

		if (Pread(P, stkp, sizeof (*stkp),
		    (uintptr_t)&ctxp->uc_stack) != sizeof (*stkp))
			return (-1);
#ifdef _LP64
	} else {
		ucontext32_t *ctxp = (void *)ls.pr_oldcontext;
		stack32_t stk32;

		if (Pread(P, &stk32, sizeof (stk32),
		    (uintptr_t)&ctxp->uc_stack) != sizeof (stk32))
			return (-1);

		stack_32_to_n(&stk32, stkp);
#endif
	}

	return (0);
}
Beispiel #14
0
static int
dt_pid_usdt_mapping(void *data, const prmap_t *pmp, const char *oname)
{
	struct ps_prochandle *P = data;
	GElf_Sym sym;
#if defined(sun)
	prsyminfo_t sip;
	GElf_Half e_type;
#endif
	dof_helper_t dh;
	const char *mname;
	const char *syms[] = { "___SUNW_dof", "__SUNW_dof" };
	int i;
#if defined(windows)
	HANDLE fd = NULL;
	DWORD ret, gen;
#endif
#if !defined(sun)
	dof_hdr_t hdr;
#endif
	/*
	 * The symbol ___SUNW_dof is for lazy-loaded DOF sections, and
	 * __SUNW_dof is for actively-loaded DOF sections. We try to force
	 * in both types of DOF section since the process may not yet have
	 * run the code to instantiate these providers.
	 */
	for (i = 0; i < 2; i++) {
		if (Pxlookup_by_name(P, PR_LMID_EVERY, oname, syms[i], &sym,
		    NULL) != 0) {
			continue;
		}

		if ((mname = strrchr(oname, '/')) == NULL)
			mname = oname;
		else
			mname++;

		dt_dprintf("lookup of %s succeeded for %s\n", syms[i], mname);
		
#if 0
		if (Pread(P, &e_type, sizeof (e_type), pmp->pr_vaddr +
		    offsetof(Elf64_Ehdr, e_type)) != sizeof (e_type)) {
			dt_dprintf("read of ELF header failed");
			continue;
		}

		dh.dofhp_dof = sym.st_value;
		dh.dofhp_addr = (e_type == ET_EXEC) ? 0 : pmp->pr_vaddr;
#endif
#if !defined(sun)
		
		dh.dofhp_addr = 0;
		dh.dofhp_dof = (uintptr_t) sym.st_value;;
		dh.dofhp_pid = Ppid(P);
		dt_pid_objname(dh.dofhp_mod, sizeof (dh.dofhp_mod),
		    0, mname);

		if (fd == NULL &&
		    (fd = CreateFile("\\\\.\\DtraceHelper", GENERIC_READ | GENERIC_WRITE, 
		    0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) == NULL) {
			dt_dprintf("open of helper device failed: %s\n",
			    strerror(errno));
			return (-1); /* errno is set for us */
		}

		if ((DeviceIoControl(fd, DTRACEHIOC_ADDDOF, &dh, 0, &gen, 0, &ret, NULL)) == 0)
			dt_dprintf("DOF was rejected for %s\n", dh.dofhp_mod);
		else
			dt_dprintf("DOF was success for %s\n", dh.dofhp_mod);

#else
		dt_pid_objname(dh.dofhp_mod, sizeof (dh.dofhp_mod), sip.prs_lmid, mname);


		if (fd == -1 &&
		    (fd = pr_open(P, "/dev/dtrace/helper", O_RDWR, 0)) < 0) {
			dt_dprintf("pr_open of helper device failed: %s\n",
			    strerror(errno));
			return (-1); /* errno is set for us */
		}

		if (pr_ioctl(P, fd, DTRACEHIOC_ADDDOF, &dh, sizeof (dh)) < 0)
			dt_dprintf("DOF was rejected for %s\n", dh.dofhp_mod);
#endif
	}

#if defined(sun)
	if (fd != -1)
		(void) pr_close(P, fd);
#else
	if (fd != 0)
		CloseHandle(fd);
#endif

	return (0);
}
void geFilePool::Writer::Pread(std::string &buffer, size_t size,
                               off64_t offset)
{
  buffer.resize(size);
  Pread(&buffer[0], size, offset);
}
Beispiel #16
0
static int
Pstack_iter32(struct ps_prochandle *P, const prgregset_t regs,
    proc_stack_f *func, void *arg)
{
	prgreg_t *prevfp = NULL;
	uint_t pfpsize = 0;
	int nfp = 0;
	struct {
		prgreg32_t fp;
		prgreg32_t pc;
		prgreg32_t args[32];
	} frame;
	uint_t argc;
	ssize_t sz;
	prgregset_t gregs;
	uint32_t fp, pfp, pc;
	long args[32];
	int rv;
	int i;

	/*
	 * Type definition for a structure corresponding to an IA32
	 * signal frame.  Refer to the comments in Pstack.c for more info
	 */
	typedef struct {
		prgreg32_t fp;
		prgreg32_t pc;
		int signo;
		caddr32_t ucp;
		caddr32_t sip;
	} sf_t;

	uclist_t ucl;
	ucontext32_t uc;
	uintptr_t uc_addr;

	init_uclist(&ucl, P);
	(void) memcpy(gregs, regs, sizeof (gregs));

	fp = regs[R_FP];
	pc = regs[R_PC];

	while (fp != 0 || pc != 0) {
		if (stack_loop(fp, &prevfp, &nfp, &pfpsize))
			break;

		if (fp != 0 &&
		    (sz = Pread(P, &frame, sizeof (frame), (uintptr_t)fp)
		    >= (ssize_t)(2* sizeof (uint32_t)))) {
			/*
			 * One more trick for signal frames: the kernel sets
			 * the return pc of the signal frame to 0xffffffff on
			 * Intel IA32, so argcount won't work.
			 */
			if (frame.pc != -1L) {
				sz -= 2* sizeof (uint32_t);
				argc = argcount(P, (uint32_t)frame.pc, sz);
			} else
				argc = 3; /* sighandler(signo, sip, ucp) */
		} else {
			(void) memset(&frame, 0, sizeof (frame));
			argc = 0;
		}

		gregs[R_FP] = fp;
		gregs[R_PC] = pc;

		for (i = 0; i < argc; i++)
			args[i] = (uint32_t)frame.args[i];

		if ((rv = func(arg, gregs, argc, args)) != 0)
			break;

		/*
		 * In order to allow iteration over java frames (which can have
		 * their own frame pointers), we allow the iterator to change
		 * the contents of gregs.  If we detect a change, then we assume
		 * that the new values point to the next frame.
		 */
		if (gregs[R_FP] != fp || gregs[R_PC] != pc) {
			fp = gregs[R_FP];
			pc = gregs[R_PC];
			continue;
		}

		pfp = fp;
		fp = frame.fp;
		pc = frame.pc;

		if (find_uclink(&ucl, pfp + sizeof (sf_t)))
			uc_addr = pfp + sizeof (sf_t);
		else
			uc_addr = NULL;

		if (uc_addr != NULL &&
		    Pread(P, &uc, sizeof (uc), uc_addr) == sizeof (uc)) {
			ucontext_32_to_prgregs(&uc, gregs);
			fp = gregs[R_FP];
			pc = gregs[R_PC];
		}
	}

	if (prevfp)
		free(prevfp);

	free_uclist(&ucl);
	return (rv);
}
Beispiel #17
0
int main(int argc, char **argv)
{
	bool walk = false, randsize = false, verbose = false, csum = false, rtest = false, wtest = false;
	int fd1, fd2 = 0, direct = 0, nbytes = 4096, j, o;
	unsigned long size, i, offset = 0, done = 0, unique = 0, benchmark = 0;
	void *buf1 = NULL, *buf2 = NULL;
	struct pagestuff *pages, *p;
	unsigned char c[16];
	time_t last_printed = 0;
	extern char *optarg;

	RC4_KEY writedata;
	RC4_set_key(&writedata, 16, bcache_magic);

	while ((o = getopt(argc, argv, "dnwvscwlb:")) != EOF)
		switch (o) {
		case 'd':
			direct = O_DIRECT;
			break;
		case 'n':
			walk = true;
			break;
		case 'v':
			verbose = true;
			break;
		case 's':
			randsize = true;
			break;
		case 'c':
			csum = true;
			break;
		case 'w':
			wtest = true;
			break;
		case 'r':
			rtest = true;
			break;
		case 'l':
			klog = true;
			break;
		case 'b':
			benchmark = atol(optarg);
			break;
		default:
			usage();
		}

	argv += optind;
	argc -= optind;

	if (!rtest && !wtest)
		rtest = true;

	if (argc < 1) {
		printf("Please enter a device to test\n");
		exit(EXIT_FAILURE);
	}

	if (!csum && !benchmark && argc < 2) {
		printf("Please enter a device to compare against\n");
		exit(EXIT_FAILURE);
	}

	fd1 = open(argv[0], (wtest ? O_RDWR : O_RDONLY)|direct);
	if (!csum && !benchmark)
		fd2 = open(argv[1], (wtest ? O_RDWR : O_RDONLY)|direct);

	if (fd1 == -1 || fd2 == -1) {
		perror("Error opening device");
		exit(EXIT_FAILURE);
	}

	size = getblocks(fd1);
	if (!csum && !benchmark)
		size = MIN(size, getblocks(fd2));

	size = size / 8 - 16;
	pages = calloc(size + 16, sizeof(*pages));
	printf("size %li\n", size);

	if (posix_memalign(&buf1, 4096, 4096 * 16) ||
	    posix_memalign(&buf2, 4096, 4096 * 16)) {
		printf("Could not allocate buffers\n");
		exit(EXIT_FAILURE);
	}
	//setvbuf(stdout, NULL, _IONBF, 0);

	for (i = 0; !benchmark || i < benchmark; i++) {
		bool writing = (wtest && (i & 1)) || !rtest;
		nbytes = randsize ? drand48() * 16 + 1 : 1;
		nbytes <<= 12;

		offset >>= 12;
		offset += walk ? normal() * 20 : random();
		offset %= size;
		offset <<= 12;

		if (!(i % 200))
			flushlog();

		if (!verbose) {
			time_t now = time(NULL);
			if (now - last_printed >= 2) {
				last_printed = now;
				goto print;
			}
		} else
print:			printf("Loop %6li offset %9li sectors %3i, %6lu mb done, %6lu mb unique\n",
			       i, offset >> 9, nbytes >> 9, done >> 11, unique >> 11);

		done += nbytes >> 9;

		if (!writing)
			Pread(fd1, buf1, nbytes, offset);
		if (!writing && !csum && !benchmark)
			Pread(fd2, buf2, nbytes, offset);

		for (j = 0; j < nbytes; j += 4096) {
			p = &pages[(offset + j) / 4096];

			if (writing)
				RC4(&writedata, 4096, zero, buf1 + j);

			if (csum) {
				MD4(buf1 + j, 4096, &c[0]);

				if (writing ||
				    (!p->readcount && !p->writecount)) {
					memcpy(&p->oldcsum[0], &p->csum[0], 16);
					memcpy(&p->csum[0], c, 16);
				} else if (memcmp(&p->csum[0], c, 16))
					goto bad;
			} else if (!writing && !benchmark &&
				   memcmp(buf1 + j,
					  buf2 + j,
					  4096))
				goto bad;

			if (!p->writecount && !p->readcount)
				unique += 8;

			writing ? p->writecount++ : p->readcount++;
		}
		if (writing)
			Pwrite(fd1, buf1, nbytes, offset);
		if (writing && !csum && !benchmark)
			Pwrite(fd2, buf2, nbytes, offset);
	}
	printf("Loop %6li offset %9li sectors %3i, %6lu mb done, %6lu mb unique\n",
	       i, offset >> 9, nbytes >> 9, done >> 11, unique >> 11);
	exit(EXIT_SUCCESS);
err:
	perror("IO error");
	flushlog();
	exit(EXIT_FAILURE);
bad:
	printf("Bad read! loop %li offset %li readcount %i writecount %i\n",
	       i, (offset + j) >> 9, p->readcount, p->writecount);

	if (!memcmp(&p->oldcsum[0], c, 16))
		printf("Matches previous csum\n");

	flushlog();
	exit(EXIT_FAILURE);
}
/* minix-without-mmap version of _rtld_map_object() */
Obj_Entry *
_rtld_map_object_fallback(const char *path, int fd, const struct stat *sb)
{
	Obj_Entry	*obj;
	Elf_Ehdr	*ehdr;
	Elf_Phdr	*phdr;
#if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
	Elf_Phdr	*phtls;
#endif
	size_t		 phsize;
	Elf_Phdr	*phlimit;
	Elf_Phdr	*segs[2];
	int		 nsegs;
	caddr_t		 mapbase = MAP_FAILED;
	size_t		 mapsize = 0;
	int		 mapflags;
	Elf_Off		 base_offset;
#ifdef MAP_ALIGNED
	Elf_Addr	 base_alignment;
#endif
	Elf_Addr	 base_vaddr;
	Elf_Addr	 base_vlimit;
	Elf_Addr	 text_vlimit;
	int		 text_flags;
	caddr_t		 base_addr;
	Elf_Off		 data_offset;
	Elf_Addr	 data_vaddr;
	Elf_Addr	 data_vlimit;
	int		 data_flags;
	caddr_t		 data_addr;
#if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
	Elf_Addr	 tls_vaddr = 0; /* Noise GCC */
#endif
	Elf_Addr	 phdr_vaddr;
	size_t		 phdr_memsz;
#if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
	caddr_t		 gap_addr;
	size_t		 gap_size;
#endif
	int i;
#ifdef RTLD_LOADER
	Elf_Addr	 clear_vaddr;
	caddr_t		 clear_addr;
	size_t		 nclear;
#endif

	if (sb != NULL && sb->st_size < (off_t)sizeof (Elf_Ehdr)) {
		_rtld_error("%s: not ELF file (too short)", path);
		return NULL;
	}

	obj = _rtld_obj_new();
	obj->path = xstrdup(path);
	obj->pathlen = strlen(path);
	if (sb != NULL) {
		obj->dev = sb->st_dev;
		obj->ino = sb->st_ino;
	}

#ifdef __minix
	ehdr = minix_mmap(NULL, _rtld_pagesz, PROT_READ|PROT_WRITE,
		MAP_PREALLOC|MAP_ANON, -1, (off_t)0);
	Pread(ehdr, _rtld_pagesz, fd, 0);
#if MINIXVERBOSE
	fprintf(stderr, "minix mmap for header: 0x%lx\n", ehdr);
#endif
#else
	ehdr = mmap(NULL, _rtld_pagesz, PROT_READ, MAP_FILE | MAP_SHARED, fd,
	    (off_t)0);
#endif
	obj->ehdr = ehdr;
	if (ehdr == MAP_FAILED) {
		_rtld_error("%s: read error: %s", path, xstrerror(errno));
		goto bad;
	}
	/* Make sure the file is valid */
	if (memcmp(ELFMAG, ehdr->e_ident, SELFMAG) != 0) {
		_rtld_error("%s: not ELF file (magic number bad)", path);
		goto bad;
	}
	if (ehdr->e_ident[EI_CLASS] != ELFCLASS) {
		_rtld_error("%s: invalid ELF class %x; expected %x", path,
		    ehdr->e_ident[EI_CLASS], ELFCLASS);
		goto bad;
	}
	/* Elf_e_ident includes class */
	if (ehdr->e_ident[EI_VERSION] != EV_CURRENT ||
	    ehdr->e_version != EV_CURRENT ||
	    ehdr->e_ident[EI_DATA] != ELFDEFNNAME(MACHDEP_ENDIANNESS)) {
		_rtld_error("%s: unsupported file version", path);
		goto bad;
	}
	if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN) {
		_rtld_error("%s: unsupported file type", path);
		goto bad;
	}
	switch (ehdr->e_machine) {
		ELFDEFNNAME(MACHDEP_ID_CASES)
	default:
		_rtld_error("%s: unsupported machine", path);
		goto bad;
	}

	/*
         * We rely on the program header being in the first page.  This is
         * not strictly required by the ABI specification, but it seems to
         * always true in practice.  And, it simplifies things considerably.
         */
	assert(ehdr->e_phentsize == sizeof(Elf_Phdr));
	assert(ehdr->e_phoff + ehdr->e_phnum * sizeof(Elf_Phdr) <=
	    _rtld_pagesz);

	/*
         * Scan the program header entries, and save key information.
         *
         * We rely on there being exactly two load segments, text and data,
         * in that order.
         */
	phdr = (Elf_Phdr *) ((caddr_t)ehdr + ehdr->e_phoff);
#if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
	phtls = NULL;
#endif
	phsize = ehdr->e_phnum * sizeof(phdr[0]);
	obj->phdr = NULL;
	phdr_vaddr = EA_UNDEF;
	phdr_memsz = 0;
	phlimit = phdr + ehdr->e_phnum;
	nsegs = 0;
	while (phdr < phlimit) {
		switch (phdr->p_type) {
		case PT_INTERP:
			obj->interp = (void *)(uintptr_t)phdr->p_vaddr;
 			dbg(("%s: PT_INTERP %p", obj->path, obj->interp));
			break;

		case PT_LOAD:
			if (nsegs < 2)
				segs[nsegs] = phdr;
			++nsegs;

#if ELFSIZE == 64
#define	PRImemsz	PRIu64
#else
#define PRImemsz	PRIu32
#endif
			dbg(("%s: %s %p phsize %" PRImemsz, obj->path, "PT_LOAD",
			    (void *)(uintptr_t)phdr->p_vaddr, phdr->p_memsz));
			break;

		case PT_PHDR:
			phdr_vaddr = phdr->p_vaddr;
			phdr_memsz = phdr->p_memsz;
			dbg(("%s: %s %p phsize %" PRImemsz, obj->path, "PT_PHDR",
			    (void *)(uintptr_t)phdr->p_vaddr, phdr->p_memsz));
			break;
		
		case PT_DYNAMIC:
			obj->dynamic = (void *)(uintptr_t)phdr->p_vaddr;
			dbg(("%s: %s %p phsize %" PRImemsz, obj->path, "PT_DYNAMIC",
			    (void *)(uintptr_t)phdr->p_vaddr, phdr->p_memsz));
			break;

#if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
		case PT_TLS:
			phtls = phdr;
			dbg(("%s: %s %p phsize %" PRImemsz, obj->path, "PT_TLS",
			    (void *)(uintptr_t)phdr->p_vaddr, phdr->p_memsz));
			break;
#endif
		}

		++phdr;
	}
	phdr = (Elf_Phdr *) ((caddr_t)ehdr + ehdr->e_phoff);
	obj->entry = (void *)(uintptr_t)ehdr->e_entry;
	if (!obj->dynamic) {
		_rtld_error("%s: not dynamically linked", path);
		goto bad;
	}
	if (nsegs != 2) {
		_rtld_error("%s: wrong number of segments (%d != 2)", path,
		    nsegs);
		goto bad;
	}

	/*
	 * Map the entire address space of the object as a file
	 * region to stake out our contiguous region and establish a
	 * base for relocation.  We use a file mapping so that
	 * the kernel will give us whatever alignment is appropriate
	 * for the platform we're running on.
	 *
	 * We map it using the text protection, map the data segment
	 * into the right place, then map an anon segment for the bss
	 * and unmap the gaps left by padding to alignment.
	 */

#ifdef MAP_ALIGNED
	base_alignment = segs[0]->p_align;
#endif
	base_offset = round_down(segs[0]->p_offset);
	base_vaddr = round_down(segs[0]->p_vaddr);
	base_vlimit = round_up(segs[1]->p_vaddr + segs[1]->p_memsz);
	text_vlimit = round_up(segs[0]->p_vaddr + segs[0]->p_memsz);
	text_flags = protflags(segs[0]->p_flags);
	data_offset = round_down(segs[1]->p_offset);
	data_vaddr = round_down(segs[1]->p_vaddr);
	data_vlimit = round_up(segs[1]->p_vaddr + segs[1]->p_filesz);
	data_flags = protflags(segs[1]->p_flags);
#ifdef RTLD_LOADER
	clear_vaddr = segs[1]->p_vaddr + segs[1]->p_filesz;
#endif

	obj->textsize = text_vlimit - base_vaddr;
	obj->vaddrbase = base_vaddr;
	obj->isdynamic = ehdr->e_type == ET_DYN;

#if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
	if (phtls != NULL) {
		++_rtld_tls_dtv_generation;
		obj->tlsindex = ++_rtld_tls_max_index;
		obj->tlssize = phtls->p_memsz;
		obj->tlsalign = phtls->p_align;
		obj->tlsinitsize = phtls->p_filesz;
		tls_vaddr = phtls->p_vaddr;
	}
#endif

	obj->phdr_loaded = false;
	for (i = 0; i < nsegs; i++) {
		if (phdr_vaddr != EA_UNDEF &&
		    segs[i]->p_vaddr <= phdr_vaddr &&
		    segs[i]->p_memsz >= phdr_memsz) {
			obj->phdr_loaded = true;
			break;
		}
		if (segs[i]->p_offset <= ehdr->e_phoff &&
		    segs[i]->p_memsz >= phsize) {
			phdr_vaddr = segs[i]->p_vaddr + ehdr->e_phoff;
			phdr_memsz = phsize;
			obj->phdr_loaded = true;
			break;
		}
	}
	if (obj->phdr_loaded) {
		obj->phdr = (void *)(uintptr_t)phdr_vaddr;
		obj->phsize = phdr_memsz;
	} else {
		Elf_Phdr *buf;
		buf = xmalloc(phsize);
		if (buf == NULL) {
			_rtld_error("%s: cannot allocate program header", path);
			goto bad;
		}
		memcpy(buf, phdr, phsize);
		obj->phdr = buf;
		obj->phsize = phsize;
	}
	dbg(("%s: phdr %p phsize %zu (%s)", obj->path, obj->phdr, obj->phsize,
	     obj->phdr_loaded ? "loaded" : "allocated"));

	/* Unmap header if it overlaps the first load section. */
	if (base_offset < _rtld_pagesz) {
		munmap(ehdr, _rtld_pagesz);
		obj->ehdr = MAP_FAILED;
	}

	/*
	 * Calculate log2 of the base section alignment.
	 */
	mapflags = 0;
#ifdef MAP_ALIGNED
	if (base_alignment > _rtld_pagesz) {
		unsigned int log2 = 0;
		for (; base_alignment > 1; base_alignment >>= 1)
			log2++;
		mapflags = MAP_ALIGNED(log2);
	}
Beispiel #19
0
int
Pstack_iter(struct ps_prochandle *P, const prgregset_t regs,
	proc_stack_f *func, void *arg)
{
	prgreg_t *prevfp = NULL;
	uint_t pfpsize = 0;
	int nfp = 0;
	prgregset_t gregs;
	long args[6];
	prgreg_t fp;
	int i;
	int rv;
	uintptr_t sp;
	ssize_t n;
	uclist_t ucl;
	ucontext_t uc;

	init_uclist(&ucl, P);
	(void) memcpy(gregs, regs, sizeof (gregs));

	for (;;) {
		fp = gregs[R_FP];
		if (stack_loop(fp, &prevfp, &nfp, &pfpsize))
			break;

		for (i = 0; i < 6; i++)
			args[i] = gregs[R_I0 + i];
		if ((rv = func(arg, gregs, 6, args)) != 0)
			break;

		gregs[R_PC] = gregs[R_I7];
		gregs[R_nPC] = gregs[R_PC] + 4;
		(void) memcpy(&gregs[R_O0], &gregs[R_I0], 8*sizeof (prgreg_t));
		if ((sp = gregs[R_FP]) == 0)
			break;

		sp += STACK_BIAS;

		if (find_uclink(&ucl, sp + SA(sizeof (struct frame))) &&
		    Pread(P, &uc, sizeof (uc), sp +
		    SA(sizeof (struct frame))) == sizeof (uc)) {
			ucontext_n_to_prgregs(&uc, gregs);
			sp = gregs[R_SP] + STACK_BIAS;
		}

		n = Pread(P, &gregs[R_L0], sizeof (struct rwindow), sp);

		if (n == sizeof (struct rwindow))
			continue;

		/*
		 * If we get here, then our Pread of the register window
		 * failed.  If this is because the address was not mapped,
		 * then we attempt to read this window via any gwindows
		 * information we have.  If that too fails, abort our loop.
		 */
		if (n > 0)
			break;	/* Failed for reason other than not mapped */

		if (read_gwin(P, (struct rwindow *)&gregs[R_L0], sp) == -1)
			break;	/* No gwindows match either */
	}

	if (prevfp)
		free(prevfp);

	free_uclist(&ucl);
	return (rv);
}
Beispiel #20
0
/*ARGSUSED*/
int
dt_pid_create_glob_offset_probes(struct ps_prochandle *P, dtrace_hdl_t *dtp,
    fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, const char *pattern)
{
	uint8_t *text;
	ulong_t i, end;
	int size;
	pid_t pid = Pstatus(P)->pr_pid;
	char dmodel = Pstatus(P)->pr_dmodel;

	if ((text = malloc(symp->st_size)) == NULL) {
		dt_dprintf("mr sparkle: malloc() failed\n");
		return (DT_PROC_ERR);
	}

	if (Pread(P, text, symp->st_size, symp->st_value) != symp->st_size) {
		dt_dprintf("mr sparkle: Pread() failed\n");
		free(text);
		return (DT_PROC_ERR);
	}

	/*
	 * We can't instrument offsets in functions with jump tables as
	 * we might interpret a jump table offset as an instruction.
	 */
	if (dt_pid_has_jump_table(P, dtp, text, ftp, symp)) {
		free(text);
		return (0);
	}

	ftp->ftps_probe_type = DTFTP_OFFSETS;
	ftp->ftps_pc = symp->st_value;
	ftp->ftps_size = (size_t)symp->st_size;
	ftp->ftps_noffs = 0;

	end = ftp->ftps_size;

	if (strcmp("*", pattern) == 0) {
		for (i = 0; i < end; i += size) {
			ftp->ftps_offs[ftp->ftps_noffs++] = i;

			size = dt_instr_size(&text[i], dtp, pid,
			    symp->st_value + i, dmodel);

			/* bail if we hit an invalid opcode */
			if (size <= 0)
				break;
		}
	} else {
		char name[sizeof (i) * 2 + 1];

		for (i = 0; i < end; i += size) {
			(void) snprintf(name, sizeof (name), "%lx", i);
			if (gmatch(name, pattern))
				ftp->ftps_offs[ftp->ftps_noffs++] = i;

			size = dt_instr_size(&text[i], dtp, pid,
			    symp->st_value + i, dmodel);

			/* bail if we hit an invalid opcode */
			if (size <= 0)
				break;
		}
	}

	free(text);
	if (ftp->ftps_noffs > 0) {
		if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) {
			dt_dprintf("fasttrap probe creation ioctl failed: %s\n",
			    strerror(errno));
			return (dt_set_errno(dtp, errno));
		}
	}

	return (ftp->ftps_noffs);
}
Beispiel #21
0
Elf *
fake_elf32(struct ps_prochandle *P, file_info_t *fptr, uintptr_t addr,
    Ehdr *ehdr, uint_t phnum, Phdr *phdr)
#endif
{
	enum {
		DI_PLTGOT,
		DI_JMPREL,
		DI_PLTRELSZ,
		DI_PLTREL,
		DI_SYMTAB,
		DI_HASH,
		DI_SYMENT,
		DI_STRTAB,
		DI_STRSZ,
		DI_SUNW_SYMTAB,
		DI_SUNW_SYMSZ,
		DI_NENT
	};
	/*
	 * Mask of dynamic options that must be present in a well
	 * formed dynamic section. We need all of these in order to
	 * put together a complete set of elf sections. They are
	 * mandatory in both executables and shared objects so if one
	 * of them is missing, we're in some trouble and should abort.
	 * The PLT items are expected, but we will let them slide if
	 * need be. The DI_SUNW_SYM* items are completely optional, so
	 * we use them if they are present and ignore them otherwise.
	 */
	const int di_req_mask = (1 << DI_SYMTAB) |
		(1 << DI_SYMENT) | (1 << DI_STRTAB) | (1 << DI_STRSZ);
	int di_mask = 0;
	size_t size = 0;
	caddr_t elfdata = NULL;
	Elf *elf;
	size_t dynsym_size = 0, ldynsym_size;
	int dynstr_shndx;
	Ehdr *ep;
	Shdr *sp;
	Dyn *dp = NULL;
	Dyn *d[DI_NENT] = { 0 };
	uint_t i;
	Off off;
	size_t pltsz = 0, pltentries = 0;
	uintptr_t hptr = NULL;
	Word hnchains = 0, hnbuckets = 0;

	if (ehdr->e_type == ET_DYN)
		phdr->p_vaddr += addr;

	if (P->rap != NULL) {
		if (rd_get_dyns(P->rap, addr, (void **)&dp, NULL) != RD_OK)
			goto bad;
	} else {
		if ((dp = malloc(phdr->p_filesz)) == NULL)
			goto bad;
		if (Pread(P, dp, phdr->p_filesz, phdr->p_vaddr) !=
		    phdr->p_filesz)
			goto bad;
	}

	/*
	 * Iterate over the items in the dynamic section, grabbing
	 * the address of items we want and saving them in dp[].
	 */
	for (i = 0; i < phdr->p_filesz / sizeof (Dyn); i++) {
		switch (dp[i].d_tag) {
		/* For the .plt section */
		case DT_PLTGOT:
			d[DI_PLTGOT] = &dp[i];
			break;
		case DT_JMPREL:
			d[DI_JMPREL] = &dp[i];
			break;
		case DT_PLTRELSZ:
			d[DI_PLTRELSZ] = &dp[i];
			break;
		case DT_PLTREL:
			d[DI_PLTREL] = &dp[i];
			break;

		/* For the .dynsym section */
		case DT_SYMTAB:
			d[DI_SYMTAB] = &dp[i];
			di_mask |= (1 << DI_SYMTAB);
			break;
		case DT_HASH:
			d[DI_HASH] = &dp[i];
			di_mask |= (1 << DI_HASH);
			break;
		case DT_SYMENT:
			d[DI_SYMENT] = &dp[i];
			di_mask |= (1 << DI_SYMENT);
			break;
		case DT_SUNW_SYMTAB:
			d[DI_SUNW_SYMTAB] = &dp[i];
			break;
		case DT_SUNW_SYMSZ:
			d[DI_SUNW_SYMSZ] = &dp[i];
			break;

		/* For the .dynstr section */
		case DT_STRTAB:
			d[DI_STRTAB] = &dp[i];
			di_mask |= (1 << DI_STRTAB);
			break;
		case DT_STRSZ:
			d[DI_STRSZ] = &dp[i];
			di_mask |= (1 << DI_STRSZ);
			break;
		}
	}

	/* Ensure all required entries were collected */
	if ((di_mask & di_req_mask) != di_req_mask) {
		dprintf("text section missing required dynamic entries: "
		    "required 0x%x, found 0x%x\n", di_req_mask, di_mask);
		goto bad;
	}

	/* SUNW_ldynsym must be adjacent to dynsym. Ignore if not */
	if ((d[DI_SUNW_SYMTAB] != NULL) && (d[DI_SUNW_SYMSZ] != NULL) &&
	    ((d[DI_SYMTAB]->d_un.d_ptr <= d[DI_SUNW_SYMTAB]->d_un.d_ptr) ||
	    (d[DI_SYMTAB]->d_un.d_ptr >= (d[DI_SUNW_SYMTAB]->d_un.d_ptr +
	    d[DI_SUNW_SYMSZ]->d_un.d_val)))) {
		d[DI_SUNW_SYMTAB] = NULL;
		d[DI_SUNW_SYMSZ] = NULL;
	}

	/* elf header */
	size = sizeof (Ehdr);

	/* program headers from in-core elf fragment */
	size += phnum * ehdr->e_phentsize;

	/* unused shdr, and .shstrtab section */
	size += sizeof (Shdr);
	size += sizeof (Shdr);
	size += roundup(sizeof (shstr), SH_ADDRALIGN);

	if (d[DI_HASH] != NULL) {
		Word hash[2];

		hptr = d[DI_HASH]->d_un.d_ptr;
		if (ehdr->e_type == ET_DYN)
			hptr += addr;

		if (Pread(P, hash, sizeof (hash), hptr) != sizeof (hash)) {
			dprintf("Pread of .hash at %lx failed\n",
			    (long)(hptr));
			goto bad;
		}

		hnbuckets = hash[0];
		hnchains = hash[1];
	}

	/*
	 * .dynsym and .SUNW_ldynsym sections.
	 *
	 * The string table section used for the symbol table and
	 * dynamic sections lies immediately after the dynsym, so the
	 * presence of SUNW_ldynsym changes the dynstr section index.
	 */
	if (d[DI_SUNW_SYMTAB] != NULL) {
		size += sizeof (Shdr);	/* SUNW_ldynsym shdr */
		ldynsym_size = (size_t)d[DI_SUNW_SYMSZ]->d_un.d_val;
		dynsym_size = ldynsym_size - (d[DI_SYMTAB]->d_un.d_ptr
		    - d[DI_SUNW_SYMTAB]->d_un.d_ptr);
		ldynsym_size -= dynsym_size;
		dynstr_shndx = 4;
	} else {
		dynsym_size = sizeof (Sym) * hnchains;
		ldynsym_size = 0;
		dynstr_shndx = 3;
	}
	size += sizeof (Shdr) + ldynsym_size + dynsym_size;

	/* .dynstr section */
	size += sizeof (Shdr);
	size += roundup(d[DI_STRSZ]->d_un.d_val, SH_ADDRALIGN);

	/* .dynamic section */
	size += sizeof (Shdr);
	size += roundup(phdr->p_filesz, SH_ADDRALIGN);

	/* .plt section */
	if (d[DI_PLTGOT] != NULL && d[DI_JMPREL] != NULL &&
	    d[DI_PLTRELSZ] != NULL && d[DI_PLTREL] != NULL) {
		size_t pltrelsz = d[DI_PLTRELSZ]->d_un.d_val;

		if (d[DI_PLTREL]->d_un.d_val == DT_RELA) {
			pltentries = pltrelsz / sizeof (Rela);
		} else if (d[DI_PLTREL]->d_un.d_val == DT_REL) {
			pltentries = pltrelsz / sizeof (Rel);
		} else {
			/* fall back to the platform default */
#if ((defined(__i386) || defined(__amd64)) && !defined(_ELF64))
			pltentries = pltrelsz / sizeof (Rel);
			dprintf("DI_PLTREL not found, defaulting to Rel");
#else /* (!(__i386 || __amd64)) || _ELF64 */
			pltentries = pltrelsz / sizeof (Rela);
			dprintf("DI_PLTREL not found, defaulting to Rela");
#endif /* (!(__i386 || __amd64) || _ELF64 */
		}

		if (pltentries < PLTREL_MIN_ENTRIES) {
			dprintf("too few PLT relocation entries "
			    "(found %lu, expected at least %d)\n",
			    (long)pltentries, PLTREL_MIN_ENTRIES);
			goto bad;
		}
		if (pltentries < PLTREL_MIN_ENTRIES + 2)
			goto done_with_plt;

		/*
		 * Now that we know the number of plt relocation entries
		 * we can calculate the size of the plt.
		 */
		pltsz = (pltentries + M_PLT_XNumber) * M_PLT_ENTSIZE;
#if defined(__sparc)
		/* The sparc PLT always has a (delay slot) nop at the end */
		pltsz += 4;
#endif /* __sparc */

		size += sizeof (Shdr);
		size += roundup(pltsz, SH_ADDRALIGN);
	}
done_with_plt:

	if ((elfdata = calloc(1, size)) == NULL) {
		dprintf("failed to allocate size %ld\n", (long)size);
		goto bad;
	}

	/* LINTED - alignment */
	ep = (Ehdr *)elfdata;
	(void) memcpy(ep, ehdr, offsetof(Ehdr, e_phoff));

	ep->e_ehsize = sizeof (Ehdr);
	ep->e_phoff = sizeof (Ehdr);
	ep->e_phentsize = ehdr->e_phentsize;
	ep->e_phnum = phnum;
	ep->e_shoff = ep->e_phoff + phnum * ep->e_phentsize;
	ep->e_shentsize = sizeof (Shdr);
	/*
	 * Plt and SUNW_ldynsym sections are optional. C logical
	 * binary operators return a 0 or 1 value, so the following
	 * adds 1 for each optional section present.
	 */
	ep->e_shnum = 5 + (pltsz != 0) + (d[DI_SUNW_SYMTAB] != NULL);
	ep->e_shstrndx = 1;

	/* LINTED - alignment */
	sp = (Shdr *)(elfdata + ep->e_shoff);
	off = ep->e_shoff + ep->e_shentsize * ep->e_shnum;

	/*
	 * Copying the program headers directly from the process's
	 * address space is a little suspect, but since we only
	 * use them for their address and size values, this is fine.
	 */
	if (Pread(P, &elfdata[ep->e_phoff], phnum * ep->e_phentsize,
	    addr + ehdr->e_phoff) != phnum * ep->e_phentsize) {
		dprintf("failed to read program headers\n");
		goto bad;
	}

	/*
	 * The first elf section is always skipped.
	 */
	sp++;

	/*
	 * Section Header: .shstrtab
	 */
	sp->sh_name = SHSTR_NDX_shstrtab;
	sp->sh_type = SHT_STRTAB;
	sp->sh_flags = SHF_STRINGS;
	sp->sh_addr = 0;
	sp->sh_offset = off;
	sp->sh_size = sizeof (shstr);
	sp->sh_link = 0;
	sp->sh_info = 0;
	sp->sh_addralign = 1;
	sp->sh_entsize = 0;

	(void) memcpy(&elfdata[off], shstr, sizeof (shstr));
	off += roundup(sp->sh_size, SH_ADDRALIGN);
	sp++;

	/*
	 * Section Header: .SUNW_ldynsym
	 */
	if (d[DI_SUNW_SYMTAB] != NULL) {
		sp->sh_name = SHSTR_NDX_SUNW_ldynsym;
		sp->sh_type = SHT_SUNW_LDYNSYM;
		sp->sh_flags = SHF_ALLOC;
		sp->sh_addr = d[DI_SUNW_SYMTAB]->d_un.d_ptr;
		if (ehdr->e_type == ET_DYN)
			sp->sh_addr += addr;
		sp->sh_offset = off;
		sp->sh_size = ldynsym_size;
		sp->sh_link = dynstr_shndx;
		/* Index of 1st global in table that has none == # items */
		sp->sh_info = sp->sh_size / sizeof (Sym);
		sp->sh_addralign = SH_ADDRALIGN;
		sp->sh_entsize = sizeof (Sym);

		if (Pread(P, &elfdata[off], sp->sh_size,
		    sp->sh_addr) != sp->sh_size) {
			dprintf("failed to read .SUNW_ldynsym at %lx\n",
			    (long)sp->sh_addr);
			goto bad;
		}
		off += sp->sh_size;
		/* No need to round up ldynsym data. Dynsym data is same type */
		sp++;
	}

	/*
	 * Section Header: .dynsym
	 */
	sp->sh_name = SHSTR_NDX_dynsym;
	sp->sh_type = SHT_DYNSYM;
	sp->sh_flags = SHF_ALLOC;
	sp->sh_addr = d[DI_SYMTAB]->d_un.d_ptr;
	if (ehdr->e_type == ET_DYN)
		sp->sh_addr += addr;
	sp->sh_offset = off;
	sp->sh_size = dynsym_size;
	sp->sh_link = dynstr_shndx;
	sp->sh_info = 1;	/* Index of 1st global in table */
	sp->sh_addralign = SH_ADDRALIGN;
	sp->sh_entsize = sizeof (Sym);

	if (Pread(P, &elfdata[off], sp->sh_size,
	    sp->sh_addr) != sp->sh_size) {
		dprintf("failed to read .dynsym at %lx\n",
		    (long)sp->sh_addr);
		goto bad;
	}

	off += roundup(sp->sh_size, SH_ADDRALIGN);
	sp++;

	/*
	 * Section Header: .dynstr
	 */
	sp->sh_name = SHSTR_NDX_dynstr;
	sp->sh_type = SHT_STRTAB;
	sp->sh_flags = SHF_ALLOC | SHF_STRINGS;
	sp->sh_addr = d[DI_STRTAB]->d_un.d_ptr;
	if (ehdr->e_type == ET_DYN)
		sp->sh_addr += addr;
	sp->sh_offset = off;
	sp->sh_size = d[DI_STRSZ]->d_un.d_val;
	sp->sh_link = 0;
	sp->sh_info = 0;
	sp->sh_addralign = 1;
	sp->sh_entsize = 0;

	if (Pread(P, &elfdata[off], sp->sh_size,
	    sp->sh_addr) != sp->sh_size) {
		dprintf("failed to read .dynstr\n");
		goto bad;
	}
	off += roundup(sp->sh_size, SH_ADDRALIGN);
	sp++;

	/*
	 * Section Header: .dynamic
	 */
	sp->sh_name = SHSTR_NDX_dynamic;
	sp->sh_type = SHT_DYNAMIC;
	sp->sh_flags = SHF_WRITE | SHF_ALLOC;
	sp->sh_addr = phdr->p_vaddr;
	if (ehdr->e_type == ET_DYN)
		sp->sh_addr -= addr;
	sp->sh_offset = off;
	sp->sh_size = phdr->p_filesz;
	sp->sh_link = dynstr_shndx;
	sp->sh_info = 0;
	sp->sh_addralign = SH_ADDRALIGN;
	sp->sh_entsize = sizeof (Dyn);

	(void) memcpy(&elfdata[off], dp, sp->sh_size);
	off += roundup(sp->sh_size, SH_ADDRALIGN);
	sp++;

	/*
	 * Section Header: .plt
	 */
	if (pltsz != 0) {
		ulong_t		plt_symhash;
		uint_t		htmp, ndx;
		uintptr_t	strtabptr, strtabname;
		Sym		sym, *symtabptr;
		uint_t		*hash;
		char		strbuf[sizeof ("_PROCEDURE_LINKAGE_TABLE_")];

		/*
		 * Now we need to find the address of the plt by looking
		 * up the "_PROCEDURE_LINKAGE_TABLE_" symbol.
		 */

		/* get the address of the symtab and strtab sections */
		strtabptr = d[DI_STRTAB]->d_un.d_ptr;
		symtabptr = (Sym *)(uintptr_t)d[DI_SYMTAB]->d_un.d_ptr;
		if (ehdr->e_type == ET_DYN) {
			strtabptr += addr;
			symtabptr = (Sym*)((uintptr_t)symtabptr + addr);
		}

		if ((hptr == NULL) || (hnbuckets == 0) || (hnchains == 0)) {
			dprintf("empty or missing .hash\n");
			goto badplt;
		}

		/* find the .hash bucket address for this symbol */
		plt_symhash = elf_hash("_PROCEDURE_LINKAGE_TABLE_");
		htmp = plt_symhash % hnbuckets;
		hash = &((uint_t *)hptr)[2 + htmp];

		/* read the elf hash bucket index */
		if (Pread(P, &ndx, sizeof (ndx), (uintptr_t)hash) !=
		    sizeof (ndx)) {
			dprintf("Pread of .hash at %lx failed\n", (long)hash);
			goto badplt;
		}

		while (ndx) {
			if (Pread(P, &sym, sizeof (sym),
			    (uintptr_t)&symtabptr[ndx]) != sizeof (sym)) {
				dprintf("Pread of .symtab at %lx failed\n",
				    (long)&symtabptr[ndx]);
				goto badplt;
			}

			strtabname = strtabptr + sym.st_name;
			if (Pread_string(P, strbuf, sizeof (strbuf),
			    strtabname) < 0) {
				dprintf("Pread of .strtab at %lx failed\n",
				    (long)strtabname);
				goto badplt;
			}

			if (strcmp("_PROCEDURE_LINKAGE_TABLE_", strbuf) == 0)
				break;

			hash = &((uint_t *)hptr)[2 + hnbuckets + ndx];
			if (Pread(P, &ndx, sizeof (ndx), (uintptr_t)hash) !=
			    sizeof (ndx)) {
				dprintf("Pread of .hash at %lx failed\n",
				    (long)hash);
				goto badplt;
			}
		}

#if defined(__sparc)
		if (sym.st_value != d[DI_PLTGOT]->d_un.d_ptr) {
			dprintf("warning: DI_PLTGOT (%lx) doesn't match "
			    ".plt symbol pointer (%lx)",
			    (long)d[DI_PLTGOT]->d_un.d_ptr,
			    (long)sym.st_value);
		}
#endif /* __sparc */

		if (ndx == 0) {
			dprintf(
			    "Failed to find \"_PROCEDURE_LINKAGE_TABLE_\"\n");
			goto badplt;
		}

		sp->sh_name = SHSTR_NDX_plt;
		sp->sh_type = SHT_PROGBITS;
		sp->sh_flags = SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR;
		sp->sh_addr = sym.st_value;
		if (ehdr->e_type == ET_DYN)
			sp->sh_addr += addr;
		sp->sh_offset = off;
		sp->sh_size = pltsz;
		sp->sh_link = 0;
		sp->sh_info = 0;
		sp->sh_addralign = SH_ADDRALIGN;
		sp->sh_entsize = M_PLT_ENTSIZE;

		if (Pread(P, &elfdata[off], sp->sh_size, sp->sh_addr) !=
		    sp->sh_size) {
			dprintf("failed to read .plt at %lx\n",
			    (long)sp->sh_addr);
			goto badplt;
		}
		off += roundup(sp->sh_size, SH_ADDRALIGN);
		sp++;
	}

badplt:
	/* make sure we didn't write past the end of allocated memory */
	sp++;
	assert(((uintptr_t)(sp) - 1) < ((uintptr_t)elfdata + size));

	free(dp);
	if ((elf = elf_memory(elfdata, size)) == NULL) {
		dprintf("failed to create ELF object "
		    "in memory for size %ld\n", (long)size);
		free(elfdata);
		return (NULL);
	}

	fptr->file_elfmem = elfdata;

	return (elf);

bad:
	if (dp != NULL)
		free(dp);
	if (elfdata != NULL)
		free(elfdata);
	return (NULL);
}
Beispiel #22
0
/*ARGSUSED*/
int
dt_pid_create_return_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp,
    fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, uint64_t *stret)
{
	uint8_t *text;
	ulong_t i, end;
	int size;
	pid_t pid = Pstatus(P)->pr_pid;
	char dmodel = Pstatus(P)->pr_dmodel;

	/*
	 * We allocate a few extra bytes at the end so we don't have to check
	 * for overrunning the buffer.
	 */
	if ((text = calloc(1, symp->st_size + 4)) == NULL) {
		dt_dprintf("mr sparkle: malloc() failed\n");
		return (DT_PROC_ERR);
	}

	if (Pread(P, text, symp->st_size, symp->st_value) != symp->st_size) {
		dt_dprintf("mr sparkle: Pread() failed\n");
		free(text);
		return (DT_PROC_ERR);
	}

	ftp->ftps_probe_type = DTFTP_RETURN;
	ftp->ftps_pc = symp->st_value;
	ftp->ftps_size = (size_t)symp->st_size;
	ftp->ftps_noffs = 0;

	/*
	 * If there's a jump table in the function we're only willing to
	 * instrument these specific (and equivalent) instruction sequences:
	 *	leave
	 *	[rep] ret
	 * and
	 *	movl	%ebp,%esp
	 *	popl	%ebp
	 *	[rep] ret
	 *
	 * We do this to avoid accidentally interpreting jump table
	 * offsets as actual instructions.
	 */
	if (dt_pid_has_jump_table(P, dtp, text, ftp, symp)) {
		for (i = 0, end = ftp->ftps_size; i < end; i += size) {
			size = dt_instr_size(&text[i], dtp, pid,
			    symp->st_value + i, dmodel);

			/* bail if we hit an invalid opcode */
			if (size <= 0)
				break;

			if (text[i] == DT_LEAVE && text[i + 1] == DT_RET) {
				dt_dprintf("leave/ret at %lx\n", i + 1);
				ftp->ftps_offs[ftp->ftps_noffs++] = i + 1;
				size = 2;
			} else if (text[i] == DT_LEAVE &&
			    text[i + 1] == DT_REP && text[i + 2] == DT_RET) {
				dt_dprintf("leave/rep ret at %lx\n", i + 1);
				ftp->ftps_offs[ftp->ftps_noffs++] = i + 1;
				size = 3;
			} else if (*(uint16_t *)&text[i] == DT_MOVL_EBP_ESP &&
			    text[i + 2] == DT_POPL_EBP &&
			    text[i + 3] == DT_RET) {
				dt_dprintf("movl/popl/ret at %lx\n", i + 3);
				ftp->ftps_offs[ftp->ftps_noffs++] = i + 3;
				size = 4;
			} else if (*(uint16_t *)&text[i] == DT_MOVL_EBP_ESP &&
			    text[i + 2] == DT_POPL_EBP &&
			    text[i + 3] == DT_REP &&
			    text[i + 4] == DT_RET) {
				dt_dprintf("movl/popl/rep ret at %lx\n", i + 3);
				ftp->ftps_offs[ftp->ftps_noffs++] = i + 3;
				size = 5;
			}
		}
	} else {
		for (i = 0, end = ftp->ftps_size; i < end; i += size) {
			size = dt_instr_size(&text[i], dtp, pid,
			    symp->st_value + i, dmodel);

			/* bail if we hit an invalid opcode */
			if (size <= 0)
				break;

			/* ordinary ret */
			if (size == 1 && text[i] == DT_RET)
				goto is_ret;

			/* two-byte ret */
			if (size == 2 && text[i] == DT_REP &&
			    text[i + 1] == DT_RET)
				goto is_ret;

			/* ret <imm16> */
			if (size == 3 && text[i] == DT_RET16)
				goto is_ret;

			/* two-byte ret <imm16> */
			if (size == 4 && text[i] == DT_REP &&
			    text[i + 1] == DT_RET16)
				goto is_ret;

			/* 32-bit displacement jmp outside of the function */
			if (size == 5 && text[i] == DT_JMP32 && symp->st_size <=
			    (uintptr_t)(i + size + *(int32_t *)&text[i + 1]))
				goto is_ret;

			/* 8-bit displacement jmp outside of the function */
			if (size == 2 && text[i] == DT_JMP8 && symp->st_size <=
			    (uintptr_t)(i + size + *(int8_t *)&text[i + 1]))
				goto is_ret;

			/* 32-bit disp. conditional jmp outside of the func. */
			if (size == 6 && DT_ISJ32(*(uint16_t *)&text[i]) &&
			    symp->st_size <=
			    (uintptr_t)(i + size + *(int32_t *)&text[i + 2]))
				goto is_ret;

			/* 8-bit disp. conditional jmp outside of the func. */
			if (size == 2 && DT_ISJ8(text[i]) && symp->st_size <=
			    (uintptr_t)(i + size + *(int8_t *)&text[i + 1]))
				goto is_ret;

			continue;
is_ret:
			dt_dprintf("return at offset %lx\n", i);
			ftp->ftps_offs[ftp->ftps_noffs++] = i;
		}
	}

	free(text);
	if (ftp->ftps_noffs > 0) {
		if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) {
			dt_dprintf("fasttrap probe creation ioctl failed: %s\n",
			    strerror(errno));
			return (dt_set_errno(dtp, errno));
		}
	}

	return (ftp->ftps_noffs);
}
Beispiel #23
0
/*ARGSUSED*/
int
dt_pid_create_offset_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp,
    fasttrap_probe_spec_t *ftp, const GElf_Sym *symp, ulong_t off)
{
	ftp->ftps_probe_type = DTFTP_OFFSETS;
	ftp->ftps_pc = symp->st_value;
	ftp->ftps_size = (size_t)symp->st_size;
	ftp->ftps_noffs = 1;

	if (strcmp("-", ftp->ftps_func) == 0) {
		ftp->ftps_offs[0] = off;
	} else {
		uint8_t *text;
		ulong_t i;
		int size;
		pid_t pid = Pstatus(P)->pr_pid;
		char dmodel = Pstatus(P)->pr_dmodel;

		if ((text = malloc(symp->st_size)) == NULL) {
			dt_dprintf("mr sparkle: malloc() failed\n");
			return (DT_PROC_ERR);
		}

		if (Pread(P, text, symp->st_size, symp->st_value) !=
		    symp->st_size) {
			dt_dprintf("mr sparkle: Pread() failed\n");
			free(text);
			return (DT_PROC_ERR);
		}

		/*
		 * We can't instrument offsets in functions with jump tables
		 * as we might interpret a jump table offset as an
		 * instruction.
		 */
		if (dt_pid_has_jump_table(P, dtp, text, ftp, symp)) {
			free(text);
			return (0);
		}

		for (i = 0; i < symp->st_size; i += size) {
			if (i == off) {
				ftp->ftps_offs[0] = i;
				break;
			}

			/*
			 * If we've passed the desired offset without a
			 * match, then the given offset must not lie on a
			 * instruction boundary.
			 */
			if (i > off) {
				free(text);
				return (DT_PROC_ALIGN);
			}

			size = dt_instr_size(&text[i], dtp, pid,
			    symp->st_value + i, dmodel);

			/*
			 * If we hit an invalid instruction, bail as if we
			 * couldn't find the offset.
			 */
			if (size <= 0) {
				free(text);
				return (DT_PROC_ALIGN);
			}
		}

		free(text);
	}

	if (ioctl(dtp->dt_ftfd, FASTTRAPIOC_MAKEPROBE, ftp) != 0) {
		dt_dprintf("fasttrap probe creation ioctl failed: %s\n",
		    strerror(errno));
		return (dt_set_errno(dtp, errno));
	}

	return (ftp->ftps_noffs);
}
Beispiel #24
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);
	}
}
Beispiel #25
0
static void
read_dumphdr(void)
{
	if (filemode)
		dumpfd = Open(dumpfile, O_RDONLY, 0644);
	else
		dumpfd = Open(dumpfile, O_RDWR | O_DSYNC, 0644);
	endoff = llseek(dumpfd, -DUMP_OFFSET, SEEK_END) & -DUMP_OFFSET;
	Pread(dumpfd, &dumphdr, sizeof (dumphdr), endoff);
	Pread(dumpfd, &datahdr, sizeof (datahdr), endoff + sizeof (dumphdr));

	pagesize = dumphdr.dump_pagesize;

	if (dumphdr.dump_magic != DUMP_MAGIC)
		logprint(SC_SL_NONE | SC_EXIT_PEND, "bad magic number %x",
		    dumphdr.dump_magic);

	if ((dumphdr.dump_flags & DF_VALID) == 0 && !disregard_valid_flag)
		logprint(SC_SL_NONE | SC_IF_VERBOSE | SC_EXIT_OK,
		    "dump already processed");

	if (dumphdr.dump_version != DUMP_VERSION)
		logprint(SC_SL_NONE | SC_IF_VERBOSE | SC_EXIT_PEND,
		    "dump version (%d) != %s version (%d)",
		    dumphdr.dump_version, progname, DUMP_VERSION);

	if (dumphdr.dump_wordsize != DUMP_WORDSIZE)
		logprint(SC_SL_NONE | SC_EXIT_PEND,
		    "dump is from %u-bit kernel - cannot save on %u-bit kernel",
		    dumphdr.dump_wordsize, DUMP_WORDSIZE);

	if (datahdr.dump_datahdr_magic == DUMP_DATAHDR_MAGIC) {
		if (datahdr.dump_datahdr_version != DUMP_DATAHDR_VERSION)
			logprint(SC_SL_NONE | SC_IF_VERBOSE | SC_EXIT_PEND,
			    "dump data version (%d) != %s data version (%d)",
			    datahdr.dump_datahdr_version, progname,
			    DUMP_DATAHDR_VERSION);
	} else {
		(void) memset(&datahdr, 0, sizeof (datahdr));
		datahdr.dump_maxcsize = pagesize;
	}

	/*
	 * Read the initial header, clear the valid bits, and compare headers.
	 * The main header may have been overwritten by swapping if we're
	 * using a swap partition as the dump device, in which case we bail.
	 */
	Pread(dumpfd, &corehdr, sizeof (dumphdr_t), dumphdr.dump_start);

	corehdr.dump_flags &= ~DF_VALID;
	dumphdr.dump_flags &= ~DF_VALID;

	if (memcmp(&corehdr, &dumphdr, sizeof (dumphdr_t)) != 0) {
		/*
		 * Clear valid bit so we don't complain on every invocation.
		 */
		if (!filemode)
			Pwrite(dumpfd, &dumphdr, sizeof (dumphdr), endoff);
		logprint(SC_SL_ERR | SC_EXIT_ERR,
		    "initial dump header corrupt");
	}
}
Beispiel #26
0
/*ARGSUSED*/
static int
dump_map(void *data, const prmap_t *pmp, const char *name)
{
	pgcore_t *pgc = data;
	struct ps_prochandle *P = pgc->P;
#ifdef _LP64
	Elf64_Phdr phdr;
#else
	Elf32_Phdr phdr;
#endif
	size_t n;

	bzero(&phdr, sizeof (phdr));
	phdr.p_type = PT_LOAD;
	phdr.p_vaddr = pmp->pr_vaddr;
	phdr.p_memsz = pmp->pr_size;
	if (pmp->pr_mflags & MA_READ)
		phdr.p_flags |= PF_R;
	if (pmp->pr_mflags & MA_WRITE)
		phdr.p_flags |= PF_W;
	if (pmp->pr_mflags & MA_EXEC)
		phdr.p_flags |= PF_X;

	if (pmp->pr_vaddr + pmp->pr_size > P->status.pr_stkbase &&
	    pmp->pr_vaddr < P->status.pr_stkbase + P->status.pr_stksize) {
		if (!(pgc->pgc_content & CC_CONTENT_STACK))
			goto exclude;

	} else if ((pmp->pr_mflags & MA_ANON) &&
	    pmp->pr_vaddr + pmp->pr_size > P->status.pr_brkbase &&
	    pmp->pr_vaddr < P->status.pr_brkbase + P->status.pr_brksize) {
		if (!(pgc->pgc_content & CC_CONTENT_HEAP))
			goto exclude;

	} else if (pmp->pr_mflags & MA_ISM) {
		if (pmp->pr_mflags & MA_NORESERVE) {
			if (!(pgc->pgc_content & CC_CONTENT_DISM))
				goto exclude;
		} else {
			if (!(pgc->pgc_content & CC_CONTENT_ISM))
				goto exclude;
		}

	} else if (pmp->pr_mflags & MA_SHM) {
		if (!(pgc->pgc_content & CC_CONTENT_SHM))
			goto exclude;

	} else if (pmp->pr_mflags & MA_SHARED) {
		if (pmp->pr_mflags & MA_ANON) {
			if (!(pgc->pgc_content & CC_CONTENT_SHANON))
				goto exclude;
		} else {
			if (!(pgc->pgc_content & CC_CONTENT_SHFILE))
				goto exclude;
		}

	} else if (pmp->pr_mflags & MA_ANON) {
		if (!(pgc->pgc_content & CC_CONTENT_ANON))
			goto exclude;

	} else if (phdr.p_flags == (PF_R | PF_X)) {
		if (!(pgc->pgc_content & CC_CONTENT_TEXT))
			goto exclude;

	} else if (phdr.p_flags == PF_R) {
		if (!(pgc->pgc_content & CC_CONTENT_RODATA))
			goto exclude;

	} else {
		if (!(pgc->pgc_content & CC_CONTENT_DATA))
			goto exclude;
	}

	n = 0;
	while (n < pmp->pr_size) {
		size_t csz = MIN(pmp->pr_size - n, pgc->pgc_chunksz);

		/*
		 * If we can't read out part of the victim's address
		 * space for some reason ignore that failure and try to
		 * emit a partial core file without that mapping's data.
		 * As in the kernel, we mark these failures with the
		 * PF_SUNW_FAILURE flag and store the errno where the
		 * mapping would have been.
		 */
		if (Pread(P, pgc->pgc_chunk, csz, pmp->pr_vaddr + n) != csz ||
		    gc_pwrite64(pgc->pgc_fd, pgc->pgc_chunk, csz,
		    *pgc->pgc_doff + n) != 0) {
			int err = errno;
			(void) gc_pwrite64(pgc->pgc_fd, &err, sizeof (err),
			    *pgc->pgc_doff);
			*pgc->pgc_doff += roundup(sizeof (err), 8);

			phdr.p_flags |= PF_SUNW_FAILURE;
			(void) ftruncate64(pgc->pgc_fd, *pgc->pgc_doff);
			goto exclude;
		}

		n += csz;
	}

	phdr.p_offset = *pgc->pgc_doff;
	phdr.p_filesz = pmp->pr_size;
	*pgc->pgc_doff += roundup(phdr.p_filesz, 8);

exclude:
	if (P->status.pr_dmodel == PR_MODEL_NATIVE) {
		if (gc_pwrite64(pgc->pgc_fd, &phdr, sizeof (phdr),
		    *pgc->pgc_poff) != 0)
			return (1);

		*pgc->pgc_poff += sizeof (phdr);
#ifdef _LP64
	} else {
		Elf32_Phdr phdr32;

		bzero(&phdr32, sizeof (phdr32));
		phdr32.p_type = phdr.p_type;
		phdr32.p_vaddr = (Elf32_Addr)phdr.p_vaddr;
		phdr32.p_memsz = (Elf32_Word)phdr.p_memsz;
		phdr32.p_flags = phdr.p_flags;
		phdr32.p_offset = (Elf32_Off)phdr.p_offset;
		phdr32.p_filesz = (Elf32_Word)phdr.p_filesz;

		if (gc_pwrite64(pgc->pgc_fd, &phdr32, sizeof (phdr32),
		    *pgc->pgc_poff) != 0)
			return (1);

		*pgc->pgc_poff += sizeof (phdr32);
#endif	/* _LP64 */
	}

	return (0);
}
Beispiel #27
0
int
Pstack_iter(struct ps_prochandle *P, const prgregset_t regs,
	proc_stack_f *func, void *arg)
{
	struct {
		uintptr_t fp;
		uintptr_t pc;
	} frame;

	uint_t pfpsize = 0;
	prgreg_t *prevfp = NULL;
	prgreg_t fp, pfp;
	prgreg_t pc;

	prgregset_t gregs;
	int nfp = 0;

	uclist_t ucl;
	int rv = 0;
	int argc;

	uintptr_t uc_addr;
	ucontext_t uc;

	/*
	 * Type definition for a structure corresponding to an IA32
	 * signal frame.  Refer to the comments in Pstack.c for more info
	 */
	typedef struct {
		prgreg_t fp;
		prgreg_t pc;
		prgreg_t signo;
		siginfo_t *sip;
	} sigframe_t;
	prgreg_t args[32] = {0};

	if (P->status.pr_dmodel != PR_MODEL_LP64)
		return (Pstack_iter32(P, regs, func, arg));

	init_uclist(&ucl, P);
	(void) memcpy(gregs, regs, sizeof (gregs));

	fp = gregs[R_FP];
	pc = gregs[R_PC];

	while (fp != 0 || pc != 0) {

		if (stack_loop(fp, &prevfp, &nfp, &pfpsize))
			break;

		if (fp != 0 &&
		    Pread(P, &frame, sizeof (frame), (uintptr_t)fp) ==
		    sizeof (frame)) {
			if (frame.pc == -1) {
				argc = 3;
				args[2] = fp + sizeof (sigframe_t);
				if (Pread(P, &args, 2 * sizeof (prgreg_t),
				    fp + 2 * sizeof (prgreg_t)) !=
				    2 * sizeof (prgreg_t))
					argc = 0;
			} else {
				argc = read_args(P, fp, pc, args,
				    sizeof (args));
			}
		} else {
			(void) memset(&frame, 0, sizeof (frame));
			argc = 0;
		}

		gregs[R_FP] = fp;
		gregs[R_PC] = pc;

		if ((rv = func(arg, gregs, argc, args)) != 0)
			break;

		pfp = fp;
		fp = frame.fp;
		pc = frame.pc;

		if (pc == -1 && find_uclink(&ucl, pfp + sizeof (sigframe_t))) {
			uc_addr = pfp + sizeof (sigframe_t);

			if (Pread(P, &uc, sizeof (uc), uc_addr)
			    == sizeof (uc)) {
				ucontext_n_to_prgregs(&uc, gregs);
				fp = gregs[R_FP];
				pc = gregs[R_PC];
			}
		}
	}

	if (prevfp)
		free(prevfp);

	free_uclist(&ucl);

	return (rv);
}
Beispiel #28
0
int
Psyscall_copyoutargs(struct ps_prochandle *P, int nargs, argdes_t *argp,
    uintptr_t ap)
{
	if (P->status.pr_dmodel == PR_MODEL_ILP32) {
		uint32_t arglist[MAXARGS + 2];
		int i;
		argdes_t *adp;

		if (Pread(P, &arglist[0], sizeof (int) * (nargs+1),
		    (uintptr_t)ap) != sizeof (int) * (nargs+1))
			return (-1);

		for (i = 0, adp = argp; i < nargs; i++, adp++)
			adp->arg_value = arglist[i];
	} else {
		int pusharg = (nargs > 6) ? nargs - 6: 0;
		int64_t arglist[MAXARGS+2];
		int i;
		argdes_t *adp;

		if (pusharg  > 0 &&
		    Pread(P, &arglist[0], sizeof (int64_t) * (pusharg + 1),
		    ap) != sizeof (int64_t) * (pusharg + 1))
			return (-1);

		for (i = 0, adp = argp; i < nargs; i++, adp++) {
			switch (i) {
			case 0:
				adp->arg_value =
				    P->status.pr_lwp.pr_reg[REG_RDI];
				break;
			case 1:
				adp->arg_value =
				    P->status.pr_lwp.pr_reg[REG_RSI];
				break;
			case 2:
				adp->arg_value =
				    P->status.pr_lwp.pr_reg[REG_RDX];
				break;
			case 3:
				adp->arg_value =
				    P->status.pr_lwp.pr_reg[REG_RCX];
				break;
			case 4:
				adp->arg_value =
				    P->status.pr_lwp.pr_reg[REG_R8];
				break;
			case 5:
				adp->arg_value =
				    P->status.pr_lwp.pr_reg[REG_R9];
				break;
			default:
				adp->arg_value = arglist[i - 6];
				break;
			}
		}

		return (0);
	}

	return (0);
}