tech-kern archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

ps_strings refactoring & compat32 fix



Hi all,
all programs get the argument and environment placed onto the initial
stack in a structure called ps_strings. NetBSD currently doesn't export
the correct version of this structure for 32bit binaries as in it
doesn't use the 32bit version of it. This breaks setproctitle(3) and
other users of it. The attached patch refactors the access in procfs and
kern.proc as well as making it honour 32bit. The Darwin code likely is
still broken, if someone wants to use that, it should be easy to adopt
the changes from copyin_procargs.

Also attached are two programs to test the consistency of the structure
and updating it (so that ps(1) can be used to ensure it works), but I
will leave it to someone with more interest in atf(7) to turn them into
full test cases.

Joerg
Index: src/sys/arch/alpha/alpha/machdep.c
===================================================================
--- src/sys/arch/alpha/alpha/machdep.c
+++ src/sys/arch/alpha/alpha/machdep.c
@@ -1617,11 +1617,11 @@
        tfp->tf_regs[FRAME_PC] = pack->ep_entry & ~3;
 
        tfp->tf_regs[FRAME_A0] = stack;                 /* a0 = sp */
        tfp->tf_regs[FRAME_A1] = 0;                     /* a1 = rtld cleanup */
        tfp->tf_regs[FRAME_A2] = 0;                     /* a2 = rtld object */
-       tfp->tf_regs[FRAME_A3] = (u_int64_t)l->l_proc->p_psstr; /* a3 = 
ps_strings */
+       tfp->tf_regs[FRAME_A3] = l->l_proc->p_psstrp;   /* a3 = ps_strings */
        tfp->tf_regs[FRAME_T12] = tfp->tf_regs[FRAME_PC];       /* a.k.a. PV */
 
        l->l_md.md_flags &= ~MDP_FPUSED;
        if (__predict_true((l->l_md.md_flags & IEEE_INHERIT) == 0)) {
                l->l_md.md_flags &= ~MDP_FP_C;

Index: src/sys/arch/amd64/amd64/machdep.c
===================================================================
--- src/sys/arch/amd64/amd64/machdep.c
+++ src/sys/arch/amd64/amd64/machdep.c
@@ -1032,11 +1032,11 @@
        tf->tf_es = LSEL(LUDATA_SEL, SEL_UPL);
        cpu_fsgs_zero(l);
        tf->tf_rdi = 0;
        tf->tf_rsi = 0;
        tf->tf_rbp = 0;
-       tf->tf_rbx = (uint64_t)l->l_proc->p_psstr;
+       tf->tf_rbx = l->l_proc->p_psstrp;
        tf->tf_rdx = 0;
        tf->tf_rcx = 0;
        tf->tf_rax = 0;
        tf->tf_rip = pack->ep_entry;
        tf->tf_cs = LSEL(LUCODE_SEL, SEL_UPL);

Index: src/sys/arch/amd64/amd64/netbsd32_machdep.c
===================================================================
--- src/sys/arch/amd64/amd64/netbsd32_machdep.c
+++ src/sys/arch/amd64/amd64/netbsd32_machdep.c
@@ -159,11 +159,11 @@
        cpu_fsgs_zero(l);
        cpu_fsgs_reload(l, tf->tf_ds, tf->tf_es);
        tf->tf_rdi = 0;
        tf->tf_rsi = 0;
        tf->tf_rbp = 0;
-       tf->tf_rbx = (uint64_t)p->p_psstr;
+       tf->tf_rbx = (uint32_t)p->p_psstrp;
        tf->tf_rdx = 0;
        tf->tf_rcx = 0;
        tf->tf_rax = 0;
        tf->tf_rip = pack->ep_entry;
        tf->tf_cs = LSEL(LUCODE32_SEL, SEL_UPL);

Index: src/sys/arch/amiga/amiga/machdep.c
===================================================================
--- src/sys/arch/amiga/amiga/machdep.c
+++ src/sys/arch/amiga/amiga/machdep.c
@@ -301,11 +301,11 @@
        frame->f_regs[D5] = 0;
        frame->f_regs[D6] = 0;
        frame->f_regs[D7] = 0;
        frame->f_regs[A0] = 0;
        frame->f_regs[A1] = 0;
-       frame->f_regs[A2] = (int)l->l_proc->p_psstr;
+       frame->f_regs[A2] = l->l_proc->p_psstrp;
        frame->f_regs[A3] = 0;
        frame->f_regs[A4] = 0;
        frame->f_regs[A5] = 0;
        frame->f_regs[A6] = 0;
        frame->f_regs[SP] = stack;

Index: src/sys/arch/arm/arm/arm_machdep.c
===================================================================
--- src/sys/arch/arm/arm/arm_machdep.c
+++ src/sys/arch/arm/arm/arm_machdep.c
@@ -153,11 +153,11 @@
 
        pcb = lwp_getpcb(l);
        tf = pcb->pcb_tf;
 
        memset(tf, 0, sizeof(*tf));
-       tf->tf_r0 = (u_int)l->l_proc->p_psstr;
+       tf->tf_r0 = l->l_proc->p_psstrp;
        tf->tf_r12 = stack;                     /* needed by pre 1.4 crt0.c */
        tf->tf_usr_sp = stack;
        tf->tf_usr_lr = pack->ep_entry;
        tf->tf_svc_lr = 0x77777777;             /* Something we can see */
        tf->tf_pc = pack->ep_entry;

Index: src/sys/arch/atari/atari/machdep.c
===================================================================
--- src/sys/arch/atari/atari/machdep.c
+++ src/sys/arch/atari/atari/machdep.c
@@ -250,11 +250,11 @@
        frame->f_regs[D5] = 0;
        frame->f_regs[D6] = 0;
        frame->f_regs[D7] = 0;
        frame->f_regs[A0] = 0;
        frame->f_regs[A1] = 0;
-       frame->f_regs[A2] = (int)l->l_proc->p_psstr;
+       frame->f_regs[A2] = l->l_proc->p_psstrp;
        frame->f_regs[A3] = 0;
        frame->f_regs[A4] = 0;
        frame->f_regs[A5] = 0;
        frame->f_regs[A6] = 0;
        frame->f_regs[SP] = stack;

Index: src/sys/arch/cesfic/cesfic/machdep.c
===================================================================
--- src/sys/arch/cesfic/cesfic/machdep.c
+++ src/sys/arch/cesfic/cesfic/machdep.c
@@ -299,11 +299,11 @@
        frame->f_regs[D5] = 0;
        frame->f_regs[D6] = 0;
        frame->f_regs[D7] = 0;
        frame->f_regs[A0] = 0;
        frame->f_regs[A1] = 0;
-       frame->f_regs[A2] = (int)l->l_proc->p_psstr;
+       frame->f_regs[A2] = l->l_proc->p_psstrp;
        frame->f_regs[A3] = 0;
        frame->f_regs[A4] = 0;
        frame->f_regs[A5] = 0;
        frame->f_regs[A6] = 0;
        frame->f_regs[SP] = stack;

Index: src/sys/arch/hp300/hp300/machdep.c
===================================================================
--- src/sys/arch/hp300/hp300/machdep.c
+++ src/sys/arch/hp300/hp300/machdep.c
@@ -359,11 +359,11 @@
        frame->f_regs[D5] = 0;
        frame->f_regs[D6] = 0;
        frame->f_regs[D7] = 0;
        frame->f_regs[A0] = 0;
        frame->f_regs[A1] = 0;
-       frame->f_regs[A2] = (int)l->l_proc->p_psstr;
+       frame->f_regs[A2] = l->l_proc->p_psstrp;
        frame->f_regs[A3] = 0;
        frame->f_regs[A4] = 0;
        frame->f_regs[A5] = 0;
        frame->f_regs[A6] = 0;
        frame->f_regs[SP] = stack;

Index: src/sys/arch/hp700/hp700/machdep.c
===================================================================
--- src/sys/arch/hp700/hp700/machdep.c
+++ src/sys/arch/hp700/hp700/machdep.c
@@ -1882,11 +1882,11 @@
 
        tf->tf_flags = TFF_SYS|TFF_LAST;
        tf->tf_iioq_tail = 4 +
            (tf->tf_iioq_head = pack->ep_entry | HPPA_PC_PRIV_USER);
        tf->tf_rp = 0;
-       tf->tf_arg0 = (u_long)p->p_psstr;
+       tf->tf_arg0 = p->p_psstrp;
        tf->tf_arg1 = tf->tf_arg2 = 0; /* XXX dynload stuff */
 
        tf->tf_sr7 = HPPA_SID_KERNEL;
 
        /* Load all of the user's space registers. */

Index: src/sys/arch/i386/i386/machdep.c
===================================================================
--- src/sys/arch/i386/i386/machdep.c
+++ src/sys/arch/i386/i386/machdep.c
@@ -1032,11 +1032,11 @@
        tf->tf_es = LSEL(LUDATA_SEL, SEL_UPL);
        tf->tf_ds = LSEL(LUDATA_SEL, SEL_UPL);
        tf->tf_edi = 0;
        tf->tf_esi = 0;
        tf->tf_ebp = 0;
-       tf->tf_ebx = (int)l->l_proc->p_psstr;
+       tf->tf_ebx = l->l_proc->p_psstrp;
        tf->tf_edx = 0;
        tf->tf_ecx = 0;
        tf->tf_eax = 0;
        tf->tf_eip = pack->ep_entry;
        tf->tf_cs = pmap->pm_hiexec > I386_MAX_EXE_ADDR ?

Index: src/sys/arch/ia64/ia64/machdep.c
===================================================================
--- src/sys/arch/ia64/ia64/machdep.c
+++ src/sys/arch/ia64/ia64/machdep.c
@@ -721,11 +721,11 @@
                 * NaT collection points.
                 */
                kst = ksttop - 1;
                if (((uintptr_t)kst & 0x1ff) == 0x1f8)
                        *kst-- = 0;
-               *kst-- = (uint64_t)l->l_proc->p_psstr;  /* in3 = ps_strings */
+               *kst-- = l->l_proc->p_psstrp;   /* in3 = ps_strings */
                if (((uintptr_t)kst & 0x1ff) == 0x1f8)
                        *kst-- = 0;
                *kst-- = 0;                             /* in2 = *obj */
                if (((uintptr_t)kst & 0x1ff) == 0x1f8)
                        *kst-- = 0;
@@ -753,11 +753,11 @@
                /* in2 == *obj */
                suword((char *)tf->tf_special.bspstore -  16, 0);
 
                /* in3 = ps_strings */
                suword((char *)tf->tf_special.bspstore - 8,
-                   (uint64_t)l->l_proc->p_psstr);
+                   l->l_proc->p_psstrp);
 
        }
 
        tf->tf_special.iip = pack->ep_entry;
        tf->tf_special.sp = (stack & ~15) - 16;

