1 /* 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. 16 */ 17 18 #ifndef lint 19 char copyright[] = 20 "@(#) Copyright (c) 1982 The Regents of the University of California.\n\ 21 All rights reserved.\n"; 22 #endif /* not lint */ 23 24 #ifndef lint 25 static char sccsid[] = "@(#)gcore.c 5.4 (Berkeley) 09/15/88"; 26 #endif /* not lint */ 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> 51 #include <machine/pte.h> 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 74 struct 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 85 { "_dmmin" }, 86 #define X_DMMIN 5 87 { "_dmmax" }, 88 #define X_DMMAX 6 89 { 0 }, 90 }; 91 92 #define FEW 20 /* for fewer system calls */ 93 struct proc proc[FEW]; 94 95 union { 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 107 int nproc; 108 int nswap; 109 int dmmin, dmmax; 110 struct pte *Usrptmap, *usrpt; 111 char coref[20]; 112 int kmem, mem, swap, cor; 113 jmp_buf cont_frame; 114 115 main(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); 134 dmmin = getw(nl[X_DMMIN].n_value); 135 dmmax = getw(nl[X_DMMAX].n_value); 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 } 166 if (p->p_flag & SWEXIT) 167 printf("Warning: process exiting.\n"); 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 184 getw(loc) 185 off_t loc; 186 { 187 int word; 188 189 Get(kmem, loc, &word, sizeof(int)); 190 return (word); 191 } 192 193 openfiles() 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 212 getkvars() 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 */ 230 struct pte *syspt; /* pte's from Usrptmap */ 231 int nsysptes; 232 233 getsyspt(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 */ 250 struct pte * 251 getpt(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 */ 287 core(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 */ 317 getu(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 */ 342 getseg(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 */ 372 vstodb(vsbase, vssize, dmp, dbp, rev) 373 register int vsbase; 374 int vssize; 375 struct dmap *dmp; 376 register struct dblock *dbp; 377 { 378 register int blk = dmmin; 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; 385 if (blk < dmmax) 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*/ 396 panic(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 408 showpt(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 422