date and time created 87/12/12 17:40:43 by bostic
[unix-history] / usr / src / usr.bin / gcore / 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
c4a87a78 14static char sccsid[] = "@(#)gcore.c 5.3 (Berkeley) %G%";
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 }
c4a87a78
MK
155 if (p->p_flag & SWEXIT)
156 printf("Warning: process exiting.\n");
4f626618
KM
157 if (p->p_flag & SSYS) {
158 printf("System process.\n");
159 /* i.e. swapper or pagedaemon */
160 continue;
161 }
162 sprintf(coref, "core.%d", pid);
163 if ((cor = creat(coref, 0666)) < 0) {
164 perror(coref);
165 exit(1);
166 }
167 core(p);
168 close(cor);
169 printf("%s dumped\n", coref);
170 }
171}
172
173getw(loc)
174 off_t loc;
175{
176 int word;
177
178 Get(kmem, loc, &word, sizeof(int));
179 return (word);
180}
181
182openfiles()
183{
184 kmem = open(KMEM, 0);
185 if (kmem < 0) {
186 perror(KMEM);
187 exit(1);
188 }
189 mem = open(MEM, 0);
190 if (mem < 0) {
191 perror(MEM);
192 exit(1);
193 }
194 swap = open(SWAP, 0);
195 if (swap < 0) {
196 perror(SWAP);
197 exit(1);
198 }
199}
200
201getkvars()
202{
203 nlist(NLIST, nl);
204 if (nl[0].n_type == 0) {
205 printf("%s: No namelist\n", NLIST);
206 exit(1);
207 }
208 Usrptmap = (struct pte *) nl[X_USRPTMA].n_value;
209 usrpt = (struct pte *) nl[X_USRPT].n_value;
210}
211
212/*
213 * Get the system page table entries (mapping the user page table).
214 * These are the entries Usrptmap[i .. i + szpt],
215 * where i = btokmx(p->p_p0br) and szpt = p->p_szpt.
216 * For our purposes, we can skip over the ptes mapping
217 * the text segment ptes.
218 */
219struct pte *syspt; /* pte's from Usrptmap */
220int nsysptes;
221
222getsyspt(p)
223 register struct proc *p;
224{
225 nsysptes = p->p_szpt - (p->p_tsize / NPTEPG);
226 syspt = (struct pte *) malloc(nsysptes * sizeof(struct pte));
227 if (syspt == NULL)
228 panic("can't alloc %d page table entries", nsysptes);
229 Get(kmem, &Usrptmap[btokmx(p->p_p0br) + (p->p_tsize / NPTEPG)],
230 syspt, nsysptes * sizeof(struct pte));
231}
232
233/*
234 * Get the user page table for a segment.
235 * seg 0 = p0 (not including text)
236 * seg 1 = p1 (stack and u area)
237 * The system pt is consulted to find each page of user ptes.
238 */
239struct pte *
240getpt(p, seg)
241 register struct proc *p;
242 int seg;
243{
244 register int i;
245 register struct pte *spt;
246 struct pte *pt;
247 int nptes, offset, n;
248
249 if (seg == 0) {
250 nptes = p->p_dsize;
251 spt = syspt;
252 offset = p->p_tsize % NPTEPG;
253 } else {
254 nptes = p->p_ssize + UPAGES;
255 spt = syspt + (nsysptes - ctopt(nptes));
256 offset = -nptes % NPTEPG;
257 if (offset < 0)
258 offset += NPTEPG;
259 }
260 pt = (struct pte *) malloc(nptes * sizeof(struct pte));
261 if (pt == NULL)
262 panic("can't alloc %d page table entries", nptes);
263 for (i = 0; i < nptes; i += n) {
264 n = min(NPTEPG - offset, nptes - i);
265 Get(mem, ctob(spt->pg_pfnum) + offset * sizeof(struct pte),
266 pt + i, n * sizeof(struct pte));
267 spt++;
268 offset = 0;
269 }
270 return (pt);
271}
272
273/*
274 * Build the core file.
275 */
276core(p)
277 register struct proc *p;
278{
279 register struct pte *p0, *p1;
280
281 if (p->p_flag & SLOAD) { /* page tables are resident */
282 getsyspt(p);
283 p0 = getpt(p, 0);
284 p1 = getpt(p, 1);
285#ifdef DEBUG
286 showpt(syspt, nsysptes, "system");
287 showpt(p0, p->p_dsize, "p0");
288 showpt(p1, p->p_ssize + UPAGES, "p1");
289#endif
290 }
291 getu(p, &p1[p->p_ssize]); /* u area */
292 getseg(p, p->p_dsize, p0, &u.u_dmap, 0); /* data */
293 getseg(p, p->p_ssize, p1, &u.u_smap, 1); /* stack */
294 if (p->p_flag & SLOAD) {
295 free((char *) syspt);
296 free((char *) p0);
297 free((char *) p1);
298 }
299}
300
301/*
302 * Get the u area.
303 * Keeps around the u structure for later use
304 * (the data and stack disk map structures).
305 */
306getu(p, pages)
307 register struct proc *p;
308 register struct pte *pages;
309{
310 register int i;
311
312 if ((p->p_flag & SLOAD) == 0) {
313 Get(swap, ctob(p->p_swaddr), uarea, ctob(UPAGES));
314 write(cor, uarea, ctob(UPAGES));
315 return;
316 }
317 for (i = 0; i < UPAGES; i += CLSIZE) {
318 Get(mem, ctob(pages[i].pg_pfnum), uarea[i], ctob(CLSIZE));
319 write(cor, uarea[i], ctob(CLSIZE));
320 }
321}
322
323/*
324 * Copy a segment to the core file.
325 * The segment is described by its size in clicks,
326 * its page table, its disk map, and whether or not
327 * it grows backwards.
328 * Note that the page table address is allowed to be meaningless
329 * if the process is swapped out.
330 */
331getseg(p, segsize, pages, map, rev)
332 register struct proc *p;
333 int segsize;
334 register struct pte *pages;
335 struct dmap *map;
336{
337 register int i;
338 struct dblock db;
339 int size;
340 char buf[ctob(CLSIZE)];
341
342 for (i = 0; i < segsize; i += CLSIZE) {
343 size = min(CLSIZE, segsize - i);
344 if ((p->p_flag & SLOAD) == 0 || pages[i].pg_fod ||
345 pages[i].pg_pfnum == 0) {
346 vstodb(i, size, map, &db, rev);
347 Get(swap, ctob(db.db_base), buf, ctob(size));
348 write(cor, buf, ctob(size));
349 } else {
350 Get(mem, ctob(pages[i].pg_pfnum), buf, ctob(size));
351 write(cor, buf, ctob(size));
352 }
353 }
354}
355
356/*
357 * Given a base/size pair in virtual swap area,
358 * return a physical base/size pair which is the
359 * (largest) initial, physically contiguous block.
360 */
361vstodb(vsbase, vssize, dmp, dbp, rev)
362 register int vsbase;
363 int vssize;
364 struct dmap *dmp;
365 register struct dblock *dbp;
366{
68d13ee3 367 register int blk = dmmin;
4f626618
KM
368 register swblk_t *ip = dmp->dm_map;
369
370 if (vsbase < 0 || vsbase + vssize > dmp->dm_size)
371 panic("can't make sense out of virtual memory (gcore probably needs to be recompiled)");
372 while (vsbase >= blk) {
373 vsbase -= blk;
68d13ee3 374 if (blk < dmmax)
4f626618
KM
375 blk *= 2;
376 ip++;
377 }
378 if (*ip <= 0 || *ip + blk > nswap)
379 panic("vstodb *ip");
380 dbp->db_size = MIN(vssize, blk - vsbase);
381 dbp->db_base = *ip + (rev ? blk - (vsbase + dbp->db_size) : vsbase);
382}
383
384/*VARARGS1*/
385panic(cp, a, b, c, d)
386 char *cp;
387{
388 printf(cp, a, b, c, d);
389 printf("\n");
390 longjmp(cont_frame, 1);
391}
392
393/*
394 * Debugging routine to print out page table.
395 */
396#ifdef DEBUG
397showpt(pt, n, s)
398 struct pte *pt;
399 int n;
400 char *s;
401{
402 register struct pte *p;
403 register int i;
404
405 printf("*** %s page table\n", s);
406 for (i = 0, p = pt; i < n; i++, p++)
407 if (! p->pg_fod)
408 printf("%d: %x\n", i, p->pg_pfnum);
409}
410#endif