Index: src/sys/arch/luna68k/luna68k/machdep.c
===================================================================
--- src/sys/arch/luna68k/luna68k/machdep.c
+++ src/sys/arch/luna68k/luna68k/machdep.c
@@ -295,11 +295,11 @@
        frame->f_regs[D5] = 0;
        frame->f_regs[D6] = 0;
        frame->f_regs[D7] = 0;
        frame->f_regs[A0] = 0;
        frame->f_regs[A1] = 0;
-       frame->f_regs[A2] = (int)l->l_proc->p_psstr;
+       frame->f_regs[A2] = l->l_proc->p_psstrp;
        frame->f_regs[A3] = 0;
        frame->f_regs[A4] = 0;
        frame->f_regs[A5] = 0;
        frame->f_regs[A6] = 0;
        frame->f_regs[SP] = stack;

Index: src/sys/arch/mac68k/mac68k/machdep.c
===================================================================
--- src/sys/arch/mac68k/mac68k/machdep.c
+++ src/sys/arch/mac68k/mac68k/machdep.c
@@ -457,11 +457,11 @@
        frame->f_regs[D5] = 0;
        frame->f_regs[D6] = 0;
        frame->f_regs[D7] = 0;
        frame->f_regs[A0] = 0;
        frame->f_regs[A1] = 0;
-       frame->f_regs[A2] = (int)l->l_proc->p_psstr;
+       frame->f_regs[A2] = l->l_proc->p_psstrp;
        frame->f_regs[A3] = 0;
        frame->f_regs[A4] = 0;
        frame->f_regs[A5] = 0;
        frame->f_regs[A6] = 0;
        frame->f_regs[SP] = stack;

Index: src/sys/arch/mips/mips/mips_machdep.c
===================================================================
--- src/sys/arch/mips/mips/mips_machdep.c
+++ src/sys/arch/mips/mips/mips_machdep.c
@@ -1262,11 +1262,11 @@
         *      - ps_strings is a NetBSD extension.
         */
        tf->tf_regs[_R_A0] = (intptr_t)stack;
        tf->tf_regs[_R_A1] = 0;
        tf->tf_regs[_R_A2] = 0;
-       tf->tf_regs[_R_A3] = (intptr_t)p->p_psstr;
+       tf->tf_regs[_R_A3] = p->p_psstrp;
 
        fpu_discard();
        memset(&pcb->pcb_fpregs, 0, sizeof(struct fpreg));
        l->l_md.md_ss_addr = 0;
 }

Index: src/sys/arch/mvme68k/mvme68k/machdep.c
===================================================================
--- src/sys/arch/mvme68k/mvme68k/machdep.c
+++ src/sys/arch/mvme68k/mvme68k/machdep.c
@@ -504,11 +504,11 @@
        frame->f_regs[D5] = 0;
        frame->f_regs[D6] = 0;
        frame->f_regs[D7] = 0;
        frame->f_regs[A0] = 0;
        frame->f_regs[A1] = 0;
-       frame->f_regs[A2] = (int)l->l_proc->p_psstr;
+       frame->f_regs[A2] = l->l_proc->p_psstrp;
        frame->f_regs[A3] = 0;
        frame->f_regs[A4] = 0;
        frame->f_regs[A5] = 0;
        frame->f_regs[A6] = 0;
        frame->f_regs[SP] = stack;

Index: src/sys/arch/news68k/news68k/machdep.c
===================================================================
--- src/sys/arch/news68k/news68k/machdep.c
+++ src/sys/arch/news68k/news68k/machdep.c
@@ -270,11 +270,11 @@
        frame->f_regs[D5] = 0;
        frame->f_regs[D6] = 0;
        frame->f_regs[D7] = 0;
        frame->f_regs[A0] = 0;
        frame->f_regs[A1] = 0;
-       frame->f_regs[A2] = (int)l->l_proc->p_psstr;
+       frame->f_regs[A2] = l->l_proc->p_psstrp;
        frame->f_regs[A3] = 0;
        frame->f_regs[A4] = 0;
        frame->f_regs[A5] = 0;
        frame->f_regs[A6] = 0;
        frame->f_regs[SP] = stack;

Index: src/sys/arch/powerpc/powerpc/powerpc_machdep.c
===================================================================
--- src/sys/arch/powerpc/powerpc/powerpc_machdep.c
+++ src/sys/arch/powerpc/powerpc/powerpc_machdep.c
@@ -79,11 +79,11 @@
 
        /*
         * XXX Machine-independent code has already copied arguments and
         * XXX environment to userland.  Get them back here.
         */
