__qdivmod => __qdivrem
[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 *
6ecf3d85 5 * %sccs.include.redist.c%
22e155fc
DF
6 */
7
8#ifndef lint
9char copyright[] =
fa6237e9 10"@(#) Copyright (c) 1982 The Regents of the University of California.\n\
22e155fc 11 All rights reserved.\n";
fa6237e9 12#endif /* not lint */
22e155fc 13
68d13ee3 14#ifndef lint
a990473f 15static char sccsid[] = "@(#)gcore.c 5.10 (Berkeley) %G%";
fa6237e9 16#endif /* not lint */
4f626618
KM
17
18/*
19 * gcore - get core images of running processes
20 *
21 * Author: Eric Cooper
22 * Written: Fall 1981.
23 *
24 * Inspired by a version 6 program by Len Levin, 1978.
25 * Several pieces of code lifted from Bill Joy's 4BSD ps.
26 *
27 * Permission to copy or modify this program in whole or in part is hereby
28 * granted, provided that the above credits are preserved.
29 *
30 * This code performs a simple simulation of the virtual memory system in user
31 * code. If the virtual memory system changes, this program must be modified
32 * accordingly. It must also be recompiled whenever system data structures
33 * change.
34 */
ff7dc584 35#include <machine/pte.h>
4f626618 36#include <sys/param.h>
a990473f 37#include <sys/user.h>
4f626618 38#include <sys/proc.h>
4f626618
KM
39#include <sys/vm.h>
40#include <setjmp.h>
ff7dc584
KB
41#include <stdio.h>
42#include <nlist.h>
ed22f418 43#include <varargs.h>
4f626618
KM
44
45/* Various macros for efficiency. */
46
47#define min(a, b) (a < b ? a : b)
48
49#define Seek(f, pos) {\
50 if (lseek(f, (long) (pos), 0) != (long) (pos)) \
51 panic("seek error"); \
52}
53
54#define Read(f, addr, n) {\
55 if (read(f, (char *) (addr), (int) (n)) != (int) (n)) \
56 panic("read error"); \
57}
58
59#define Get(f, pos, addr, n) {\
60 Seek(f, pos); \
61 Read(f, addr, n); \
62}
63
64struct nlist nl[] = {
65 { "_proc" },
66#define X_PROC 0
67 { "_Usrptmap" },
68#define X_USRPTMA 1
69 { "_usrpt" },
70#define X_USRPT 2
71 { "_nswap" },
72#define X_NSWAP 3
73 { "_nproc" },
74#define X_NPROC 4
68d13ee3
SL
75 { "_dmmin" },
76#define X_DMMIN 5
77 { "_dmmax" },
78#define X_DMMAX 6
4f626618
KM
79 { 0 },
80};
81
82#define FEW 20 /* for fewer system calls */
83struct proc proc[FEW];
84
85union {
86 struct user user;
87 char upages[UPAGES][NBPG];
88} user;
89#define u user.user
90#define uarea user.upages
91
92#define NLIST "/vmunix"
93#define KMEM "/dev/kmem"
94#define MEM "/dev/mem"
95#define SWAP "/dev/drum" /* "/dev/swap" on some systems */
96
97int nproc;
98int nswap;
68d13ee3 99int dmmin, dmmax;
4f626618
KM
100struct pte *Usrptmap, *usrpt;
101char coref[20];
102int kmem, mem, swap, cor;
103jmp_buf cont_frame;
104
105main(argc, argv)
106 int argc;
107 char **argv;
108{
109 register int i, j;
110 register struct proc *p;
111 off_t procbase, procp;
112 int pid, uid;
113 char c;
114
115 if (argc < 2) {
116 printf("Usage: %s pid ...\n", argv[0]);
117 exit(1);
118 }
119 openfiles();
120 getkvars();
ed22f418
CT
121 procbase = getword(nl[X_PROC].n_value);
122 nproc = getword(nl[X_NPROC].n_value);
123 nswap = getword(nl[X_NSWAP].n_value);
124 dmmin = getword(nl[X_DMMIN].n_value);
125 dmmax = getword(nl[X_DMMAX].n_value);
4f626618
KM
126 while (--argc > 0) {
127 if ((pid = atoi(*++argv)) <= 0 || setjmp(cont_frame))
128 continue;
129 printf("%d: ", pid);
130 procp = procbase;
131 for (i = 0; i < nproc; i += FEW) {
132 Seek(kmem, procp);
133 j = nproc - i;
134 if (j > FEW)
135 j = FEW;
136 j *= sizeof(struct proc);
137 Read(kmem, (char *) proc, j);
138 procp += j;
139 for (j = j / sizeof(struct proc) - 1; j >= 0; j--) {
140 p = &proc[j];
141 if (p->p_pid == pid)
142 goto found;
143 }
144 }
145 printf("Process not found.\n");
146 continue;
147 found:
148 if (p->p_uid != (uid = getuid()) && uid != 0) {
149 printf("Not owner.\n");
150 continue;
151 }
152 if (p->p_stat == SZOMB) {
153 printf("Zombie.\n");
154 continue;
155 }
c4a87a78
MK
156 if (p->p_flag & SWEXIT)
157 printf("Warning: process exiting.\n");
4f626618
KM
158 if (p->p_flag & SSYS) {
159 printf("System process.\n");
160 /* i.e. swapper or pagedaemon */
161 continue;
162 }
163 sprintf(coref, "core.%d", pid);
164 if ((cor = creat(coref, 0666)) < 0) {
165 perror(coref);
166 exit(1);
167 }
168 core(p);
169 close(cor);
170 printf("%s dumped\n", coref);
171 }
25c96cee 172 exit(0);
4f626618
KM
173}
174
ed22f418 175getword(loc)
4f626618
KM
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
ed22f418
CT
292 } else
293 p0 = p1 = NULL; /* not actually used */
4f626618
KM
294 getu(p, &p1[p->p_ssize]); /* u area */
295 getseg(p, p->p_dsize, p0, &u.u_dmap, 0); /* data */
296 getseg(p, p->p_ssize, p1, &u.u_smap, 1); /* stack */
297 if (p->p_flag & SLOAD) {
298 free((char *) syspt);
299 free((char *) p0);
300 free((char *) p1);
301 }
302}
303
304/*
305 * Get the u area.
306 * Keeps around the u structure for later use
307 * (the data and stack disk map structures).
308 */
309getu(p, pages)
310 register struct proc *p;
311 register struct pte *pages;
312{
313 register int i;
314
315 if ((p->p_flag & SLOAD) == 0) {
316 Get(swap, ctob(p->p_swaddr), uarea, ctob(UPAGES));
317 write(cor, uarea, ctob(UPAGES));
318 return;
319 }
320 for (i = 0; i < UPAGES; i += CLSIZE) {
321 Get(mem, ctob(pages[i].pg_pfnum), uarea[i], ctob(CLSIZE));
322 write(cor, uarea[i], ctob(CLSIZE));
323 }
324}
325
326/*
327 * Copy a segment to the core file.
328 * The segment is described by its size in clicks,
329 * its page table, its disk map, and whether or not
330 * it grows backwards.
331 * Note that the page table address is allowed to be meaningless
332 * if the process is swapped out.
333 */
334getseg(p, segsize, pages, map, rev)
335 register struct proc *p;
336 int segsize;
337 register struct pte *pages;
338 struct dmap *map;
ed22f418 339 int rev;
4f626618
KM
340{
341 register int i;
342 struct dblock db;
343 int size;
344 char buf[ctob(CLSIZE)];
345
346 for (i = 0; i < segsize; i += CLSIZE) {
347 size = min(CLSIZE, segsize - i);
348 if ((p->p_flag & SLOAD) == 0 || pages[i].pg_fod ||
349 pages[i].pg_pfnum == 0) {
350 vstodb(i, size, map, &db, rev);
351 Get(swap, ctob(db.db_base), buf, ctob(size));
352 write(cor, buf, ctob(size));
353 } else {
354 Get(mem, ctob(pages[i].pg_pfnum), buf, ctob(size));
355 write(cor, buf, ctob(size));
356 }
357 }
358}
359
360/*
361 * Given a base/size pair in virtual swap area,
362 * return a physical base/size pair which is the
363 * (largest) initial, physically contiguous block.
364 */
365vstodb(vsbase, vssize, dmp, dbp, rev)
366 register int vsbase;
367 int vssize;
368 struct dmap *dmp;
369 register struct dblock *dbp;
ed22f418 370 int rev;
4f626618 371{
68d13ee3 372 register int blk = dmmin;
4f626618
KM
373 register swblk_t *ip = dmp->dm_map;
374
375 if (vsbase < 0 || vsbase + vssize > dmp->dm_size)
376 panic("can't make sense out of virtual memory (gcore probably needs to be recompiled)");
377 while (vsbase >= blk) {
378 vsbase -= blk;
68d13ee3 379 if (blk < dmmax)
4f626618
KM
380 blk *= 2;
381 ip++;
382 }
383 if (*ip <= 0 || *ip + blk > nswap)
384 panic("vstodb *ip");
385 dbp->db_size = MIN(vssize, blk - vsbase);
386 dbp->db_base = *ip + (rev ? blk - (vsbase + dbp->db_size) : vsbase);
387}
388
ed22f418 389#ifdef lint
4f626618 390/*VARARGS1*/
ed22f418
CT
391panic(fmt)
392 char *fmt;
393{
394
395 fmt = fmt;
396 longjmp(cont_frame, 1);
397}
398#else /* lint */
399panic(va_alist)
400 va_dcl
4f626618 401{
ed22f418
CT
402 va_list ap;
403 char *fmt;
404
405 va_start(ap);
406 fmt = va_arg(ap, char *);
407 (void) vprintf(fmt, ap);
408 va_end(ap);
409 (void) printf("\n");
4f626618
KM
410 longjmp(cont_frame, 1);
411}
ed22f418 412#endif /* lint */
4f626618
KM
413
414/*
415 * Debugging routine to print out page table.
416 */
417#ifdef DEBUG
418showpt(pt, n, s)
419 struct pte *pt;
420 int n;
421 char *s;
422{
423 register struct pte *p;
424 register int i;
425
426 printf("*** %s page table\n", s);
427 for (i = 0, p = pt; i < n; i++, p++)
428 if (! p->pg_fod)
429 printf("%d: %x\n", i, p->pg_pfnum);
430}
431#endif