Ejemplo n.º 1
0
/*
 * Look up the symbol at addr, returning a copy of the symbol and its name.
 */
static int
lookup_addr(Elf *e, Elf_Scn *scn, u_long stridx, uintptr_t off, uintptr_t addr,
    const char **name, GElf_Sym *symcopy)
{
	GElf_Sym sym;
	Elf_Data *data;
	const char *s;
	uint64_t rsym;
	int i;

	if ((data = elf_getdata(scn, NULL)) == NULL) {
		DPRINTFX("ERROR: elf_getdata() failed: %s", elf_errmsg(-1));
		return (1);
	}
	for (i = 0; gelf_getsym(data, i, &sym) != NULL; i++) {
		rsym = off + sym.st_value;
		if (addr >= rsym && addr < rsym + sym.st_size) {
			s = elf_strptr(e, stridx, sym.st_name);
			if (s != NULL) {
				*name = s;
				memcpy(symcopy, &sym, sizeof(*symcopy));
				/*
				 * DTrace expects the st_value to contain
				 * only the address relative to the start of
				 * the function.
				 */
				symcopy->st_value = rsym;
				return (0);
			}
		}
	}
	return (1);
}
Ejemplo n.º 2
0
int
proc_bkptset(struct proc_handle *phdl, uintptr_t address,
             unsigned long *saved)
{
    struct ptrace_io_desc piod;
    unsigned long paddr, caddr;
    int ret = 0;

    *saved = 0;
    if (phdl->status == PS_DEAD || phdl->status == PS_UNDEAD ||
            phdl->status == PS_IDLE) {
        errno = ENOENT;
        return (-1);
    }

    DPRINTFX("adding breakpoint at 0x%lx", address);

    if (phdl->status != PS_STOP)
        if (proc_stop(phdl) != 0)
            return (-1);

    /*
     * Read the original instruction.
     */
    caddr = address;
    paddr = 0;
    piod.piod_op = PIOD_READ_I;
    piod.piod_offs = (void *)caddr;
    piod.piod_addr = &paddr;
    piod.piod_len  = BREAKPOINT_INSTR_SZ;
    if (ptrace(PT_IO, proc_getpid(phdl), (caddr_t)&piod, 0) < 0) {
        DPRINTF("ERROR: couldn't read instruction at address 0x%"
                PRIuPTR, address);
        ret = -1;
        goto done;
    }
    *saved = paddr;
    /*
     * Write a breakpoint instruction to that address.
     */
    caddr = address;
    paddr = BREAKPOINT_INSTR;
    piod.piod_op = PIOD_WRITE_I;
    piod.piod_offs = (void *)caddr;
    piod.piod_addr = &paddr;
    piod.piod_len  = BREAKPOINT_INSTR_SZ;
    if (ptrace(PT_IO, proc_getpid(phdl), (caddr_t)&piod, 0) < 0) {
        DPRINTF("ERROR: couldn't write instruction at address 0x%"
                PRIuPTR, address);
        ret = -1;
        goto done;
    }

done:
    if (phdl->status != PS_STOP)
        /* Restart the process if we had to stop it. */
        proc_cont(phdl);

    return (ret);
}
Ejemplo n.º 3
0
int
proc_bkptdel(struct proc_handle *phdl, uintptr_t address,
    unsigned long saved)
{
	struct ptrace_io_desc piod;
	unsigned long paddr, caddr;

	if (phdl->status == PS_DEAD || phdl->status == PS_UNDEAD ||
	    phdl->status == PS_IDLE) {
		errno = ENOENT;
		return (-1);
	}
	DPRINTFX("removing breakpoint at 0x%lx\n", address);
	/*
	 * Overwrite the breakpoint instruction that we setup previously.
	 */
	caddr = address;
	paddr = saved;
	piod.piod_op = PIOD_WRITE_I;
	piod.piod_offs = (void *)caddr;
	piod.piod_addr = &paddr;
	piod.piod_len  = BREAKPOINT_INSTR_SZ;
	if (ptrace(PT_IO, proc_getpid(phdl), (caddr_t)&piod, 0) < 0) {
		DPRINTF("ERROR: couldn't write instruction at address 0x%"
		    PRIuPTR, address);
		return (-1);
	}
 
	return (0);
}
Ejemplo n.º 4
0
int
proc_regset(struct proc_handle *phdl, proc_reg_t reg, unsigned long regvalue)
{
	struct reg regs;

	if (phdl->status == PS_DEAD || phdl->status == PS_UNDEAD ||
	    phdl->status == PS_IDLE) {
		errno = ENOENT;
		return (-1);
	}
	if (ptrace(PT_GETREGS, proc_getpid(phdl), (caddr_t)&regs, 0) < 0)
		return (-1);
	switch (reg) {
	case REG_PC:
#if defined(__aarch64__)
		regs.elr = regvalue;
#elif defined(__amd64__)
		regs.r_rip = regvalue;
#elif defined(__arm__)
		regs.r_pc = regvalue;
#elif defined(__i386__)
		regs.r_eip = regvalue;
#elif defined(__mips__)
		regs.r_regs[PC] = regvalue;
#elif defined(__powerpc__)
		regs.pc = regvalue;
#elif defined(__riscv__)
		regs.sepc = regvalue;
#endif
		break;
	case REG_SP:
#if defined(__aarch64__)
		regs.sp = regvalue;
#elif defined(__amd64__)
		regs.r_rsp = regvalue;
#elif defined(__arm__)
		regs.r_sp = regvalue;
#elif defined(__i386__)
		regs.r_esp = regvalue;
#elif defined(__mips__)
		regs.r_regs[PC] = regvalue;
#elif defined(__powerpc__)
		regs.fixreg[1] = regvalue;
#elif defined(__riscv__)
		regs.sp = regvalue;
#endif
		break;
	default:
		DPRINTFX("ERROR: no support for reg number %d", reg);
		return (-1);
	}
	if (ptrace(PT_SETREGS, proc_getpid(phdl), (caddr_t)&regs, 0) < 0)
		return (-1);

	return (0);
}
Ejemplo n.º 5
0
/*
 * Step over the breakpoint.
 */