-       (void)copyin((char *)p->p_psstr, &arginfo, sizeof (arginfo));
+       (void)copyin_psstrings(p, &arginfo);
 
        /*
         * Set up arguments for _start():
         *      _start(argc, argv, envp, obj, cleanup, ps_strings);
         *
@@ -100,11 +100,11 @@
        tf->tf_fixreg[3] = arginfo.ps_nargvstr;
        tf->tf_fixreg[4] = (register_t)arginfo.ps_argvstr;
        tf->tf_fixreg[5] = (register_t)arginfo.ps_envstr;
        tf->tf_fixreg[6] = 0;                   /* auxillary vector */
        tf->tf_fixreg[7] = 0;                   /* termination vector */
-       tf->tf_fixreg[8] = (register_t)p->p_psstr;      /* NetBSD extension */
+       tf->tf_fixreg[8] = p->p_psstrp; /* NetBSD extension */
 
        tf->tf_srr0 = pack->ep_entry;
        tf->tf_srr1 = PSL_MBO | PSL_USERSET;
 #ifdef ALTIVEC
        tf->tf_vrsave = 0;

Index: src/sys/arch/sh3/sh3/sh3_machdep.c
===================================================================
--- src/sys/arch/sh3/sh3/sh3_machdep.c
+++ src/sys/arch/sh3/sh3/sh3_machdep.c
@@ -563,11 +563,11 @@
        tf->tf_r4 = fuword((void *)stack);      /* argc */
        tf->tf_r5 = stack + 4;                  /* argv */
        tf->tf_r6 = stack + 4 * tf->tf_r4 + 8;  /* envp */
        tf->tf_r7 = 0;
        tf->tf_r8 = 0;
-       tf->tf_r9 = (int)l->l_proc->p_psstr;
+       tf->tf_r9 = l->l_proc->p_psstrp;
        tf->tf_r10 = 0;
        tf->tf_r11 = 0;
        tf->tf_r12 = 0;
        tf->tf_r13 = 0;
        tf->tf_r14 = 0;

Index: src/sys/arch/sparc/sparc/machdep.c
===================================================================
--- src/sys/arch/sparc/sparc/machdep.c
+++ src/sys/arch/sparc/sparc/machdep.c
@@ -354,11 +354,11 @@
 
        /*
         * Set the registers to 0 except for:
         *      %o6: stack pointer, built in exec())
         *      %psr: (retain CWP and PSR_S bits)
-        *      %g1: address of p->p_psstr (used by crt0)
+        *      %g1: p->p_psstrp (used by crt0)
         *      %pc,%npc: entry point of program
         */
        psr = tf->tf_psr & (PSR_S | PSR_CWP);
        if ((fs = l->l_md.md_fpstate) != NULL) {
                struct cpu_info *cpi;
@@ -386,11 +386,11 @@
                free((void *)fs, M_SUBPROC);
                l->l_md.md_fpstate = NULL;
        }
        memset((void *)tf, 0, sizeof *tf);
        tf->tf_psr = psr;
-       tf->tf_global[1] = (int)l->l_proc->p_psstr;
+       tf->tf_global[1] = l->l_proc->p_psstrp;
        tf->tf_pc = pack->ep_entry & ~3;
        tf->tf_npc = tf->tf_pc + 4;
        stack -= sizeof(struct rwindow);
        tf->tf_out[6] = stack;
 }

Index: src/sys/arch/sparc64/sparc64/machdep.c
===================================================================
--- src/sys/arch/sparc64/sparc64/machdep.c
+++ src/sys/arch/sparc64/sparc64/machdep.c
@@ -238,11 +238,11 @@
 
        /*
         * Set the registers to 0 except for:
         *      %o6: stack pointer, built in exec())
         *      %tstate: (retain icc and xcc and cwp bits)
-        *      %g1: address of p->p_psstr (used by crt0)
+        *      %g1: p->p_psstrp (used by crt0)
         *      %tpc,%tnpc: entry point of program
         */
 #ifdef __arch64__
        /* Check what memory model is requested */
        switch ((eh->e_flags & EF_SPARCV9_MM)) {
@@ -273,11 +273,11 @@
                pool_cache_put(fpstate_cache, fs);
                l->l_md.md_fpstate = NULL;
        }
        memset(tf, 0, sizeof *tf);
        tf->tf_tstate = tstate;
-       tf->tf_global[1] = (vaddr_t)l->l_proc->p_psstr;
+       tf->tf_global[1] = l->l_proc->p_psstrp;
        /* %g4 needs to point to the start of the data segment */
        tf->tf_global[4] = 0; 
        tf->tf_pc = pack->ep_entry & ~3;
        tf->tf_npc = tf->tf_pc + 4;
        stack -= sizeof(struct rwindow);

Index: src/sys/arch/sparc64/sparc64/netbsd32_machdep.c
===================================================================
--- src/sys/arch/sparc64/sparc64/netbsd32_machdep.c
+++ src/sys/arch/sparc64/sparc64/netbsd32_machdep.c
@@ -127,11 +127,11 @@
 
        /*
         * Set the registers to 0 except for:
         *      %o6: stack pointer, built in exec())
         *      %tstate: (retain icc and xcc and cwp bits)
-        *      %g1: address of p->p_psstr (used by crt0)
+        *      %g1: p->p_psstrp (used by crt0)
         *      %tpc,%tnpc: entry point of program
         */
        tstate = ((PSTATE_USER32)<<TSTATE_PSTATE_SHIFT) 
                | (tf->tf_tstate & TSTATE_CWP);
        if ((fs = l->l_md.md_fpstate) != NULL) {
@@ -144,11 +144,11 @@
                pool_cache_put(fpstate_cache, fs);
                l->l_md.md_fpstate = NULL;
        }
        memset(tf, 0, sizeof *tf);
        tf->tf_tstate = tstate;
-       tf->tf_global[1] = (u_int)(u_long)p->p_psstr;
+       tf->tf_global[1] = p->p_psstrp;
        tf->tf_pc = pack->ep_entry & ~3;
        tf->tf_npc = tf->tf_pc + 4;
 
        stack -= sizeof(struct rwindow32);
        tf->tf_out[6] = stack;
@@ -283,11 +283,11 @@
 #endif
        /*
         * Arrange to continue execution at the code copied out in exec().
         * It needs the function to call in %g1, and a new stack pointer.
         */
-       addr = (long)p->p_psstr - szsigcode;
+       addr = p->p_psstrp - szsigcode;
        tf->tf_global[1] = (long)catcher;
        tf->tf_pc = addr;
        tf->tf_npc = addr + 4;
        tf->tf_out[6] = (uint64_t)(u_int)(u_long)newsp;
 

Index: src/sys/arch/sparc64/sparc64/sunos32_machdep.c
===================================================================
--- src/sys/arch/sparc64/sparc64/sunos32_machdep.c
+++ src/sys/arch/sparc64/sparc64/sunos32_machdep.c
@@ -125,11 +125,11 @@
 
        /*
         * Set the registers to 0 except for:
         *      %o6: stack pointer, built in exec())
         *      %tstate: (retain icc and xcc and cwp bits)
-        *      %g1: address of p->p_psstr (used by crt0)
+        *      %g1: p->p_psstrp (used by crt0)
         *      %tpc,%tnpc: entry point of program
         */
        tstate = ((PSTATE_USER32)<<TSTATE_PSTATE_SHIFT) 
                | (tf->tf_tstate & TSTATE_CWP);
        if ((fs = l->l_md.md_fpstate) != NULL) {
@@ -145,11 +145,11 @@
                pool_cache_put(fpstate_cache, fs);
                l->l_md.md_fpstate = NULL;
        }
        memset(tf, 0, sizeof *tf);
        tf->tf_tstate = tstate;
