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