int
proc_bkptexec(struct proc_handle *phdl, unsigned long saved)
{
	unsigned long pc;
	unsigned long samesaved;
	int status;

	if (proc_regget(phdl, REG_PC, &pc) < 0) {
		DPRINTFX("ERROR: couldn't get PC register");
		return (-1);
	}
	proc_bkptregadj(&pc);
	if (proc_bkptdel(phdl, pc, saved) < 0) {
		DPRINTFX("ERROR: couldn't delete breakpoint");
		return (-1);
	}
	/*
	 * Go back in time and step over the new instruction just
	 * set up by proc_bkptdel().
	 */
	proc_regset(phdl, REG_PC, pc);
	if (ptrace(PT_STEP, proc_getpid(phdl), (caddr_t)1, 0) < 0) {
		DPRINTFX("ERROR: ptrace step failed");
		return (-1);
	}
	proc_wstatus(phdl);
	status = proc_getwstat(phdl);
	if (!WIFSTOPPED(status)) {
		DPRINTFX("ERROR: don't know why process stopped");
		return (-1);
	}
	/*
	 * Restore the breakpoint. The saved instruction should be
	 * the same as the one that we were passed in.
	 */
	if (proc_bkptset(phdl, pc, &samesaved) < 0) {
		DPRINTFX("ERROR: couldn't restore breakpoint");
		return (-1);
	}
	assert(samesaved == saved);

	return (0);
}
Ejemplo n.º 6
0
int
proc_attach(pid_t pid, int flags, struct proc_handle **pphdl)
{
	struct proc_handle *phdl;
	int error = 0;
	int status;

	if (pid == 0 || pid == getpid())
		return (EINVAL);

	/*
	 * Allocate memory for the process handle, a structure containing
	 * all things related to the process.
	 */
	if ((phdl = malloc(sizeof(struct proc_handle))) == NULL)
		return (ENOMEM);

	memset(phdl, 0, sizeof(struct proc_handle));
	phdl->pid = pid;
	phdl->flags = flags;
	phdl->status = PS_RUN;
	elf_version(EV_CURRENT);

	if (ptrace(PT_ATTACH, phdl->pid, 0, 0) != 0) {
		error = errno;
		DPRINTF("ERROR: cannot ptrace child process %d", pid);
		goto out;
	}

	/* Wait for the child process to stop. */
	if (waitpid(pid, &status, WUNTRACED) == -1) {
		error = errno;
		DPRINTF("ERROR: child process %d didn't stop as expected", pid);
		goto out;
	}

	/* Check for an unexpected status. */
	if (WIFSTOPPED(status) == 0)
		DPRINTFX("ERROR: child process %d status 0x%x", pid, status);
	else
		phdl->status = PS_STOP;

out:
	if (error)
		proc_free(phdl);
	else
		*pphdl = phdl;
	return (error);
}
Ejemplo n.º 7
0
int
proc_bkptdel(struct proc_handle *phdl, uintptr_t address,
    unsigned long saved)
{
	struct ptrace_io_desc piod;
	uintptr_t caddr;
	int ret = 0, stopped;
	instr_t instr;

	if (phdl->status == PS_DEAD || phdl->status == PS_UNDEAD ||
	    phdl->status == PS_IDLE) {
		errno = ENOENT;
		return (-1);
	}

	DPRINTFX("removing breakpoint at 0x%lx", address);

	stopped = 0;
	if (phdl->status != PS_STOP) {
		if (proc_stop(phdl) != 0)
			return (-1);
		stopped = 1;
	}

	/*
	 * Overwrite the breakpoint instruction that we setup previously.
	 */
	caddr = address;
	instr = saved;
	piod.piod_op = PIOD_WRITE_I;
	piod.piod_offs = (void *)caddr;
	piod.piod_addr = &instr;
	piod.piod_len  = BREAKPOINT_INSTR_SZ;
	if (ptrace(PT_IO, proc_getpid(phdl), (caddr_t)&piod, 0) < 0) {
		DPRINTF("ERROR: couldn't write instruction at address 0x%"
		    PRIuPTR, address);
		ret = -1;
	}

	if (stopped)
		/* Restart the process if we had to stop it. */
		proc_continue(phdl);
 
	return (ret);
}
Ejemplo n.º 8
0
static int
proc_stop(struct proc_handle *phdl)
{
	int status;

	if (kill(proc_getpid(phdl), SIGSTOP) == -1) {
		DPRINTF("kill %d", proc_getpid(phdl));
		return (-1);
	} else if (waitpid(proc_getpid(phdl), &status, WSTOPPED) == -1) {
		DPRINTF("waitpid %d", proc_getpid(phdl));
		return (-1);
	} else if (!WIFSTOPPED(status)) {
		DPRINTFX("waitpid: unexpected status 0x%x", status);
		return (-1);
	}

	return (0);
}
Ejemplo n.º 9
0
int
proc_regget(struct proc_handle *phdl, proc_reg_t reg, unsigned long *regvalue)
{
	struct reg regs;

	if (phdl->status == PS_DEAD || phdl->status == PS_UNDEAD ||
	    phdl->status == PS_IDLE) {
		errno = ENOENT;
		return (-1);
	}
	memset(&regs, 0, sizeof(regs));
	if (ptrace(PT_GETREGS, proc_getpid(phdl), (caddr_t)&regs, 0) < 0)
		return (-1);
	switch (reg) {
	case REG_PC:
#if defined(__amd64__)
		*regvalue = regs.r_rip;
#elif defined(__i386__)
		*regvalue = regs.r_eip;
#elif defined(__mips__)
		*regvalue = regs.r_regs[PC];
#elif defined(__powerpc__)
		*regvalue = regs.pc;
#endif
		break;
	case REG_SP:
#if defined(__amd64__)
		*regvalue = regs.r_rsp;
#elif defined(__i386__)
		*regvalue = regs.r_esp;
#elif defined(__mips__)
		*regvalue = regs.r_regs[SP];
#elif defined(__powerpc__)
		*regvalue = regs.fixreg[1];
#endif
		break;
	default:
		DPRINTFX("ERROR: no support for reg number %d", reg);
		return (-1);
	}

	return (0);
}
Ejemplo n.º 10
0
/*
 * Look up the symbol with the given name and return a copy of it.
 */