-       tf->tf_global[1] = (u_int)(u_long)p->p_psstr;
+       tf->tf_global[1] = (u_int)p->p_psstrp;
        tf->tf_pc = pack->ep_entry & ~3;
        tf->tf_npc = tf->tf_pc + 4;
 
        stack -= sizeof(struct rwindow32);
        tf->tf_out[6] = stack;

Index: src/sys/arch/sparc64/sparc64/svr4_32_machdep.c
===================================================================
--- src/sys/arch/sparc64/sparc64/svr4_32_machdep.c
+++ src/sys/arch/sparc64/sparc64/svr4_32_machdep.c
@@ -76,11 +76,11 @@
 {
        register struct trapframe64 *tf = l->l_md.md_tf;
 
        netbsd32_setregs(l, epp, stack);
        
-       /* This should be the exit function, not p->p_psstr. */
+       /* This should be the exit function, not p->p_psstrp. */
        tf->tf_global[1] = (vaddr_t)0;
 }
 
 #ifdef DEBUG
 #include <sparc64/sparc64/sigdebug.h>

Index: src/sys/arch/sparc64/sparc64/svr4_machdep.c
===================================================================
--- src/sys/arch/sparc64/sparc64/svr4_machdep.c
+++ src/sys/arch/sparc64/sparc64/svr4_machdep.c
@@ -74,11 +74,11 @@
 {
        register struct trapframe64 *tf = l->l_md.md_tf;
 
        setregs(l, epp, stack);
        
-       /* This should be the exit function, not p->p_psstr. */
+       /* This should be the exit function, not p->p_psstrp. */
        tf->tf_global[1] = (vaddr_t)0;
 }
 
 #ifdef DEBUG
 #include <sparc64/sparc64/sigdebug.h>

Index: src/sys/arch/sun2/sun2/machdep.c
===================================================================
--- src/sys/arch/sun2/sun2/machdep.c
+++ src/sys/arch/sun2/sun2/machdep.c
@@ -386,11 +386,11 @@
        tf->tf_regs[D5] = 0;
        tf->tf_regs[D6] = 0;
        tf->tf_regs[D7] = 0;
        tf->tf_regs[A0] = 0;
        tf->tf_regs[A1] = 0;
-       tf->tf_regs[A2] = (int)l->l_proc->p_psstr;
+       tf->tf_regs[A2] = l->l_proc->p_psstrp;
        tf->tf_regs[A3] = 0;
        tf->tf_regs[A4] = 0;
        tf->tf_regs[A5] = 0;
        tf->tf_regs[A6] = 0;
        tf->tf_regs[SP] = stack;

Index: src/sys/arch/sun3/sun3/machdep.c
===================================================================
--- src/sys/arch/sun3/sun3/machdep.c
+++ src/sys/arch/sun3/sun3/machdep.c
@@ -303,11 +303,11 @@
        tf->tf_regs[D5] = 0;
        tf->tf_regs[D6] = 0;
        tf->tf_regs[D7] = 0;
        tf->tf_regs[A0] = 0;
        tf->tf_regs[A1] = 0;
-       tf->tf_regs[A2] = (int)l->l_proc->p_psstr;
+       tf->tf_regs[A2] = l->l_proc->p_psstrp;
        tf->tf_regs[A3] = 0;
        tf->tf_regs[A4] = 0;
        tf->tf_regs[A5] = 0;
        tf->tf_regs[A6] = 0;
        tf->tf_regs[SP] = stack;

Index: src/sys/arch/sun3/sun3x/machdep.c
===================================================================
--- src/sys/arch/sun3/sun3x/machdep.c
+++ src/sys/arch/sun3/sun3x/machdep.c
@@ -266,11 +266,11 @@
        tf->tf_regs[D5] = 0;
        tf->tf_regs[D6] = 0;
        tf->tf_regs[D7] = 0;
        tf->tf_regs[A0] = 0;
        tf->tf_regs[A1] = 0;
-       tf->tf_regs[A2] = (int)l->l_proc->p_psstr;
+       tf->tf_regs[A2] = l->l_proc->p_psstrp;
        tf->tf_regs[A3] = 0;
        tf->tf_regs[A4] = 0;
        tf->tf_regs[A5] = 0;
        tf->tf_regs[A6] = 0;
        tf->tf_regs[SP] = stack;

Index: src/sys/arch/vax/vax/trap.c
===================================================================
--- src/sys/arch/vax/vax/trap.c
+++ src/sys/arch/vax/vax/trap.c
@@ -375,11 +375,11 @@
        exptr->pc = pack->ep_entry + 2;
        exptr->sp = stack;
        exptr->r6 = stack;                              /* for ELF */
        exptr->r7 = 0;                                  /* for ELF */
        exptr->r8 = 0;                                  /* for ELF */
-       exptr->r9 = (u_long) l->l_proc->p_psstr;        /* for ELF */
+       exptr->r9 = l->l_proc->p_psstrp;                /* for ELF */
 }
 
 
 /* 
  * Start a new LWP

Index: src/sys/arch/x68k/x68k/machdep.c
===================================================================
--- src/sys/arch/x68k/x68k/machdep.c
+++ src/sys/arch/x68k/x68k/machdep.c
@@ -293,11 +293,11 @@
        frame->f_regs[D5] = 0;
        frame->f_regs[D6] = 0;
        frame->f_regs[D7] = 0;
        frame->f_regs[A0] = 0;
        frame->f_regs[A1] = 0;
-       frame->f_regs[A2] = (int)l->l_proc->p_psstr;
+       frame->f_regs[A2] = l->l_proc->p_psstrp;
        frame->f_regs[A3] = 0;
        frame->f_regs[A4] = 0;
        frame->f_regs[A5] = 0;
        frame->f_regs[A6] = 0;
        frame->f_regs[SP] = stack;

Index: src/sys/compat/darwin/darwin_sysctl.c
===================================================================
--- src/sys/compat/darwin/darwin_sysctl.c
+++ src/sys/compat/darwin/darwin_sysctl.c
@@ -967,29 +967,21 @@
        }
 
        /*
         * Read in the ps_strings structure.
         */
-       aiov.iov_base = &pss;
-       aiov.iov_len = sizeof(pss);
-       auio.uio_iov = &aiov;
-       auio.uio_iovcnt = 1;
-       auio.uio_offset = (vaddr_t)p->p_psstr;
-       auio.uio_resid = sizeof(pss);
-       auio.uio_rw = UIO_READ;
-       UIO_SETUP_SYSSPACE(&auio);
-       if ((error = uvm_io(&p->p_vmspace->vm_map, &auio)) != 0)
+       if ((error = copyin_psstrings(p, &pss)) != 0)
                goto done;
 
        /*
         * Get argument vector address and length. Since we want to
         * copy argv and env at the same time, we add their lengths.
         */
-       memcpy(&nargv, (char *)&pss + p->p_psnargv, sizeof(nargv));
-       memcpy(&nenv, (char *)&pss + p->p_psnenv, sizeof(nargv));
+       nargv = pss.ps_nargvstr;
+       nenv = pss.ps_nenvvstr;
+       tmp = pss.ps_argvstr;
        nstr = nargv + nenv;
-       memcpy(&tmp, (char *)&pss + p->p_psargv, sizeof(tmp));
 
        auio.uio_offset = (off_t)(long)tmp;
        aiov.iov_base = &argv;
        aiov.iov_len = sizeof(argv);
        auio.uio_iov = &aiov;

