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 8 char copyright[] = 9 "@(#) Copyright (c) 1983 Regents of the University of California.\n\ 10 All rights reserved.\n"; 11 #endif not lint 12 13 #ifndef lint 14 static char sccsid[] = "@(#)gcore.c 5.3 (Berkeley) 03/30/87"; 15 #endif not lint 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> 40 #include <machine/pte.h> 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 63 struct 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 74 { "_dmmin" }, 75 #define X_DMMIN 5 76 { "_dmmax" }, 77 #define X_DMMAX 6 78 { 0 }, 79 }; 80 81 #define FEW 20 /* for fewer system calls */ 82 struct proc proc[FEW]; 83 84 union { 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 96 int nproc; 97 int nswap; 98 int dmmin, dmmax; 99 struct pte *Usrptmap, *usrpt; 100 char coref[20]; 101 int kmem, mem, swap, cor; 102 jmp_buf cont_frame; 103 104 main(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); 123 dmmin = getw(nl[X_DMMIN].n_value); 124 dmmax = getw(nl[X_DMMAX].n_value); 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("Warning: process exiting.\n"); 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 173 getw(loc) 174 off_t loc; 175 { 176 int word; 177 178 Get(kmem, loc, &word, sizeof(int)); 179 return (word); 180 } 181 182 openfiles() 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 201 getkvars() 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 */ 219 struct pte *syspt; /* pte's from Usrptmap */ 220 int nsysptes; 221 222 getsyspt(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 */ 239 struct pte * 240 getpt(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 */ 276 core(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 */ 306 getu(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 */ 331 getseg(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 */ 361 vstodb(vsbase, vssize, dmp, dbp, rev) 362 register int vsbase; 363 int vssize; 364 struct dmap *dmp; 365 register struct dblock *dbp; 366 { 367 register int blk = dmmin; 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; 374 if (blk < dmmax) 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*/ 385 panic(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 397 showpt(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 411