static int
lookup_name(Elf *e, Elf_Scn *scn, u_long stridx, const char *symbol,
    GElf_Sym *symcopy, prsyminfo_t *si)
{
	GElf_Sym sym;
	Elf_Data *data;
	char *s;
	int i;

	if ((data = elf_getdata(scn, NULL)) == NULL) {
		DPRINTFX("ERROR: elf_getdata() failed: %s", elf_errmsg(-1));
		return (1);
	}
	for (i = 0; gelf_getsym(data, i, &sym) != NULL; i++) {
		s = elf_strptr(e, stridx, sym.st_name);
		if (s != NULL && strcmp(s, symbol) == 0) {
			memcpy(symcopy, &sym, sizeof(*symcopy));
			if (si != NULL)
				si->prs_id = i;
			return (0);
		}
	}
	return (1);
}
Ejemplo n.º 11
0
int
proc_iter_symbyaddr(struct proc_handle *p, const char *object, int which,
    int mask, proc_sym_f *func, void *cd)
{
	Elf *e;
	int i, fd;
	prmap_t *map;
	Elf_Scn *scn, *foundscn = NULL;
	Elf_Data *data;
	GElf_Ehdr ehdr;
	GElf_Shdr shdr;
	GElf_Sym sym;
	unsigned long stridx = -1;
	char *s;
	int error = -1;

	if ((map = proc_name2map(p, object)) == NULL)
		return (-1);
	if ((fd = find_dbg_obj(map->pr_mapname)) < 0) {
		DPRINTF("ERROR: open %s failed", map->pr_mapname);
		goto err0;
	}
	if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
		DPRINTFX("ERROR: elf_begin() failed: %s", elf_errmsg(-1));
		goto err1;
	}
	if (gelf_getehdr(e, &ehdr) == NULL) {
		DPRINTFX("ERROR: gelf_getehdr() failed: %s", elf_errmsg(-1));
		goto err2;
	}
	/*
	 * Find the section we are looking for.
	 */
	scn = NULL;
	while ((scn = elf_nextscn(e, scn)) != NULL) {
		gelf_getshdr(scn, &shdr);
		if (which == PR_SYMTAB &&
		    shdr.sh_type == SHT_SYMTAB) {
			foundscn = scn;
			break;
		} else if (which == PR_DYNSYM &&
		    shdr.sh_type == SHT_DYNSYM) {
			foundscn = scn;
			break;
		}
	}
	if (!foundscn)
		return (-1);
	stridx = shdr.sh_link;
	if ((data = elf_getdata(foundscn, NULL)) == NULL) {
		DPRINTFX("ERROR: elf_getdata() failed: %s", elf_errmsg(-1));
		goto err2;
	}
	for (i = 0; gelf_getsym(data, i, &sym) != NULL; i++) {
		if (GELF_ST_BIND(sym.st_info) == STB_LOCAL &&
		    (mask & BIND_LOCAL) == 0)
			continue;
		if (GELF_ST_BIND(sym.st_info) == STB_GLOBAL &&
		    (mask & BIND_GLOBAL) == 0)
			continue;
		if (GELF_ST_BIND(sym.st_info) == STB_WEAK &&
		    (mask & BIND_WEAK) == 0)
			continue;
		if (GELF_ST_TYPE(sym.st_info) == STT_NOTYPE &&
		    (mask & TYPE_NOTYPE) == 0)
			continue;
		if (GELF_ST_TYPE(sym.st_info) == STT_OBJECT &&
		    (mask & TYPE_OBJECT) == 0)
			continue;
		if (GELF_ST_TYPE(sym.st_info) == STT_FUNC &&
		    (mask & TYPE_FUNC) == 0)
			continue;
		if (GELF_ST_TYPE(sym.st_info) == STT_SECTION &&
		    (mask & TYPE_SECTION) == 0)
			continue;
		if (GELF_ST_TYPE(sym.st_info) == STT_FILE &&
		    (mask & TYPE_FILE) == 0)
			continue;
		s = elf_strptr(e, stridx, sym.st_name);
		if (ehdr.e_type != ET_EXEC)
			sym.st_value += map->pr_vaddr;
		if ((error = (*func)(cd, &sym, s)) != 0)
			goto err2;
	}
	error = 0;
