| /* |
| * dproc.c - /dev/kmem-based HP-UX process access functions for lsof |
| */ |
| |
| |
| /* |
| * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana |
| * 47907. All rights reserved. |
| * |
| * Written by Victor A. Abell |
| * |
| * This software is not subject to any license of the American Telephone |
| * and Telegraph Company or the Regents of the University of California. |
| * |
| * Permission is granted to anyone to use this software for any purpose on |
| * any computer system, and to alter it and redistribute it freely, subject |
| * to the following restrictions: |
| * |
| * 1. Neither the authors nor Purdue University are responsible for any |
| * consequences of the use of this software. |
| * |
| * 2. The origin of this software must not be misrepresented, either by |
| * explicit claim or by omission. Credit to the authors and Purdue |
| * University must appear in documentation and sources. |
| * |
| * 3. Altered versions must be plainly marked as such, and must not be |
| * misrepresented as being the original software. |
| * |
| * 4. This notice may not be removed or altered. |
| */ |
| |
| #ifndef lint |
| static char copyright[] = |
| "@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n"; |
| static char *rcsid = "$Id: dproc.c,v 1.18 2008/10/08 13:24:36 abe Exp $"; |
| #endif |
| |
| #if defined(HPUXKERNBITS) |
| # if HPUXKERNBITS>=64 |
| #define _INO_T |
| typedef int ino_t; |
| #define _TIME_T |
| typedef int time_t; |
| # else /* HPUXKERNBITS<64 */ |
| #define _RLIM_T |
| # if !defined(__STDC_32_MODE__) |
| typedef unsigned long long rlim_t; |
| # else /* defined(__STDC_32_MODE__) */ |
| typedef unsigned long rlim_t; |
| # endif /* !defined(__STDC_32_MODE__) */ |
| # endif /* HPUXKERNBITS>=64 */ |
| #endif /* defined(HPUXKERNBITS) */ |
| |
| #include "lsof.h" |
| |
| #if defined(HASNCACHE) |
| #include <sys/dnlc.h> |
| #endif /* defined(HASNCACHE) */ |
| |
| |
| #if HPUXV>=1010 |
| /* |
| * HP doesn't include a definition for the proc structure in HP-UX 10.10 |
| * or above in an attempt to force use of pstat(2). Unfortunately, pstat(2) |
| * doesn't return the information lsof needs. Hence, this private proc |
| * structure definition. |
| */ |
| |
| #include <sys/vas.h> |
| |
| #define SZOMB 3 |
| |
| # if HPUXV<1020 |
| struct proc { |
| caddr_t d1[2]; /* dummy to occupy space */ |
| caddr_t p_firstthreadp; /* thread pointer */ |
| caddr_t d2[4]; /* dummy to occupy space */ |
| int p_stat; /* process status */ |
| caddr_t d3[9]; /* dummy to occupy space */ |
| uid_t p_uid; /* UID */ |
| caddr_t d4[2]; /* dummy to occupy space */ |
| gid_t p_pgid; /* process group ID */ |
| pid_t p_pid; /* PID */ |
| pid_t p_ppid; /* parent PID */ |
| caddr_t d5[9]; /* dummy to occupy space */ |
| vas_t *p_vas; /* virtual address space */ |
| caddr_t d6[16]; /* dummy to occupy space */ |
| int p_maxof; /* max open files allowed */ |
| struct vnode *p_cdir; /* current directory */ |
| struct vnode *p_rdir; /* root directory */ |
| struct ofile_t **p_ofilep; /* file descriptor chunks */ |
| caddr_t d7[43]; /* dummy to occupy space */ |
| }; |
| # endif /* HPUXV<1020 */ |
| |
| # if HPUXV>=1020 && HPUXV<1030 |
| struct proc { |
| caddr_t d1[2]; /* dummy to occupy space */ |
| caddr_t p_firstthreadp; /* thread pointer */ |
| caddr_t d2[6]; /* dummy to occupy space */ |
| int p_stat; /* process status */ |
| caddr_t d3[14]; /* dummy to occupy space */ |
| uid_t p_uid; /* real UID */ |
| uid_t p_suid; /* effective UID */ |
| caddr_t d4; /* dummy to occupy space */ |
| gid_t p_pgid; /* process group ID */ |
| pid_t p_pid; /* PID */ |
| pid_t p_ppid; /* parent PID */ |
| caddr_t d5[9]; /* dummy to occupy space */ |
| vas_t *p_vas; /* virtual address space */ |
| caddr_t d6[16]; /* dummy to occupy space */ |
| int p_maxof; /* max open files allowed */ |
| struct vnode *p_cdir; /* current directory */ |
| struct vnode *p_rdir; /* root directory */ |
| struct ofile_t **p_ofilep; /* file descriptor chunks */ |
| caddr_t d7[84]; /* dummy to occupy space */ |
| }; |
| # endif /* HPUXV>=1020 && HPUXV<1030 */ |
| #endif /* HPUXV<1010 */ |
| |
| |
| /* |
| * Local static values |
| */ |
| |
| static KA_T Kp; /* kernel's process table address */ |
| static int Np; /* number of kernel processes */ |
| |
| #if HPUXV>=800 |
| static MALLOC_S Nva = 0; /* number of entries allocated to |
| * vnode address cache */ |
| static KA_T *Vp = (KA_T *)NULL; /* vnode address cache */ |
| #endif /* HPUXV>=800 */ |
| |
| |
| _PROTOTYPE(static void get_kernel_access,(void)); |
| |
| #if HPUXV>=800 |
| _PROTOTYPE(static void process_text,(KA_T vasp)); |
| #endif /* HPUXV>=800 */ |
| |
| |
| /* |
| * gather_proc_info() -- gather process information |
| */ |
| |
| void |
| gather_proc_info() |
| { |
| KA_T fp; |
| int err, i, j; |
| |
| #if HPUXV>=1020 && HPUXV<1100 |
| struct ofile_t { |
| struct ofa { |
| KA_T ofile; |
| int d1; |
| int pofile; |
| } ofa[SFDCHUNK]; |
| }; |
| struct ofa *ofap; |
| int ofasz = (int)sizeof(struct ofa); |
| struct ofile_t oft; |
| char *oftp = (char *)&oft; |
| int oftsz = (int)sizeof(struct ofile_t); |
| #else /* HPUXV<1020 || HPUXV>=1100 */ |
| # if HPUXV>=1100 |
| struct ofa { |
| KA_T ofile; |
| int d1; |
| short d2; |
| char d3; |
| char pofile; |
| }; |
| struct ofa *ofap; |
| int ofasz = (int)sizeof(struct ofa); |
| char *oftp = (char *)NULL; |
| int oftsz = (int)(sizeof(struct ofa) * SFDCHUNK); |
| KA_T v; |
| # endif /* HPUXV>=1100 */ |
| #endif /* HPUXV>=1020 && HPUXV<1100 */ |
| |
| #if HPUXV>=800 |
| char *c, *s; |
| KA_T pfp, ofp; |
| |
| #if HPUXV<1020 |
| struct ofile_t oft; |
| char *oftp = (char *)&oft; |
| int oftsz = (int)sizeof(struct ofile_t); |
| #endif /* HPUXV<1020 */ |
| |
| struct pst_status ps; |
| |
| # if HPUXV<1010 |
| struct user us; |
| # else /* HPUXV>=1010 */ |
| struct user { |
| char u_comm[PST_CLEN]; |
| } us; |
| # endif /* HPUXV<1010 */ |
| #else /* HPUXV<800 */ |
| int k; |
| long sw; |
| char us[U_SIZE]; /* must read HP-UX SWAP in DEV_BSIZE chunks */ |
| |
| # if defined(hp9000s300) |
| struct pte pte1, pte2; |
| KA_T pte_off, pte_addr; |
| # endif /* defined(hp9000s300) */ |
| #endif /* HPUXV>=800 */ |
| |
| struct proc *p; |
| struct proc pbuf; |
| short pss, sf; |
| int px; |
| struct user *u; |
| |
| #if defined(HASFSTRUCT) |
| # if HPUXV>=1020 || (HPUXV>=900 && HPUXV<1000) |
| #define USESPOFILE 1 |
| long pof; |
| # endif /* HPUXV>=1020 || (HPUXV>=900 && HPUXV<1000) */ |
| #endif /* defined(HASFSTRUCT) */ |
| |
| #if HPUXV>=1100 |
| /* |
| * Define FD chunk size and pointer for HP-UX >= 11. |
| */ |
| if (!oftp) { |
| if ((get_Nl_value("chunksz", Drive_Nl, &v) >= 0) && v) { |
| if (kread(v, (char *)&oftsz, sizeof(oftsz))) { |
| (void) fprintf(stderr, "%s: can't get FD chunk size\n", |
| Pn); |
| Exit(1); |
| } |
| if (!oftsz) { |
| (void) fprintf(stderr, "%s: bad FD chunk size: %d\n", |
| Pn, oftsz); |
| Exit(1); |
| } |
| } |
| ofasz = (int)(oftsz / SFDCHUNK); |
| if (oftsz != (ofasz * SFDCHUNK)) { |
| (void) fprintf(stderr, |
| "%s: FD chunk size (%d) not exact multiple of %d\n", |
| Pn, oftsz, SFDCHUNK); |
| Exit(1); |
| } |
| if (!(oftp = (char *)malloc((MALLOC_S)oftsz))) { |
| (void) fprintf(stderr, "%s: no space for %d FD bytes\n", |
| Pn, oftsz); |
| Exit(1); |
| } |
| } |
| #endif /* HPUXV>=1100 */ |
| |
| /* |
| * Examine proc structures and their associated information. |
| */ |
| |
| #if HPUXV>=800 |
| u = &us; |
| (void) zeromem((char *)u, U_SIZE); |
| for (p = &pbuf, px = 0; px < Np; px++) |
| #else /* HPUXV<800 */ |
| for (p = &pbuf, px = 0, u = (struct user *)us; px < Np; px++) |
| #endif /* HPUXV>=800 */ |
| |
| { |
| Kpa = Kp + (KA_T)(px * sizeof(struct proc)); |
| if (kread(Kpa, (char *)&pbuf, sizeof(pbuf))) |
| continue; |
| if (p->p_stat == 0 || p->p_stat == SZOMB) |
| continue; |
| /* |
| * See if process is excluded. |
| */ |
| if (is_proc_excl(p->p_pid, (int)p->p_pgid, (UID_ARG)p->p_uid, |
| &pss, &sf)) |
| continue; |
| |
| #if HPUXV>=1010 |
| /* |
| * Save the kernel thread pointer. |
| */ |
| Ktp = (KA_T)p->p_firstthreadp; |
| #endif /* HPUXV>=1010 */ |
| |
| /* |
| * Read the user area. |
| */ |
| |
| #if HPUXV>=800 |
| /* |
| * Use the pstat() syscall to read process status. |
| */ |
| |
| if (pstat(PSTAT_PROC, &ps, sizeof(ps), 0, p->p_pid) != 1) { |
| if (!Fwarn) |
| (void) fprintf(stderr, "%s: can't pstat process %d: %s\n", |
| Pn, p->p_pid, strerror(errno)); |
| continue; |
| } |
| /* |
| * Use the pst_cmd command buffer. |
| */ |
| c = ps.pst_cmd; |
| ps.pst_cmd[PST_CLEN - 1] = '\0'; /* paranoia */ |
| /* |
| * Skip to the last component of the first path name. Also skip any |
| * leading `-', signifying a login shell. Copy the result to u_comm[]. |
| */ |
| if (*c == '-') |
| c++; |
| for (s = c; *c && (*c != ' '); c++) { |
| if (*c == '/') |
| s = c + 1; |
| } |
| for (i = 0; i < MAXCOMLEN; i++) { |
| if (*s == '\0' || *s == ' ' || *s == '/') |
| break; |
| u->u_comm[i] = *s++; |
| } |
| u->u_comm[i] = '\0'; |
| #else /* HPUXV<800 */ |
| /* |
| * Read the user area from the swap file or memory. |
| */ |
| if ((p->p_flag & SLOAD) == 0) { |
| |
| /* |
| * If the process is not loaded, read the user area from the swap |
| * file. |
| */ |
| if (Swap < 0) |
| continue; |
| sw = (long)p->p_swaddr; |
| |
| # if defined(hp9000s800) |
| sw += (long)ctod(btoc(STACKSIZE * NBPG)); |
| # endif /* defined(hp9000s800) */ |
| |
| if (lseek(Swap, (off_t)dtob(sw), L_SET) == (off_t)-1 |
| || read(Swap, u, U_SIZE) != U_SIZE) |
| continue; |
| } else { |
| |
| /* |
| * Read the user area via the page table. |
| */ |
| |
| # if defined(hp9000s300) |
| pte_off = (KA_T) &Usrptmap[btokmx(p->p_p0br) + p->p_szpt - 1]; |
| if (kread(pte_off, (char *)&pte1, sizeof(pte1))) |
| continue; |
| pte_addr = (KA_T)(ctob(pte1.pg_pfnum + 1) |
| - ((UPAGES + FLOAT) * sizeof(pte2))); |
| if (mread(pte_addr, (char *)&pte2, sizeof(pte2))) |
| continue; |
| if (mread((KA_T)ctob(pte2.pg_pfnum), (char *)u, |
| sizeof(struct user))) |
| continue; |
| # endif /* defined(hp9000s300) */ |
| |
| # if defined(hp9000s800) |
| if (kread((KA_T)uvadd((struct proc *)Kpa), (char *)u, |
| sizeof(struct user))) |
| continue; |
| } |
| # endif /* defined(hp9000s800) */ |
| #endif /* HPUXV>=800 */ |
| |
| /* |
| * Allocate a local process structure. |
| */ |
| if (is_cmd_excl(u->u_comm, &pss, &sf)) |
| continue; |
| alloc_lproc(p->p_pid, (int)p->p_pgid, (int)p->p_ppid, |
| (UID_ARG)p->p_uid, u->u_comm, (int)pss, (int)sf); |
| Plf = (struct lfile *)NULL; |
| /* |
| * Save current working directory information. |
| */ |
| if (CURDIR) { |
| alloc_lfile(CWD, -1); |
| process_node((KA_T)CURDIR); |
| if (Lf->sf) |
| link_lfile(); |
| } |
| /* |
| * Save root directory information. |
| */ |
| if (ROOTDIR) { |
| alloc_lfile(RTD, -1); |
| process_node((KA_T)ROOTDIR); |
| if (Lf->sf) |
| link_lfile(); |
| } |
| |
| #if HPUXV>=800 |
| /* |
| * Print information on the text file. |
| */ |
| if (p->p_vas) |
| process_text((KA_T)p->p_vas); |
| #endif /* HPUXV>=800 */ |
| |
| /* |
| * Loop through user's files. |
| */ |
| |
| #if HPUXV>=800 |
| for (i = 0, j = SFDCHUNK, pfp = (KA_T)p->p_ofilep; |
| i < p->p_maxof; |
| i++) |
| #else /* HPUXV<800 */ |
| for (i = j = k = 0;; i++) |
| #endif /* HPUXV>=800 */ |
| |
| { |
| |
| #if HPUXV>=800 |
| if (j >= SFDCHUNK) { |
| if (!pfp || kread((KA_T)pfp, (char *)&ofp, sizeof(ofp)) |
| || !ofp || kread((KA_T)ofp, oftp, oftsz)) |
| break; |
| j = 0; |
| pfp += sizeof(KA_T); |
| |
| # if HPUXV>=1020 |
| ofap = (struct ofa *)oftp; |
| # endif /* HPUXV>=1020 */ |
| |
| } |
| j++; |
| |
| # if HPUXV>=1020 |
| # if defined(USESPOFILE) |
| pof = (long)ofap->pofile; |
| # endif /* defined(USESPOFILE) */ |
| |
| fp = (KA_T)ofap->ofile; |
| ofap = (struct ofa *)((char *)ofap + ofasz); |
| if (fp) |
| # else /* HPUXV<1020 */ |
| # if defined(USESPOFILE) |
| pof = (long)oft.pofile[j - 1]; |
| # endif /* defined(USESPOFILE) */ |
| |
| if ((fp = (KA_T)oft.ofile[j - 1])) |
| # endif /* HPUXV>=1020 */ |
| #else /* HPUXV<800 */ |
| if (j >= SFDCHUNK) { |
| |
| /* |
| * Get next file pointer "chunk". |
| */ |
| while (++k < NFDCHUNKS && !u->u_ofilep[k]) |
| ; |
| if (k >= NFDCHUNKS) |
| break; |
| if (kread((KA_T)u->u_ofilep[k], (char *)&u->u_ofile, |
| sizeof(struct ofile_t))) |
| { |
| break; |
| } |
| j = 0; |
| } |
| j++; |
| if ((fp = (KA_T)u->u_ofile.ofile[j - 1])) |
| #endif /* HPUXV>=800 */ |
| |
| /* |
| * Process the file pointer. |
| */ |
| |
| { |
| alloc_lfile(NULL, i); |
| process_file(fp); |
| if (Lf->sf) { |
| |
| #if defined(USESPOFILE) |
| if (Fsv & FSV_FG) |
| Lf->pof = pof; |
| #endif /* defined(USESPOFILE) */ |
| |
| link_lfile(); |
| } |
| } |
| } |
| /* |
| * Examine results. |
| */ |
| if (examine_lproc()) |
| return; |
| } |
| } |
| |
| |
| /* |
| * get_kernel_access() - access the required information in the kernel |
| */ |
| |
| static void |
| get_kernel_access() |
| { |
| KA_T v; |
| /* |
| * Check the kernel version. |
| */ |
| (void) ckkv("HP-UX", LSOF_VSTR, (char *)NULL, (char *)NULL); |
| |
| #if HPUXV>=1030 |
| /* |
| * See if build and run bit sizes match. Exit if they don't. |
| */ |
| { |
| long rv; |
| |
| if ((rv = sysconf(_SC_KERNEL_BITS)) < 0) { |
| (void) fprintf(stderr, |
| "%s: sysconf(_SC_KERNEL_BITS) returns: %s\n", |
| Pn, strerror(errno)); |
| Exit(1); |
| } |
| if (rv != (long)HPUXKERNBITS) { |
| (void) fprintf(stderr, |
| "%s: FATAL: %s was built for a %d bit kernel, but this\n", |
| Pn, Pn, HPUXKERNBITS); |
| (void) fprintf(stderr, " is a %ld bit kernel.\n", rv); |
| Exit(1); |
| } |
| } |
| #endif /* HPUXV>=1030 */ |
| |
| #if defined(HAS_AFS) |
| struct NLIST_TYPE *nl = (struct NLIST_TYPE *)NULL; |
| #endif /* defined(HAS_AFS) */ |
| |
| #if HPUXV<800 |
| /* |
| * Open access to /dev/mem and SWAP. |
| */ |
| if ((Mem = open("/dev/mem", O_RDONLY, 0)) < 0) { |
| (void) fprintf(stderr, "%s: can't open /dev/mem: %s\n", |
| Pn, strerror(errno)); |
| err = 1; |
| } |
| if (!Memory || strcmp(Memory, KMEM) == 0) { |
| if ((Swap = open(SWAP, O_RDONLY, 0)) < 0) { |
| (void) fprintf(stderr, "%s: %s: %s\n", |
| Pn, SWAP, strerror(errno)); |
| err = 1; |
| } |
| } |
| #endif /* HPUXV<800 */ |
| |
| #if defined(WILLDROPGID) |
| /* |
| * If kernel memory isn't coming from KMEM, drop setgid permission |
| * before attempting to open the (Memory) file. |
| */ |
| if (Memory) |
| (void) dropgid(); |
| #else /* !defined(WILLDROPGID) */ |
| /* |
| * See if the non-KMEM memory file is readable. |
| */ |
| if (Memory && !is_readable(Memory, 1)) |
| Exit(1); |
| #endif /* defined(WILLDROPGID) */ |
| |
| /* |
| * Open kernel memory access. |
| */ |
| if ((Kd = open(Memory ? Memory : KMEM, O_RDONLY, 0)) < 0) { |
| int errno_save = errno; |
| |
| (void) fprintf(stderr, "%s: can't open ", Pn); |
| safestrprt(Memory ? Memory : KMEM, stderr, 0); |
| (void) fprintf(stderr, ": %s\n", strerror(errno_save)); |
| Exit(1); |
| } |
| |
| #if defined(WILLDROPGID) |
| /* |
| * Drop setgid permission, if necessary. |
| */ |
| if (!Memory) |
| (void) dropgid(); |
| #else /* !defined(WILLDROPGID) */ |
| /* |
| * See if the name list file is readable. |
| */ |
| if (Nmlst && !is_readable(Nmlst, 1)) |
| Exit(1); |
| #endif /* defined(WILLDROPGID) */ |
| |
| (void) build_Nl(Drive_Nl); |
| |
| #if defined(HAS_AFS) |
| if (!Nmlst) { |
| |
| /* |
| * If AFS is defined and we're getting kernel symbol values from |
| * from N_UNIX, make a copy of Nl[] for possible use with the AFS |
| * module name list file. |
| */ |
| if (!(nl = (struct NLIST_TYPE *)malloc(Nll))) { |
| (void) fprintf(stderr, |
| "%s: no space (%d) for Nl[] copy\n", Pn, Nll); |
| Exit(1); |
| } |
| (void) memcpy((void *)nl, (void *)Nl, (size_t)Nll); |
| } |
| #endif /* defined(HAS_AFS) */ |
| |
| /* |
| * Access kernel symbols. |
| */ |
| if (NLIST_TYPE(Nmlst ? Nmlst : N_UNIX, Nl) < 0) { |
| (void) fprintf(stderr, "%s: can't read namelist from: ", Pn); |
| safestrprt(Nmlst ? Nmlst : N_UNIX, stderr, 1); |
| Exit(1); |
| } |
| if (get_Nl_value("proc", Drive_Nl, &v) < 0 || !v |
| || kread((KA_T)v, (char *)&Kp, sizeof(Kp)) |
| || get_Nl_value("nproc", Drive_Nl, &v) < 0 || !v |
| || kread((KA_T)v, (char *)&Np, sizeof(Np)) |
| || !Kp || Np < 1) { |
| (void) fprintf(stderr, "%s: can't read proc table info\n", Pn); |
| Exit(1); |
| } |
| if (get_Nl_value("vfops", Drive_Nl, (KA_T *)&Vnfops) < 0) |
| Vnfops = (KA_T)NULL; |
| |
| #if HPUXV<800 && defined(hp9000s300) |
| if (get_Nl_value("upmap", Drive_Nl, (unsigned long *)&Usrptmap) < 0) { |
| (void) fprintf(stderr, "%s: can't get kernel's Usrptmap\n", Pn); |
| Exit(1); |
| } |
| if (get_Nl_value("upt", Drive_Nl, (unsigned long *)&usrpt) < 0) { |
| (void) fprintf(stderr, "%s: can't get kernel's usrpt\n", Pn); |
| Exit(1); |
| } |
| #endif /* HPUXV<800 && defined(hp9000s300) */ |
| |
| #if HPUXV<800 && defined(hp9000s800) |
| proc = (struct proc *)Kp; |
| if (get_Nl_value("ubase", Drive_Nl, (unsigned long *)&ubase) < 0) { |
| (void) fprintf(stderr, "%s: can't get kernel's ubase\n", Pn); |
| Exit(1); |
| } |
| if (get_Nl_value("npids", Drive_Nl, &v) < 0 || !v |
| || kread((KA_T)v, (char *)&npids, sizeof(npids))) { |
| (void) fprintf(stderr, "%s: can't get kernel's npids\n", Pn); |
| Exit(1); |
| } |
| #endif /* HPUXV<800 && defined(hp9000s800) */ |
| |
| #if HPUXV>=1030 |
| if (get_Nl_value("clmaj", Drive_Nl, &v) < 0 || !v |
| || kread((KA_T)v, (char *)&CloneMaj, sizeof(CloneMaj))) |
| HaveCloneMaj = 0; |
| else |
| HaveCloneMaj = 1; |
| #endif /* HPUXV>=1030 */ |
| |
| #if defined(HAS_AFS) |
| if (nl) { |
| |
| /* |
| * If AFS is defined and we're getting kernel symbol values from |
| * N_UNIX, and if any X_AFS_* symbols isn't there, see if it is in the |
| * the AFS module name list file. Make sure that other symbols that |
| * appear in both name list files have the same values. |
| */ |
| if ((get_Nl_value("arFid", Drive_Nl, &v) >= 0 && !v) |
| || (get_Nl_value("avops", Drive_Nl, &v) >= 0 && !v) |
| || (get_Nl_value("avol", Drive_Nl, &v) >= 0 && !v)) |
| (void) ckAFSsym(nl); |
| (void) free((FREE_P *)nl); |
| } |
| #endif /* defined(HAS_AFS) */ |
| |
| } |
| |
| |
| /* |
| * initialize() - perform all initialization |
| */ |
| |
| void |
| initialize() |
| { |
| get_kernel_access(); |
| } |
| |
| |
| /* |
| * kread() - read from kernel memory |
| */ |
| |
| int |
| kread(addr, buf, len) |
| KA_T addr; /* kernel memory address */ |
| char *buf; /* buffer to receive data */ |
| READLEN_T len; /* length to read */ |
| { |
| int br; |
| |
| if (lseek(Kd, (off_t)addr, L_SET) == (off_t)-1L) |
| return(-1); |
| br = read(Kd, buf, len); |
| return((br == len) ? 0 : 1); |
| } |
| |
| |
| #if HPUXV<800 |
| /* |
| * mread() -- read from /dev/mem |
| */ |
| |
| static int |
| mread(addr, buf, len) |
| KA_T addr; /* /dev/mem address */ |
| char *buf; /* buffer to receive data */ |
| READLEN_T len; /* length to read */ |
| { |
| int br; |
| |
| if (lseek(Mem, addr, L_SET) == (off_t)-1L) |
| return(1); |
| br = read(Mem, buf, len); |
| return((br == len) ? 0 : 1); |
| } |
| #endif /* HPUXV<800 */ |
| |
| |
| #if HPUXV>=800 |
| /* |
| * process_text() - process text access information |
| */ |
| |
| static void |
| process_text(vasp) |
| KA_T vasp; /* kernel's virtual address space |
| * pointer */ |
| { |
| char fd[FDLEN]; |
| int i, j, lm; |
| MALLOC_S len; |
| struct pregion p; |
| KA_T prp; |
| struct region r; |
| struct vas v; |
| KA_T va; |
| /* |
| * Read virtual address space pointer. |
| */ |
| if (kread(vasp, (char *)&v, sizeof(v))) |
| return; |
| /* |
| * Follow the virtual address space pregion structure chain. |
| */ |
| for (i = lm = 0, prp = (KA_T)v.va_next; |
| prp != vasp; |
| prp = (KA_T)p.p_next, lm++) |
| { |
| |
| /* |
| * Avoid infinite loop. |
| */ |
| if (lm > 1000) { |
| if (!Fwarn) |
| (void) fprintf(stderr, |
| "%s: too many virtual address regions for PID %d\n", |
| Pn, Lp->pid); |
| return; |
| } |
| /* |
| * Read the pregion and region. |
| */ |
| if (kread(prp, (char *)&p, sizeof(p))) |
| return; |
| if (kread((KA_T)p.p_reg, (char *)&r, sizeof(r))) |
| return; |
| /* |
| * Skip file entries with no file pointers. |
| */ |
| if (!(va = (KA_T)r.r_fstore)) |
| continue; |
| /* |
| * Skip entries whose vnodes have already been displayed. |
| * |
| * Record new, unique vnode pointers. |
| */ |
| for (j = 0; j < i; j++) { |
| if (Vp[j] == va) |
| break; |
| } |
| if (j < i) |
| continue; |
| if (i >= Nva) { |
| Nva += 10; |
| len = (MALLOC_S)(Nva * sizeof(KA_T)); |
| if (!Vp) |
| Vp = (KA_T *)malloc(len); |
| else |
| Vp = (KA_T *)realloc((MALLOC_P *)Vp, len); |
| if (!Vp) { |
| (void) fprintf(stderr, |
| "%s: no more space for text vnode pointers\n", Pn); |
| Exit(1); |
| } |
| } |
| Vp[i++] = va; |
| /* |
| * Allocate local file structure. |
| */ |
| switch (p.p_type) { |
| case PT_DATA: |
| case PT_TEXT: |
| alloc_lfile(" txt", -1); |
| break; |
| case PT_MMAP: |
| alloc_lfile(" mem", -1); |
| break; |
| default: |
| (void) snpf(fd, sizeof(fd), "R%02d", p.p_type); |
| alloc_lfile(fd, -1); |
| } |
| /* |
| * Save vnode information. |
| */ |
| process_node(va); |
| if (Lf->sf) |
| link_lfile(); |
| } |
| } |
| #endif /* HPUXV>=800 */ |