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