err2:
	elf_end(e);
err1:
	close(fd);
err0:
	free(map);
	return (error);
}
Ejemplo n.º 12
0
int
proc_name2sym(struct proc_handle *p, const char *object, const char *symbol,
    GElf_Sym *symcopy, prsyminfo_t *si)
{
	Elf *e;
	Elf_Scn *scn, *dynsymscn = NULL, *symtabscn = NULL;
	GElf_Shdr shdr;
	GElf_Ehdr ehdr;
	prmap_t *map;
	uintptr_t off;
	u_long symtabstridx = 0, dynsymstridx = 0;
	int fd, error = -1;

	if ((map = proc_name2map(p, object)) == NULL) {
		DPRINTFX("ERROR: couldn't find object %s", object);
		goto err0;
	}
	if ((fd = find_dbg_obj(map->pr_mapname)) < 0) {
		DPRINTF("ERROR: open %s failed", map->pr_mapname);
		goto err0;
	}
	if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
		DPRINTFX("ERROR: elf_begin() failed: %s", elf_errmsg(-1));
		goto err1;
	}
	if (gelf_getehdr(e, &ehdr) == NULL) {
		DPRINTFX("ERROR: gelf_getehdr() failed: %s", elf_errmsg(-1));
		goto err2;
	}
	/*
	 * Find the index of the STRTAB and SYMTAB sections to locate
	 * symbol names.
	 */
	scn = NULL;
	while ((scn = elf_nextscn(e, scn)) != NULL) {
		gelf_getshdr(scn, &shdr);
		switch (shdr.sh_type) {
		case SHT_SYMTAB:
			symtabscn = scn;
			symtabstridx = shdr.sh_link;
			break;
		case SHT_DYNSYM:
			dynsymscn = scn;
			dynsymstridx = shdr.sh_link;
			break;
		}
	}

	/*
	 * First look up the symbol in the dynsymtab, and fall back to the
	 * symtab if the lookup fails.
	 */
	error = lookup_name(e, dynsymscn, dynsymstridx, symbol, symcopy, si);
	if (error == 0)
		goto out;

	error = lookup_name(e, symtabscn, symtabstridx, symbol, symcopy, si);
	if (error == 0)
		goto out;