Index: src/sys/compat/linux/arch/alpha/linux_machdep.c
===================================================================
--- src/sys/compat/linux/arch/alpha/linux_machdep.c
+++ src/sys/compat/linux/arch/alpha/linux_machdep.c
@@ -198,11 +198,11 @@
        tf->tf_regs[FRAME_A1] = (unsigned long)&sfp->info;
        tf->tf_regs[FRAME_A2] = (unsigned long)&sfp->uc;
 
        /* Address of trampoline code.  End up at this PC after mi_switch */
        tf->tf_regs[FRAME_PC] =
-           (u_int64_t)(p->p_psstr - (linux_rt_esigcode - linux_rt_sigcode));
+           (u_int64_t)(p->p_psstrp - (linux_rt_esigcode - linux_rt_sigcode));
 
        /* Adjust the stack */
        alpha_pal_wrusp((unsigned long)sfp);
 
        /* Remember that we're now on the signal stack. */
@@ -292,11 +292,11 @@
        tf->tf_regs[FRAME_A1] = 0;
        tf->tf_regs[FRAME_A2] = (unsigned long)&sfp->sf_sc;
 
        /* Address of trampoline code.  End up at this PC after mi_switch */
        tf->tf_regs[FRAME_PC] =
-           (u_int64_t)(p->p_psstr - (linux_esigcode - linux_sigcode));
+           (u_int64_t)(p->p_psstrp - (linux_esigcode - linux_sigcode));
 
        /* Adjust the stack */
        alpha_pal_wrusp((unsigned long)sfp);
 
        /* Remember that we're now on the signal stack. */

Index: src/sys/compat/linux/arch/i386/linux_machdep.c
===================================================================
--- src/sys/compat/linux/arch/i386/linux_machdep.c
+++ src/sys/compat/linux/arch/i386/linux_machdep.c
@@ -153,11 +153,11 @@
        tf->tf_es = GSEL(GUDATA_SEL, SEL_UPL);
        tf->tf_ds = GSEL(GUDATA_SEL, SEL_UPL);
        tf->tf_edi = 0;
        tf->tf_esi = 0;
        tf->tf_ebp = 0;
-       tf->tf_ebx = (int)l->l_proc->p_psstr;
+       tf->tf_ebx = l->l_proc->p_psstrp;
        tf->tf_edx = 0;
        tf->tf_ecx = 0;
        tf->tf_eax = 0;
        tf->tf_eip = epp->ep_entry;
        tf->tf_cs = GSEL(GUCODEBIG_SEL, SEL_UPL);

Index: src/sys/compat/linux32/arch/amd64/linux32_machdep.c
===================================================================
--- src/sys/compat/linux32/arch/amd64/linux32_machdep.c
+++ src/sys/compat/linux32/arch/amd64/linux32_machdep.c
@@ -294,11 +294,11 @@
 
        p->p_flag |= PK_32;
 
        tf = l->l_md.md_regs;
        tf->tf_rax = 0;
-       tf->tf_rbx = (u_int64_t)p->p_psstr & 0xffffffff;
+       tf->tf_rbx = (u_int32_t)p->p_psstrp;
        tf->tf_rcx = pack->ep_entry & 0xffffffff;
        tf->tf_rdx = 0;
        tf->tf_rsi = 0;
        tf->tf_rdi = 0;
        tf->tf_rbp = 0;

Index: src/sys/kern/kern_exec.c
===================================================================
--- src/sys/kern/kern_exec.c
+++ src/sys/kern/kern_exec.c
@@ -520,11 +520,12 @@
        char                    *dp, *sp;
        long                    argc, envc;
        size_t                  i, len;
        char                    *stack;
        struct ps_strings       arginfo;
-       struct ps_strings       *aip = &arginfo;
+       struct ps_strings32     arginfo32;
+       void                    *aip;
        struct vmspace          *vm;
        struct exec_fakearg     *tmpfap;
        int                     szsigcode;
        struct exec_vmcmd       *base_vcp;
        int                     oldlwpflags;
@@ -532,10 +533,11 @@
        ksiginfoq_t             kq;
        const char              *pathstring;
        char                    *resolvedpathbuf;
        const char              *commandname;
        u_int                   modgen;
+       size_t                  ps_strings_sz;
 
        p = l->l_proc;
        modgen = 0;
 
        SDT_PROBE(proc,,,exec, path, 0, 0, 0, 0);
@@ -718,20 +720,25 @@
 #else
 #define        RTLD_GAP        0
 #endif
 
        /* Now check if args & environ fit into new stack */
-       if (pack.ep_flags & EXEC_32)
+       if (pack.ep_flags & EXEC_32) {
+               aip = &arginfo32;
+               ps_strings_sz = sizeof(struct ps_strings32);
                len = ((argc + envc + 2 + pack.ep_esch->es_arglen) *
                    sizeof(int) + sizeof(int) + dp + RTLD_GAP +
-                   szsigcode + sizeof(struct ps_strings) + STACK_PTHREADSPACE)
+                   szsigcode + ps_strings_sz + STACK_PTHREADSPACE)
                    - argp;
-       else
+       } else {
+               aip = &arginfo;
+               ps_strings_sz = sizeof(struct ps_strings);
                len = ((argc + envc + 2 + pack.ep_esch->es_arglen) *
                    sizeof(char *) + sizeof(int) + dp + RTLD_GAP +
-                   szsigcode + sizeof(struct ps_strings) + STACK_PTHREADSPACE)
+                   szsigcode + ps_strings_sz + STACK_PTHREADSPACE)
                    - argp;
+       }
 
 #ifdef PAX_ASLR
        if (pax_aslr_active(l))
                len += (arc4random() % PAGE_SIZE);
 #endif /* PAX_ASLR */
@@ -891,11 +898,11 @@
                PNBUF_PUT(dp);
        }
 
        stack = (char *)STACK_ALLOC(STACK_GROW(vm->vm_minsaddr,
                STACK_PTHREADSPACE + sizeof(struct ps_strings) + szsigcode),
-               len - (sizeof(struct ps_strings) + szsigcode));
+               len - (ps_strings_sz + szsigcode));
 
 #ifdef __MACHINE_STACK_GROWS_UP
        /*
         * The copyargs call always copies into lower addresses
         * first, moving towards higher addresses, starting with
@@ -933,23 +940,24 @@
        }
        /* Move the stack back to original point */
        stack = (char *)STACK_GROW(vm->vm_minsaddr, len);
 
        /* fill process ps_strings info */
-       p->p_psstr = (struct ps_strings *)
-           STACK_ALLOC(STACK_GROW(vm->vm_minsaddr, STACK_PTHREADSPACE),
-           sizeof(struct ps_strings));
-       p->p_psargv = offsetof(struct ps_strings, ps_argvstr);
-       p->p_psnargv = offsetof(struct ps_strings, ps_nargvstr);
-       p->p_psenv = offsetof(struct ps_strings, ps_envstr);
-       p->p_psnenv = offsetof(struct ps_strings, ps_nenvstr);
+       p->p_psstrp = (vaddr_t)STACK_ALLOC(STACK_GROW(vm->vm_minsaddr,
+           STACK_PTHREADSPACE), ps_strings_sz);
+
+       if (pack.ep_flags & EXEC_32) {
+               arginfo32.ps_argvstr = (vaddr_t)arginfo.ps_argvstr;
+               arginfo32.ps_nargvstr = arginfo.ps_nargvstr;
+               arginfo32.ps_envstr = (vaddr_t)arginfo.ps_envstr;
+               arginfo32.ps_nenvstr = arginfo.ps_nenvstr;
+       }
 
        /* copy out the process's ps_strings structure */
