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