out:
	off = ehdr.e_type == ET_EXEC ? 0 : map->pr_vaddr;
	symcopy->st_value += off;

err2:
	elf_end(e);
err1:
	close(fd);
err0:
	free(map);

	return (error);
}
Ejemplo n.º 13
0
int
proc_addr2sym(struct proc_handle *p, uintptr_t addr, char *name,
    size_t namesz, GElf_Sym *symcopy)
{
	GElf_Ehdr ehdr;
	GElf_Shdr shdr;
	Elf *e;
	Elf_Scn *scn, *dynsymscn = NULL, *symtabscn = NULL;
	prmap_t *map;
	const char *s;
	uintptr_t off;
	u_long symtabstridx = 0, dynsymstridx = 0;
	int fd, error = -1;

	if ((map = proc_addr2map(p, addr)) == NULL)
		return (-1);
	if ((fd = find_dbg_obj(map->pr_mapname)) < 0) {
		DPRINTF("ERROR: open %s failed", map->pr_mapname);
		goto err0;
	}
	if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
		DPRINTFX("ERROR: elf_begin() failed: %s", elf_errmsg(-1));
		goto err1;
	}
	if (gelf_getehdr(e, &ehdr) == NULL) {
		DPRINTFX("ERROR: gelf_getehdr() failed: %s", elf_errmsg(-1));
		goto err2;
	}

	/*
	 * Find the index of the STRTAB and SYMTAB sections to locate
	 * symbol names.
	 */
	scn = NULL;
	while ((scn = elf_nextscn(e, scn)) != NULL) {
		gelf_getshdr(scn, &shdr);
		switch (shdr.sh_type) {
		case SHT_SYMTAB:
			symtabscn = scn;
			symtabstridx = shdr.sh_link;
			break;
		case SHT_DYNSYM:
			dynsymscn = scn;
			dynsymstridx = shdr.sh_link;
			break;
		}
	}

	off = ehdr.e_type == ET_EXEC ? 0 : map->pr_vaddr;

	/*
	 * First look up the symbol in the dynsymtab, and fall back to the
	 * symtab if the lookup fails.
	 */
	error = lookup_addr(e, dynsymscn, dynsymstridx, off, addr, &s, symcopy);
	if (error == 0)
		goto out;

	error = lookup_addr(e, symtabscn, symtabstridx, off, addr, &s, symcopy);
	if (error != 0)
		goto err2;

