#include <kvm.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <kvm.h>
#include <strings.h>
#include <sys/types32.h>
#define _SYSCALL32
#define RoundUp(v, t) (((v) + sizeof (t) - 1) & ~(sizeof (t) - 1))
static int
kvm_getcmd32(kvm_t *kd,
struct proc *p, struct user *u, char ***arg, char ***env)
{
#if defined(_LP64) || defined(lint)
size_t size32;
void *stack32;
int i, argc, envc;
int auxc = 0;
size_t asize, esize;
char **argv = NULL;
char **envp = NULL;
size_t strpoolsz;
int aptrcount;
int eptrcount;
caddr_t stackp;
ptrdiff_t reloc;
char *str;
size32 = (size_t)p->p_usrstack - (size_t)u->u_argv;
if ((stack32 = malloc(size32)) == NULL)
return (-1);
if (kvm_uread(kd, (uintptr_t)u->u_argv, stack32, size32) != size32) {
free(stack32);
return (-1);
}
argc = u->u_argc;
stackp = (caddr_t)stack32 + ((1 + argc) * sizeof (caddr32_t));
for (envc = 0; *(caddr32_t *)stackp; envc++) {
stackp += sizeof (caddr32_t);
if ((stackp - (caddr_t)stack32) >= size32) {
free(stack32);
return (-1);
}
}
if (u->u_auxv[0].a_type != AT_NULL) {
stackp += sizeof (caddr32_t);
for (auxc = 0; *(int32_t *)stackp; auxc++) {
stackp += 2 * sizeof (caddr32_t);
if ((stackp - (caddr_t)stack32) >= size32) {
free(stack32);
return (-1);
}
}
auxc++;
}
eptrcount = (envc + 1) + 2 * auxc;
aptrcount = (argc + 1) + eptrcount;
strpoolsz = size32 - aptrcount * sizeof (caddr32_t);
asize = aptrcount * sizeof (uintptr_t) + RoundUp(strpoolsz, uintptr_t);
if (arg && (argv = calloc(1, asize + sizeof (uintptr_t))) == NULL) {
free(stack32);
return (-1);
}
esize = eptrcount * sizeof (uintptr_t) + RoundUp(strpoolsz, uintptr_t);
if (env && (envp = calloc(1, esize + sizeof (uintptr_t))) == NULL) {
if (argv)
free(argv);
free(stack32);
return (-1);
}
stackp = (caddr_t)stack32;
if (argv) {
for (i = 0; i < argc; i++) {
argv[i] = (char *)(uintptr_t)(*(caddr32_t *)stackp);
stackp += sizeof (caddr32_t);
}
argv[argc] = 0;
stackp += sizeof (caddr32_t);
} else
stackp += (1 + argc) * sizeof (caddr32_t);
if (envp) {
for (i = 0; i < envc; i++) {
envp[i] = (char *)(uintptr_t)(*(caddr32_t *)stackp);
stackp += sizeof (caddr32_t);
}
envp[envc] = 0;
stackp += sizeof (caddr32_t);
} else
stackp += (1 + envc) * sizeof (caddr32_t);
stackp += auxc * (sizeof (int32_t) + sizeof (uint32_t));
if (argv)
(void) memcpy(argv + aptrcount, (void *)stackp, strpoolsz);
if (envp)
(void) memcpy(envp + eptrcount, (void *)stackp, strpoolsz);
free(stack32);
if (argv) {
char *argv_null = (char *)argv + asize;
reloc = (char *)(argv + aptrcount) - (char *)
((caddr_t)u->u_argv + aptrcount * sizeof (caddr32_t));
for (i = 0; i < argc; i++)
if (argv[i] != NULL) {
str = (argv[i] += reloc);
if (str < (char *)argv ||
str >= (char *)argv + asize)
argv[i] = argv_null;
}
*arg = argv;
}
if (envp) {
char *envp_null = (char *)envp + esize;
char *last_str;
reloc = (char *)(envp + eptrcount) - (char *)
((caddr_t)u->u_envp + eptrcount * sizeof (caddr32_t));
last_str = (char *)((size_t)u->u_argv +
(1 + argc) * sizeof (caddr32_t) + reloc);
if (last_str < (char *)envp ||
last_str >= (char *)envp + esize)
last_str = envp_null;
for (i = 0; i < envc; i++) {
str = (envp[i] += reloc);
if (str < (char *)envp ||
str >= (char *)envp + esize) {
if (last_str != envp_null)
envp[i] = (char *)((size_t)last_str +
strlen(last_str) + 1);
else
envp[i] = envp_null;
}
last_str = envp[i];
}
*env = envp;
}
#endif
return (0);
}
int
kvm_getcmd(kvm_t *kd,
struct proc *proc, struct user *u, char ***arg, char ***env)
{
size_t asize;
size_t esize;
size_t offset;
int i;
int argc;
char **argv = NULL;
char **envp = NULL;
char *str;
char *last_str;
char *argv_null;
char *envp_null;
if (proc->p_flag & SSYS)
return (-1);
if (u->u_argv == (uintptr_t)NULL || u->u_envp == (uintptr_t)NULL)
return (-1);
if (proc->p_model != DATAMODEL_NATIVE &&
proc->p_model == DATAMODEL_ILP32)
return (kvm_getcmd32(kd, proc, u, arg, env));
if (arg) {
asize = (size_t)proc->p_usrstack - (size_t)u->u_argv;
if ((argv = malloc(asize + sizeof (uintptr_t))) == NULL)
return (-1);
argv_null = (char *)argv + asize;
*(uintptr_t *)argv_null = 0;
}
if (env) {
esize = (size_t)proc->p_usrstack - (size_t)u->u_envp;
if ((envp = malloc(esize + sizeof (uintptr_t))) == NULL) {
if (argv)
free(argv);
return (-1);
}
envp_null = (char *)envp + esize;
*(uintptr_t *)envp_null = 0;
}
argc = u->u_argc;
if (argv) {
if (kvm_uread(kd,
(uintptr_t)u->u_argv, argv, asize) != asize) {
free(argv);
if (envp)
free(envp);
return (-1);
}
argv[argc] = 0;
if (envp) {
(void) memcpy(envp, &argv[argc + 1], esize);
}
} else if (envp) {
if (kvm_uread(kd,
(uintptr_t)u->u_envp, envp, esize) != esize) {
free(envp);
return (-1);
}
}
if (argv) {
offset = (char *)argv - (char *)u->u_argv;
for (i = 0; i < argc; i++) {
if (argv[i] != NULL) {
str = (argv[i] += offset);
if (str < (char *)argv ||
str >= (char *)argv + asize)
argv[i] = argv_null;
}
}
argv[i] = NULL;
*arg = argv;
}
if (envp) {
offset = (char *)envp - (char *)u->u_envp;
if (kvm_uread(kd,
(uintptr_t)u->u_argv + (argc - 1) * sizeof (char **),
&last_str, sizeof (last_str)) != sizeof (last_str))
last_str = envp_null;
else {
last_str += offset;
if (last_str < (char *)envp ||
last_str >= (char *)envp + esize)
last_str = envp_null;
}
for (i = 0; envp[i] != NULL; i++) {
str = (envp[i] += offset);
if (str < (char *)envp || str >= (char *)envp + esize) {
if (last_str != envp_null)
envp[i] = last_str +
strlen(last_str) + 1;
else
envp[i] = envp_null;
}
last_str = envp[i];
}
envp[i] = NULL;
*env = envp;
}
return (0);
}