1 /* 2 * Copyright (c) 1982 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 char copyright[] = 10 "@(#) Copyright (c) 1982 The Regents of the University of California.\n\ 11 All rights reserved.\n"; 12 #endif /* not lint */ 13 14 #ifndef lint 15 static char sccsid[] = "@(#)gcore.c 5.7 (Berkeley) 02/06/91"; 16 #endif /* not lint */ 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 */ 35 #include <machine/pte.h> 36 #include <sys/param.h> 37 #include <sys/user.h> 38 #include <sys/proc.h> 39 #include <sys/vm.h> 40 #include <setjmp.h> 41 #include <stdio.h> 42 #include <nlist.h> 43 #include <varargs.h> 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 64 struct 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 75 { "_dmmin" }, 76 #define X_DMMIN 5 77 { "_dmmax" }, 78 #define X_DMMAX 6 79 { 0 }, 80 }; 81 82 #define FEW 20 /* for fewer system calls */ 83 struct proc proc[FEW]; 84 85 union { 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 97 int nproc; 98 int nswap; 99 int dmmin, dmmax; 100 struct pte *Usrptmap, *usrpt; 101 char coref[20]; 102 int kmem, mem, swap, cor; 103 jmp_buf cont_frame; 104 105 main(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(); 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); 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 } 156 if (p->p_flag & SWEXIT) 157 printf("Warning: process exiting.\n"); 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 } 172 } 173 174 getword(loc) 175 off_t loc; 176 { 177 int word; 178 179 Get(kmem, loc, &word, sizeof(int)); 180 return (word); 181 } 182 183 openfiles() 184 { 185 kmem = open(KMEM, 0); 186 if (kmem < 0) { 187 perror(KMEM); 188 exit(1); 189 } 190 mem = open(MEM, 0); 191 if (mem < 0) { 192 perror(MEM); 193 exit(1); 194 } 195 swap = open(SWAP, 0); 196 if (swap < 0) { 197 perror(SWAP); 198 exit(1); 199 } 200 } 201 202 getkvars() 203 { 204 nlist(NLIST, nl); 205 if (nl[0].n_type == 0) { 206 printf("%s: No namelist\n", NLIST); 207 exit(1); 208 } 209 Usrptmap = (struct pte *) nl[X_USRPTMA].n_value; 210 usrpt = (struct pte *) nl[X_USRPT].n_value; 211 } 212 213 /* 214 * Get the system page table entries (mapping the user page table). 215 * These are the entries Usrptmap[i .. i + szpt], 216 * where i = btokmx(p->p_p0br) and szpt = p->p_szpt. 217 * For our purposes, we can skip over the ptes mapping 218 * the text segment ptes. 219 */ 220 struct pte *syspt; /* pte's from Usrptmap */ 221 int nsysptes; 222 223 getsyspt(p) 224 register struct proc *p; 225 { 226 nsysptes = p->p_szpt - (p->p_tsize / NPTEPG); 227 syspt = (struct pte *) malloc(nsysptes * sizeof(struct pte)); 228 if (syspt == NULL) 229 panic("can't alloc %d page table entries", nsysptes); 230 Get(kmem, &Usrptmap[btokmx(p->p_p0br) + (p->p_tsize / NPTEPG)], 231 syspt, nsysptes * sizeof(struct pte)); 232 } 233 234 /* 235 * Get the user page table for a segment. 236 * seg 0 = p0 (not including text) 237 * seg 1 = p1 (stack and u area) 238 * The system pt is consulted to find each page of user ptes. 239 */ 240 struct pte * 241 getpt(p, seg) 242 register struct proc *p; 243 int seg; 244 { 245 register int i; 246 register struct pte *spt; 247 struct pte *pt; 248 int nptes, offset, n; 249 250 if (seg == 0) { 251 nptes = p->p_dsize; 252 spt = syspt; 253 offset = p->p_tsize % NPTEPG; 254 } else { 255 nptes = p->p_ssize + UPAGES; 256 spt = syspt + (nsysptes - ctopt(nptes)); 257 offset = -nptes % NPTEPG; 258 if (offset < 0) 259 offset += NPTEPG; 260 } 261 pt = (struct pte *) malloc(nptes * sizeof(struct pte)); 262 if (pt == NULL) 263 panic("can't alloc %d page table entries", nptes); 264 for (i = 0; i < nptes; i += n) { 265 n = min(NPTEPG - offset, nptes - i); 266 Get(mem, ctob(spt->pg_pfnum) + offset * sizeof(struct pte), 267 pt + i, n * sizeof(struct pte)); 268 spt++; 269 offset = 0; 270 } 271 return (pt); 272 } 273 274 /* 275 * Build the core file. 276 */ 277 core(p) 278 register struct proc *p; 279 { 280 register struct pte *p0, *p1; 281 282 if (p->p_flag & SLOAD) { /* page tables are resident */ 283 getsyspt(p); 284 p0 = getpt(p, 0); 285 p1 = getpt(p, 1); 286 #ifdef DEBUG 287 showpt(syspt, nsysptes, "system"); 288 showpt(p0, p->p_dsize, "p0"); 289 showpt(p1, p->p_ssize + UPAGES, "p1"); 290 #endif 291 } else 292 p0 = p1 = NULL; /* not actually used */ 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 */ 308 getu(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 */ 333 getseg(p, segsize, pages, map, rev) 334 register struct proc *p; 335 int segsize; 336 register struct pte *pages; 337 struct dmap *map; 338 int rev; 339 { 340 register int i; 341 struct dblock db; 342 int size; 343 char buf[ctob(CLSIZE)]; 344 345 for (i = 0; i < segsize; i += CLSIZE) { 346 size = min(CLSIZE, segsize - i); 347 if ((p->p_flag & SLOAD) == 0 || pages[i].pg_fod || 348 pages[i].pg_pfnum == 0) { 349 vstodb(i, size, map, &db, rev); 350 Get(swap, ctob(db.db_base), buf, ctob(size)); 351 write(cor, buf, ctob(size)); 352 } else { 353 Get(mem, ctob(pages[i].pg_pfnum), buf, ctob(size)); 354 write(cor, buf, ctob(size)); 355 } 356 } 357 } 358 359 /* 360 * Given a base/size pair in virtual swap area, 361 * return a physical base/size pair which is the 362 * (largest) initial, physically contiguous block. 363 */ 364 vstodb(vsbase, vssize, dmp, dbp, rev) 365 register int vsbase; 366 int vssize; 367 struct dmap *dmp; 368 register struct dblock *dbp; 369 int rev; 370 { 371 register int blk = dmmin; 372 register swblk_t *ip = dmp->dm_map; 373 374 if (vsbase < 0 || vsbase + vssize > dmp->dm_size) 375 panic("can't make sense out of virtual memory (gcore probably needs to be recompiled)"); 376 while (vsbase >= blk) { 377 vsbase -= blk; 378 if (blk < dmmax) 379 blk *= 2; 380 ip++; 381 } 382 if (*ip <= 0 || *ip + blk > nswap) 383 panic("vstodb *ip"); 384 dbp->db_size = MIN(vssize, blk - vsbase); 385 dbp->db_base = *ip + (rev ? blk - (vsbase + dbp->db_size) : vsbase); 386 } 387 388 #ifdef lint 389 /*VARARGS1*/ 390 panic(fmt) 391 char *fmt; 392 { 393 394 fmt = fmt; 395 longjmp(cont_frame, 1); 396 } 397 #else /* lint */ 398 panic(va_alist) 399 va_dcl 400 { 401 va_list ap; 402 char *fmt; 403 404 va_start(ap); 405 fmt = va_arg(ap, char *); 406 (void) vprintf(fmt, ap); 407 va_end(ap); 408 (void) printf("\n"); 409 longjmp(cont_frame, 1); 410 } 411 #endif /* lint */ 412 413 /* 414 * Debugging routine to print out page table. 415 */ 416 #ifdef DEBUG 417 showpt(pt, n, s) 418 struct pte *pt; 419 int n; 420 char *s; 421 { 422 register struct pte *p; 423 register int i; 424 425 printf("*** %s page table\n", s); 426 for (i = 0, p = pt; i < n; i++, p++) 427 if (! p->pg_fod) 428 printf("%d: %x\n", i, p->pg_pfnum); 429 } 430 #endif 431