FUNCTION VOID BRIDGE2_NAME(xrattr) ( TAEINT *block, /* in: parameter block */ FORSTR *name, /* in: parameter name */ TAEINT *type, /* out: parameter type */ TAEINT *n, /* out: number of components */ TAELOG *defalt, /* out: .TRUE. if defaulted */ TAEINT *access, /* out: access mode if a file */ TAEINT *status /* out: status code */ ) { struct PARBLK *parblk; struct VARIABLE *v; CODE code; TEXT c_name[STRINGSIZ+1]; /* name in C string format */ parblk = (struct PARBLK *) block; code = s_for2c(name, c_name, 0); /* convert name to C string */ if (code != SUCCESS) goto p__bnerr; s_strip(c_name); /* remove trailing blanks */ v = p_find(parblk,c_name); if (v == NULL) goto p__bnerr; *defalt = (*v).v_default; /* default in var is already TRUE/FALSE */ *n = (*v).v_count; *type = (*v).v_file ? P_FILE : (*v).v_type; /* file or other types */ *access = (*v).v_file ? (*v).v_filemode : P_NONE; /* none if not file */ *status = SUCCESS; return; p__bnerr: *status = P_BADNAME; return; }
FUNCTION VOID BRIDGE2_NAME(xrstr) ( TAEINT *block, /* in: parameter block */ FORSTR *name, /* in: parameter name */ TAEINT *dimen, /* in: dimension of string */ FORSTR *string, /* out: FOR-77 string(s) */ TAEINT length[], /* out: length of each string */ TAEINT *n, /* out: number of strings */ TAEINT *status /* out: status code */ ) { IMPORT TEXT pm_dim[],pk_dim[],pm_type[],pk_type[]; struct PARBLK *parblk; struct VARIABLE *v; TEXT **s; /* ptr to value vector in block */ TEXT c_name[STRINGSIZ+1]; /* name in C string format */ COUNT i; CODE code; parblk = (struct PARBLK *) block; s_for2c(name, c_name, 0); /* convert name to C string */ s_strip(c_name); /* remove trailing blanks */ *n = 0; /* caution in case error */ v = p_find(parblk, c_name); if (v == NULL) goto p__bnerr; if ((*v).v_type != V_STRING) goto p__bterr; /* error if not string */ s = (TEXT **) (*v).v_cvp; /* value pointer */ *status = SUCCESS; *n = (*v).v_count; /* number of strings */ for (i=0; i < (*v).v_count && i < *dimen; i++) { length[i] = s_length(s[i]); /* pass this length to caller */ code = s_c2for(s[i], string, i); /* copy string to caller */ if (code != SUCCESS) { x_error((*parblk).mode, "String size overflows buffer", "TAE-OVER", 0, 0, 0); *status = P_OVER; return; } } if ((*v).v_count > *dimen) { x_error((*parblk).mode, pm_dim, pk_dim,(uintptr_t) c_name, 0, 0); *status = P_BADCOUNT; /* bad count */ } return; p__bnerr: *status = P_BADNAME; return; p__bterr: *status = P_BADTYPE; x_error((*parblk).mode, pm_type, pk_type, (uintptr_t) c_name, 0, 0); return; }
/* * Send a signal to one process. */ static int kill_one(pid_t pid, int sig) { struct proc *p; DPRINTF(("proc: killone pid=%d sig=%d\n", pid, sig)); if ((p = p_find(pid)) == NULL) return ESRCH; return sendsig(p, sig); }
/* * getpgid - get the process group ID for a process. * * If the specified pid is equal to 0, it returns the process * group ID of the calling process. */ int sys_getpgid(pid_t pid, pid_t *retval) { struct proc *p; ASSERT(curproc); if (pid == 0) p = curproc; else { if ((p = p_find(pid)) == NULL) return ESRCH; } *retval = p->p_pgrp->pg_pgid; return 0; }
/* * XRINTG. Get integer parameters/variables. */ FUNCTION VOID BRIDGE2_NAME(xrintg) ( TAEINT *block, /* in: parameter block */ FORSTR *name, /* in: parameter name */ TAEINT *dimen, /* in: max # of values(dim of intg) */ int intg[], /* out: array with intger var */ TAEINT *n, /* out: integer value count */ TAEINT *status /* out: status code */ ) { IMPORT TEXT pm_dim[],pk_dim[],pm_type[],pk_type[]; struct PARBLK *parblk; struct VARIABLE *v; TEXT c_name[STRINGSIZ+1]; /* name in C string format */ COUNT i; parblk = (struct PARBLK *) block; s_for2c(name, c_name, 0); /* convert name to C string */ s_strip(c_name); /* remove trailing blanks */ *n = 0; /* caution in case error */ v = p_find(parblk, c_name); if (v == NULL) goto p__bnerr; if ((*v).v_type != V_INTEGER) goto p__bterr; if ((*v).v_count > *dimen) goto p__bcerr; *n = (*v).v_count; for (i = 0; i < (*v).v_count; i++) intg[i] = IVAL(*v, i); *status = SUCCESS; return; p__bnerr: *status = P_BADNAME; return; p__bterr: *status = P_BADTYPE; x_error((*parblk).mode, pm_type, pk_type, (uintptr_t) c_name, 0, 0); return; p__bcerr: *status = P_BADCOUNT; x_error((*parblk).mode, pm_dim, pk_dim, (uintptr_t) c_name, 0, 0); return; }
/* * getsid - get the process group ID of a session leader. */ int sys_getsid(pid_t pid, pid_t *retval) { pid_t sid; struct proc *p, *leader; ASSERT(curproc); if (pid == 0) p = curproc; else { if ((p = p_find(pid)) == NULL) return ESRCH; } leader = p->p_pgrp->pg_session->s_leader; sid = leader->p_pid; DPRINTF(("proc: getsid sid=%d\n", sid)); *retval = sid; return 0; }
/* * setpgid - set process group ID for job control. * * If the specified pid is equal to 0, the process ID of * the calling process is used. Also, if pgid is 0, the process * ID of the indicated process is used. */ int sys_setpgid(pid_t pid, pid_t pgid) { struct proc *p; DPRINTF(("proc: setpgid pid=%d pgid=%d\n", pid, pgid)); if (pid == 0) p = curproc; else { if ((p = p_find(pid)) == NULL) return ESRCH; } if (pgid < 0) return EINVAL; if (pgid == 0) pgid = p->p_pid; if (p->p_pgrp->pg_pgid == pgid) /* already leader */ return 0; return (enterpgrp(p, pgid)); }
void db_stack_trace_print(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif, void (*pr)(const char *, ...)) { register_t *fp, pc, rp; bool kernel_only = true; bool trace_thread = false; bool lwpaddr = false; db_sym_t sym; db_expr_t off; const char *name; const char *cp = modif; char c; if (count < 0) count = 65536; while ((c = *cp++) != 0) { if (c == 'a') { lwpaddr = true; trace_thread = true; } if (c == 't') trace_thread = true; if (c == 'u') kernel_only = false; } if (!have_addr) { fp = (register_t *)ddb_regs.tf_r3; pc = ddb_regs.tf_iioq_head; rp = ddb_regs.tf_rp; } else { if (trace_thread) { struct proc *p; struct user *u; struct lwp *l; if (lwpaddr) { l = (struct lwp *)addr; p = l->l_proc; (*pr)("trace: pid %d ", p->p_pid); } else { (*pr)("trace: pid %d ", (int)addr); p = p_find(addr, PFIND_LOCKED); if (p == NULL) { (*pr)("not found\n"); return; } l = LIST_FIRST(&p->p_lwps); KASSERT(l != NULL); } (*pr)("lid %d ", l->l_lid); if (!(l->l_flag & LW_INMEM)) { (*pr)("swapped out\n"); return; } u = l->l_addr; if (p == curproc && l == curlwp) { fp = (int *)ddb_regs.tf_r3; pc = ddb_regs.tf_iioq_head; rp = ddb_regs.tf_rp; } else { /* cpu_switchto fp, and return point */ fp = (int *)(u->u_pcb.pcb_ksp - (HPPA_FRAME_SIZE + 16*4)); pc = 0; rp = fp[-5]; } (*pr)("at %p\n", fp); } else { pc = 0; fp = (register_t *)addr; rp = fp[-5]; } } while (fp && count--) { #ifdef DDB_DEBUG pr(">> %08x %08x %08x\t", fp, pc, rp); #endif if (USERMODE(pc)) return; sym = db_search_symbol(pc, DB_STGY_ANY, &off); db_symbol_values (sym, &name, NULL); pr("%s() at ", name); db_printsym(pc, DB_STGY_PROC, pr); pr("\n"); /* XXX NH - unwind info here */ /* aue = ue_find(pc); */ /* * get rp? * fp -= ue_total_frame_size(aue) */ /* * if a terminal frame then report the trapframe * and continue after it (if not the last one). */ if (!fp[0]) { register_t *scargs; struct trapframe *tf; int scoff; /* Stack space for syscall args */ scoff = HPPA_FRAME_ROUND(HPPA_FRAME_SIZE + HPPA_FRAME_MAXARGS); scargs = (register_t *)((char *)fp - scoff); tf = (struct trapframe *)((char *)scargs - sizeof(*tf)); if (tf->tf_flags & TFF_SYS) pr("-- syscall #%d(%x, %x, %x, %x, ...)\n", tf->tf_t1, scargs[1], scargs[2], scargs[3], scargs[4]); else pr("-- trap #%d%s\n", tf->tf_flags & 0x3f, (tf->tf_flags & T_USER)? " from user" : ""); if (!(tf->tf_flags & TFF_LAST)) { fp = (register_t *)tf->tf_r3; pc = tf->tf_iioq_head; rp = tf->tf_rp; } else { pc = 0; fp = 0; } } else { /* next frame */ fp = (register_t *)fp[0]; pc = rp; rp = fp[-5]; } } if (count && pc) { db_printsym(pc, DB_STGY_XTRN, pr); pr(":\n"); } }
FUNCTION FILE *z_init ( #ifdef LARGE_PARBLK_FIX struct LARGE_PARBLK *block, /* out: parameter block */ #else struct PARBLK *block, /* out: parameter block */ #endif FUNINT mode /* in: mode: P_ABORT or P_CONT */ ) { IMPORT FILE *stdo_file; /* pointer to stdout file */ IMPORT BOOL term_std; /* true if terminal is stdout */ IMPORT CODE applic_type; /* application type ('c') */ IMPORT TEXT pm_type[], pk_type[]; struct VARIABLE *v; CODE termtype; COUNT termlines; COUNT termcols; TEXT msgbuf[STRINGSIZ+1]; TEXT **stdr_ptr = 0; /* stdrec string vector pointer */ COUNT len; CODE code; TEXT filemode[2]; /* create or append */ FILE *stdo_ptr; t_init(&termlines, &termcols, &termtype); /* initialize terminal pkg */ #ifdef LARGE_PARBLK_FIX code = p_inim((struct PARBLK *)block, sizeof(struct LARGE_PARBLK), mode); #else code = p_inim(block, sizeof(struct PARBLK), mode); #endif /* receive parblk from TM */ if (code != SUCCESS) return (NULL); z_call ((struct PARBLK *)block); /* application init */ v = p_find ((struct PARBLK *)block, "_STDOUT"); /* get the string */ if ((*v).v_type != V_STRING) x_error ((*block).mode, pm_type, pk_type, (uintptr_t) "_STDOUT", 0, 0); else stdr_ptr = (TEXT **) (*v).v_cvp; /* get value pointer */ term_std = (s_equal(TERMINAL, stdr_ptr[0])); /* filename = terminal ? */ #ifdef VICAR_BATCH_LOG #ifdef VAX_VMS if (s_equal("SYS$OUTPUT:.;", stdr_ptr[0])) /* alternate form of terminal */ term_std = TRUE; #endif #endif s_copy("w", filemode); /* assume create */ if (!s_equal(stdr_ptr[1] , "CREATE")) s_copy("a", filemode); #ifdef UNIX s_lower(stdr_ptr[0]); /* make file name lower case */ #endif stdo_ptr = fopen(stdr_ptr[0], filemode); /* open the file */ if (stdo_ptr == NULL) { if (mode == P_ABORT) { len = s_copy("Could not open standard output file ", msgbuf); s_bcopy(stdr_ptr[0], &msgbuf[len], STRINGSIZ); t_write(msgbuf, T_STDCC); /* errmsg to terminal*/ z_exit(-1, "TAE-STDOPEN"); /* set SFI, SKEY */ } stdo_ptr = stdout; /* Allow running with no terminal! */ /* (without triggering shell-vicar) */ } else stdo_file = stdo_ptr; /* save stdout ptr globally */ applic_type = C_TYPE; /* 'c' language application */ return (stdo_ptr); }
/* * Process debugging system call. */ int sys_ptrace(struct lwp *l, const struct sys_ptrace_args *uap, register_t *retval) { /* { syscallarg(int) req; syscallarg(pid_t) pid; syscallarg(void *) addr; syscallarg(int) data; } */ struct proc *p = l->l_proc; struct lwp *lt; struct proc *t; /* target process */ struct uio uio; struct iovec iov; struct ptrace_io_desc piod; struct ptrace_lwpinfo pl; struct vmspace *vm; int error, write, tmp, req, pheld; int signo; ksiginfo_t ksi; #ifdef COREDUMP char *path; #endif error = 0; req = SCARG(uap, req); /* * If attaching or detaching, we need to get a write hold on the * proclist lock so that we can re-parent the target process. */ mutex_enter(proc_lock); /* "A foolish consistency..." XXX */ if (req == PT_TRACE_ME) { t = p; mutex_enter(t->p_lock); } else { /* Find the process we're supposed to be operating on. */ if ((t = p_find(SCARG(uap, pid), PFIND_LOCKED)) == NULL) { mutex_exit(proc_lock); return (ESRCH); } /* XXX-elad */ mutex_enter(t->p_lock); error = kauth_authorize_process(l->l_cred, KAUTH_PROCESS_CANSEE, t, KAUTH_ARG(KAUTH_REQ_PROCESS_CANSEE_ENTRY), NULL, NULL); if (error) { mutex_exit(proc_lock); mutex_exit(t->p_lock); return (ESRCH); } } /* * Grab a reference on the process to prevent it from execing or * exiting. */ if (!rw_tryenter(&t->p_reflock, RW_READER)) { mutex_exit(proc_lock); mutex_exit(t->p_lock); return EBUSY; } /* Make sure we can operate on it. */ switch (req) { case PT_TRACE_ME: /* Saying that you're being traced is always legal. */ break; case PT_ATTACH: /* * You can't attach to a process if: * (1) it's the process that's doing the attaching, */ if (t->p_pid == p->p_pid) { error = EINVAL; break; } /* * (2) it's a system process */ if (t->p_flag & PK_SYSTEM) { error = EPERM; break; } /* * (3) it's already being traced, or */ if (ISSET(t->p_slflag, PSL_TRACED)) { error = EBUSY; break; } /* * (4) the tracer is chrooted, and its root directory is * not at or above the root directory of the tracee */ mutex_exit(t->p_lock); /* XXXSMP */ tmp = proc_isunder(t, l); mutex_enter(t->p_lock); /* XXXSMP */ if (!tmp) { error = EPERM; break; } break; case PT_READ_I: case PT_READ_D: case PT_WRITE_I: case PT_WRITE_D: case PT_IO: #ifdef PT_GETREGS case PT_GETREGS: #endif #ifdef PT_SETREGS case PT_SETREGS: #endif #ifdef PT_GETFPREGS case PT_GETFPREGS: #endif #ifdef PT_SETFPREGS case PT_SETFPREGS: #endif #ifdef __HAVE_PTRACE_MACHDEP PTRACE_MACHDEP_REQUEST_CASES #endif /* * You can't read/write the memory or registers of a process * if the tracer is chrooted, and its root directory is not at * or above the root directory of the tracee. */ mutex_exit(t->p_lock); /* XXXSMP */ tmp = proc_isunder(t, l); mutex_enter(t->p_lock); /* XXXSMP */ if (!tmp) { error = EPERM; break; } /*FALLTHROUGH*/ case PT_CONTINUE: case PT_KILL: case PT_DETACH: case PT_LWPINFO: case PT_SYSCALL: #ifdef COREDUMP case PT_DUMPCORE: #endif #ifdef PT_STEP case PT_STEP: #endif /* * You can't do what you want to the process if: * (1) It's not being traced at all, */ if (!ISSET(t->p_slflag, PSL_TRACED)) { error = EPERM; break; } /* * (2) it's being traced by procfs (which has * different signal delivery semantics), */ if (ISSET(t->p_slflag, PSL_FSTRACE)) { uprintf("file system traced\n"); error = EBUSY; break; } /* * (3) it's not being traced by _you_, or */ if (t->p_pptr != p) { uprintf("parent %d != %d\n", t->p_pptr->p_pid, p->p_pid); error = EBUSY; break; } /* * (4) it's not currently stopped. */ if (t->p_stat != SSTOP || !t->p_waited /* XXXSMP */) { uprintf("stat %d flag %d\n", t->p_stat, !t->p_waited); error = EBUSY; break; } break; default: /* It was not a legal request. */ error = EINVAL; break; } if (error == 0) error = kauth_authorize_process(l->l_cred, KAUTH_PROCESS_PTRACE, t, KAUTH_ARG(req), NULL, NULL); if (error != 0) { mutex_exit(proc_lock); mutex_exit(t->p_lock); rw_exit(&t->p_reflock); return error; } /* Do single-step fixup if needed. */ FIX_SSTEP(t); /* * XXX NJWLWP * * The entire ptrace interface needs work to be useful to a * process with multiple LWPs. For the moment, we'll kluge * this; memory access will be fine, but register access will * be weird. */ lt = LIST_FIRST(&t->p_lwps); KASSERT(lt != NULL); lwp_addref(lt); /* * Which locks do we need held? XXX Ugly. */ switch (req) { #ifdef PT_STEP case PT_STEP: #endif case PT_CONTINUE: case PT_DETACH: case PT_KILL: case PT_SYSCALL: case PT_ATTACH: case PT_TRACE_ME: pheld = 1; break; default: mutex_exit(proc_lock); mutex_exit(t->p_lock); pheld = 0; break; } /* Now do the operation. */ write = 0; *retval = 0; tmp = 0; switch (req) { case PT_TRACE_ME: /* Just set the trace flag. */ SET(t->p_slflag, PSL_TRACED); t->p_opptr = t->p_pptr; break; case PT_WRITE_I: /* XXX no separate I and D spaces */ case PT_WRITE_D: #if defined(__HAVE_RAS) /* * Can't write to a RAS */ if (ras_lookup(t, SCARG(uap, addr)) != (void *)-1) { error = EACCES; break; } #endif write = 1; tmp = SCARG(uap, data); /* FALLTHROUGH */ case PT_READ_I: /* XXX no separate I and D spaces */ case PT_READ_D: /* write = 0 done above. */ iov.iov_base = (void *)&tmp; iov.iov_len = sizeof(tmp); uio.uio_iov = &iov; uio.uio_iovcnt = 1; uio.uio_offset = (off_t)(unsigned long)SCARG(uap, addr); uio.uio_resid = sizeof(tmp); uio.uio_rw = write ? UIO_WRITE : UIO_READ; UIO_SETUP_SYSSPACE(&uio); error = process_domem(l, lt, &uio); if (!write) *retval = tmp; break; case PT_IO: error = copyin(SCARG(uap, addr), &piod, sizeof(piod)); if (error) break; switch (piod.piod_op) { case PIOD_READ_D: case PIOD_READ_I: uio.uio_rw = UIO_READ; break; case PIOD_WRITE_D: case PIOD_WRITE_I: /* * Can't write to a RAS */ if (ras_lookup(t, SCARG(uap, addr)) != (void *)-1) { return (EACCES); } uio.uio_rw = UIO_WRITE; break; default: error = EINVAL; break; } if (error) break; error = proc_vmspace_getref(l->l_proc, &vm); if (error) break; iov.iov_base = piod.piod_addr; iov.iov_len = piod.piod_len; uio.uio_iov = &iov; uio.uio_iovcnt = 1; uio.uio_offset = (off_t)(unsigned long)piod.piod_offs; uio.uio_resid = piod.piod_len; uio.uio_vmspace = vm; error = process_domem(l, lt, &uio); piod.piod_len -= uio.uio_resid; (void) copyout(&piod, SCARG(uap, addr), sizeof(piod)); uvmspace_free(vm); break; #ifdef COREDUMP case PT_DUMPCORE: if ((path = SCARG(uap, addr)) != NULL) { char *dst; int len = SCARG(uap, data); if (len < 0 || len >= MAXPATHLEN) { error = EINVAL; break; } dst = malloc(len + 1, M_TEMP, M_WAITOK); if ((error = copyin(path, dst, len)) != 0) { free(dst, M_TEMP); break; } path = dst; path[len] = '\0'; } error = coredump(lt, path); if (path) free(path, M_TEMP); break; #endif #ifdef PT_STEP case PT_STEP: /* * From the 4.4BSD PRM: * "Execution continues as in request PT_CONTINUE; however * as soon as possible after execution of at least one * instruction, execution stops again. [ ... ]" */ #endif case PT_CONTINUE: case PT_SYSCALL: case PT_DETACH: if (req == PT_SYSCALL) { if (!ISSET(t->p_slflag, PSL_SYSCALL)) { SET(t->p_slflag, PSL_SYSCALL); #ifdef __HAVE_SYSCALL_INTERN (*t->p_emul->e_syscall_intern)(t); #endif } } else { if (ISSET(t->p_slflag, PSL_SYSCALL)) { CLR(t->p_slflag, PSL_SYSCALL); #ifdef __HAVE_SYSCALL_INTERN (*t->p_emul->e_syscall_intern)(t); #endif } } p->p_trace_enabled = trace_is_enabled(p); /* * From the 4.4BSD PRM: * "The data argument is taken as a signal number and the * child's execution continues at location addr as if it * incurred that signal. Normally the signal number will * be either 0 to indicate that the signal that caused the * stop should be ignored, or that value fetched out of * the process's image indicating which signal caused * the stop. If addr is (int *)1 then execution continues * from where it stopped." */ /* Check that the data is a valid signal number or zero. */ if (SCARG(uap, data) < 0 || SCARG(uap, data) >= NSIG) { error = EINVAL; break; } uvm_lwp_hold(lt); /* If the address parameter is not (int *)1, set the pc. */ if ((int *)SCARG(uap, addr) != (int *)1) if ((error = process_set_pc(lt, SCARG(uap, addr))) != 0) { uvm_lwp_rele(lt); break; } #ifdef PT_STEP /* * Arrange for a single-step, if that's requested and possible. */ error = process_sstep(lt, req == PT_STEP); if (error) { uvm_lwp_rele(lt); break; } #endif uvm_lwp_rele(lt); if (req == PT_DETACH) { CLR(t->p_slflag, PSL_TRACED|PSL_FSTRACE|PSL_SYSCALL); /* give process back to original parent or init */ if (t->p_opptr != t->p_pptr) { struct proc *pp = t->p_opptr; proc_reparent(t, pp ? pp : initproc); } /* not being traced any more */ t->p_opptr = NULL; } signo = SCARG(uap, data); sendsig: /* Finally, deliver the requested signal (or none). */ if (t->p_stat == SSTOP) { /* * Unstop the process. If it needs to take a * signal, make all efforts to ensure that at * an LWP runs to see it. */ t->p_xstat = signo; proc_unstop(t); } else if (signo != 0) { KSI_INIT_EMPTY(&ksi); ksi.ksi_signo = signo; kpsignal2(t, &ksi); } break; case PT_KILL: /* just send the process a KILL signal. */ signo = SIGKILL; goto sendsig; /* in PT_CONTINUE, above. */ case PT_ATTACH: /* * Go ahead and set the trace flag. * Save the old parent (it's reset in * _DETACH, and also in kern_exit.c:wait4() * Reparent the process so that the tracing * proc gets to see all the action. * Stop the target. */ t->p_opptr = t->p_pptr; if (t->p_pptr != p) { struct proc *parent = t->p_pptr; if (parent->p_lock < t->p_lock) { if (!mutex_tryenter(parent->p_lock)) { mutex_exit(t->p_lock); mutex_enter(parent->p_lock); } } else if (parent->p_lock > t->p_lock) { mutex_enter(parent->p_lock); } parent->p_slflag |= PSL_CHTRACED; proc_reparent(t, p); if (parent->p_lock != t->p_lock) mutex_exit(parent->p_lock); } SET(t->p_slflag, PSL_TRACED); signo = SIGSTOP; goto sendsig; case PT_LWPINFO: if (SCARG(uap, data) != sizeof(pl)) { error = EINVAL; break; } error = copyin(SCARG(uap, addr), &pl, sizeof(pl)); if (error) break; tmp = pl.pl_lwpid; lwp_delref(lt); mutex_enter(t->p_lock); if (tmp == 0) lt = LIST_FIRST(&t->p_lwps); else { lt = lwp_find(t, tmp); if (lt == NULL) { mutex_exit(t->p_lock); error = ESRCH; break; } lt = LIST_NEXT(lt, l_sibling); } while (lt != NULL && lt->l_stat == LSZOMB) lt = LIST_NEXT(lt, l_sibling); pl.pl_lwpid = 0; pl.pl_event = 0; if (lt) { lwp_addref(lt); pl.pl_lwpid = lt->l_lid; if (lt->l_lid == t->p_sigctx.ps_lwp) pl.pl_event = PL_EVENT_SIGNAL; } mutex_exit(t->p_lock); error = copyout(&pl, SCARG(uap, addr), sizeof(pl)); break; #ifdef PT_SETREGS case PT_SETREGS: write = 1; #endif #ifdef PT_GETREGS case PT_GETREGS: /* write = 0 done above. */ #endif #if defined(PT_SETREGS) || defined(PT_GETREGS) tmp = SCARG(uap, data); if (tmp != 0 && t->p_nlwps > 1) { lwp_delref(lt); mutex_enter(t->p_lock); lt = lwp_find(t, tmp); if (lt == NULL) { mutex_exit(t->p_lock); error = ESRCH; break; } lwp_addref(lt); mutex_exit(t->p_lock); } if (!process_validregs(lt)) error = EINVAL; else { error = proc_vmspace_getref(l->l_proc, &vm); if (error) break; iov.iov_base = SCARG(uap, addr); iov.iov_len = sizeof(struct reg); uio.uio_iov = &iov; uio.uio_iovcnt = 1; uio.uio_offset = 0; uio.uio_resid = sizeof(struct reg); uio.uio_rw = write ? UIO_WRITE : UIO_READ; uio.uio_vmspace = vm; error = process_doregs(l, lt, &uio); uvmspace_free(vm); } break; #endif #ifdef PT_SETFPREGS case PT_SETFPREGS: write = 1; #endif #ifdef PT_GETFPREGS case PT_GETFPREGS: /* write = 0 done above. */ #endif #if defined(PT_SETFPREGS) || defined(PT_GETFPREGS) tmp = SCARG(uap, data); if (tmp != 0 && t->p_nlwps > 1) { lwp_delref(lt); mutex_enter(t->p_lock); lt = lwp_find(t, tmp); if (lt == NULL) { mutex_exit(t->p_lock); error = ESRCH; break; } lwp_addref(lt); mutex_exit(t->p_lock); } if (!process_validfpregs(lt)) error = EINVAL; else { error = proc_vmspace_getref(l->l_proc, &vm); if (error) break; iov.iov_base = SCARG(uap, addr); iov.iov_len = sizeof(struct fpreg); uio.uio_iov = &iov; uio.uio_iovcnt = 1; uio.uio_offset = 0; uio.uio_resid = sizeof(struct fpreg); uio.uio_rw = write ? UIO_WRITE : UIO_READ; uio.uio_vmspace = vm; error = process_dofpregs(l, lt, &uio); uvmspace_free(vm); } break; #endif #ifdef __HAVE_PTRACE_MACHDEP PTRACE_MACHDEP_REQUEST_CASES error = ptrace_machdep_dorequest(l, lt, req, SCARG(uap, addr), SCARG(uap, data)); break; #endif } if (pheld) { mutex_exit(t->p_lock); mutex_exit(proc_lock); } if (lt != NULL) lwp_delref(lt); rw_exit(&t->p_reflock); return error; }
FUNCTION VOID BRIDGE2_NAME(xrfile) ( TAEINT *block, /* in: parameter block */ FORSTR *name, /* in: parameter name */ TAEINT *dimen, /* in: dimension of string */ FORSTR *tae_file, /* out: FOR-77 tae file string(s) */ TAEINT tae_length[], /* out: length of each tae file string */ FORSTR *host_file, /* out: FOR-77 host file string(s) */ TAEINT host_length[], /* out: length of each host file string */ TAEINT *n, /* out: number of strings */ TAEINT *status /* out: status code */ ) { struct PARBLK *parblk; TEXT **s; /* ptr to value vector in block */ TEXT c_name[STRINGSIZ+1]; /* name in C string format */ COUNT i; struct VARIABLE *v; /* variable in parm block */ TEXT temp[FSPECSIZ+1]; TAEINT filemode; CODE code; parblk = (struct PARBLK *) block; s_for2c(name, c_name, 0); /* convert name to C string */ s_strip(c_name); /* remove trailing blanks */ *n = 0; /* caution in case error */ v = p_find(parblk, c_name); /* get string */ if (v == NULL) goto p__bnerr; /* check for name error */ if ((*v).v_type != V_STRING) goto p__bterr; /* check for type error */ s = (TEXT **) (*v).v_cvp; /* value pointer */ if (!(*v).v_file) goto p__bterr; filemode = (*v).v_filemode; *status = SUCCESS; *n = (*v).v_count; /* number of strings */ for (i=0; i < (*v).v_count && i < *dimen; i++) /* get all tae & host files */ { tae_length[i] = s_length(s[i]); /* pass this length to caller */ code = s_c2for(s[i], tae_file, i); /* copy tae file to caller*/ if (code != SUCCESS) { x_error((*parblk).mode, "File name longer than buffer size.", "TAE-OVER", 0, 0, 0); *status = P_OVER; return; } xzhost(s[i], temp, &filemode, status); /* get host spec */ if (*status != SUCCESS) { x_error((*parblk).mode, (TEXT *) pm_trans, (TEXT *) pk_trans, (uintptr_t) s[i], 0, 0); *status = P_FAIL; /* failed to translate */ return; } host_length[i] = s_length(temp); /* pass this length to caller */ s_c2for(temp, host_file, i); /* copy host file to caller */ } if ((*v).v_count > *dimen) *status = P_BADCOUNT; /* bad count */ return; p__bnerr: *status = P_BADNAME; return; p__bterr: x_error((*parblk).mode, (TEXT *) pm_type, (TEXT *) pk_type, (uintptr_t) (*v).v_name, 0, 0); *status = P_BADTYPE; return; }
void db_stack_trace_print(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif, void (*pr)(const char *, ...)) { struct frame *frame, *prevframe; db_addr_t pc; bool kernel_only = true; bool trace_thread = false; bool lwpaddr = false; const char *cp = modif; char c; if (ddb_cpuinfo == NULL) ddb_cpuinfo = curcpu(); while ((c = *cp++) != 0) { if (c == 'a') { lwpaddr = true; trace_thread = true; } if (c == 't') trace_thread = true; if (c == 'u') kernel_only = false; } if (!have_addr) { frame = (struct frame *)DDB_TF->tf_out[6]; pc = DDB_TF->tf_pc; } else { if (trace_thread) { struct proc *p; struct user *u; struct lwp *l; if (lwpaddr) { l = (struct lwp *)addr; p = l->l_proc; (*pr)("trace: pid %d ", p->p_pid); } else { (*pr)("trace: pid %d ", (int)addr); p = p_find(addr, PFIND_LOCKED); if (p == NULL) { (*pr)("not found\n"); return; } l = LIST_FIRST(&p->p_lwps); KASSERT(l != NULL); } (*pr)("lid %d ", l->l_lid); if ((l->l_flag & LW_INMEM) == 0) { (*pr)("swapped out\n"); return; } u = l->l_addr; frame = (struct frame *)u->u_pcb.pcb_sp; pc = u->u_pcb.pcb_pc; (*pr)("at %p\n", frame); } else { frame = (struct frame *)addr; pc = 0; } } while (count--) { int i; db_expr_t offset; const char *name; db_addr_t prevpc; #define FR(framep,field) (INKERNEL(framep) \ ? (u_int)(framep)->field \ : fuword(&(framep)->field)) /* Fetch return address and arguments frame */ prevpc = (db_addr_t)FR(frame, fr_pc); prevframe = (struct frame *)FR(frame, fr_fp); /* * Switch to frame that contains arguments */ if (prevframe == NULL || (!INKERNEL(prevframe) && kernel_only)) return; if ((ONINTSTACK(frame) && !ONINTSTACK(prevframe)) || (INKERNEL(frame) && !INKERNEL(prevframe))) { /* We're crossing a trap frame; pc = %l1 */ prevpc = (db_addr_t)FR(frame, fr_local[1]); } name = NULL; if (INKERNEL(pc)) db_find_sym_and_offset(pc, &name, &offset); if (name == NULL) (*pr)("0x%lx(", pc); else (*pr)("%s(", name); /* * Print %i0..%i5, hope these still reflect the * actual arguments somewhat... */ for (i = 0; i < 6; i++) (*pr)("0x%x%s", FR(frame, fr_arg[i]), (i < 5) ? ", " : ") at "); if (INKERNEL(prevpc)) db_printsym(prevpc, DB_STGY_PROC, pr); else (*pr)("0x%lx", prevpc); (*pr)("\n"); pc = prevpc; frame = prevframe; } }
void db_stack_trace_print(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif, void (*pr)(const char *, ...)) { #ifndef DDB_TRACE struct pcb *pcb; struct proc *p; struct lwp *l; if (!have_addr) { stacktrace_subr(ddb_regs.f_regs[_R_A0], ddb_regs.f_regs[_R_A1], ddb_regs.f_regs[_R_A2], ddb_regs.f_regs[_R_A3], ddb_regs.f_regs[_R_PC], ddb_regs.f_regs[_R_SP], /* non-virtual frame pointer */ ddb_regs.f_regs[_R_S8], ddb_regs.f_regs[_R_RA], pr); return; } /* "trace/t" */ (*pr)("pid %d ", (int)addr); p = p_find(addr, PFIND_LOCKED); if (p == NULL) { (*pr)("not found\n"); return; } l = LIST_FIRST(&p->p_lwps); /* XXX NJWLWP */ if (!(l->l_flag & LW_INMEM)) { (*pr)("swapped out\n"); return; } pcb = &(l->l_addr->u_pcb); (*pr)("at %p\n", pcb); stacktrace_subr(0,0,0,0, /* no args known */ (int)cpu_switchto, pcb->pcb_context[8], pcb->pcb_context[9], pcb->pcb_context[10], pr); #else /* * Incomplete but practically useful stack backtrace. */ #define MIPS_JR_RA 0x03e00008 /* instruction code for jr ra */ #define MIPS_JR_K0 0x03400008 /* instruction code for jr k0 */ #define MIPS_ERET 0x42000018 /* instruction code for eret */ unsigned va, pc, ra, sp, func; int insn; InstFmt i; int stacksize; db_addr_t offset; const char *name; extern char verylocore[]; pc = ddb_regs.f_regs[_R_PC]; sp = ddb_regs.f_regs[_R_SP]; ra = ddb_regs.f_regs[_R_RA]; do { va = pc; do { va -= sizeof(int); insn = *(int *)va; if (insn == MIPS_ERET) goto mips3_eret; } while (insn != MIPS_JR_RA && insn != MIPS_JR_K0); va += sizeof(int); mips3_eret: va += sizeof(int); while (*(int *)va == 0x00000000) va += sizeof(int); func = va; stacksize = 0; do { i.word = *(int *)va; if (i.IType.op == OP_SW && i.IType.rs == _R_SP && i.IType.rt == _R_RA) ra = *(int *)(sp + (short)i.IType.imm); if (i.IType.op == OP_ADDIU && i.IType.rs == _R_SP && i.IType.rt == _R_SP) stacksize = -(short)i.IType.imm; va += sizeof(int); } while (va < pc); db_find_sym_and_offset(func, &name, &offset); if (name == 0) name = "?"; (*pr)("%s()+0x%x, called by %p, stack size %d\n", name, pc - func, (void *)ra, stacksize); if (ra == pc) { (*pr)("-- loop? --\n"); return; } sp += stacksize; pc = ra; } while (pc > (unsigned)verylocore); if (pc < 0x80000000) (*pr)("-- user process --\n"); else (*pr)("-- kernel entry --\n"); #endif }
void db_stack_trace_print(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif, void (*pr)(const char *, ...)) { long *frame, *lastframe; long *retaddr, *arg0; long *argp; db_addr_t callpc; int is_trap; bool kernel_only = true; bool trace_thread = false; bool lwpaddr = false; #if 0 if (!db_trace_symbols_found) db_find_trace_symbols(); #endif { const char *cp = modif; char c; while ((c = *cp++) != 0) { if (c == 'a') { lwpaddr = true; trace_thread = true; } if (c == 't') trace_thread = true; if (c == 'u') kernel_only = false; } } if (!have_addr) { frame = (long *)ddb_regs.tf_rbp; callpc = (db_addr_t)ddb_regs.tf_rip; } else { if (trace_thread) { struct proc *p; struct user *u; struct lwp *l; if (lwpaddr) { l = (struct lwp *)addr; p = l->l_proc; (*pr)("trace: pid %d ", p->p_pid); } else { (*pr)("trace: pid %d ", (int)addr); p = p_find(addr, PFIND_LOCKED); if (p == NULL) { (*pr)("not found\n"); return; } l = LIST_FIRST(&p->p_lwps); KASSERT(l != NULL); } (*pr)("lid %d ", l->l_lid); if (!(l->l_flag & LW_INMEM)) { (*pr)("swapped out\n"); return; } u = l->l_addr; if (p == curproc && l == curlwp) { frame = (long *)ddb_regs.tf_rbp; callpc = (db_addr_t)ddb_regs.tf_rip; (*pr)("at %p\n", frame); } else { frame = (long *)u->u_pcb.pcb_rbp; callpc = (db_addr_t) db_get_value((long)(frame + 1), 8, false); (*pr)("at %p\n", frame); frame = (long *)*frame; /* XXXfvdl db_get_value? */ } } else { frame = (long *)addr; callpc = (db_addr_t) db_get_value((long)(frame + 1), 8, false); frame = (long *)*frame; /* XXXfvdl db_get_value? */ } } retaddr = frame + 1; arg0 = frame + 2; lastframe = 0; while (count && frame != 0) { int narg; const char * name; db_expr_t offset; db_sym_t sym; char *argnames[16], **argnp = NULL; db_addr_t lastcallpc; name = "?"; is_trap = NONE; offset = 0; sym = db_frame_info(frame, callpc, &name, &offset, &is_trap, &narg); if (lastframe == 0 && sym == (db_sym_t)0) { /* Symbol not found, peek at code */ u_long instr = db_get_value(callpc, 4, false); offset = 1; if (instr == 0xe5894855 || /* enter: pushq %rbp, movq %rsp, %rbp */ (instr & 0x00ffffff) == 0x0048e589 /* enter+1: movq %rsp, %rbp */) { offset = 0; } } if (is_trap == NONE) { if (db_sym_numargs(sym, &narg, argnames)) argnp = argnames; else narg = db_numargs(frame); } (*pr)("%s(", name); if (lastframe == 0 && offset == 0 && !have_addr) { /* * We have a breakpoint before the frame is set up * Use %rsp instead */ argp = &((struct x86_64_frame *)(ddb_regs.tf_rsp-8))->f_arg0; } else { argp = frame + 2; } while (narg) { if (argnp) (*pr)("%s=", *argnp++); (*pr)("%lx", db_get_value((long)argp, 8, false)); argp++; if (--narg != 0) (*pr)(","); } (*pr)(") at "); db_printsym(callpc, DB_STGY_PROC, pr); (*pr)("\n"); if (lastframe == 0 && offset == 0 && !have_addr) { /* Frame really belongs to next callpc */ struct x86_64_frame *fp = (void *)(ddb_regs.tf_rsp-8); lastframe = (long *)fp; callpc = (db_addr_t) db_get_value((db_addr_t)&fp->f_retaddr, 8, false); continue; } lastframe = frame; lastcallpc = callpc; if (!db_nextframe(&frame, &retaddr, &arg0, &callpc, frame + 2, is_trap, pr)) break; if (INKERNEL((long)frame)) { /* staying in kernel */ if (frame < lastframe || (frame == lastframe && callpc == lastcallpc)) { (*pr)("Bad frame pointer: %p\n", frame); break; } } else if (INKERNEL((long)lastframe)) { /* switch from user to kernel */ if (kernel_only) break; /* kernel stack only */ } else { /* in user */ if (frame <= lastframe) { (*pr)("Bad user frame pointer: %p\n", frame); break; } } --count; } if (count && is_trap != NONE) { db_printsym(callpc, DB_STGY_XTRN, pr); (*pr)(":\n"); } }