out:
	demangle(s, name, namesz);
err2:
	elf_end(e);
err1:
	close(fd);
err0:
	free(map);
	return (error);
}
Ejemplo n.º 14
0
int
proc_name2sym(struct proc_handle *p, const char *object, const char *symbol,
    GElf_Sym *symcopy)
{
	Elf *e;
	Elf_Scn *scn, *dynsymscn = NULL, *symtabscn = NULL;
	Elf_Data *data;
	GElf_Shdr shdr;
	GElf_Sym sym;
	GElf_Ehdr ehdr;
	int fd, error = -1;
	size_t i;
	prmap_t *map;
	char *s;
	unsigned long symtabstridx = 0, dynsymstridx = 0;

	if ((map = proc_name2map(p, object)) == NULL) {
		DPRINTFX("ERROR: couldn't find object %s", object);
		goto err0;
	}
	if ((fd = open(map->pr_mapname, O_RDONLY, 0)) < 0) {
		DPRINTF("ERROR: open %s failed", map->pr_mapname);
		goto err0;
	}
	if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
		DPRINTFX("ERROR: elf_begin() failed: %s", elf_errmsg(-1));
		goto err1;
	}
	if (gelf_getehdr(e, &ehdr) == NULL) {
		DPRINTFX("ERROR: gelf_getehdr() failed: %s", elf_errmsg(-1));
		goto err2;
	}
	/*
	 * Find the index of the STRTAB and SYMTAB sections to locate
	 * symbol names.
	 */
	scn = NULL;
	while ((scn = elf_nextscn(e, scn)) != NULL) {
		gelf_getshdr(scn, &shdr);
		switch (shdr.sh_type) {
		case SHT_SYMTAB:
			symtabscn = scn;
			symtabstridx = shdr.sh_link;
			break;
		case SHT_DYNSYM:
			dynsymscn = scn;
			dynsymstridx = shdr.sh_link;
			break;
		default:
			break;
		}
	}
	/*
	 * Iterate over the Dynamic Symbols table to find the symbol.
	 * Then look up the string name in STRTAB (.dynstr)
	 */
	if ((data = elf_getdata(dynsymscn, NULL))) {
		i = 0;
		while (gelf_getsym(data, i++, &sym) != NULL) {
			s = elf_strptr(e, dynsymstridx, sym.st_name);
			if (s && strcmp(s, symbol) == 0) {
				memcpy(symcopy, &sym, sizeof(sym));
				if (ehdr.e_type != ET_EXEC)
					symcopy->st_value += map->pr_vaddr;
				error = 0;
				goto out;
			}
		}
	}
	/*
	 * Iterate over the Symbols Table to find the symbol.
	 * Then look up the string name in STRTAB (.dynstr)
	 */
	if ((data = elf_getdata(symtabscn, NULL))) {
		i = 0;
		while (gelf_getsym(data, i++, &sym) != NULL) {
			s = elf_strptr(e, symtabstridx, sym.st_name);
			if (s && strcmp(s, symbol) == 0) {
				memcpy(symcopy, &sym, sizeof(sym));
				if (ehdr.e_type != ET_EXEC)
					symcopy->st_value += map->pr_vaddr;
				error = 0;
				goto out;
			}
		}
	}