-       if ((error = copyout(aip, (char *)p->p_psstr,
-           sizeof(arginfo))) != 0) {
-               DPRINTF(("execve: ps_strings copyout %p->%p size %ld failed\n",
-                      aip, (char *)p->p_psstr, (long)sizeof(arginfo)));
+       if ((error = copyout(aip, (void *)p->p_psstrp, ps_strings_sz)) != 0) {
+               DPRINTF(("execve: ps_strings copyout %p->%p size %zu failed\n",
+                      aip, (void *)p->p_psstrp, ps_strings_sz));
                goto exec_abort;
        }
 
        cwdexec(p);
        fd_closeexec();         /* handle close on exec */
@@ -1255,11 +1263,10 @@
        exit1(l, W_EXITCODE(error, SIGABRT));
 
        /* NOTREACHED */
        return 0;
 }
-
 
 int
 copyargs(struct lwp *l, struct exec_package *pack, struct ps_strings *arginfo,
     char **stackp, void *argp)
 {

Index: src/sys/kern/kern_proc.c
===================================================================
--- src/sys/kern/kern_proc.c
+++ src/sys/kern/kern_proc.c
@@ -1831,40 +1831,63 @@
                kmem_free(marker, sizeof(*marker));
        sysctl_relock();
        return error;
 }
 
