int setpriority(int dummy, int who, int niceval) { int scale; int prio; pcinfo_t pcinfo; pcparms_t pcparms; tsparms_t *tsparms; strcpy(pcinfo.pc_clname, "TS"); if (priocntl(0, 0, PC_GETCID, (caddr_t) & pcinfo) == -1) return (-1); prio = niceval; if (prio > PRIO_MAX) prio = PRIO_MAX; else if (prio < PRIO_MIN) prio = PRIO_MIN; tsparms = (tsparms_t *) pcparms.pc_clparms; scale = ((tsinfo_t *) pcinfo.pc_clinfo)->ts_maxupri; tsparms->ts_uprilim = tsparms->ts_upri = -(scale * prio) / 20; pcparms.pc_cid = pcinfo.pc_cid; if (priocntl(P_PID, who, PC_SETPARMS, (caddr_t) & pcparms) == -1) return (-1); return (0); }
void ptwq_set_current_thread_priority(int priority) { long retval = 0; dbg_printf("reconfiguring thread for priority level=%u", priority); switch (priority) { case WORKQ_LOW_PRIOQUEUE: retval = priocntl(P_LWPID, P_MYID, PC_SETXPARMS, "TS", 0); // run low prio queues as time sharing break; case WORKQ_DEFAULT_PRIOQUEUE: retval = priocntl(P_LWPID, P_MYID, PC_SETXPARMS, "TS", 0); // run low prio queues as time sharing // retval = priocntl(P_LWPID, P_MYID, PC_SETXPARMS, "RT", RT_KY_PRI, WORKQ_NUM_PRIOQUEUE - priority - 1, 0); break; case WORKQ_HIGH_PRIOQUEUE: retval = priocntl(P_LWPID, P_MYID, PC_SETXPARMS, "FX", 0); // retval = priocntl(P_LWPID, P_MYID, PC_SETXPARMS, "RT", RT_KY_PRI, WORKQ_NUM_PRIOQUEUE - priority - 1, 0); break; default: dbg_printf("Unknown priority level = %u", priority); break; } if (retval != 0) dbg_perror("priocntl()"); return; }
/* * Retrieve the current rt_dptbl from memory, convert the time quantum * values to the resolution specified by res and write the table to stdout. */ static void get_rtdptbl(ulong_t res) { int i; int rtdpsz; pcinfo_t pcinfo; pcadmin_t pcadmin; rtadmin_t rtadmin; rtdpent_t *rt_dptbl; hrtimer_t hrtime; (void) strcpy(pcinfo.pc_clname, "RT"); if (priocntl(0, 0, PC_GETCID, (caddr_t)&pcinfo) == -1) fatalerr("%s: Can't get RT class ID, priocntl system call " "failed with errno %d\n", basenm, errno); pcadmin.pc_cid = pcinfo.pc_cid; pcadmin.pc_cladmin = (char *)&rtadmin; rtadmin.rt_cmd = RT_GETDPSIZE; if (priocntl(0, 0, PC_ADMIN, (caddr_t)&pcadmin) == -1) fatalerr("%s: Can't get rt_dptbl size, priocntl system call " "failed with errno %d\n", basenm, errno); rtdpsz = rtadmin.rt_ndpents * sizeof (rtdpent_t); if ((rt_dptbl = (rtdpent_t *)malloc(rtdpsz)) == NULL) fatalerr("%s: Can't allocate memory for rt_dptbl\n", basenm); rtadmin.rt_dpents = rt_dptbl; rtadmin.rt_cmd = RT_GETDPTBL; if (priocntl(0, 0, PC_ADMIN, (caddr_t)&pcadmin) == -1) fatalerr("%s: Can't get rt_dptbl, priocntl system call " "failed with errno %d\n", basenm, errno); (void) printf("# Real Time Dispatcher Configuration\n"); (void) printf("RES=%ld\n\n", res); (void) printf("# TIME QUANTUM PRIORITY\n"); (void) printf("# (rt_quantum) LEVEL\n"); for (i = 0; i < rtadmin.rt_ndpents; i++) { if (res != HZ && rt_dptbl[i].rt_quantum != RT_TQINF) { hrtime.hrt_secs = 0; hrtime.hrt_rem = rt_dptbl[i].rt_quantum; hrtime.hrt_res = HZ; if (_hrtnewres(&hrtime, res, HRT_RNDUP) == -1) fatalerr("%s: Can't convert to requested " "resolution\n", basenm); if ((rt_dptbl[i].rt_quantum = hrtconvert(&hrtime)) == -1) fatalerr("%s: Can't express time quantum in " "requested resolution,\n" "try coarser resolution\n", basenm); } (void) printf("%10d # %3d\n", rt_dptbl[i].rt_quantum, i); } }
static void * soaker(void *arg) { struct tstate *state = arg; pcparms_t pcparms; fxparms_t *fx = (fxparms_t *)pcparms.pc_clparms; if (processor_bind(P_LWPID, P_MYID, state->cpuid, NULL) != 0) (void) fprintf(stderr, gettext("%s: couldn't bind soaker " "thread to cpu%d: %s\n"), opts->pgmname, state->cpuid, strerror(errno)); /* * Put the soaker thread in the fixed priority (FX) class so it runs * at the lowest possible global priority. */ pcparms.pc_cid = fxinfo.pc_cid; fx->fx_upri = 0; fx->fx_uprilim = 0; fx->fx_tqsecs = fx->fx_tqnsecs = FX_TQDEF; if (priocntl(P_LWPID, P_MYID, PC_SETPARMS, &pcparms) != 0) (void) fprintf(stderr, gettext("%s: couldn't put soaker " "thread in FX sched class: %s\n"), opts->pgmname, strerror(errno)); /* * Let the parent thread know we're ready to roll. */ (void) mutex_lock(&state->soak_lock); state->soak_state = SOAK_RUN; (void) cond_signal(&state->soak_cv); (void) mutex_unlock(&state->soak_lock); for (;;) { spin: (void) mutex_lock(&state->soak_lock); if (state->soak_state == SOAK_RUN) { (void) mutex_unlock(&state->soak_lock); goto spin; } while (state->soak_state == SOAK_PAUSE) (void) cond_wait(&state->soak_cv, &state->soak_lock); (void) mutex_unlock(&state->soak_lock); } /*NOTREACHED*/ return (NULL); }
/* * Checks if a process is marked 'system'. Returns FALSE only when it is not. */ static boolean_t proc_issystem(pid_t pid) { char pc_clname[PC_CLNMSZ]; if (priocntl(P_PID, pid, PC_GETXPARMS, NULL, PC_KY_CLNAME, pc_clname, PC_KY_NULL) != -1) { return (strcmp(pc_clname, "SYS") == 0); } else { debug("cannot get class-specific scheduling parameters; " "assuming system process\n"); return (B_TRUE); } }
/* * Execute the command pointed to by cmdargv as a real-time process * with real time priority rtpri, quantum tqntm/res and quantum signal rtqsig. */ static void exec_rtcmd(char **cmdargv, uint_t cflags, pri_t rtpri, long tqntm, long res, int rtqsig) { pcinfo_t pcinfo; uintptr_t args[2*RT_KEYCNT+1]; uintptr_t *argsp = &args[0]; pri_t maxrtpri; hrtimer_t hrtime; /* * Get the real time class ID and max configured RT priority. */ (void) strcpy(pcinfo.pc_clname, "RT"); if (priocntl(0, 0, PC_GETCID, (caddr_t)&pcinfo) == -1) fatalerr("%s: Can't get RT class ID, priocntl system call" " failed with errno %d\n", basenm, errno); maxrtpri = ((rtinfo_t *)pcinfo.pc_clinfo)->rt_maxpri; if ((cflags & RT_DOPRI) != 0) { if (rtpri > maxrtpri || rtpri < 0) fatalerr("%s: Specified real time priority %d out of" " configured range\n", basenm, rtpri); ADDKEYVAL(argsp, RT_KY_PRI, rtpri); } if ((cflags & RT_DOTQ) != 0) { hrtime.hrt_secs = 0; hrtime.hrt_rem = tqntm; hrtime.hrt_res = res; if (_hrtnewres(&hrtime, NANOSEC, HRT_RNDUP) == -1) fatalerr("%s: Can't convert resolution.\n", basenm); ADDKEYVAL(argsp, RT_KY_TQSECS, hrtime.hrt_secs); ADDKEYVAL(argsp, RT_KY_TQNSECS, hrtime.hrt_rem); } if ((cflags & RT_DOSIG) != 0) ADDKEYVAL(argsp, RT_KY_TQSIG, rtqsig); *argsp = 0; if (rt_priocntl(P_PID, P_MYID, PC_SETXPARMS, "RT", args) == -1) fatalerr("%s: Can't reset real time parameters\n" "priocntl system call failed with errno %d\n", basenm, errno); (void) execvp(cmdargv[0], cmdargv); fatalerr("%s: Can't execute %s, exec failed with errno %d\n", basenm, cmdargv[0], errno); }
/* * Print our class name and the configured user priority range. */ static void print_rtinfo(void) { pcinfo_t pcinfo; (void) strcpy(pcinfo.pc_clname, "RT"); (void) printf("RT (Real Time)\n"); if (priocntl(0, 0, PC_GETCID, (caddr_t)&pcinfo) == -1) fatalerr("\tCan't get maximum configured RT priority\n"); (void) printf("\tConfigured RT User Priority Range: 0 through %d\n", ((rtinfo_t *)pcinfo.pc_clinfo)->rt_maxpri); }
/* * Read the fx_dptbl values from infile, convert the time quantum values * to HZ resolution, do a little sanity checking and overwrite the table * in memory with the values from the file. */ static void set_fxdptbl(char *infile) { int i; int nfxdpents; char *tokp; pcinfo_t pcinfo; pcadmin_t pcadmin; fxadmin_t fxadmin; fxdpent_t *fx_dptbl; int linenum; ulong_t res; hrtimer_t hrtime; FILE *fp; char buf[512]; int wslength; char *endp; char name[512], value[512]; int len; (void) strcpy(pcinfo.pc_clname, "FX"); if (priocntl(0, 0, PC_GETCID, (caddr_t)&pcinfo) == -1) fatalerr("%s: Can't get FX class ID, priocntl system call " "failed with errno %d\n", basenm, errno); pcadmin.pc_cid = pcinfo.pc_cid; pcadmin.pc_cladmin = (char *)&fxadmin; fxadmin.fx_cmd = FX_GETDPSIZE; if (priocntl(0, 0, PC_ADMIN, (caddr_t)&pcadmin) == -1) fatalerr("%s: Can't get fx_dptbl size, priocntl system call " "failed with errno %d\n", basenm, errno); nfxdpents = fxadmin.fx_ndpents; if ((fx_dptbl = (fxdpent_t *)malloc(nfxdpents * sizeof (fxdpent_t))) == NULL) fatalerr("%s: Can't allocate memory for fx_dptbl\n", basenm); if ((fp = fopen(infile, "r")) == NULL) fatalerr("%s: Can't open %s for input\n", basenm, infile); linenum = 0; /* * Find the first non-blank, non-comment line. A comment line * is any line with '#' as the first non-white-space character. */ do { if (fgets(buf, sizeof (buf), fp) == NULL) fatalerr("%s: Too few lines in input table\n", basenm); linenum++; } while (buf[0] == '#' || buf[0] == '\0' || (wslength = strspn(buf, " \t\n")) == strlen(buf) || strchr(buf, '#') == buf + wslength); /* LINTED - unbounded string specifier */ if (sscanf(buf, " %[^=]=%s \n%n", name, value, &len) == 2 && name[0] != '\0' && value[0] != '\0' && len == strlen(buf)) { if (strcmp(name, "RES") == 0) { errno = 0; i = (int)strtol(value, &endp, 10); if (errno != 0 || endp == value || i < 0 || *endp != '\0') fatalerr("%s: Bad RES specification, " "line %d of input file\n", basenm, linenum); else res = i; } else { fatalerr("%s: Bad RES specification, " "line %d of input file\n", basenm, linenum); } } /* * The remainder of the input file should contain exactly enough * non-blank, non-comment lines to fill the table (fx_ndpents lines). * We assume that any non-blank, non-comment line is data for the * table and fail if we find more or less than we need. */ for (i = 0; i < fxadmin.fx_ndpents; i++) { /* * Get the next non-blank, non-comment line. */ do { if (fgets(buf, sizeof (buf), fp) == NULL) fatalerr("%s: Too few lines in input table\n", basenm); linenum++; } while (buf[0] == '#' || buf[0] == '\0' || (wslength = strspn(buf, " \t\n")) == strlen(buf) || strchr(buf, '#') == buf + wslength); if ((tokp = strtok(buf, " \t")) == NULL) fatalerr("%s: Too few values, line %d of input file\n", basenm, linenum); fx_dptbl[i].fx_quantum = atol(tokp); if (fx_dptbl[i].fx_quantum <= 0) { fatalerr("%s: fx_quantum value out of " "valid range; line %d of input,\n" "table not overwritten\n", basenm, linenum); } else if (res != HZ) { hrtime.hrt_secs = 0; hrtime.hrt_rem = fx_dptbl[i].fx_quantum; hrtime.hrt_res = res; if (_hrtnewres(&hrtime, HZ, HRT_RNDUP) == -1) fatalerr("%s: Can't convert specified " "resolution to ticks\n", basenm); if ((fx_dptbl[i].fx_quantum = hrtconvert(&hrtime)) == -1) fatalerr("%s: fx_quantum value out of " "valid range; line %d of input,\n" "table not overwritten\n", basenm, linenum); } if ((tokp = strtok(NULL, " \t")) != NULL && tokp[0] != '#') fatalerr("%s: Too many values, line %d of input file\n", basenm, linenum); } /* * We've read enough lines to fill the table. We fail * if the input file contains any more. */ while (fgets(buf, sizeof (buf), fp) != NULL) { if (buf[0] != '#' && buf[0] != '\0' && (wslength = strspn(buf, " \t\n")) != strlen(buf) && strchr(buf, '#') != buf + wslength) fatalerr("%s: Too many lines in input table\n", basenm); } fxadmin.fx_dpents = fx_dptbl; fxadmin.fx_cmd = FX_SETDPTBL; if (priocntl(0, 0, PC_ADMIN, (caddr_t)&pcadmin) == -1) fatalerr("%s: Can't set fx_dptbl, priocntl system call failed " "with errno %d\n", basenm, errno); }
static int cpustat(void) { cpc_setgrp_t *accum; cpc_set_t *start; int c, i, retval; int lwps = 0; psetid_t mypset, cpupset; char *errstr; cpc_buf_t **data1, **data2, **scratch; int nreqs; kstat_ctl_t *kc; ncpus = (int)sysconf(_SC_NPROCESSORS_CONF); if ((gstate = calloc(ncpus, sizeof (*gstate))) == NULL) { (void) fprintf(stderr, gettext( "%s: out of heap\n"), opts->pgmname); return (1); } max_chip_id = sysconf(_SC_CPUID_MAX); if ((chip_designees = malloc(max_chip_id * sizeof (int))) == NULL) { (void) fprintf(stderr, gettext( "%s: out of heap\n"), opts->pgmname); return (1); } for (i = 0; i < max_chip_id; i++) chip_designees[i] = -1; if (smt) { if ((kc = kstat_open()) == NULL) { (void) fprintf(stderr, gettext( "%s: kstat_open() failed: %s\n"), opts->pgmname, strerror(errno)); return (1); } } if (opts->dosoaker) if (priocntl(0, 0, PC_GETCID, &fxinfo) == -1) { (void) fprintf(stderr, gettext( "%s: couldn't get FX scheduler class: %s\n"), opts->pgmname, strerror(errno)); return (1); } /* * Only include processors that are participating in the system */ for (c = 0, i = 0; i < ncpus; c++) { switch (p_online(c, P_STATUS)) { case P_ONLINE: case P_NOINTR: if (smt) { gstate[i].chip_id = get_chipid(kc, c); if (gstate[i].chip_id != -1 && chip_designees[gstate[i].chip_id] == -1) chip_designees[gstate[i].chip_id] = c; } gstate[i++].cpuid = c; break; case P_OFFLINE: case P_POWEROFF: case P_FAULTED: case P_SPARE: gstate[i++].cpuid = -1; break; default: gstate[i++].cpuid = -1; (void) fprintf(stderr, gettext("%s: cpu%d in unknown state\n"), opts->pgmname, c); break; case -1: break; } } /* * Examine the processor sets; if we're in one, only attempt * to report on the set we're in. */ if (pset_bind(PS_QUERY, P_PID, P_MYID, &mypset) == -1) { errstr = strerror(errno); (void) fprintf(stderr, gettext("%s: pset_bind - %s\n"), opts->pgmname, errstr); } else { for (i = 0; i < ncpus; i++) { struct tstate *this = &gstate[i]; if (this->cpuid == -1) continue; if (pset_assign(PS_QUERY, this->cpuid, &cpupset) == -1) { errstr = strerror(errno); (void) fprintf(stderr, gettext("%s: pset_assign - %s\n"), opts->pgmname, errstr); continue; } if (mypset != cpupset) this->cpuid = -1; } } if (opts->dotitle) print_title(opts->master); zerotime(); for (i = 0; i < ncpus; i++) { struct tstate *this = &gstate[i]; if (this->cpuid == -1) continue; this->sgrp = cpc_setgrp_clone(opts->master); if (this->sgrp == NULL) { this->cpuid = -1; continue; } if (thr_create(NULL, 0, gtick, this, THR_BOUND|THR_NEW_LWP, &this->tid) == 0) lwps++; else { (void) fprintf(stderr, gettext("%s: cannot create thread for cpu%d\n"), opts->pgmname, this->cpuid); this->status = 4; } } if (lwps != 0) for (i = 0; i < ncpus; i++) (void) thr_join(gstate[i].tid, NULL, NULL); if ((accum = cpc_setgrp_clone(opts->master)) == NULL) { (void) fprintf(stderr, gettext("%s: out of heap\n"), opts->pgmname); return (1); } retval = 0; for (i = 0; i < ncpus; i++) { struct tstate *this = &gstate[i]; if (this->cpuid == -1) continue; cpc_setgrp_accum(accum, this->sgrp); cpc_setgrp_free(this->sgrp); this->sgrp = NULL; if (this->status != 0) retval = 1; } cpc_setgrp_reset(accum); start = cpc_setgrp_getset(accum); do { nreqs = cpc_setgrp_getbufs(accum, &data1, &data2, &scratch); print_total(lwps, *data1, nreqs, cpc_setgrp_getname(accum)); } while (cpc_setgrp_nextset(accum) != start); cpc_setgrp_free(accum); accum = NULL; free(gstate); return (retval); }
int main(int argc, char *argv[], char *envp[]) { extern int mdb_kvm_is_compressed_dump(mdb_io_t *); mdb_tgt_ctor_f *tgt_ctor = NULL; const char **tgt_argv = alloca(argc * sizeof (char *)); int tgt_argc = 0; mdb_tgt_t *tgt; char object[MAXPATHLEN], execname[MAXPATHLEN]; mdb_io_t *in_io, *out_io, *err_io, *null_io; struct termios tios; int status, c; char *p; const char *Iflag = NULL, *Lflag = NULL, *Vflag = NULL, *pidarg = NULL; int fflag = 0, Kflag = 0, Rflag = 0, Sflag = 0, Oflag = 0, Uflag = 0; int ttylike; int longmode = 0; stack_t sigstack; if (realpath(getexecname(), execname) == NULL) { (void) strncpy(execname, argv[0], MAXPATHLEN); execname[MAXPATHLEN - 1] = '\0'; } mdb_create(execname, argv[0]); bzero(tgt_argv, argc * sizeof (char *)); argv[0] = (char *)mdb.m_pname; _mdb_self_fd = open("/proc/self/as", O_RDONLY); mdb.m_env = envp; out_io = mdb_fdio_create(STDOUT_FILENO); mdb.m_out = mdb_iob_create(out_io, MDB_IOB_WRONLY); err_io = mdb_fdio_create(STDERR_FILENO); mdb.m_err = mdb_iob_create(err_io, MDB_IOB_WRONLY); mdb_iob_clrflags(mdb.m_err, MDB_IOB_AUTOWRAP); null_io = mdb_nullio_create(); mdb.m_null = mdb_iob_create(null_io, MDB_IOB_WRONLY); in_io = mdb_fdio_create(STDIN_FILENO); if ((mdb.m_termtype = getenv("TERM")) != NULL) { mdb.m_termtype = strdup(mdb.m_termtype); mdb.m_flags |= MDB_FL_TERMGUESS; } mdb.m_term = NULL; mdb_dmode(mdb_dstr2mode(getenv("MDB_DEBUG"))); mdb.m_pgid = getpgrp(); if (getenv("_MDB_EXEC") != NULL) mdb.m_flags |= MDB_FL_EXEC; /* * Setup an alternate signal stack. When tearing down pipelines in * terminate(), we may have to destroy the stack of the context in * which we are currently executing the signal handler. */ sigstack.ss_sp = mmap(NULL, SIGSTKSZ, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); if (sigstack.ss_sp == MAP_FAILED) die("could not allocate signal stack"); sigstack.ss_size = SIGSTKSZ; sigstack.ss_flags = 0; if (sigaltstack(&sigstack, NULL) != 0) die("could not set signal stack"); (void) mdb_signal_sethandler(SIGPIPE, SIG_IGN, NULL); (void) mdb_signal_sethandler(SIGQUIT, SIG_IGN, NULL); (void) mdb_signal_sethandler(SIGILL, flt_handler, NULL); (void) mdb_signal_sethandler(SIGTRAP, flt_handler, NULL); (void) mdb_signal_sethandler(SIGIOT, flt_handler, NULL); (void) mdb_signal_sethandler(SIGEMT, flt_handler, NULL); (void) mdb_signal_sethandler(SIGFPE, flt_handler, NULL); (void) mdb_signal_sethandler(SIGBUS, flt_handler, NULL); (void) mdb_signal_sethandler(SIGSEGV, flt_handler, NULL); (void) mdb_signal_sethandler(SIGHUP, (mdb_signal_f *)terminate, NULL); (void) mdb_signal_sethandler(SIGTERM, (mdb_signal_f *)terminate, NULL); for (mdb.m_rdvers = RD_VERSION; mdb.m_rdvers > 0; mdb.m_rdvers--) { if (rd_init(mdb.m_rdvers) == RD_OK) break; } for (mdb.m_ctfvers = CTF_VERSION; mdb.m_ctfvers > 0; mdb.m_ctfvers--) { if (ctf_version(mdb.m_ctfvers) != -1) break; } if ((p = getenv("HISTSIZE")) != NULL && strisnum(p)) { mdb.m_histlen = strtoi(p); if (mdb.m_histlen < 1) mdb.m_histlen = 1; } while (optind < argc) { while ((c = getopt(argc, argv, "fkmo:p:s:uwyACD:FI:KL:MOP:R:SUV:W")) != (int)EOF) { switch (c) { case 'f': fflag++; tgt_ctor = mdb_rawfile_tgt_create; break; case 'k': tgt_ctor = mdb_kvm_tgt_create; break; case 'm': mdb.m_tgtflags |= MDB_TGT_F_NOLOAD; mdb.m_tgtflags &= ~MDB_TGT_F_PRELOAD; break; case 'o': if (!mdb_set_options(optarg, TRUE)) terminate(2); break; case 'p': tgt_ctor = mdb_proc_tgt_create; pidarg = optarg; break; case 's': if (!strisnum(optarg)) { warn("expected integer following -s\n"); terminate(2); } mdb.m_symdist = (size_t)(uint_t)strtoi(optarg); break; case 'u': tgt_ctor = mdb_proc_tgt_create; break; case 'w': mdb.m_tgtflags |= MDB_TGT_F_RDWR; break; case 'y': mdb.m_flags |= MDB_FL_USECUP; break; case 'A': (void) mdb_set_options("nomods", TRUE); break; case 'C': (void) mdb_set_options("noctf", TRUE); break; case 'D': mdb_dmode(mdb_dstr2mode(optarg)); break; case 'F': mdb.m_tgtflags |= MDB_TGT_F_FORCE; break; case 'I': Iflag = optarg; break; case 'L': Lflag = optarg; break; case 'K': Kflag++; break; case 'M': mdb.m_tgtflags |= MDB_TGT_F_PRELOAD; mdb.m_tgtflags &= ~MDB_TGT_F_NOLOAD; break; case 'O': Oflag++; break; case 'P': if (!mdb_set_prompt(optarg)) terminate(2); break; case 'R': (void) strncpy(mdb.m_root, optarg, MAXPATHLEN); mdb.m_root[MAXPATHLEN - 1] = '\0'; Rflag++; break; case 'S': Sflag++; break; case 'U': Uflag++; break; case 'V': Vflag = optarg; break; case 'W': mdb.m_tgtflags |= MDB_TGT_F_ALLOWIO; break; case '?': if (optopt == '?') usage(0); /* FALLTHROUGH */ default: usage(2); } } if (optind < argc) { const char *arg = argv[optind++]; if (arg[0] == '+' && strlen(arg) == 2) { if (arg[1] != 'o') { warn("illegal option -- %s\n", arg); terminate(2); } if (optind >= argc) { warn("option requires an argument -- " "%s\n", arg); terminate(2); } if (!mdb_set_options(argv[optind++], FALSE)) terminate(2); } else tgt_argv[tgt_argc++] = arg; } } if (rd_ctl(RD_CTL_SET_HELPPATH, (void *)mdb.m_root) != RD_OK) { warn("cannot set librtld_db helper path to %s\n", mdb.m_root); terminate(2); } if (mdb.m_debug & MDB_DBG_HELP) terminate(0); /* Quit here if we've printed out the tokens */ if (Iflag != NULL && strchr(Iflag, ';') != NULL) { warn("macro path cannot contain semicolons\n"); terminate(2); } if (Lflag != NULL && strchr(Lflag, ';') != NULL) { warn("module path cannot contain semicolons\n"); terminate(2); } if (Kflag || Uflag) { char *nm; if (tgt_ctor != NULL || Iflag != NULL) { warn("neither -f, -k, -p, -u, nor -I " "may be used with -K\n"); usage(2); } if (Lflag != NULL) mdb_set_lpath(Lflag); if ((nm = ttyname(STDIN_FILENO)) == NULL || strcmp(nm, "/dev/console") != 0) { /* * Due to the consequences of typing mdb -K instead of * mdb -k on a tty other than /dev/console, we require * -F when starting kmdb from a tty other than * /dev/console. */ if (!(mdb.m_tgtflags & MDB_TGT_F_FORCE)) { die("-F must also be supplied to start kmdb " "from non-console tty\n"); } if (mdb.m_termtype == NULL || (mdb.m_flags & MDB_FL_TERMGUESS)) { if (mdb.m_termtype != NULL) strfree(mdb.m_termtype); if ((mdb.m_termtype = mdb_scf_console_term()) != NULL) mdb.m_flags |= MDB_FL_TERMGUESS; } } else { /* * When on console, $TERM (if set) takes precedence over * the SMF setting. */ if (mdb.m_termtype == NULL && (mdb.m_termtype = mdb_scf_console_term()) != NULL) mdb.m_flags |= MDB_FL_TERMGUESS; } control_kmdb(Kflag); terminate(0); /*NOTREACHED*/ } /* * If standard input appears to have tty attributes, attempt to * initialize a terminal i/o backend on top of stdin and stdout. */ ttylike = (IOP_CTL(in_io, TCGETS, &tios) == 0); if (ttylike) { if ((mdb.m_term = mdb_termio_create(mdb.m_termtype, in_io, out_io)) == NULL) { if (!(mdb.m_flags & MDB_FL_EXEC)) { warn("term init failed: command-line editing " "and prompt will not be available\n"); } } else { in_io = mdb.m_term; } } mdb.m_in = mdb_iob_create(in_io, MDB_IOB_RDONLY); if (mdb.m_term != NULL) { mdb_iob_setpager(mdb.m_out, mdb.m_term); if (mdb.m_flags & MDB_FL_PAGER) mdb_iob_setflags(mdb.m_out, MDB_IOB_PGENABLE); else mdb_iob_clrflags(mdb.m_out, MDB_IOB_PGENABLE); } else if (ttylike) mdb_iob_setflags(mdb.m_in, MDB_IOB_TTYLIKE); else mdb_iob_setbuf(mdb.m_in, mdb_alloc(1, UM_SLEEP), 1); mdb_pservice_init(); mdb_lex_reset(); if ((mdb.m_shell = getenv("SHELL")) == NULL) mdb.m_shell = "/bin/sh"; /* * If the debugger state is to be inherited from a previous instance, * restore it now prior to path evaluation so that %R is updated. */ if ((p = getenv(MDB_CONFIG_ENV_VAR)) != NULL) { mdb_set_config(p); (void) unsetenv(MDB_CONFIG_ENV_VAR); } /* * Path evaluation part 1: Create the initial module path to allow * the target constructor to load a support module. Then expand * any command-line arguments that modify the paths. */ if (Iflag != NULL) mdb_set_ipath(Iflag); else mdb_set_ipath(MDB_DEF_IPATH); if (Lflag != NULL) mdb_set_lpath(Lflag); else mdb_set_lpath(MDB_DEF_LPATH); if (mdb_get_prompt() == NULL && !(mdb.m_flags & MDB_FL_ADB)) (void) mdb_set_prompt(MDB_DEF_PROMPT); if (tgt_ctor == mdb_kvm_tgt_create) { if (pidarg != NULL) { warn("-p and -k options are mutually exclusive\n"); terminate(2); } if (tgt_argc == 0) tgt_argv[tgt_argc++] = "/dev/ksyms"; if (tgt_argc == 1 && strisnum(tgt_argv[0]) == 0) { if (mdb.m_tgtflags & MDB_TGT_F_ALLOWIO) tgt_argv[tgt_argc++] = "/dev/allkmem"; else tgt_argv[tgt_argc++] = "/dev/kmem"; } } if (pidarg != NULL) { if (tgt_argc != 0) { warn("-p may not be used with other arguments\n"); terminate(2); } if (proc_arg_psinfo(pidarg, PR_ARG_PIDS, NULL, &status) == -1) { die("cannot attach to %s: %s\n", pidarg, Pgrab_error(status)); } if (strchr(pidarg, '/') != NULL) (void) mdb_iob_snprintf(object, MAXPATHLEN, "%s/object/a.out", pidarg); else (void) mdb_iob_snprintf(object, MAXPATHLEN, "/proc/%s/object/a.out", pidarg); tgt_argv[tgt_argc++] = object; tgt_argv[tgt_argc++] = pidarg; } /* * Find the first argument that is not a special "-" token. If one is * found, we will examine this file and make some inferences below. */ for (c = 0; c < tgt_argc && strcmp(tgt_argv[c], "-") == 0; c++) continue; if (c < tgt_argc) { Elf32_Ehdr ehdr; mdb_io_t *io; /* * If special "-" tokens preceded an argument, shift the entire * argument list to the left to remove the leading "-" args. */ if (c > 0) { bcopy(&tgt_argv[c], tgt_argv, sizeof (const char *) * (tgt_argc - c)); tgt_argc -= c; } if (fflag) goto tcreate; /* skip re-exec and just create target */ /* * If we just have an object file name, and that file doesn't * exist, and it's a string of digits, infer it to be a * sequence number referring to a pair of crash dump files. */ if (tgt_argc == 1 && access(tgt_argv[0], F_OK) == -1 && strisnum(tgt_argv[0])) { size_t len = strlen(tgt_argv[0]) + 8; const char *object = tgt_argv[0]; tgt_argv[0] = mdb_alloc(len, UM_SLEEP); tgt_argv[1] = mdb_alloc(len, UM_SLEEP); (void) strcpy((char *)tgt_argv[0], "unix."); (void) strcat((char *)tgt_argv[0], object); (void) strcpy((char *)tgt_argv[1], "vmcore."); (void) strcat((char *)tgt_argv[1], object); if (access(tgt_argv[0], F_OK) == -1 && access(tgt_argv[1], F_OK) == -1) { (void) strcpy((char *)tgt_argv[1], "vmdump."); (void) strcat((char *)tgt_argv[1], object); if (access(tgt_argv[1], F_OK) == 0) { mdb_iob_printf(mdb.m_err, "cannot open compressed dump; " "decompress using savecore -f %s\n", tgt_argv[1]); terminate(0); } } tgt_argc = 2; } /* * We need to open the object file in order to determine its * ELF class and potentially re-exec ourself. */ if ((io = mdb_fdio_create_path(NULL, tgt_argv[0], O_RDONLY, 0)) == NULL) die("failed to open %s", tgt_argv[0]); /* * Check for a single vmdump.N compressed dump file, * and give a helpful message. */ if (tgt_argc == 1) { if (mdb_kvm_is_compressed_dump(io)) { mdb_iob_printf(mdb.m_err, "cannot open compressed dump; " "decompress using savecore -f %s\n", tgt_argv[0]); terminate(0); } } /* * If the target is unknown or is not the rawfile target, do * a gelf_check to determine if the file is an ELF file. If * it is not and the target is unknown, use the rawfile tgt. * Otherwise an ELF-based target is needed, so we must abort. */ if (mdb_gelf_check(io, &ehdr, ET_NONE) == -1) { if (tgt_ctor != NULL) { (void) mdb_gelf_check(io, &ehdr, ET_EXEC); mdb_io_destroy(io); terminate(1); } else tgt_ctor = mdb_rawfile_tgt_create; } mdb_io_destroy(io); if (identify_xvm_file(tgt_argv[0], &longmode) == 1) { #ifdef _LP64 if (!longmode) goto reexec; #else if (longmode) goto reexec; #endif tgt_ctor = mdb_kvm_tgt_create; goto tcreate; } /* * The object file turned out to be a user core file (ET_CORE), * and no other arguments were specified, swap 0 and 1. The * proc target will infer the executable for us. */ if (ehdr.e_type == ET_CORE) { tgt_argv[tgt_argc++] = tgt_argv[0]; tgt_argv[0] = NULL; tgt_ctor = mdb_proc_tgt_create; } /* * If tgt_argv[1] is filled in, open it up and determine if it * is a vmcore file. If it is, gelf_check will fail and we * set tgt_ctor to 'kvm'; otherwise we use the default. */ if (tgt_argc > 1 && strcmp(tgt_argv[1], "-") != 0 && tgt_argv[0] != NULL && pidarg == NULL) { Elf32_Ehdr chdr; if (access(tgt_argv[1], F_OK) == -1) die("failed to access %s", tgt_argv[1]); /* *.N case: drop vmdump.N from the list */ if (tgt_argc == 3) { if ((io = mdb_fdio_create_path(NULL, tgt_argv[2], O_RDONLY, 0)) == NULL) die("failed to open %s", tgt_argv[2]); if (mdb_kvm_is_compressed_dump(io)) tgt_argv[--tgt_argc] = NULL; mdb_io_destroy(io); } if ((io = mdb_fdio_create_path(NULL, tgt_argv[1], O_RDONLY, 0)) == NULL) die("failed to open %s", tgt_argv[1]); if (mdb_gelf_check(io, &chdr, ET_NONE) == -1) tgt_ctor = mdb_kvm_tgt_create; mdb_io_destroy(io); } /* * At this point, we've read the ELF header for either an * object file or core into ehdr. If the class does not match * ours, attempt to exec the mdb of the appropriate class. */ #ifdef _LP64 if (ehdr.e_ident[EI_CLASS] == ELFCLASS32) goto reexec; #else if (ehdr.e_ident[EI_CLASS] == ELFCLASS64) goto reexec; #endif } tcreate: if (tgt_ctor == NULL) tgt_ctor = mdb_proc_tgt_create; tgt = mdb_tgt_create(tgt_ctor, mdb.m_tgtflags, tgt_argc, tgt_argv); if (tgt == NULL) { if (errno == EINVAL) usage(2); /* target can return EINVAL to get usage */ if (errno == EMDB_TGT) terminate(1); /* target already printed error msg */ die("failed to initialize target"); } mdb_tgt_activate(tgt); mdb_create_loadable_disasms(); if (Vflag != NULL && mdb_dis_select(Vflag) == -1) warn("invalid disassembler mode -- %s\n", Vflag); if (Rflag && mdb.m_term != NULL) warn("Using proto area %s\n", mdb.m_root); /* * If the target was successfully constructed and -O was specified, * we now attempt to enter piggy-mode for debugging jurassic problems. */ if (Oflag) { pcinfo_t pci; (void) strcpy(pci.pc_clname, "RT"); if (priocntl(P_LWPID, P_MYID, PC_GETCID, (caddr_t)&pci) != -1) { pcparms_t pcp; rtparms_t *rtp = (rtparms_t *)pcp.pc_clparms; rtp->rt_pri = 35; rtp->rt_tqsecs = 0; rtp->rt_tqnsecs = RT_TQDEF; pcp.pc_cid = pci.pc_cid; if (priocntl(P_LWPID, P_MYID, PC_SETPARMS, (caddr_t)&pcp) == -1) { warn("failed to set RT parameters"); Oflag = 0; } } else { warn("failed to get RT class id"); Oflag = 0; } if (mlockall(MCL_CURRENT | MCL_FUTURE) == -1) { warn("failed to lock address space"); Oflag = 0; } if (Oflag) mdb_printf("%s: oink, oink!\n", mdb.m_pname); } /* * Path evaluation part 2: Re-evaluate the path now that the target * is ready (and thus we have access to the real platform string). * Do this before reading ~/.mdbrc to allow path modifications prior * to performing module auto-loading. */ mdb_set_ipath(mdb.m_ipathstr); mdb_set_lpath(mdb.m_lpathstr); if (!Sflag && (p = getenv("HOME")) != NULL) { char rcpath[MAXPATHLEN]; mdb_io_t *rc_io; int fd; (void) mdb_iob_snprintf(rcpath, MAXPATHLEN, "%s/.mdbrc", p); fd = open64(rcpath, O_RDONLY); if (fd >= 0 && (rc_io = mdb_fdio_create_named(fd, rcpath))) { mdb_iob_t *iob = mdb_iob_create(rc_io, MDB_IOB_RDONLY); mdb_iob_t *old = mdb.m_in; mdb.m_in = iob; (void) mdb_run(); mdb.m_in = old; } } if (!(mdb.m_flags & MDB_FL_NOMODS)) mdb_module_load_all(0); (void) mdb_signal_sethandler(SIGINT, int_handler, NULL); while ((status = mdb_run()) == MDB_ERR_ABORT || status == MDB_ERR_OUTPUT) { /* * If a write failed on stdout, give up. A more informative * error message will already have been printed by mdb_run(). */ if (status == MDB_ERR_OUTPUT && mdb_iob_getflags(mdb.m_out) & MDB_IOB_ERR) { mdb_warn("write to stdout failed, exiting\n"); break; } continue; } terminate((status == MDB_ERR_QUIT || status == 0) ? 0 : 1); /*NOTREACHED*/ return (0); reexec: if ((p = strrchr(execname, '/')) == NULL) die("cannot determine absolute pathname\n"); #ifdef _LP64 #ifdef __sparc (void) strcpy(p, "/../sparcv7/"); #else (void) strcpy(p, "/../i86/"); #endif #else #ifdef __sparc (void) strcpy(p, "/../sparcv9/"); #else (void) strcpy(p, "/../amd64/"); #endif #endif (void) strcat(p, mdb.m_pname); if (mdb.m_term != NULL) (void) IOP_CTL(in_io, TCSETSW, &tios); (void) putenv("_MDB_EXEC=1"); (void) execv(execname, argv); /* * If execv fails, suppress ENOEXEC. Experience shows the most common * reason is that the machine is booted under a 32-bit kernel, in which * case it is clearer to only print the message below. */ if (errno != ENOEXEC) warn("failed to exec %s", execname); #ifdef _LP64 die("64-bit %s cannot debug 32-bit program %s\n", mdb.m_pname, tgt_argv[0] ? tgt_argv[0] : tgt_argv[1]); #else die("32-bit %s cannot debug 64-bit program %s\n", mdb.m_pname, tgt_argv[0] ? tgt_argv[0] : tgt_argv[1]); #endif goto tcreate; }
/* * Set all processes in the set specified by idtype/idargv to real time * (if they aren't already real time) and set their real-time priority, * real-time quantum and real-time quantum signal to those specified by * rtpri, tqntm/res and rtqsig. */ static int set_rtprocs(idtype_t idtype, int idargc, char **idargv, uint_t cflags, pri_t rtpri, long tqntm, long res, int rtqsig) { pcinfo_t pcinfo; uintptr_t args[2*RT_KEYCNT+1]; uintptr_t *argsp = &args[0]; pri_t maxrtpri; hrtimer_t hrtime; char idtypnm[PC_IDTYPNMSZ]; int i; id_t id; int error = 0; /* * Get the real time class ID and max configured RT priority. */ (void) strcpy(pcinfo.pc_clname, "RT"); if (priocntl(0, 0, PC_GETCID, (caddr_t)&pcinfo) == -1) fatalerr("%s: Can't get RT class ID, priocntl system call" " failed with errno %d\n", basenm, errno); maxrtpri = ((rtinfo_t *)pcinfo.pc_clinfo)->rt_maxpri; /* * Validate the rtpri and res arguments. */ if ((cflags & RT_DOPRI) != 0) { if (rtpri > maxrtpri || rtpri < 0) fatalerr("%s: Specified real time priority %d out of" " configured range\n", basenm, rtpri); ADDKEYVAL(argsp, RT_KY_PRI, rtpri); } if ((cflags & RT_DOTQ) != 0) { hrtime.hrt_secs = 0; hrtime.hrt_rem = tqntm; hrtime.hrt_res = res; if (_hrtnewres(&hrtime, NANOSEC, HRT_RNDUP) == -1) fatalerr("%s: Can't convert resolution.\n", basenm); ADDKEYVAL(argsp, RT_KY_TQSECS, hrtime.hrt_secs); ADDKEYVAL(argsp, RT_KY_TQNSECS, hrtime.hrt_rem); } if ((cflags & RT_DOSIG) != 0) ADDKEYVAL(argsp, RT_KY_TQSIG, rtqsig); *argsp = 0; if (idtype == P_ALL) { if (rt_priocntl(P_ALL, 0, PC_SETXPARMS, "RT", args) == -1) { if (errno == EPERM) { (void) fprintf(stderr, "Permissions error encountered" " on one or more processes.\n"); error = 1; } else { fatalerr("%s: Can't reset real time parameters" "\npriocntl system call failed with" " errno %d\n", basenm, errno); } } } else if (idargc == 0) { if (rt_priocntl(idtype, P_MYID, PC_SETXPARMS, "RT", args) == -1) { if (errno == EPERM) { (void) idtyp2str(idtype, idtypnm); (void) fprintf(stderr, "Permissions error" " encountered on current %s.\n", idtypnm); error = 1; } else { fatalerr("%s: Can't reset real time parameters" "\npriocntl system call failed with" " errno %d\n", basenm, errno); } } } else { (void) idtyp2str(idtype, idtypnm); for (i = 0; i < idargc; i++) { if (idtype == P_CID) { (void) strcpy(pcinfo.pc_clname, idargv[i]); if (priocntl(0, 0, PC_GETCID, (caddr_t)&pcinfo) == -1) fatalerr("%s: Invalid or unconfigured" " class %s, priocntl system call" " failed with errno %d\n", basenm, pcinfo.pc_clname, errno); id = pcinfo.pc_cid; } else { id = (id_t)str2num(idargv[i], INT_MIN, INT_MAX); if (errno) fatalerr("%s: Invalid id \"%s\"\n", basenm, idargv[i]); } if (rt_priocntl(idtype, id, PC_SETXPARMS, "RT", args) == -1) { if (errno == EPERM) { (void) fprintf(stderr, "Permissions error encountered on" " %s %s.\n", idtypnm, idargv[i]); error = 1; } else { fatalerr("%s: Can't reset real time" " parameters\npriocntl system call" " failed with errno %d\n", basenm, errno); } } } } return (error); }
/* * Call priocntl() with command codes PC_SETXPARMS or PC_GETXPARMS. * The first parameter behind the command code is always the class name. * Each parameter is headed by a key, which determines the meaning of the * following value. There are maximal RT_KEYCNT = 4 (key, value) pairs. */ static int rt_priocntl(idtype_t idtype, id_t id, int cmd, char *clname, uintptr_t *argsp) { return (priocntl(idtype, id, cmd, clname, argsp[0], argsp[1], argsp[2], argsp[3], argsp[4], argsp[5], argsp[6], argsp[7], 0)); }
/* * Read a list of pids from stdin and print the real-time priority and time * quantum (in millisecond resolution) for each of the corresponding processes. */ static int print_rtprocs(void) { pid_t *pidlist; size_t numread; int i; char clname[PC_CLNMSZ]; pri_t rt_pri; uint_t rt_tqsecs; int rt_tqnsecs; int rt_tqsig; int error = 0; /* * Read a list of pids from stdin. */ if ((pidlist = read_pidlist(&numread, stdin)) == NULL) fatalerr("%s: Can't read pidlist.\n", basenm); (void) printf("REAL TIME PROCESSES:\n" " PID RTPRI TQNTM TQSIG\n"); if (numread == 0) fatalerr("%s: No pids on input\n", basenm); for (i = 0; i < numread; i++) { (void) printf("%7ld", pidlist[i]); if (priocntl(P_PID, pidlist[i], PC_GETXPARMS, "RT", RT_KY_TQSECS, &rt_tqsecs, RT_KY_TQNSECS, &rt_tqnsecs, RT_KY_PRI, &rt_pri, RT_KY_TQSIG, &rt_tqsig, 0) != -1) { (void) printf(" %5d", rt_pri); if (rt_tqnsecs == RT_TQINF) (void) printf(" RT_TQINF"); else (void) printf(" %11lld", (longlong_t)rt_tqsecs * 1000 + rt_tqnsecs / 1000000); (void) printf(" %3d\n", rt_tqsig); } else { error = 1; if (priocntl(P_PID, pidlist[i], PC_GETXPARMS, NULL, PC_KY_CLNAME, clname, 0) != -1 && strcmp(clname, "RT")) /* * Process from some class other than real time. * It has probably changed class while priocntl * command was executing (otherwise we wouldn't * have been passed its pid). Print the little * we know about it. */ (void) printf("\tChanged to class %s while" " priocntl command executing\n", clname); else (void) printf("\tCan't get real time" " parameters\n"); } } free_pidlist(pidlist); return (error); }