out:
	DPRINTFX("found addr 0x%lx for %s", symcopy->st_value, symbol);
err2:
	elf_end(e);
err1:
	close(fd);
err0:
	free(map);

	return (error);
}
Ejemplo n.º 15
0
int
proc_addr2sym(struct proc_handle *p, uintptr_t addr, char *name,
    size_t namesz, GElf_Sym *symcopy)
{
	Elf *e;
	Elf_Scn *scn, *dynsymscn = NULL, *symtabscn = NULL;
	Elf_Data *data;
	GElf_Shdr shdr;
	GElf_Sym sym;
	GElf_Ehdr ehdr;
	int fd, error = -1;
	size_t i;
	uint64_t rsym;
	prmap_t *map;
	char *s;
	unsigned long symtabstridx = 0, dynsymstridx = 0;

	if ((map = proc_addr2map(p, addr)) == NULL)
		return (-1);
	if ((fd = open(map->pr_mapname, O_RDONLY, 0)) < 0) {
		DPRINTF("ERROR: open %s failed", map->pr_mapname);
		goto err0;
	}
	if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
		DPRINTFX("ERROR: elf_begin() failed: %s", elf_errmsg(-1));
		goto err1;
	}
	if (gelf_getehdr(e, &ehdr) == NULL) {
		DPRINTFX("ERROR: gelf_getehdr() failed: %s", elf_errmsg(-1));
		goto err2;
	}
	/*
	 * Find the index of the STRTAB and SYMTAB sections to locate
	 * symbol names.
	 */
	scn = NULL;
	while ((scn = elf_nextscn(e, scn)) != NULL) {
		gelf_getshdr(scn, &shdr);
		switch (shdr.sh_type) {
		case SHT_SYMTAB:
			symtabscn = scn;
			symtabstridx = shdr.sh_link;
			break;
		case SHT_DYNSYM:
			dynsymscn = scn;
			dynsymstridx = shdr.sh_link;
			break;
		default:
			break;
		}
	}
	/*
	 * Iterate over the Dynamic Symbols table to find the symbol.
	 * Then look up the string name in STRTAB (.dynstr)
	 */
	if ((data = elf_getdata(dynsymscn, NULL)) == NULL) {
		DPRINTFX("ERROR: elf_getdata() failed: %s", elf_errmsg(-1));
		goto symtab;
	}
	i = 0;
	while (gelf_getsym(data, i++, &sym) != NULL) {
		/*
		 * Calculate the address mapped to the virtual memory
		 * by rtld.
		 */
		if (ehdr.e_type != ET_EXEC)
			rsym = map->pr_vaddr + sym.st_value;
		else
			rsym = sym.st_value;
		if (addr >= rsym && addr < rsym + sym.st_size) {
			s = elf_strptr(e, dynsymstridx, sym.st_name);
			if (s) {
				if (s[0] == '_' && s[1] == 'Z' && s[2])
					demangle(s, name, namesz);
				else
					strlcpy(name, s, namesz);
				memcpy(symcopy, &sym, sizeof(sym));
				/*
				 * DTrace expects the st_value to contain
				 * only the address relative to the start of
				 * the function.
				 */
				symcopy->st_value = rsym;
				error = 0;
				goto out;
			}
		}
	}
