Add spl's around queue manipulation
[unix-history] / usr / src / usr.bin / gcore / gcore.c
CommitLineData
68d13ee3
SL
1#ifndef lint
2static char sccsid[] = "@(#)gcore.c 4.3 (Berkeley) %G%";
3#endif
4f626618
KM
4
5/*
6 * gcore - get core images of running processes
7 *
8 * Author: Eric Cooper
9 * Written: Fall 1981.
10 *
11 * Inspired by a version 6 program by Len Levin, 1978.
12 * Several pieces of code lifted from Bill Joy's 4BSD ps.
13 *
14 * Permission to copy or modify this program in whole or in part is hereby
15 * granted, provided that the above credits are preserved.
16 *
17 * This code performs a simple simulation of the virtual memory system in user
18 * code. If the virtual memory system changes, this program must be modified
19 * accordingly. It must also be recompiled whenever system data structures
20 * change.
21 */
22#include <stdio.h>
23#include <nlist.h>
24#include <sys/param.h>
25#include <sys/dir.h>
26#include <sys/user.h>
27#include <sys/proc.h>
57ee57ff 28#include <machine/pte.h>
4f626618
KM
29#include <sys/vm.h>
30#include <setjmp.h>
31
32/* Various macros for efficiency. */
33
34#define min(a, b) (a < b ? a : b)
35
36#define Seek(f, pos) {\
37 if (lseek(f, (long) (pos), 0) != (long) (pos)) \
38 panic("seek error"); \
39}
40
41#define Read(f, addr, n) {\
42 if (read(f, (char *) (addr), (int) (n)) != (int) (n)) \
43 panic("read error"); \
44}
45
46#define Get(f, pos, addr, n) {\
47 Seek(f, pos); \
48 Read(f, addr, n); \
49}
50
51struct nlist nl[] = {
52 { "_proc" },
53#define X_PROC 0
54 { "_Usrptmap" },
55#define X_USRPTMA 1
56 { "_usrpt" },
57#define X_USRPT 2
58 { "_nswap" },
59#define X_NSWAP 3
60 { "_nproc" },
61#define X_NPROC 4
68d13ee3
SL
62 { "_dmmin" },
63#define X_DMMIN 5
64 { "_dmmax" },
65#define X_DMMAX 6
4f626618
KM
66 { 0 },
67};
68
69#define FEW 20 /* for fewer system calls */
70struct proc proc[FEW];
71
72union {
73 struct user user;
74 char upages[UPAGES][NBPG];
75} user;
76#define u user.user
77#define uarea user.upages
78
79#define NLIST "/vmunix"
80#define KMEM "/dev/kmem"
81#define MEM "/dev/mem"
82#define SWAP "/dev/drum" /* "/dev/swap" on some systems */
83
84int nproc;
85int nswap;
68d13ee3 86int dmmin, dmmax;
4f626618
KM
87struct pte *Usrptmap, *usrpt;
88char coref[20];
89int kmem, mem, swap, cor;
90jmp_buf cont_frame;
91
92main(argc, argv)
93 int argc;
94 char **argv;
95{
96 register int i, j;
97 register struct proc *p;
98 off_t procbase, procp;
99 int pid, uid;
100 char c;
101
102 if (argc < 2) {
103 printf("Usage: %s pid ...\n", argv[0]);
104 exit(1);
105 }
106 openfiles();
107 getkvars();
108 procbase = getw(nl[X_PROC].n_value);
109 nproc = getw(nl[X_NPROC].n_value);
110 nswap = getw(nl[X_NSWAP].n_value);
68d13ee3
SL
111 dmmin = getw(nl[X_DMMIN].n_value);
112 dmmax = getw(nl[X_DMMAX].n_value);
4f626618
KM
113 while (--argc > 0) {
114 if ((pid = atoi(*++argv)) <= 0 || setjmp(cont_frame))
115 continue;
116 printf("%d: ", pid);
117 procp = procbase;
118 for (i = 0; i < nproc; i += FEW) {
119 Seek(kmem, procp);
120 j = nproc - i;
121 if (j > FEW)
122 j = FEW;
123 j *= sizeof(struct proc);
124 Read(kmem, (char *) proc, j);
125 procp += j;
126 for (j = j / sizeof(struct proc) - 1; j >= 0; j--) {
127 p = &proc[j];
128 if (p->p_pid == pid)
129 goto found;
130 }
131 }
132 printf("Process not found.\n");
133 continue;
134 found:
135 if (p->p_uid != (uid = getuid()) && uid != 0) {
136 printf("Not owner.\n");
137 continue;
138 }
139 if (p->p_stat == SZOMB) {
140 printf("Zombie.\n");
141 continue;
142 }
143 if (p->p_flag & SWEXIT) {
144 printf("Process exiting.\n");
145 continue;
146 }
147 if (p->p_flag & SSYS) {
148 printf("System process.\n");
149 /* i.e. swapper or pagedaemon */
150 continue;
151 }
152 sprintf(coref, "core.%d", pid);
153 if ((cor = creat(coref, 0666)) < 0) {
154 perror(coref);
155 exit(1);
156 }
157 core(p);
158 close(cor);
159 printf("%s dumped\n", coref);
160 }
161}
162
163getw(loc)
164 off_t loc;
165{
166 int word;
167
168 Get(kmem, loc, &word, sizeof(int));
169 return (word);
170}
171
172openfiles()
173{
174 kmem = open(KMEM, 0);
175 if (kmem < 0) {
176 perror(KMEM);
177 exit(1);
178 }
179 mem = open(MEM, 0);
180 if (mem < 0) {
181 perror(MEM);
182 exit(1);
183 }
184 swap = open(SWAP, 0);
185 if (swap < 0) {
186 perror(SWAP);
187 exit(1);
188 }
189}
190
191getkvars()
192{
193 nlist(NLIST, nl);
194 if (nl[0].n_type == 0) {
195 printf("%s: No namelist\n", NLIST);
196 exit(1);
197 }
198 Usrptmap = (struct pte *) nl[X_USRPTMA].n_value;
199 usrpt = (struct pte *) nl[X_USRPT].n_value;
200}
201
202/*
203 * Get the system page table entries (mapping the user page table).
204 * These are the entries Usrptmap[i .. i + szpt],
205 * where i = btokmx(p->p_p0br) and szpt = p->p_szpt.
206 * For our purposes, we can skip over the ptes mapping
207 * the text segment ptes.
208 */
209struct pte *syspt; /* pte's from Usrptmap */
210int nsysptes;
211
212getsyspt(p)
213 register struct proc *p;
214{
215 nsysptes = p->p_szpt - (p->p_tsize / NPTEPG);
216 syspt = (struct pte *) malloc(nsysptes * sizeof(struct pte));
217 if (syspt == NULL)
218 panic("can't alloc %d page table entries", nsysptes);
219 Get(kmem, &Usrptmap[btokmx(p->p_p0br) + (p->p_tsize / NPTEPG)],
220 syspt, nsysptes * sizeof(struct pte));
221}
222
223/*
224 * Get the user page table for a segment.
225 * seg 0 = p0 (not including text)
226 * seg 1 = p1 (stack and u area)
227 * The system pt is consulted to find each page of user ptes.
228 */
229struct pte *
230getpt(p, seg)
231 register struct proc *p;
232 int seg;
233{
234 register int i;
235 register struct pte *spt;
236 struct pte *pt;
237 int nptes, offset, n;
238
239 if (seg == 0) {
240 nptes = p->p_dsize;
241 spt = syspt;
242 offset = p->p_tsize % NPTEPG;
243 } else {
244 nptes = p->p_ssize + UPAGES;
245 spt = syspt + (nsysptes - ctopt(nptes));
246 offset = -nptes % NPTEPG;
247 if (offset < 0)
248 offset += NPTEPG;
249 }
250 pt = (struct pte *) malloc(nptes * sizeof(struct pte));
251 if (pt == NULL)
252 panic("can't alloc %d page table entries", nptes);
253 for (i = 0; i < nptes; i += n) {
254 n = min(NPTEPG - offset, nptes - i);
255 Get(mem, ctob(spt->pg_pfnum) + offset * sizeof(struct pte),
256 pt + i, n * sizeof(struct pte));
257 spt++;
258 offset = 0;
259 }
260 return (pt);
261}
262
263/*
264 * Build the core file.
265 */
266core(p)
267 register struct proc *p;
268{
269 register struct pte *p0, *p1;
270
271 if (p->p_flag & SLOAD) { /* page tables are resident */
272 getsyspt(p);
273 p0 = getpt(p, 0);
274 p1 = getpt(p, 1);
275#ifdef DEBUG
276 showpt(syspt, nsysptes, "system");
277 showpt(p0, p->p_dsize, "p0");
278 showpt(p1, p->p_ssize + UPAGES, "p1");
279#endif
280 }
281 getu(p, &p1[p->p_ssize]); /* u area */
282 getseg(p, p->p_dsize, p0, &u.u_dmap, 0); /* data */
283 getseg(p, p->p_ssize, p1, &u.u_smap, 1); /* stack */
284 if (p->p_flag & SLOAD) {
285 free((char *) syspt);
286 free((char *) p0);
287 free((char *) p1);
288 }
289}
290
291/*
292 * Get the u area.
293 * Keeps around the u structure for later use
294 * (the data and stack disk map structures).
295 */
296getu(p, pages)
297 register struct proc *p;
298 register struct pte *pages;
299{
300 register int i;
301
302 if ((p->p_flag & SLOAD) == 0) {
303 Get(swap, ctob(p->p_swaddr), uarea, ctob(UPAGES));
304 write(cor, uarea, ctob(UPAGES));
305 return;
306 }
307 for (i = 0; i < UPAGES; i += CLSIZE) {
308 Get(mem, ctob(pages[i].pg_pfnum), uarea[i], ctob(CLSIZE));
309 write(cor, uarea[i], ctob(CLSIZE));
310 }
311}
312
313/*
314 * Copy a segment to the core file.
315 * The segment is described by its size in clicks,
316 * its page table, its disk map, and whether or not
317 * it grows backwards.
318 * Note that the page table address is allowed to be meaningless
319 * if the process is swapped out.
320 */
321getseg(p, segsize, pages, map, rev)
322 register struct proc *p;
323 int segsize;
324 register struct pte *pages;
325 struct dmap *map;
326{
327 register int i;
328 struct dblock db;
329 int size;
330 char buf[ctob(CLSIZE)];
331
332 for (i = 0; i < segsize; i += CLSIZE) {
333 size = min(CLSIZE, segsize - i);
334 if ((p->p_flag & SLOAD) == 0 || pages[i].pg_fod ||
335 pages[i].pg_pfnum == 0) {
336 vstodb(i, size, map, &db, rev);
337 Get(swap, ctob(db.db_base), buf, ctob(size));
338 write(cor, buf, ctob(size));
339 } else {
340 Get(mem, ctob(pages[i].pg_pfnum), buf, ctob(size));
341 write(cor, buf, ctob(size));
342 }
343 }
344}
345
346/*
347 * Given a base/size pair in virtual swap area,
348 * return a physical base/size pair which is the
349 * (largest) initial, physically contiguous block.
350 */
351vstodb(vsbase, vssize, dmp, dbp, rev)
352 register int vsbase;
353 int vssize;
354 struct dmap *dmp;
355 register struct dblock *dbp;
356{
68d13ee3 357 register int blk = dmmin;
4f626618
KM
358 register swblk_t *ip = dmp->dm_map;
359
360 if (vsbase < 0 || vsbase + vssize > dmp->dm_size)
361 panic("can't make sense out of virtual memory (gcore probably needs to be recompiled)");
362 while (vsbase >= blk) {
363 vsbase -= blk;
68d13ee3 364 if (blk < dmmax)
4f626618
KM
365 blk *= 2;
366 ip++;
367 }
368 if (*ip <= 0 || *ip + blk > nswap)
369 panic("vstodb *ip");
370 dbp->db_size = MIN(vssize, blk - vsbase);
371 dbp->db_base = *ip + (rev ? blk - (vsbase + dbp->db_size) : vsbase);
372}
373
374/*VARARGS1*/
375panic(cp, a, b, c, d)
376 char *cp;
377{
378 printf(cp, a, b, c, d);
379 printf("\n");
380 longjmp(cont_frame, 1);
381}
382
383/*
384 * Debugging routine to print out page table.
385 */
386#ifdef DEBUG
387showpt(pt, n, s)
388 struct pte *pt;
389 int n;
390 char *s;
391{
392 register struct pte *p;
393 register int i;
394
395 printf("*** %s page table\n", s);
396 for (i = 0, p = pt; i < n; i++, p++)
397 if (! p->pg_fod)
398 printf("%d: %x\n", i, p->pg_pfnum);
399}
400#endif