* Copyright (c) 1983 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
"@(#) Copyright (c) 1983 Regents of the University of California.\n\
static char sccsid
[] = "@(#)gcore.c 5.2 (Berkeley) %G%";
* gcore - get core images of running processes
* Inspired by a version 6 program by Len Levin, 1978.
* Several pieces of code lifted from Bill Joy's 4BSD ps.
* Permission to copy or modify this program in whole or in part is hereby
* granted, provided that the above credits are preserved.
* This code performs a simple simulation of the virtual memory system in user
* code. If the virtual memory system changes, this program must be modified
* accordingly. It must also be recompiled whenever system data structures
/* Various macros for efficiency. */
#define min(a, b) (a < b ? a : b)
if (lseek(f, (long) (pos), 0) != (long) (pos)) \
#define Read(f, addr, n) {\
if (read(f, (char *) (addr), (int) (n)) != (int) (n)) \
#define Get(f, pos, addr, n) {\
#define FEW 20 /* for fewer system calls */
char upages
[UPAGES
][NBPG
];
#define uarea user.upages
#define SWAP "/dev/drum" /* "/dev/swap" on some systems */
struct pte
*Usrptmap
, *usrpt
;
int kmem
, mem
, swap
, cor
;
printf("Usage: %s pid ...\n", argv
[0]);
procbase
= getw(nl
[X_PROC
].n_value
);
nproc
= getw(nl
[X_NPROC
].n_value
);
nswap
= getw(nl
[X_NSWAP
].n_value
);
dmmin
= getw(nl
[X_DMMIN
].n_value
);
dmmax
= getw(nl
[X_DMMAX
].n_value
);
if ((pid
= atoi(*++argv
)) <= 0 || setjmp(cont_frame
))
for (i
= 0; i
< nproc
; i
+= FEW
) {
j
*= sizeof(struct proc
);
Read(kmem
, (char *) proc
, j
);
for (j
= j
/ sizeof(struct proc
) - 1; j
>= 0; j
--) {
printf("Process not found.\n");
if (p
->p_uid
!= (uid
= getuid()) && uid
!= 0) {
if (p
->p_stat
== SZOMB
) {
if (p
->p_flag
& SWEXIT
) {
printf("Process exiting.\n");
printf("System process.\n");
/* i.e. swapper or pagedaemon */
sprintf(coref
, "core.%d", pid
);
if ((cor
= creat(coref
, 0666)) < 0) {
printf("%s dumped\n", coref
);
Get(kmem
, loc
, &word
, sizeof(int));
printf("%s: No namelist\n", NLIST
);
Usrptmap
= (struct pte
*) nl
[X_USRPTMA
].n_value
;
usrpt
= (struct pte
*) nl
[X_USRPT
].n_value
;
* Get the system page table entries (mapping the user page table).
* These are the entries Usrptmap[i .. i + szpt],
* where i = btokmx(p->p_p0br) and szpt = p->p_szpt.
* For our purposes, we can skip over the ptes mapping
struct pte
*syspt
; /* pte's from Usrptmap */
nsysptes
= p
->p_szpt
- (p
->p_tsize
/ NPTEPG
);
syspt
= (struct pte
*) malloc(nsysptes
* sizeof(struct pte
));
panic("can't alloc %d page table entries", nsysptes
);
Get(kmem
, &Usrptmap
[btokmx(p
->p_p0br
) + (p
->p_tsize
/ NPTEPG
)],
syspt
, nsysptes
* sizeof(struct pte
));
* Get the user page table for a segment.
* seg 0 = p0 (not including text)
* seg 1 = p1 (stack and u area)
* The system pt is consulted to find each page of user ptes.
register struct pte
*spt
;
offset
= p
->p_tsize
% NPTEPG
;
nptes
= p
->p_ssize
+ UPAGES
;
spt
= syspt
+ (nsysptes
- ctopt(nptes
));
offset
= -nptes
% NPTEPG
;
pt
= (struct pte
*) malloc(nptes
* sizeof(struct pte
));
panic("can't alloc %d page table entries", nptes
);
for (i
= 0; i
< nptes
; i
+= n
) {
n
= min(NPTEPG
- offset
, nptes
- i
);
Get(mem
, ctob(spt
->pg_pfnum
) + offset
* sizeof(struct pte
),
pt
+ i
, n
* sizeof(struct pte
));
register struct pte
*p0
, *p1
;
if (p
->p_flag
& SLOAD
) { /* page tables are resident */
showpt(syspt
, nsysptes
, "system");
showpt(p0
, p
->p_dsize
, "p0");
showpt(p1
, p
->p_ssize
+ UPAGES
, "p1");
getu(p
, &p1
[p
->p_ssize
]); /* u area */
getseg(p
, p
->p_dsize
, p0
, &u
.u_dmap
, 0); /* data */
getseg(p
, p
->p_ssize
, p1
, &u
.u_smap
, 1); /* stack */
* Keeps around the u structure for later use
* (the data and stack disk map structures).
register struct pte
*pages
;
if ((p
->p_flag
& SLOAD
) == 0) {
Get(swap
, ctob(p
->p_swaddr
), uarea
, ctob(UPAGES
));
write(cor
, uarea
, ctob(UPAGES
));
for (i
= 0; i
< UPAGES
; i
+= CLSIZE
) {
Get(mem
, ctob(pages
[i
].pg_pfnum
), uarea
[i
], ctob(CLSIZE
));
write(cor
, uarea
[i
], ctob(CLSIZE
));
* Copy a segment to the core file.
* The segment is described by its size in clicks,
* its page table, its disk map, and whether or not
* Note that the page table address is allowed to be meaningless
* if the process is swapped out.
getseg(p
, segsize
, pages
, map
, rev
)
register struct pte
*pages
;
for (i
= 0; i
< segsize
; i
+= CLSIZE
) {
size
= min(CLSIZE
, segsize
- i
);
if ((p
->p_flag
& SLOAD
) == 0 || pages
[i
].pg_fod
||
pages
[i
].pg_pfnum
== 0) {
vstodb(i
, size
, map
, &db
, rev
);
Get(swap
, ctob(db
.db_base
), buf
, ctob(size
));
write(cor
, buf
, ctob(size
));
Get(mem
, ctob(pages
[i
].pg_pfnum
), buf
, ctob(size
));
write(cor
, buf
, ctob(size
));
* Given a base/size pair in virtual swap area,
* return a physical base/size pair which is the
* (largest) initial, physically contiguous block.
vstodb(vsbase
, vssize
, dmp
, dbp
, rev
)
register struct dblock
*dbp
;
register int blk
= dmmin
;
register swblk_t
*ip
= dmp
->dm_map
;
if (vsbase
< 0 || vsbase
+ vssize
> dmp
->dm_size
)
panic("can't make sense out of virtual memory (gcore probably needs to be recompiled)");
if (*ip
<= 0 || *ip
+ blk
> nswap
)
dbp
->db_size
= MIN(vssize
, blk
- vsbase
);
dbp
->db_base
= *ip
+ (rev
? blk
- (vsbase
+ dbp
->db_size
) : vsbase
);
* Debugging routine to print out page table.
printf("*** %s page table\n", s
);
for (i
= 0, p
= pt
; i
< n
; i
++, p
++)
printf("%d: %x\n", i
, p
->pg_pfnum
);