symtab:
	/*
	 * Iterate over the Symbols Table to find the symbol.
	 * Then look up the string name in STRTAB (.dynstr)
	 */
	if ((data = elf_getdata(symtabscn, NULL)) == NULL) {
		DPRINTFX("ERROR: elf_getdata() failed: %s", elf_errmsg(-1));
		goto err2;
	}
	i = 0;
	while (gelf_getsym(data, i++, &sym) != NULL) {
		/*
		 * Calculate the address mapped to the virtual memory
		 * by rtld.
		 */
		if (ehdr.e_type != ET_EXEC)
			rsym = map->pr_vaddr + sym.st_value;
		else
			rsym = sym.st_value;
		if (addr >= rsym && addr < rsym + sym.st_size) {
			s = elf_strptr(e, symtabstridx, sym.st_name);
			if (s) {
				if (s[0] == '_' && s[1] == 'Z' && s[2])
					demangle(s, name, namesz);
				else
					strlcpy(name, s, namesz);
				memcpy(symcopy, &sym, sizeof(sym));
				/*
				 * DTrace expects the st_value to contain
				 * only the address relative to the start of
				 * the function.
				 */
				symcopy->st_value = rsym;
				error = 0;
				goto out;
			}
		}
	}
out:
err2:
	elf_end(e);
err1:
	close(fd);
err0:
	free(map);
	return (error);
}
Ejemplo n.º 16
0
int
proc_create(const char *file, char * const *argv, proc_child_func *pcf,
    void *child_arg, struct proc_handle **pphdl)
{
	struct proc_handle *phdl;
	int error = 0;
	int status;
	pid_t pid;

	/*
	 * Allocate memory for the process handle, a structure containing
	 * all things related to the process.
	 */
	if ((phdl = malloc(sizeof(struct proc_handle))) == NULL)
		return (ENOMEM);

	elf_version(EV_CURRENT);

	/* Fork a new process. */
	if ((pid = vfork()) == -1)
		error = errno;
	else if (pid == 0) {
		/* The child expects to be traced. */
		if (ptrace(PT_TRACE_ME, 0, 0, 0) != 0)
			_exit(1);

		if (pcf != NULL)
			(*pcf)(child_arg);

		/* Execute the specified file: */
		execvp(file, argv);

		/* Couldn't execute the file. */
		_exit(2);
	} else {
		/* The parent owns the process handle. */
		memset(phdl, 0, sizeof(struct proc_handle));
		phdl->pid = pid;
		phdl->status = PS_IDLE;

		/* Wait for the child process to stop. */
		if (waitpid(pid, &status, WUNTRACED) == -1) {
			error = errno;
			DPRINTF("ERROR: child process %d didn't stop as expected", pid);
			goto bad;
		}

		/* Check for an unexpected status. */
		if (WIFSTOPPED(status) == 0) {
			error = errno;
			DPRINTFX("ERROR: child process %d status 0x%x", pid, status);
			goto bad;
		} else
			phdl->status = PS_STOP;
	}
bad:
	if (error)
		proc_free(phdl);
	else
		*pphdl = phdl;
	return (error);
}