+int
+copyin_psstrings(struct proc *p, struct ps_strings *arginfo)
+{
+       struct ps_strings32 arginfo32;
+       int error;
+
+       if (p->p_flag & PK_32) {
+               error = copyin_proc(p, (void *)p->p_psstrp, &arginfo32,
+                   sizeof(arginfo32));
+               if (error)
+                       return error;
+               arginfo->ps_argvstr = (void *)(uintptr_t)arginfo32.ps_argvstr;
+               arginfo->ps_nargvstr = arginfo32.ps_nargvstr;
+               arginfo->ps_envstr = (void *)(uintptr_t)arginfo32.ps_envstr;
+               arginfo->ps_nenvstr = arginfo32.ps_nenvstr;
+       } else {
+               error = copyin_proc(p, (void *)p->p_psstrp, arginfo,
+                   sizeof(*arginfo));
+               if (error)
+                       return error;
+       }
+       return 0;
+}
+
+static int
+copy_procargs_sysctl_cb(void *cookie_, const void *src, size_t off, size_t len)
+{
+       void **cookie = cookie_;
+       struct lwp *l = cookie[0];
+       char *dst = cookie[1];
+
+       return sysctl_copyout(l, src, dst + off, len);
+}
+
 /*
  * sysctl helper routine for kern.proc_args pseudo-subtree.
  */
 static int
 sysctl_kern_proc_args(SYSCTLFN_ARGS)
 {
        struct ps_strings pss;
        struct proc *p;
-       size_t len, i;
-       struct uio auio;
-       struct iovec aiov;
        pid_t pid;
-       int nargv, type, error, argvlen;
-       char *arg;
-       char **argv = NULL;
-       char *tmp;
-       struct vmspace *vmspace;
-       vaddr_t psstr_addr;
-       vaddr_t offsetn;
-       vaddr_t offsetv;
+       int type, error;
+       void *cookie[2];
 
        if (namelen == 1 && name[0] == CTL_QUERY)
                return (sysctl_query(SYSCTLFN_CALL(rnode)));
 
        if (newp != NULL || namelen != 2)
                return (EINVAL);
        pid = name[0];
        type = name[1];
-       argv = NULL;
-       argvlen = 0;
 
        switch (type) {
        case KERN_PROC_ARGV:
        case KERN_PROC_NARGV:
        case KERN_PROC_ENV:
@@ -1917,107 +1940,136 @@
                error = EINVAL;
                mutex_exit(p->p_lock);
                goto out_locked;
        }
 
-       /*
-        * Lock the process down in memory.
-        */
-       psstr_addr = (vaddr_t)p->p_psstr;
-       if (type == KERN_PROC_ARGV || type == KERN_PROC_NARGV) {
-               offsetn = p->p_psnargv;
-               offsetv = p->p_psargv;
-       } else {
-               offsetn = p->p_psnenv;
-               offsetv = p->p_psenv;
-       }
-       vmspace = p->p_vmspace;
-       uvmspace_addref(vmspace);
+       rw_enter(&p->p_reflock, RW_READER);
        mutex_exit(p->p_lock);
        mutex_exit(proc_lock);
 
+       if (type == KERN_PROC_NARGV || type == KERN_PROC_NENV) {
+               int value;
+               if ((error = copyin_psstrings(p, &pss)) == 0) {
+                       if (type == KERN_PROC_NARGV)
+                               value = pss.ps_nargvstr;
+                       else
+                               value = pss.ps_nenvstr;
+                       error = sysctl_copyout(l, &value, oldp, sizeof(value));
+                       *oldlenp = sizeof(value);
+               }
+       } else {
+               cookie[0] = l;
+               cookie[1] = oldp;
+               error = copy_procargs(p, type, oldlenp,
+                   copy_procargs_sysctl_cb, cookie);
+       }
+       rw_exit(&p->p_reflock);
+       sysctl_relock();
+       return error;
+
+out_locked:
+       mutex_exit(proc_lock);
+       sysctl_relock();
+       return error;
+}
+
+int
+copy_procargs(struct proc *p, int oid, size_t *limit,
+    int (*cb)(void *, const void *, size_t, size_t), void *cookie)
+{
+       struct ps_strings pss;
+       size_t len, i, loaded, entry_len;
+       struct uio auio;
+       struct iovec aiov;
+       int error, argvlen;
+       char *arg;
+       char **argv;
+       vaddr_t user_argv;
+       struct vmspace *vmspace;
+
        /*
-        * Allocate a temporary buffer to hold the arguments.
+        * Allocate a temporary buffer to hold the argument vector and
+        * the arguments themselve.
         */
        arg = kmem_alloc(PAGE_SIZE, KM_SLEEP);
+       argv = kmem_alloc(PAGE_SIZE, KM_SLEEP);
+
+       /*
+        * Lock the process down in memory.
+        */
+       vmspace = p->p_vmspace;
+       uvmspace_addref(vmspace);
 
        /*
         * Read in the ps_strings structure.
         */
-       aiov.iov_base = &pss;
-       aiov.iov_len = sizeof(pss);
-       auio.uio_iov = &aiov;
-       auio.uio_iovcnt = 1;
-       auio.uio_offset = psstr_addr;
-       auio.uio_resid = sizeof(pss);
-       auio.uio_rw = UIO_READ;
-       UIO_SETUP_SYSSPACE(&auio);
-       error = uvm_io(&vmspace->vm_map, &auio);
-       if (error)
+       if ((error = copyin_psstrings(p, &pss)) != 0)
                goto done;
 
-       memcpy(&nargv, (char *)&pss + offsetn, sizeof(nargv));
-       if (type == KERN_PROC_NARGV || type == KERN_PROC_NENV) {
-               error = sysctl_copyout(l, &nargv, oldp, sizeof(nargv));
-               *oldlenp = sizeof(nargv);
-               goto done;
-       }
        /*
         * Now read the address of the argument vector.
         */
-       switch (type) {
+       switch (oid) {
        case KERN_PROC_ARGV:
-               /* FALLTHROUGH */
+               user_argv = (uintptr_t)pss.ps_argvstr;
+               argvlen = pss.ps_nargvstr;
+               break;
        case KERN_PROC_ENV:
-               memcpy(&tmp, (char *)&pss + offsetv, sizeof(tmp));
+               user_argv = (uintptr_t)pss.ps_envstr;
+               argvlen = pss.ps_nenvstr;
                break;
        default:
                error = EINVAL;
                goto done;
        }
 
+       if (argvlen < 0) {
+               error = EIO;
+               goto done;
+       }
+
 #ifdef COMPAT_NETBSD32
        if (p->p_flag & PK_32)
-               len = sizeof(netbsd32_charp) * nargv;
+               entry_len = sizeof(netbsd32_charp);
        else
 #endif
-               len = sizeof(char *) * nargv;
-
-       if ((argvlen = len) != 0)
-               argv = kmem_alloc(len, KM_SLEEP);
-
-       aiov.iov_base = argv;
-       aiov.iov_len = len;
-       auio.uio_iov = &aiov;
-       auio.uio_iovcnt = 1;
-       auio.uio_offset = (off_t)(unsigned long)tmp;
-       auio.uio_resid = len;
-       auio.uio_rw = UIO_READ;
-       UIO_SETUP_SYSSPACE(&auio);
-       error = uvm_io(&vmspace->vm_map, &auio);
-       if (error)
-               goto done;
+               entry_len = sizeof(char *);
 
        /*
         * Now copy each string.
         */
        len = 0; /* bytes written to user buffer */
-       for (i = 0; i < nargv; i++) {
+       loaded = 0; /* bytes from argv already processed */
+       i = 0; /* To make compiler happy */
+
+       for (; argvlen; --argvlen) {
                int finished = 0;
                vaddr_t base;
                size_t xlen;
                int j;
+
+               if (loaded == 0) {
+                       size_t rem = entry_len * argvlen;
+                       loaded = MIN(rem, PAGE_SIZE);
+                       error = copyin_vmspace(vmspace,
+                           (const void *)user_argv, argv, loaded);
+                       if (error)
+                               break;
+                       user_argv += loaded;
+                       i = 0;
+               }
 
 #ifdef COMPAT_NETBSD32
                if (p->p_flag & PK_32) {
                        netbsd32_charp *argv32;
 
                        argv32 = (netbsd32_charp *)argv;
-                       base = (vaddr_t)NETBSD32PTR64(argv32[i]);
+                       base = (vaddr_t)NETBSD32PTR64(argv32[i++]);
                } else
 #endif
-                       base = (vaddr_t)argv[i];
+                       base = (vaddr_t)argv[i++];
+               loaded -= entry_len;
 
                /*
                 * The program has messed around with its arguments,
                 * possibly deleting some, and replacing them with
                 * NULL's. Treat this as the last argument and not
@@ -2049,40 +2101,33 @@
                                        break;
                                }
                        }
 
                        /* Check for user buffer overflow */
-                       if (len + xlen > *oldlenp) {
+                       if (len + xlen > *limit) {
                                finished = 1;
-                               if (len > *oldlenp)
+                               if (len > *limit)
                                        xlen = 0;
                                else
-                                       xlen = *oldlenp - len;
+                                       xlen = *limit - len;
                        }
 
                        /* Copyout the page */
-                       error = sysctl_copyout(l, arg, (char*)oldp + len, xlen);
+                       error = (*cb)(cookie, arg, len, xlen);
                        if (error)
                                goto done;
 
                        len += xlen;
                        base += xlen;
                }
        }
-       *oldlenp = len;
+       *limit = len;
 
 done:
-       if (argvlen != 0)
-               kmem_free(argv, argvlen);
-       uvmspace_free(vmspace);
+       kmem_free(argv, PAGE_SIZE);
        kmem_free(arg, PAGE_SIZE);
-       sysctl_relock();
-       return error;
-
-out_locked:
-       mutex_exit(proc_lock);
-       sysctl_relock();
+       uvmspace_free(vmspace);
        return error;
 }
 
 /*
  * Fill in an eproc structure for the specified process.

Index: src/sys/miscfs/procfs/procfs_cmdline.c
===================================================================
--- src/sys/miscfs/procfs/procfs_cmdline.c
+++ src/sys/miscfs/procfs/procfs_cmdline.c
@@ -38,13 +38,26 @@
 #include <sys/syslimits.h>
 #include <sys/proc.h>
 #include <sys/vnode.h>
 #include <sys/exec.h>
 #include <sys/malloc.h>
+#include <sys/sysctl.h>
 #include <miscfs/procfs/procfs.h>
 
 #include <uvm/uvm_extern.h>
+
+static int
+procfs_docmdline_helper(void *cookie, const void *src, size_t off, size_t len)
+{
+       struct uio *uio = cookie;
+       char *buf = __UNCONST(src);
+
+       buf += uio->uio_offset - off;
+       if (off + len <= uio->uio_offset)
+               return 0;
+       return uiomove(buf, off + len - uio->uio_offset, cookie);
+}
 
 /*
  * code for returning process's command line arguments
  */
 int
@@ -53,124 +66,45 @@
     struct proc *p,
     struct pfsnode *pfs,
     struct uio *uio
 )
 {
-       struct ps_strings pss;
-       int count, error;
-       size_t i, len, xlen, upper_bound;
-       struct uio auio;
-       struct iovec aiov;
-       struct vmspace *vm;
-       vaddr_t argv;
-       char *arg;
+       size_t len, start;
+       int error;
 
        /* Don't allow writing. */
        if (uio->uio_rw != UIO_READ)
                return (EOPNOTSUPP);
-
-       /*
-        * Allocate a temporary buffer to hold the arguments.
-        */
-       arg = malloc(PAGE_SIZE, M_TEMP, M_WAITOK);
 
        /*
         * Zombies don't have a stack, so we can't read their psstrings.
         * System processes also don't have a user stack.  This is what
         * ps(1) would display.
         */
        if (P_ZOMBIE(p) || (p->p_flag & PK_SYSTEM) != 0) {
-               len = snprintf(arg, PAGE_SIZE, "(%s)", p->p_comm) + 1;
-               error = uiomove_frombuf(arg, len, uio);
-               free(arg, M_TEMP);
-               return (error);
-       }
-
-       /*
-        * NOTE: Don't bother doing a process_checkioperm() here
-        * because the psstrings info is available by using ps(1),
-        * so it's not like there's anything to protect here.
-        */
-
-       /*
-        * Lock the process down in memory.
-        */
-       if ((error = proc_vmspace_getref(p, &vm)) != 0) {
-               free(arg, M_TEMP);
+               static char msg[] = "()";
+               error = 0;
+               if (0 == uio->uio_offset) {
+                       error = uiomove(msg, 1, uio);
+                       if (error)
+                               return (error);
+               }
+               len = strlen(p->p_comm);
+               if (len >= uio->uio_offset) {
+                       start = uio->uio_offset - 1;
+                       error = uiomove(p->p_comm + start, len - start, uio);
+                       if (error)
+                               return (error);
+               }
+               if (len + 2 >= uio->uio_offset) {
+                       start = uio->uio_offset - 1 - len;
+                       error = uiomove(msg + 1 + start, 2 - start, uio);
+               }
                return (error);
        }
 
-       /*
-        * Read in the ps_strings structure.
-        */
-       aiov.iov_base = &pss;
-       aiov.iov_len = sizeof(pss);
-       auio.uio_iov = &aiov;
-       auio.uio_iovcnt = 1;
-       auio.uio_offset = (vaddr_t)p->p_psstr;
-       auio.uio_resid = sizeof(pss);
-       auio.uio_rw = UIO_READ;
-       UIO_SETUP_SYSSPACE(&auio);
-       error = uvm_io(&vm->vm_map, &auio);
-       if (error)
-               goto bad;
+       len = uio->uio_offset + uio->uio_resid;
 
-       /*
-        * Now read the address of the argument vector.
-        */
-       aiov.iov_base = &argv;
-       aiov.iov_len = sizeof(argv);
-       auio.uio_iov = &aiov;
-       auio.uio_iovcnt = 1;
-       auio.uio_offset = (vaddr_t)pss.ps_argvstr;
-       auio.uio_resid = sizeof(argv);
-       auio.uio_rw = UIO_READ;
-       UIO_SETUP_SYSSPACE(&auio);
-       error = uvm_io(&vm->vm_map, &auio);
-       if (error)
-               goto bad;
-
-       /*
-        * Now copy in the actual argument vector, one page at a time,
-        * since we don't know how long the vector is (though, we do
-        * know how many NUL-terminated strings are in the vector).
-        */
-       len = 0;
-       count = pss.ps_nargvstr;
-       upper_bound = round_page(uio->uio_offset + uio->uio_resid);
-       for (; count && len < upper_bound; len += xlen) {
-               aiov.iov_base = arg;
-               aiov.iov_len = PAGE_SIZE;
-               auio.uio_iov = &aiov;
-               auio.uio_iovcnt = 1;
-               auio.uio_offset = argv + len;
-               xlen = PAGE_SIZE - ((argv + len) & PAGE_MASK);
-               auio.uio_resid = xlen;
-               auio.uio_rw = UIO_READ;
-               UIO_SETUP_SYSSPACE(&auio);
-               error = uvm_io(&vm->vm_map, &auio);
-               if (error)
-                       goto bad;
-
-               for (i = 0; i < xlen && count != 0; i++) {
-                       if (arg[i] == '\0')
-                               count--;        /* one full string */
-               }
-
-               if (len + i > uio->uio_offset) {
-                       /* Have data in this page, copy it out */
-                       error = uiomove(arg + uio->uio_offset - len,
-                           i + len - uio->uio_offset, uio);
-                       if (error || uio->uio_resid <= 0)
-                               break;
-               }
-       }
-
- bad:
-       /*
-        * Release the process.
-        */
-       uvmspace_free(vm);
-
-       free(arg, M_TEMP);
-       return (error);
+       error = copy_procargs(p, KERN_PROC_ARGV, &len,
+           procfs_docmdline_helper, uio);
+       return error;
 }

Index: src/sys/sys/exec.h
===================================================================
--- src/sys/sys/exec.h
+++ src/sys/sys/exec.h
@@ -113,10 +113,19 @@
        int     ps_nargvstr;    /* the number of argument strings */
        char    **ps_envstr;    /* first of 0 or more environment strings */
        int     ps_nenvstr;     /* the number of environment strings */
 };
 
