1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License").  You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22/*
23 * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27#pragma ident	"%Z%%M%	%I%	%E% SMI"
28
29/*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
30/*	  All Rights Reserved  	*/
31
32	/*
33	 * This command can now print the value of data items
34	 * from [1] /dev/kmem is the default, and [2] a named
35	 * file passed with the -n argument.  If the read is from
36	 * /dev/kmem, we also print the value of BSS symbols.
37	 * The logic to support this is: if read is from file,
38	 * [1] find the section number of .bss, [2] look through
39	 * nlist for symbols that are in .bss section and zero
40	 * the n_value field.  At print time, if the n_value field
41	 * is non-zero, print the info.
42	 *
43	 * This protects us from trying to read a bss symbol from
44	 * the file and, possibly, dropping core.
45	 *
46	 * When reading from /dev/kmem, the n_value field is the
47	 * seek address, and the contents are read from that address.
48	 *
49	 * NOTE: when reading from /dev/kmem, the actual, incore
50	 * values will be printed, for example: the current nodename
51	 * will be printed, etc.
52	 *
53	 * the cmn line usage is: sysdef -i -n namelist -h -d -D
54	 * (-i for incore, though this is now the default, the option
55	 * is left in place for SVID compatibility)
56	 */
57#include	<stdio.h>
58#include	<nlist.h>
59#include	<string.h>
60#include	<sys/types.h>
61#include	<sys/sysmacros.h>
62#include	<sys/var.h>
63#include	<sys/tuneable.h>
64#include	<sys/modctl.h>
65#include	<sys/fcntl.h>
66#include	<sys/utsname.h>
67#include	<sys/resource.h>
68#include	<sys/conf.h>
69#include	<sys/stat.h>
70#include	<sys/signal.h>
71#include	<sys/priocntl.h>
72#include	<sys/procset.h>
73#include	<sys/systeminfo.h>
74#include	<sys/machelf.h>
75#include	<dirent.h>
76#include	<ctype.h>
77#include	<stdlib.h>
78#include	<time.h>
79#include	<unistd.h>
80#include	<fcntl.h>
81
82#include	<libelf.h>
83
84extern void sysdef_devinfo(void);
85
86static gid_t egid;
87
88#define	SYM_VALUE(sym)	(nl[(sym)].n_value)
89#define	MEMSEEK(sym)	memseek(sym)
90#define	MEMREAD(var)	fread((char *)&var, sizeof (var), 1, \
91				(incore ? memfile : sysfile))
92
93struct	var	v;
94struct  tune	tune;
95
96int incore = 1;		/* The default is "incore" */
97int bss;		/* if read from file, don't read bss symbols */
98int hostidf = 0;	/* 0 == print hostid with other info, */
99			/* 1 == print just the hostid */
100int devflag = 0;	/* SunOS4.x devinfo compatible output */
101int drvname_flag = 0;	/* print the driver name as well as the node */
102int nflag = 0;
103char	*os = "/dev/ksyms";	/* Wont always have a /kernel/unix */
104				/* This wont fully replace it funtionally */
105				/* but is a reasonable default/placeholder */
106
107char	*mem = "/dev/kmem";
108
109int	nstrpush;
110ssize_t	strmsgsz, strctlsz;
111short	ts_maxupri;
112char 	sys_name[10];
113int	nlsize, lnsize;
114FILE	*sysfile, *memfile;
115
116void	setln(char *, int, int, int);
117void	getnlist(void);
118void	memseek(int);
119void	devices(void);
120void	sysdev(void);
121int	setup(char *);
122void	modules(void);
123
124struct nlist	*nl, *nlptr;
125int vs, tu, utsnm, bdev, pnstrpush,
126    pstrmsgsz, pstrctlsz, endnm,
127    pts_maxupri, psys_name, fd_cur, fd_max;
128
129#define	MAXI	300
130#define	MAXL	MAXI/11+10
131#define	EXPAND	99
132
133struct	link {
134	char	*l_cfnm;	/* config name from master table */
135	int l_funcidx;		/* index into name list structure */
136	unsigned int l_soft :1;	/* software driver flag from master table */
137	unsigned int l_dtype:1;	/* set if block device */
138	unsigned int l_used :1;	/* set when device entry is printed */
139} *ln, *lnptr, *majsrch();
140
141	/* ELF Items */
142Elf *elfd = NULL;
143Ehdr *ehdr = NULL;
144
145#ifdef _ELF64
146#define	elf_getehdr elf64_getehdr
147#define	elf_getshdr elf64_getshdr
148#else
149#define	elf_getehdr elf32_getehdr
150#define	elf_getshdr elf32_getshdr
151#endif
152
153/* This procedure checks if module "name" is currently loaded */
154
155int
156loaded_mod(const char *name)
157{
158	struct modinfo modinfo;
159
160	/* mi_nextid of -1 means we're getting info on all modules */
161	modinfo.mi_id = modinfo.mi_nextid = -1;
162	modinfo.mi_info = MI_INFO_ALL;
163
164	while (modctl(MODINFO, modinfo.mi_id, &modinfo) >= 0)
165		if (strcmp(modinfo.mi_name, name) == 0)
166			return (1);
167
168	return (0);
169}
170
171const char *sysv_transition =
172	"*\n* IPC %s\n*\n"
173	"* The IPC %s module no longer has system-wide limits.\n"
174	"* Please see the \"Solaris Tunable Parameters Reference Manual\" for\n"
175	"* information on how the old limits map to resource controls and\n"
176	"* the prctl(1) and getrctl(2) manual pages for information on\n"
177	"* observing the new limits.\n*\n";
178
179const char *sysv_notloaded =
180	"*\n* IPC %s module is not loaded\n*\n";
181
182/*
183 * Emit a message pointing script writers to the new source for
184 * System V IPC information.
185 */
186void
187sysvipc(const char *module, const char *name)
188{
189	if (loaded_mod(module))
190		(void) printf(sysv_transition, name, name);
191	else
192		(void) printf(sysv_notloaded, name);
193}
194
195int
196main(int argc, char *argv[])
197{
198	struct	utsname utsname;
199	Elf_Scn *scn;
200	Shdr *shdr;
201	char *name;
202	int ndx;
203	int i;
204	char hostid[256], *end;
205	unsigned long hostval;
206	uint_t	rlim_fd_cur, rlim_fd_max;
207
208	egid = getegid();
209	setegid(getgid());
210
211	while ((i = getopt(argc, argv, "dihDn:?")) != EOF) {
212		switch (i) {
213		case 'D':
214			drvname_flag++;
215			break;
216		case 'd':
217			devflag++;
218			break;
219		case 'h':
220			hostidf++;
221			break;
222		case 'i':
223			incore++;	/* In case "-i and -n" passed */
224			break;		/* Not logical, but not disallowed */
225		case 'n':
226			nflag = 1;
227			incore--;	/* Not incore, use specified file */
228			os = optarg;
229			break;
230		default:
231			fprintf(stderr,
232				"usage: %s [-D -d -i -h -n namelist]\n",
233					argv[0]);
234			return (1);
235		}
236	}
237
238	/*
239	 * Prints hostid of machine.
240	 */
241	if (sysinfo(SI_HW_SERIAL, hostid, sizeof (hostid)) == -1) {
242		fprintf(stderr, "hostid: sysinfo failed\n");
243		return (1);
244	}
245	hostval = strtoul(hostid, &end, 10);
246	if (hostval == 0 && end == hostid) {
247		fprintf(stderr, "hostid: hostid string returned by "
248		    "sysinfo not numeric: \"%s\"\n", hostid);
249		return (1);
250	}
251	if (!devflag)
252		fprintf(stdout, "*\n* Hostid\n*\n  %8.8x\n", hostval);
253
254	if (hostidf)
255		return (0);
256
257	if (((sysfile = fopen(os, "r")) == NULL) && nflag) {
258		fprintf(stderr, "cannot open %s\n", os);
259		return (1);
260	}
261
262	if (sysfile) {
263		if (incore) {
264			int memfd;
265
266			setegid(egid);
267			if ((memfile = fopen(mem, "r")) == NULL) {
268				fprintf(stderr, "cannot open %s\n", mem);
269				return (1);
270			}
271			setegid(getgid());
272
273			memfd = fileno(memfile);
274			fcntl(memfd, F_SETFD,
275			    fcntl(memfd, F_GETFD, 0) | FD_CLOEXEC);
276		}
277
278		/*
279		 *	Use libelf to read both COFF and ELF namelists
280		 */
281
282		if ((elf_version(EV_CURRENT)) == EV_NONE) {
283			fprintf(stderr, "ELF Access Library out of date\n");
284			return (1);
285		}
286
287		if ((elfd = elf_begin(fileno(sysfile), ELF_C_READ,
288		    NULL)) == NULL) {
289			fprintf(stderr, "Unable to elf begin %s (%s)\n",
290				os, elf_errmsg(-1));
291			return (1);
292		}
293
294		if ((ehdr = elf_getehdr(elfd)) == NULL) {
295			fprintf(stderr, "%s: Can't read Exec header (%s)\n",
296				os, elf_errmsg(-1));
297			return (1);
298		}
299
300		if ((((elf_kind(elfd)) != ELF_K_ELF) &&
301		    ((elf_kind(elfd)) != ELF_K_COFF)) ||
302		    (ehdr->e_type != ET_EXEC)) {
303			fprintf(stderr, "%s: invalid file\n", os);
304			elf_end(elfd);
305			return (1);
306		}
307
308		/*
309		 *	If this is a file read, look for .bss section
310		 */
311
312		if (!incore) {
313			ndx = 1;
314			scn = NULL;
315			while ((scn = elf_nextscn(elfd, scn)) != NULL) {
316				if ((shdr = elf_getshdr(scn)) == NULL) {
317					fprintf(stderr,
318					    "%s: Error reading Shdr (%s)\n",
319					    os, elf_errmsg(-1));
320					return (1);
321				}
322				name = elf_strptr(elfd, ehdr->e_shstrndx,
323				    (size_t)shdr->sh_name);
324				if ((name) && ((strcmp(name, ".bss")) == 0)) {
325					bss = ndx;
326				}
327				ndx++;
328			}
329		} /* (!incore) */
330	}
331
332	uname(&utsname);
333	if (!devflag)
334		printf("*\n* %s Configuration\n*\n", utsname.machine);
335
336	if (sysfile) {
337		nlsize = MAXI;
338		lnsize = MAXL;
339		nl = (struct nlist *)calloc(nlsize, sizeof (struct nlist));
340		ln = (struct link *)calloc(lnsize, sizeof (struct link));
341		nlptr = nl;
342		lnptr = ln;
343
344		bdev = setup("bdevsw");
345		setup("");
346
347		getnlist();
348
349		if (!devflag)
350			printf("*\n* Devices\n*\n");
351		devices();
352		if (devflag)
353			return (0);
354
355		printf("*\n* Loadable Objects\n");
356
357		modules();
358	}
359
360	printf("*\n* System Configuration\n*\n");
361
362	sysdev();
363
364	if (sysfile) {
365		/* easy stuff */
366		printf("*\n* Tunable Parameters\n*\n");
367		nlptr = nl;
368		vs = setup("v");
369		tu = setup("tune");
370		utsnm = setup("utsname");
371		pnstrpush = setup("nstrpush");
372		pstrmsgsz = setup("strmsgsz");
373		pstrctlsz = setup("strctlsz");
374		pts_maxupri = setup("ts_maxupri");
375		psys_name = setup("sys_name");
376		fd_cur = setup("rlim_fd_cur");
377		fd_max = setup("rlim_fd_max");
378
379		/*
380		 * This assignment to endnm must follow all calls to setup().
381		 */
382		endnm = setup("");
383
384		getnlist();
385
386		for (nlptr = &nl[vs]; nlptr != &nl[endnm]; nlptr++) {
387			if (nlptr->n_value == 0 &&
388			    (incore || nlptr->n_scnum != bss)) {
389				fprintf(stderr, "namelist error on <%s>\n",
390				    nlptr->n_name);
391				/* return (1); */
392			}
393		}
394		if (SYM_VALUE(vs)) {
395			MEMSEEK(vs);
396			MEMREAD(v);
397		}
398		printf("%8d	maximum memory allowed in buffer cache "
399		    "(bufhwm)\n", v.v_bufhwm * 1024);
400		printf("%8d	maximum number of processes (v.v_proc)\n",
401		    v.v_proc);
402		printf("%8d	maximum global priority in sys class "
403		    "(MAXCLSYSPRI)\n", v.v_maxsyspri);
404		printf("%8d	maximum processes per user id (v.v_maxup)\n",
405		    v.v_maxup);
406		printf("%8d	auto update time limit in seconds (NAUTOUP)\n",
407		    v.v_autoup);
408		if (SYM_VALUE(tu)) {
409			MEMSEEK(tu);
410			MEMREAD(tune);
411		}
412		printf("%8d	page stealing low water mark (GPGSLO)\n",
413		    tune.t_gpgslo);
414		printf("%8d	fsflush run rate (FSFLUSHR)\n",
415		    tune.t_fsflushr);
416		printf("%8d	minimum resident memory for avoiding "
417		    "deadlock (MINARMEM)\n", tune.t_minarmem);
418		printf("%8d	minimum swapable memory for avoiding deadlock "
419		    "(MINASMEM)\n", tune.t_minasmem);
420	}
421
422	printf("*\n* Utsname Tunables\n*\n");
423	if (sysfile && SYM_VALUE(utsnm)) {
424		MEMSEEK(utsnm);
425		MEMREAD(utsname);
426	}
427	printf("%8s  release (REL)\n", utsname.release);
428	printf("%8s  node name (NODE)\n", utsname.nodename);
429	printf("%8s  system name (SYS)\n", utsname.sysname);
430	printf("%8s  version (VER)\n", utsname.version);
431
432	if (sysfile) {
433		printf("*\n* Process Resource Limit Tunables "
434		    "(Current:Maximum)\n*\n");
435		if (SYM_VALUE(fd_cur)) {
436			MEMSEEK(fd_cur);
437			MEMREAD(rlim_fd_cur);
438		}
439		if (SYM_VALUE(fd_max)) {
440			MEMSEEK(fd_max);
441			MEMREAD(rlim_fd_max);
442		}
443
444		printf("0x%16.16x:", rlim_fd_cur);
445		printf("0x%16.16x", rlim_fd_max);
446		printf("\tfile descriptors\n");
447
448		printf("*\n* Streams Tunables\n*\n");
449		if (SYM_VALUE(pnstrpush)) {
450			MEMSEEK(pnstrpush);	MEMREAD(nstrpush);
451			printf("%6d	maximum number of pushes allowed "
452			    "(NSTRPUSH)\n", nstrpush);
453		}
454		if (SYM_VALUE(pstrmsgsz)) {
455			MEMSEEK(pstrmsgsz);	MEMREAD(strmsgsz);
456			printf("%6ld	maximum stream message size "
457			    "(STRMSGSZ)\n", strmsgsz);
458		}
459		if (SYM_VALUE(pstrctlsz)) {
460			MEMSEEK(pstrctlsz);	MEMREAD(strctlsz);
461			printf("%6ld	max size of ctl part of message "
462			    "(STRCTLSZ)\n", strctlsz);
463		}
464	}
465
466	sysvipc("msgsys", "Messages");
467	sysvipc("semsys", "Semaphores");
468	sysvipc("shmsys", "Shared Memory");
469
470	if (sysfile) {
471		if (SYM_VALUE(pts_maxupri)) {
472			printf("*\n* Time Sharing Scheduler Tunables\n*\n");
473			MEMSEEK(pts_maxupri);	MEMREAD(ts_maxupri);
474			printf("%d	maximum time sharing user "
475			    "priority (TSMAXUPRI)\n", ts_maxupri);
476		}
477
478		if (SYM_VALUE(psys_name)) {
479			MEMSEEK(psys_name);	MEMREAD(sys_name);
480			printf("%s	system class name (SYS_NAME)\n",
481			    sys_name);
482		}
483
484		if (elfd)
485			elf_end(elfd);
486	}
487	return (0);
488}
489
490/*
491 * setup - add an entry to a namelist structure array
492 */
493int
494setup(char *nam)
495{
496	int idx;
497
498	if (nlptr >= &nl[nlsize]) {
499		if ((nl = (struct nlist *)realloc(nl,
500		    (nlsize + EXPAND) * sizeof (struct nlist))) == NULL) {
501			fprintf(stderr, "Namelist space allocation failed\n");
502			exit(1);
503		}
504		nlptr = &nl[nlsize];
505		nlsize += EXPAND;
506	}
507
508	nlptr->n_name = malloc(strlen(nam) + 1); /* pointer to next string */
509	strcpy(nlptr->n_name, nam);	/* move name into string table */
510	nlptr->n_type = 0;
511	nlptr->n_value = 0;
512	idx = nlptr++ - nl;
513	return (idx);
514}
515
516/*
517 * Handle the configured devices
518 */
519void
520devices(void)
521{
522	setegid(egid);
523	sysdef_devinfo();
524	setegid(getgid());
525}
526
527char	*LS_MODULES = "/bin/ls -R -p -i -1 ";
528char	*MODULES_TMPFILE = "/tmp/sysdef.sort.XXXXXX";
529
530void
531modules()
532{
533	int i;
534	int n_dirs = 0;
535	ino_t *inodes;
536	char *curr, *next;
537	char **dirs;
538	char *modpath, *ls_cmd;
539	char *tmpf;
540	int curr_len, modpathlen;
541	int ls_cmd_len = strlen(LS_MODULES);
542	int sfd;
543
544	if ((modctl(MODGETPATHLEN, NULL, &modpathlen)) != 0) {
545		fprintf(stderr, "sysdef: fail to get module path length\n");
546		exit(1);
547	}
548	if ((modpath = malloc(modpathlen + 1)) == NULL) {
549		fprintf(stderr, "sysdef: malloc failed\n");
550		exit(1);
551	}
552	if (modctl(MODGETPATH, NULL, modpath) != 0) {
553		fprintf(stderr, "sysdef: fail to get module path\n");
554		exit(1);
555	}
556
557	/*
558	 * Figure out number of directory entries in modpath.
559	 * Module paths are stored in a space separated string
560	 */
561	curr = modpath;
562	while (curr) {
563		n_dirs++;
564		curr = strchr(curr + 1, ' ');
565	}
566
567	if (((inodes = (ino_t *)malloc(n_dirs * sizeof (ino_t))) == NULL) ||
568	    ((dirs = (char **)malloc(n_dirs * sizeof (char *))) == NULL)) {
569		fprintf(stderr, "sysdef: malloc failed\n");
570		exit(1);
571	}
572
573	if ((tmpf = malloc(strlen(MODULES_TMPFILE) + 1)) == NULL) {
574		fprintf(stderr, "sysdef: malloc failed\n");
575		exit(1);
576	}
577
578	curr = modpath;
579	for (i = 0; i < n_dirs; i++) {
580		int j, len, inode, ino;
581		char line[100], path[100], *pathptr = "";
582		char srtbuf[100], *sorted_fname;
583		FILE *lspipe, *srtpipe, *fp;
584		struct stat stat_buf;
585
586		if (next = strchr(curr, ' ')) {
587			*next = '\0';
588		}
589
590		/*
591		 * Make sure the module path is present.
592		 */
593		if (stat(curr, &stat_buf) == -1) {
594			curr = next ? next + 1 : NULL;
595			inodes[i] = (ino_t)-1;
596			continue;
597		}
598
599		/*
600		 * On sparcs, /platform/SUNW,... can be symbolic link to
601		 * /platform/sun4x. We check the inode number of directory
602		 * and skip any duplication.
603		 */
604		dirs[i] = curr;
605		inodes[i] = stat_buf.st_ino;
606
607		for (j = 0; inodes[i] != inodes[j]; j++)
608			;
609		if (j != i) {
610			curr = next ? next + 1 : NULL;
611			continue;
612		}
613
614		printf("*\n* Loadable Object Path = %s\n*\n", curr);
615
616		curr_len = strlen(curr);
617		if ((ls_cmd = malloc(ls_cmd_len + curr_len + 1)) == NULL) {
618			fprintf(stderr, "sysdef: malloc failed\n");
619			exit(1);
620		}
621
622		(void) sprintf(ls_cmd, "%s%s", LS_MODULES, curr);
623
624		/*
625		 * List the loadable objects in the directory tree, sorting
626		 * them by inode so as to note any hard links.  A temporary
627		 * file in /tmp  is used to store output from sort before
628		 * listing.
629		 */
630		if ((lspipe = popen(ls_cmd, "r")) == NULL) {
631			fprintf(stderr, "sysdef: cannot open ls pipe\n");
632			exit(1);
633		}
634		free(ls_cmd);
635
636		(void) strcpy(tmpf, MODULES_TMPFILE);
637		if ((sorted_fname = mktemp(tmpf)) == NULL ||
638		    (strcmp(sorted_fname, "") == 0)) {
639			fprintf(stderr,
640			    "sysdef: cannot create unique tmp file name\n");
641			exit(1);
642		}
643
644		if ((sfd = open(sorted_fname, O_RDWR|O_CREAT|O_EXCL,
645		    0600)) == -1) {
646			fprintf(stderr, "sysdef: cannot open %s\n",
647			    sorted_fname);
648			exit(1);
649		}
650
651		sprintf(srtbuf, "/bin/sort - > %s", sorted_fname);
652		if ((srtpipe = popen(srtbuf, "w")) == NULL) {
653			fprintf(stderr, "sysdef: cannot open sort pipe\n");
654			exit(1);
655		}
656
657		while (fgets(line, 99, lspipe) != NULL) {
658			char *tmp;
659			/*
660			 * 'line' has <cr>, skip blank lines & dir entries
661			 */
662			if (((len = strlen(line)) <= 1) ||
663			    (line[len-2] == '/'))
664				continue;
665
666			/* remember path of each subdirectory */
667
668			if (line[0] == '/') {
669				(void) strcpy(path, &line[curr_len]);
670				tmp = strtok(&path[1], ":");
671				if ((tmp == NULL) || (tmp[0] == '\n')) {
672					continue;
673				}
674				pathptr = &path[1];
675				(void) strcat(pathptr, "/");
676				continue;
677			} else {
678				char *tmp1 = strtok(line, " ");
679				tmp = strtok(NULL, "\n");
680				/*
681				 * eliminate .conf file
682				 */
683				if (strstr(tmp, ".conf")) {
684					continue;
685				}
686				/*
687				 * Printing the (inode, path, module)
688				 * ripple.
689				 */
690				fprintf(srtpipe, "%s %s%s\n",
691				    tmp1, pathptr, tmp);
692			}
693		}
694		(void) pclose(lspipe);
695		(void) pclose(srtpipe);
696
697		/*
698		 * A note on data synchronization. We opened sfd above,
699		 * before calling popen, to ensure that the tempfile
700		 * was created exclusively to prevent a malicious user
701		 * from creating a link in /tmp to make us overwrite
702		 * another file. We have never read from sfd, there
703		 * can be no stale data cached anywhere.
704		 */
705		if ((fp = fdopen(sfd, "r")) == NULL) {
706			fprintf(stderr, "sysdef: cannot open sorted file: %s",
707			    sorted_fname);
708			exit(1);
709		}
710		inode = -1;
711		while (fgets(line, 99, fp) != NULL) {
712
713			sscanf(line, "%d %s",  &ino, path);
714			if (ino == inode)
715				printf("\thard link:  ");
716			printf("%s\n", path);
717			inode = ino;
718		}
719		(void) fclose(fp);
720		(void) unlink(sorted_fname);
721		curr = next ? next + 1 : NULL;
722	}
723	free(tmpf);
724	free(modpath);
725}
726
727void
728sysdev(void)
729{
730	printf("  swap files\n");
731	fflush(stdout);
732	if (system("/usr/sbin/swap -l") < 0)
733		fprintf(stderr, "unknown swap file(s)\n");
734}
735
736void
737memseek(int sym)
738{
739	Elf_Scn *scn;
740	Shdr *eshdr;
741	long eoff;
742
743	if (incore) {
744		if ((fseek(memfile, nl[sym].n_value, 0)) != 0) {
745			fprintf(stderr, "%s: fseek error (in memseek)\n", mem);
746			exit(1);
747		}
748	} else {
749		if ((scn = elf_getscn(elfd, nl[sym].n_scnum)) == NULL) {
750			fprintf(stderr, "%s: Error reading Scn %d (%s)\n",
751				os, nl[sym].n_scnum, elf_errmsg(-1));
752			exit(1);
753		}
754
755		if ((eshdr = elf_getshdr(scn)) == NULL) {
756			fprintf(stderr, "%s: Error reading Shdr %d (%s)\n",
757				os, nl[sym].n_scnum, elf_errmsg(-1));
758			exit(1);
759		}
760
761		eoff = (long)(nl[sym].n_value - eshdr->sh_addr +
762		    eshdr->sh_offset);
763
764		if ((fseek(sysfile, eoff, 0)) != 0) {
765			fprintf(stderr, "%s: fseek error (in memseek)\n", os);
766			exit(1);
767		}
768	}
769}
770
771/*
772 * filter out bss symbols if the reads are from the file
773 */
774void
775getnlist(void)
776{
777	struct nlist *p;
778
779	nlist(os, nl);
780
781	/*
782	 * The nlist is done. If any symbol is a bss
783	 * and we are not reading from incore, zero
784	 * the n_value field. (Won't be printed if
785	 * n_value == 0.)
786	 */
787	if (!incore) {
788		for (p = nl; p->n_name && p->n_name[0]; p++) {
789			if (p->n_scnum == bss) {
790				p->n_value = 0;
791			}
792		}
793	}
794}
795