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; }
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; } }
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 }