+#ifdef _KERNEL
+struct ps_strings32 {
+       uint32_t        ps_argvstr;     /* first of 0 or more argument strings 
*/
+       int32_t         ps_nargvstr;    /* the number of argument strings */
+       uint32_t        ps_envstr;      /* first of 0 or more environment 
strings */
+       int32_t         ps_nenvstr;     /* the number of environment strings */
+};
+#endif
+
 /*
  * the following structures allow execve() to put together processes
  * in a more extensible and cleaner way.
  *
  * the exec_package struct defines an executable being execve()'d.
@@ -243,10 +252,13 @@
 int    vmcmd_map_readvn        (struct lwp *, struct exec_vmcmd *);
 int    vmcmd_readvn            (struct lwp *, struct exec_vmcmd *);
 int    vmcmd_map_zero          (struct lwp *, struct exec_vmcmd *);
 int    copyargs                (struct lwp *, struct exec_package *,
                                    struct ps_strings *, char **, void *);
+int    copyin_psstrings        (struct proc *, struct ps_strings *);
+int    copy_procargs           (struct proc *, int, size_t *,
+    int (*)(void *, const void *, size_t, size_t), void *);
 void   setregs                 (struct lwp *, struct exec_package *, vaddr_t);
 int    check_veriexec          (struct lwp *, struct vnode *,
                                     struct exec_package *, int);
 int    check_exec              (struct lwp *, struct exec_package *,
                                     struct pathbuf *);

Index: src/sys/sys/exec_elf.h
===================================================================
--- src/sys/sys/exec_elf.h
+++ src/sys/sys/exec_elf.h
@@ -1063,10 +1063,12 @@
 #endif
 
 #ifdef _KERNEL_OPT
 #include "opt_execfmt.h"
 #endif
+
+struct ps_strings;
 
 #ifdef EXEC_ELF32
 int    exec_elf32_makecmds(struct lwp *, struct exec_package *);
 int    elf32_copyargs(struct lwp *, struct exec_package *,
            struct ps_strings *, char **, void *);

Index: src/sys/sys/proc.h
===================================================================
--- src/sys/sys/proc.h
+++ src/sys/sys/proc.h
@@ -121,11 +121,10 @@
 
 /*
  * One structure allocated per emulation.
  */
 struct exec_package;
-struct ps_strings;
 struct ras;
 struct kauth_cred;
 
 struct emul {
        const char      *e_name;        /* Symbolic name */
@@ -306,15 +305,11 @@
        u_char          p_nice;         /* p: Process "nice" value */
        char            p_comm[MAXCOMLEN+1];
                                        /* p: basename of last exec file */
        struct pgrp     *p_pgrp;        /* l: Pointer to process group */
 
-       struct ps_strings *p_psstr;     /* :: address of process's ps_strings */
-       size_t          p_psargv;       /* :: offset of ps_argvstr in above */
-       size_t          p_psnargv;      /* :: offset of ps_nargvstr in above */
-       size_t          p_psenv;        /* :: offset of ps_envstr in above */
-       size_t          p_psnenv;       /* :: offset of ps_nenvstr in above */
+       vaddr_t         p_psstrp;       /* :: address of process's ps_strings */
        u_int           p_pax;          /* :: PAX flags */
 
 /*
  * End area that is copied on creation
  */

/*      $NetBSD$        */
/*-
 * Copyright (c) 2011 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Joerg Sonnenberger.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#include <sys/types.h>
#include <sys/exec.h>
#include <stdlib.h>
#include <unistd.h>

extern struct ps_strings *__ps_strings;

int
main(int argc, char **argv, char **environ)
{
        int ret = 0;
        int nenv;

        if (__ps_strings->ps_nargvstr != argc) {
                static const char nargv_err[] = "Wrong argc in ps_strings";
                write(STDOUT_FILENO, nargv_err, sizeof(nargv_err));
                ret = 1;
        }

        if (__ps_strings->ps_argvstr != argv) {
                static const char argv_err[] = "Wrong argv in ps_strings";
                write(STDOUT_FILENO, argv_err, sizeof(argv_err));
                ret = 1;
        }

        if (__ps_strings->ps_envstr != environ) {
                static const char env_err[] = "Wrong env in ps_strings";
                write(STDOUT_FILENO, env_err, sizeof(env_err));
                ret = 1;
        }
        nenv = 0;
        while (environ[nenv])
                ++nenv;
        if (__ps_strings->ps_nenvstr != nenv) {
                static const char nenv_err[] = "Wrong nenv in ps_strings";
                write(STDOUT_FILENO, nenv_err, sizeof(nenv_err));
                ret = 1;
        }

        return ret;
}
/*      $NetBSD$        */
/*-
 * Copyright (c) 2011 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Joerg Sonnenberger.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#include <sys/types.h>
#include <sys/exec.h>
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#define LEN     16384

extern struct ps_strings *__ps_strings;

int
main(void)
{
        size_t i;
        char c;
        char buf[16];
        char **argv;

        if ((argv = calloc(LEN, sizeof(*argv))) == NULL)
                errx(1, "calloc failed");
        for (i = 0; i < LEN; ++i) {
                snprintf(buf, sizeof(buf), "arg%04zx", i);
                if ((argv[i] = strdup(buf)) == NULL)
                        errx(1, "strdup failed");
        }
        __ps_strings->ps_argvstr = argv;
        __ps_strings->ps_nargvstr = LEN;

        read(STDIN_FILENO, &c, sizeof(c));
        return 0;
}


Home | Main Index | Thread Index | Old Index