bool
pink_util_putn_safe(pid_t pid, long addr, const char *src, size_t len)
{
	int n, m;
	union {
		long val;
		char x[sizeof(long)];
	} u;

	n = 0;
	m = len / sizeof(long);

	while (n < m) {
		memcpy(u.x, src, sizeof(long));
		if (PINK_GCC_UNLIKELY(!pink_util_peekdata(pid, addr + n * ADDR_MUL, NULL)))
			return false;
		if (PINK_GCC_UNLIKELY(!pink_util_pokedata(pid, addr + n * ADDR_MUL, u.val)))
			return false;
		++n;
		src += sizeof(long);
	}

	m = len % sizeof(long);
	if (m) {
		memcpy(u.x, src, m);
		if (PINK_GCC_UNLIKELY(!pink_util_peekdata(pid, addr + n * ADDR_MUL, NULL)))
			return false;
		if (PINK_GCC_UNLIKELY(!pink_util_pokedata(pid, addr + n * ADDR_MUL, u.val)))
			return false;
	}

	return true;
}
bool
pink_util_movestr(pid_t pid, long addr, char *dest, size_t len)
{
	int n, m;
	int started = 0;
	union {
		long val;
		char x[sizeof(long)];
	} u;

	if (addr & (sizeof(long) -1)) {
		/* addr not a multiple of sizeof(long) */
		n = addr - (addr & -sizeof(long)); /* residue */
		addr &= -sizeof(long); /* residue */

		if (PINK_GCC_UNLIKELY(!pink_util_peekdata(pid, addr, &u.val))) {
			if (PINK_GCC_LIKELY(started && (errno == EPERM || errno == EIO || errno == EFAULT))) {
				/* Ran into end of memory */
				return true;
			}
			/* But if not started, we had a bogus address */
			return false;
		}
		started = 1;
		memcpy(dest, &u.x[n], m = MIN(sizeof(long) - n, len));
		while (n & (sizeof(long) - 1))
			if (u.x[n++] == '\0')
				return true;
		addr += sizeof(long), dest += m, len -= m;
	}
	while (len > 0) {
		if (PINK_GCC_UNLIKELY(!pink_util_peekdata(pid, addr, &u.val))) {
			if (PINK_GCC_LIKELY(started && (errno == EPERM || errno == EIO || errno == EFAULT))) {
				/* Ran into end of memory */
				return true;
			}
			/* But if not started, we had a bogus address */
			return false;
		}
		started = 1;
		memcpy(dest, u.x, m = MIN(sizeof(long), len));
		for (unsigned int i = 0; i < sizeof(long); i++)
			if (u.x[i] == '\0')
				return true;
		addr += sizeof(long), dest += m, len -= m;
	}
	return true;
}
long
pink_name_lookup(const char *name, pink_bitness_t bitness)
{
	int n;
	long scno;
	const char **names;

	if (PINK_GCC_UNLIKELY(name == NULL || name[0] == '\0'))
		return -1;

	switch (bitness) {
	case PINK_BITNESS_32:
		n = nsys32;
		names = sysnames32;
		break;
	case PINK_BITNESS_64:
		n = nsys;
		names = sysnames;
		break;
	default:
		return -1;
	}

	for (scno = 0; scno < n; scno++) {
		if (!strcmp(names[scno], name))
			return scno;
	}

	return -1;
}
Exemple #4
0
char *
pink_decode_string_array_member_persistent(pid_t pid, pink_bitness_t bitness, long arg, unsigned ind)
{
	int save_errno;
	unsigned short wordsize;
	union {
		unsigned int p32;
		unsigned long p64;
		char data[sizeof(long)];
	} cp;

	save_errno = errno;
	wordsize = pink_bitness_wordsize(bitness);
	arg += ind * wordsize;

	if (PINK_GCC_UNLIKELY(!pink_util_moven(pid, arg, cp.data, wordsize)))
		return NULL;
	if (bitness == PINK_BITNESS_32)
		cp.p64 = cp.p32;
	if (cp.p64 == 0) {
		/* hit NULL, end of the array */
		errno = save_errno;
		return NULL;
	}
	return pink_util_movestr_persistent(pid, cp.p64);
}
Exemple #5
0
bool
pink_decode_string_array_member(pid_t pid, pink_bitness_t bitness, long arg, unsigned ind, char *dest, size_t len, bool *nil)
{
	unsigned short wordsize;
	union {
		unsigned int p32;
		unsigned long p64;
		char data[sizeof(long)];
	} cp;

	wordsize = pink_bitness_wordsize(bitness);
	arg += ind * wordsize;

	if (PINK_GCC_UNLIKELY(!pink_util_moven(pid, arg, cp.data, wordsize)))
		return false;
	if (bitness == PINK_BITNESS_32)
		cp.p64 = cp.p32;
	if (cp.p64 == 0) {
		/* hit NULL, end of the array */
		if (nil)
			*nil = true;
		return true;
	}
	if (nil)
		*nil = false;
	return pink_util_movestr(pid, cp.p64, dest, len);
}
bool
pink_util_get_syscall(pid_t pid, pink_bitness_t bitness, long *res)
{
	long parm_offset;
	struct reg r;

	assert(bitness == PINK_BITNESS_32 || bitness == PINK_BITNESS_64);

	if (PINK_GCC_UNLIKELY(!pink_util_get_regs(pid, &r)))
		return false;

	/*
	 * FreeBSD has two special kinds of system call redirections --
	 * SYS_syscall, and SYS___syscall.  The former is the old syscall()
	 * routine, basicly; the latter is for quad-aligned arguments.
	 */
	*res = r.r_rax;
	switch (*res) {
	case SYS_syscall:
	case SYS___syscall:
		if (bitness == PINK_BITNESS_32) {
			parm_offset = r.r_rsp + sizeof(int);
			if (!pink_util_peekdata(pid, parm_offset, res))
				return false;
		}
		else
			*res = r.r_rdi;
		return true;
	default:
		return true;
	}
}
Exemple #7
0
long
pink_name_lookup_with_length(const char *name, size_t length, pink_bitness_t bitness)
{
    long scno;

    if (PINK_GCC_UNLIKELY(bitness != PINK_BITNESS_32))
        return -1;
    if (PINK_GCC_UNLIKELY(name == NULL || name[0] == '\0'))
        return -1;

    for (scno = 0; scno < nsys; scno++) {
        if (!strncmp(sysnames[scno], name, length))
            return scno;
    }

    return -1;
}
Exemple #8
0
const char *
pink_name_syscall(long scno, pink_bitness_t bitness)
{
    int n;
    const char **names;

    if (PINK_GCC_UNLIKELY(bitness != PINK_BITNESS_32))
        return NULL;
    if (scno < 0) {
        /* Architecture specific system call */
        scno = -scno;
        n = nsys_arch;
        names = sysnames_arch;
    }
    else {
        /* Thumb-mode system call */
        n = nsys;
        names = sysnames;
    }

    if (PINK_GCC_UNLIKELY(scno < 0 || scno >= n))
        return NULL;
    return names[scno];
}
bool
pink_util_peekdata(pid_t pid, long off, long *res)
{
	long val;

	errno = 0;
	val = ptrace(PTRACE_PEEKDATA, pid, off, NULL);
	if (PINK_GCC_UNLIKELY(val == -1 && errno != 0))
		return false;

	if (res)
		*res = val;

	return true;
}
const char *
pink_name_syscall(long scno, pink_bitness_t bitness)
{
	int n;
	const char **names;

	switch (bitness) {
	case PINK_BITNESS_32:
		n = nsys32;
		names = sysnames32;
		break;
	case PINK_BITNESS_64:
		n = nsys;
		names = sysnames;
		break;
	default:
		return NULL;
	}

	if (PINK_GCC_UNLIKELY(scno < 0 || scno >= n))
		return NULL;
	return names[scno];
}
pink_bitness_t
pink_bitness_get(pid_t pid)
{
	char progt[32];
	size_t len = sizeof(progt);
	int mib[4];
	struct bitness_types *walk;

	mib[0] = CTL_KERN;
	mib[1] = KERN_PROC;
	mib[2] = KERN_PROC_SV_NAME;
	mib[3] = pid;

	if (PINK_GCC_UNLIKELY(sysctl(mib, 4, progt, &len, NULL, 0) < 0))
		return PINK_BITNESS_UNKNOWN;

	for (walk = bitness_types; walk->type; walk++) {
		if (!strcmp(walk->type, progt))
			return walk->bitness;
	}

	return PINK_BITNESS_UNKNOWN;
}
pink_bitness_t
pink_bitness_get(pid_t pid)
{
	long cs;

	/*
	 * Check CS register value,
	 * On x86-64 linux this is:
	 * 0x33    for long mode (64 bit)
	 * 0x23    for compatibility mode (32 bit)
	 */

	if (PINK_GCC_UNLIKELY(!pink_util_peek(pid, 8 * CS, &cs)))
		return PINK_BITNESS_UNKNOWN;

	switch (cs) {
	case 0x33:
		return PINK_BITNESS_64;
	case 0x23:
		return PINK_BITNESS_32;
	default:
		return PINK_BITNESS_UNKNOWN;
	}
}
char *
pink_util_movestr_persistent(pid_t pid, long addr)
{
	int n, m, sum, save_errno;
	bool started;
	union {
		long val;
		char x[sizeof(long)];
	} u;
	char *res, *res_ptr;

#define XFREE(x)			\
	do {				\
		if ((x)) {		\
			free((x));	\
		}			\
	} while (0)

	save_errno = errno;
	started = false;
	res = res_ptr = NULL;
	sum = 0;

	if (addr & (sizeof(long) -1)) {
		/* addr not a multiple of sizeof(long) */
		n = addr - (addr & -sizeof(long)); /* residue */
		addr &= -sizeof(long); /* residue */

		if (PINK_GCC_UNLIKELY(!pink_util_peekdata(pid, addr, &u.val))) {
			if (PINK_GCC_LIKELY(started && (errno == EPERM || errno == EIO || errno == EFAULT))) {
				/* Ran into end of memory */
				return res;
			}
			/* But if not started, we had a bogus address */
			XFREE(res);
			if (PINK_GCC_UNLIKELY(!started)) {
				/* NULL */
				errno = save_errno;
			}
			return NULL;
		}
		m = sizeof(long) - n;
		sum += m;
		if ((res = realloc(res, sum)) == NULL)
			return NULL;
		res_ptr = started ? res + (sum - m) : res;
		started = true;
		memcpy(res_ptr, &u.x[n], m);
		while (n & (sizeof(long) - 1))
			if (u.x[n++] == '\0')
				return res;
		addr += sizeof(long);
	}

	for (;;) {
		if (PINK_GCC_UNLIKELY(!pink_util_peekdata(pid, addr, &u.val))) {
			if (PINK_GCC_LIKELY(started && (errno == EPERM || errno == EIO || errno == EFAULT))) {
				/* Ran into end of memory */
				return res;
			}
			/* But if not started, we had a bogus address */
			XFREE(res);
			if (PINK_GCC_UNLIKELY(!started)) {
				/* NULL */
				errno = save_errno;
			}
			return NULL;
		}
		sum += sizeof(long);
		if ((res = realloc(res, sum)) == NULL)
			return NULL;
		res_ptr = started ? res + (sum - sizeof(long)) : res;
		started = true;
		memcpy(res_ptr, u.x, sizeof(long));
		for (unsigned int i = 0; i < sizeof(long); i++)
			if (u.x[i] == '\0')
				return res;
		addr += sizeof(long);
	}
	/* never reached */
	assert(false);
#undef XFREE
}