xref: /titanic_50/usr/src/tools/chk4ubin/chk4ubin.c (revision b31b5de1357c915fe7dab4d9646d9d84f9fe69bc)
1*b31b5de1SJerry Gilliam /*
2*b31b5de1SJerry Gilliam  * CDDL HEADER START
3*b31b5de1SJerry Gilliam  *
4*b31b5de1SJerry Gilliam  * The contents of this file are subject to the terms of the
5*b31b5de1SJerry Gilliam  * Common Development and Distribution License (the "License").
6*b31b5de1SJerry Gilliam  * You may not use this file except in compliance with the License.
7*b31b5de1SJerry Gilliam  *
8*b31b5de1SJerry Gilliam  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*b31b5de1SJerry Gilliam  * or http://www.opensolaris.org/os/licensing.
10*b31b5de1SJerry Gilliam  * See the License for the specific language governing permissions
11*b31b5de1SJerry Gilliam  * and limitations under the License.
12*b31b5de1SJerry Gilliam  *
13*b31b5de1SJerry Gilliam  * When distributing Covered Code, include this CDDL HEADER in each
14*b31b5de1SJerry Gilliam  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*b31b5de1SJerry Gilliam  * If applicable, add the following below this CDDL HEADER, with the
16*b31b5de1SJerry Gilliam  * fields enclosed by brackets "[]" replaced with your own identifying
17*b31b5de1SJerry Gilliam  * information: Portions Copyright [yyyy] [name of copyright owner]
18*b31b5de1SJerry Gilliam  *
19*b31b5de1SJerry Gilliam  * CDDL HEADER END
20*b31b5de1SJerry Gilliam  */
21*b31b5de1SJerry Gilliam 
22*b31b5de1SJerry Gilliam /*
23*b31b5de1SJerry Gilliam  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24*b31b5de1SJerry Gilliam  * Use is subject to license terms.
25*b31b5de1SJerry Gilliam  */
26*b31b5de1SJerry Gilliam 
27*b31b5de1SJerry Gilliam #include <stdio.h>
28*b31b5de1SJerry Gilliam #include <sys/types.h>
29*b31b5de1SJerry Gilliam #include <sys/param.h>
30*b31b5de1SJerry Gilliam #include <fcntl.h>
31*b31b5de1SJerry Gilliam #include <string.h>
32*b31b5de1SJerry Gilliam #include <unistd.h>
33*b31b5de1SJerry Gilliam #include <libgen.h>
34*b31b5de1SJerry Gilliam #include <stdlib.h>
35*b31b5de1SJerry Gilliam #include <errno.h>
36*b31b5de1SJerry Gilliam #include <malloc.h>
37*b31b5de1SJerry Gilliam #include <memory.h>
38*b31b5de1SJerry Gilliam #include <libelf.h>
39*b31b5de1SJerry Gilliam #include <gelf.h>
40*b31b5de1SJerry Gilliam #include <utility.h>
41*b31b5de1SJerry Gilliam 
42*b31b5de1SJerry Gilliam /*
43*b31b5de1SJerry Gilliam  * Tool to inspect a sun4u bootable module for a symbol table size
44*b31b5de1SJerry Gilliam  * that will trigger a fatal error on older versions of OBP.
45*b31b5de1SJerry Gilliam  *
46*b31b5de1SJerry Gilliam  * The failure mode when booting is recorded in CR 6828121
47*b31b5de1SJerry Gilliam  * and appears as follows:
48*b31b5de1SJerry Gilliam  *
49*b31b5de1SJerry Gilliam  *	Executing last command: boot
50*b31b5de1SJerry Gilliam  *	Boot device: /pci@1f,0/pci@1/scsi@8/disk@0,0:a  File and args: kmdb
51*b31b5de1SJerry Gilliam  *
52*b31b5de1SJerry Gilliam  *	Error in Fcode execution !!!
53*b31b5de1SJerry Gilliam  *	Evaluating: to load-base init-program
54*b31b5de1SJerry Gilliam  *	Out of memory
55*b31b5de1SJerry Gilliam  *	Warning: Fcode sequence resulted in a net stack depth change of 1
56*b31b5de1SJerry Gilliam  *
57*b31b5de1SJerry Gilliam  *	Error in Fcode execution !!!
58*b31b5de1SJerry Gilliam  *	Evaluating: to load-base init-program
59*b31b5de1SJerry Gilliam  *
60*b31b5de1SJerry Gilliam  *	Evaluating: to load-base init-program
61*b31b5de1SJerry Gilliam  *	The file just loaded does not appear to be executable.
62*b31b5de1SJerry Gilliam  *	ok
63*b31b5de1SJerry Gilliam  *
64*b31b5de1SJerry Gilliam  * The OBP bug is CR 4777088, fixed in OBP versions 4.12.1 and forward.
65*b31b5de1SJerry Gilliam  *
66*b31b5de1SJerry Gilliam  * The OBP memory allocator for the memory into which the module's
67*b31b5de1SJerry Gilliam  * symbol table is read fails for a specific memory range on
68*b31b5de1SJerry Gilliam  * each page, where the size &= 0x1fff is > 0x1fe1 && <= 0x1ff0.
69*b31b5de1SJerry Gilliam  * Note the symbol table size is the size of both the SYMTAB
70*b31b5de1SJerry Gilliam  * and the STRTAB ELF sections.
71*b31b5de1SJerry Gilliam  *
72*b31b5de1SJerry Gilliam  * To prevent this problem on a given machine, update or patch the OBP.
73*b31b5de1SJerry Gilliam  *
74*b31b5de1SJerry Gilliam  * If this tool reports that a module has a symbol table size in
75*b31b5de1SJerry Gilliam  * the failing range, that build will not boot on any machine with
76*b31b5de1SJerry Gilliam  * this OBP problem.  The only known work-around is to make some
77*b31b5de1SJerry Gilliam  * source change to add or remove symbols to adjust the symbol table
78*b31b5de1SJerry Gilliam  * size outside the triggering range.
79*b31b5de1SJerry Gilliam  *
80*b31b5de1SJerry Gilliam  * Each sun4u bootable module is in theory affected by this, including
81*b31b5de1SJerry Gilliam  * cprboot, bootlst, and each unix module.  Although the serengeti
82*b31b5de1SJerry Gilliam  * (Sun-Fire) and opl (SPARC-Enterprise) OBP implementations never
83*b31b5de1SJerry Gilliam  * included this bug.  The bug only occurs for allocations
84*b31b5de1SJerry Gilliam  * pagesize or greater, and the only such OBP allocation is for a
85*b31b5de1SJerry Gilliam  * module's symbol table, for the sum of the SYMTAB and STRTAB
86*b31b5de1SJerry Gilliam  * sections.  The wanboot and inetboot binaries do not include
87*b31b5de1SJerry Gilliam  * these sections and are therefore also unaffected.
88*b31b5de1SJerry Gilliam  */
89*b31b5de1SJerry Gilliam 
90*b31b5de1SJerry Gilliam static char	*whoami;
91*b31b5de1SJerry Gilliam static int	verbose		= 0;
92*b31b5de1SJerry Gilliam static int	inject_err	= 0;
93*b31b5de1SJerry Gilliam static int	no_err		= 0;
94*b31b5de1SJerry Gilliam static int	exitcode	= 0;
95*b31b5de1SJerry Gilliam static uint_t	pagemask	= 0x1fff;
96*b31b5de1SJerry Gilliam 
97*b31b5de1SJerry Gilliam static char *sun4u_bootables[] = {
98*b31b5de1SJerry Gilliam 	"platform/sun4u/kernel/sparcv9/unix",
99*b31b5de1SJerry Gilliam 	"platform/SUNW,Ultra-Enterprise-10000/kernel/sparcv9/unix",
100*b31b5de1SJerry Gilliam 	"platform/SUNW,Sun-Fire-15000/kernel/sparcv9/unix",
101*b31b5de1SJerry Gilliam 	"platform/sun4u/cprboot",
102*b31b5de1SJerry Gilliam 	"platform/sun4u/bootlst"
103*b31b5de1SJerry Gilliam };
104*b31b5de1SJerry Gilliam static int nsun4ubootables = sizeof (sun4u_bootables) / sizeof (char *);
105*b31b5de1SJerry Gilliam 
106*b31b5de1SJerry Gilliam /*
107*b31b5de1SJerry Gilliam  * size check should be:
108*b31b5de1SJerry Gilliam  *	size &= 0x1fff, size > 0x1fe1 && size <= 0x1ff0
109*b31b5de1SJerry Gilliam  */
110*b31b5de1SJerry Gilliam static uint_t toxic_start	= 0x1fe2;
111*b31b5de1SJerry Gilliam static uint_t toxic_end		= 0x1ff0;
112*b31b5de1SJerry Gilliam 
113*b31b5de1SJerry Gilliam /*
114*b31b5de1SJerry Gilliam  * Tag each error message so it shows up in the build summary mail
115*b31b5de1SJerry Gilliam  */
116*b31b5de1SJerry Gilliam static char *detailed_error_msg =
117*b31b5de1SJerry Gilliam 	"ERROR: This binary will not boot on any machine with an older\n"
118*b31b5de1SJerry Gilliam 	"ERROR: version of OBP.  See CR 4777088 and 6828121 for more details.\n"
119*b31b5de1SJerry Gilliam 	"ERROR: No work-around is possible other than making changes to\n"
120*b31b5de1SJerry Gilliam 	"ERROR: add/remove symbols from the module to move the symbol\n"
121*b31b5de1SJerry Gilliam 	"ERROR: table size outside the toxic range.\n";
122*b31b5de1SJerry Gilliam 
123*b31b5de1SJerry Gilliam 
124*b31b5de1SJerry Gilliam static int
chk4ubin(char * root,char * binary)125*b31b5de1SJerry Gilliam chk4ubin(char *root, char *binary)
126*b31b5de1SJerry Gilliam {
127*b31b5de1SJerry Gilliam 	int  		fd;
128*b31b5de1SJerry Gilliam 	Elf		*elf;
129*b31b5de1SJerry Gilliam 	Elf_Scn		*symscn;
130*b31b5de1SJerry Gilliam 	Elf_Scn		*strscn;
131*b31b5de1SJerry Gilliam 	GElf_Shdr	symhdr;
132*b31b5de1SJerry Gilliam 	GElf_Shdr	strhdr;
133*b31b5de1SJerry Gilliam 	int64_t		symtab_size;
134*b31b5de1SJerry Gilliam 	int64_t		strtab_size;
135*b31b5de1SJerry Gilliam 	int64_t		total;
136*b31b5de1SJerry Gilliam 	int		found_symtab = 0;
137*b31b5de1SJerry Gilliam 	int		found_strtab = 0;
138*b31b5de1SJerry Gilliam 	uint_t		off;
139*b31b5de1SJerry Gilliam 	int		rv = 1;
140*b31b5de1SJerry Gilliam 	char		path[MAXPATHLEN];
141*b31b5de1SJerry Gilliam 
142*b31b5de1SJerry Gilliam 	if (root == NULL) {
143*b31b5de1SJerry Gilliam 		(void) snprintf(path, sizeof (path), "%s", binary);
144*b31b5de1SJerry Gilliam 	} else {
145*b31b5de1SJerry Gilliam 		(void) snprintf(path, sizeof (path), "%s/%s", root, binary);
146*b31b5de1SJerry Gilliam 	}
147*b31b5de1SJerry Gilliam 
148*b31b5de1SJerry Gilliam 	if ((fd = open(path, O_RDONLY)) == -1) {
149*b31b5de1SJerry Gilliam 		(void) printf("%s: cannot open %s - %s\n",
150*b31b5de1SJerry Gilliam 		    whoami, path, strerror(errno));
151*b31b5de1SJerry Gilliam 		return (1);
152*b31b5de1SJerry Gilliam 	}
153*b31b5de1SJerry Gilliam 
154*b31b5de1SJerry Gilliam 	elf_version(EV_CURRENT);
155*b31b5de1SJerry Gilliam 	elf = elf_begin(fd, ELF_C_READ, NULL);
156*b31b5de1SJerry Gilliam 
157*b31b5de1SJerry Gilliam 	symscn = NULL;
158*b31b5de1SJerry Gilliam 	while ((symscn = elf_nextscn(elf, symscn)) != NULL) {
159*b31b5de1SJerry Gilliam 		gelf_getshdr(symscn, &symhdr);
160*b31b5de1SJerry Gilliam 		switch (symhdr.sh_type) {
161*b31b5de1SJerry Gilliam 		case SHT_SYMTAB:
162*b31b5de1SJerry Gilliam 			found_symtab = 1;
163*b31b5de1SJerry Gilliam 			symtab_size = symhdr.sh_size;
164*b31b5de1SJerry Gilliam 			strscn = elf_getscn(elf, symhdr.sh_link);
165*b31b5de1SJerry Gilliam 			if (strscn != NULL) {
166*b31b5de1SJerry Gilliam 				gelf_getshdr(strscn, &strhdr);
167*b31b5de1SJerry Gilliam 				strtab_size = strhdr.sh_size;
168*b31b5de1SJerry Gilliam 				found_strtab = 1;
169*b31b5de1SJerry Gilliam 			}
170*b31b5de1SJerry Gilliam 			break;
171*b31b5de1SJerry Gilliam 		}
172*b31b5de1SJerry Gilliam 		if (found_symtab && found_strtab)
173*b31b5de1SJerry Gilliam 			break;
174*b31b5de1SJerry Gilliam 	}
175*b31b5de1SJerry Gilliam 
176*b31b5de1SJerry Gilliam 	elf_end(elf);
177*b31b5de1SJerry Gilliam 	(void) close(fd);
178*b31b5de1SJerry Gilliam 
179*b31b5de1SJerry Gilliam 	if (found_symtab && found_strtab) {
180*b31b5de1SJerry Gilliam 		int err;
181*b31b5de1SJerry Gilliam 		total = symtab_size + strtab_size;
182*b31b5de1SJerry Gilliam 		off = total & pagemask;
183*b31b5de1SJerry Gilliam 		err = (off >= toxic_start && off <= toxic_end);
184*b31b5de1SJerry Gilliam 		if (inject_err || err) {
185*b31b5de1SJerry Gilliam 			(void) printf("%s: ERROR: %s\n", whoami, binary);
186*b31b5de1SJerry Gilliam 			(void) printf("ERROR: symbol table size 0x%llx is "
187*b31b5de1SJerry Gilliam 			    "in toxic range (0x%x - 0x%x)!\n",
188*b31b5de1SJerry Gilliam 			    total, toxic_start, toxic_end);
189*b31b5de1SJerry Gilliam 			(void) printf("%s", detailed_error_msg);
190*b31b5de1SJerry Gilliam 		} else {
191*b31b5de1SJerry Gilliam 			rv = 0;
192*b31b5de1SJerry Gilliam 			(void) printf("%s: %s ok\n", whoami, binary);
193*b31b5de1SJerry Gilliam 			if (verbose) {
194*b31b5de1SJerry Gilliam 				(void) printf("symbol table size 0x%llx "
195*b31b5de1SJerry Gilliam 				    "not in toxic range (0x%x - 0x%x)\n",
196*b31b5de1SJerry Gilliam 				    total, toxic_start, toxic_end);
197*b31b5de1SJerry Gilliam 			}
198*b31b5de1SJerry Gilliam 		}
199*b31b5de1SJerry Gilliam 		if (verbose) {
200*b31b5de1SJerry Gilliam 			(void) printf(".symtab size: 0x%llx\n",
201*b31b5de1SJerry Gilliam 			    symtab_size);
202*b31b5de1SJerry Gilliam 			(void) printf(".strtab size: 0x%llx\n",
203*b31b5de1SJerry Gilliam 			    strtab_size);
204*b31b5de1SJerry Gilliam 			(void) printf("total:        0x%llx "
205*b31b5de1SJerry Gilliam 			    "(0x%llx, 0x%llx)\n", total, (total & ~pagemask),
206*b31b5de1SJerry Gilliam 			    (total & pagemask));
207*b31b5de1SJerry Gilliam 		}
208*b31b5de1SJerry Gilliam 		if (verbose || err || inject_err)
209*b31b5de1SJerry Gilliam 			(void) printf("\n");
210*b31b5de1SJerry Gilliam 	} else {
211*b31b5de1SJerry Gilliam 		if (!found_symtab && !found_strtab) {
212*b31b5de1SJerry Gilliam 			(void) fprintf(stderr,
213*b31b5de1SJerry Gilliam 			    "%s: %s - no symtab or strtab section found\n",
214*b31b5de1SJerry Gilliam 			    whoami, binary);
215*b31b5de1SJerry Gilliam 		} else if (!found_symtab) {
216*b31b5de1SJerry Gilliam 			(void) fprintf(stderr,
217*b31b5de1SJerry Gilliam 			    "%s: %s - no symtab section found\n",
218*b31b5de1SJerry Gilliam 			    whoami, binary);
219*b31b5de1SJerry Gilliam 		} else if (!found_strtab) {
220*b31b5de1SJerry Gilliam 			(void) fprintf(stderr,
221*b31b5de1SJerry Gilliam 			    "%s: %s - no strtab section found\n",
222*b31b5de1SJerry Gilliam 			    whoami, binary);
223*b31b5de1SJerry Gilliam 		}
224*b31b5de1SJerry Gilliam 	}
225*b31b5de1SJerry Gilliam 
226*b31b5de1SJerry Gilliam 	return (rv);
227*b31b5de1SJerry Gilliam }
228*b31b5de1SJerry Gilliam 
229*b31b5de1SJerry Gilliam static void
usage()230*b31b5de1SJerry Gilliam usage()
231*b31b5de1SJerry Gilliam {
232*b31b5de1SJerry Gilliam 	int i;
233*b31b5de1SJerry Gilliam 
234*b31b5de1SJerry Gilliam 	(void) fprintf(stderr,
235*b31b5de1SJerry Gilliam 	    "usage: %s [-n] [-v] [-r <root>] [<binary>] ...\n", whoami);
236*b31b5de1SJerry Gilliam 	(void) fprintf(stderr,
237*b31b5de1SJerry Gilliam 	    "    -n: exit with 0 even with an error detected to allow\n");
238*b31b5de1SJerry Gilliam 	(void) fprintf(stderr,
239*b31b5de1SJerry Gilliam 	    "        a build to succeed even with a failing binary\n");
240*b31b5de1SJerry Gilliam 	(void) fprintf(stderr,
241*b31b5de1SJerry Gilliam 	    "The default list of binaries checked if none supplied is:\n");
242*b31b5de1SJerry Gilliam 	for (i = 0; i < nsun4ubootables; i++) {
243*b31b5de1SJerry Gilliam 		(void) fprintf(stderr, "    %s\n", sun4u_bootables[i]);
244*b31b5de1SJerry Gilliam 	}
245*b31b5de1SJerry Gilliam 	exit(0);
246*b31b5de1SJerry Gilliam }
247*b31b5de1SJerry Gilliam 
248*b31b5de1SJerry Gilliam int
main(int argc,char * argv[])249*b31b5de1SJerry Gilliam main(int argc, char *argv[])
250*b31b5de1SJerry Gilliam {
251*b31b5de1SJerry Gilliam 	int	i;
252*b31b5de1SJerry Gilliam 	char	*root = NULL;
253*b31b5de1SJerry Gilliam 
254*b31b5de1SJerry Gilliam 	whoami = basename(argv[0]);
255*b31b5de1SJerry Gilliam 
256*b31b5de1SJerry Gilliam 	opterr = 0;
257*b31b5de1SJerry Gilliam 	while ((i = getopt(argc, argv, "enr:R:v")) != -1) {
258*b31b5de1SJerry Gilliam 		switch (i) {
259*b31b5de1SJerry Gilliam 		case 'v':
260*b31b5de1SJerry Gilliam 			verbose = 1;
261*b31b5de1SJerry Gilliam 			break;
262*b31b5de1SJerry Gilliam 		case 'e':
263*b31b5de1SJerry Gilliam 			inject_err = 1;
264*b31b5de1SJerry Gilliam 			break;
265*b31b5de1SJerry Gilliam 		case 'n':
266*b31b5de1SJerry Gilliam 			no_err = 1;
267*b31b5de1SJerry Gilliam 			break;
268*b31b5de1SJerry Gilliam 		case 'r':
269*b31b5de1SJerry Gilliam 		case 'R':
270*b31b5de1SJerry Gilliam 			root = optarg;
271*b31b5de1SJerry Gilliam 			break;
272*b31b5de1SJerry Gilliam 		default:
273*b31b5de1SJerry Gilliam 			usage();
274*b31b5de1SJerry Gilliam 			break;
275*b31b5de1SJerry Gilliam 		}
276*b31b5de1SJerry Gilliam 	}
277*b31b5de1SJerry Gilliam 
278*b31b5de1SJerry Gilliam 	if (optind < argc) {
279*b31b5de1SJerry Gilliam 		for (i = optind; i < argc; i++) {
280*b31b5de1SJerry Gilliam 			if (chk4ubin(root, argv[i]) != 0)
281*b31b5de1SJerry Gilliam 				exitcode = 1;
282*b31b5de1SJerry Gilliam 		}
283*b31b5de1SJerry Gilliam 	} else {
284*b31b5de1SJerry Gilliam 		for (i = 0; i < nsun4ubootables; i++) {
285*b31b5de1SJerry Gilliam 			if (root == NULL)
286*b31b5de1SJerry Gilliam 				root = "/";
287*b31b5de1SJerry Gilliam 			if (chk4ubin(root, sun4u_bootables[i]) != 0)
288*b31b5de1SJerry Gilliam 				exitcode = 1;
289*b31b5de1SJerry Gilliam 		}
290*b31b5de1SJerry Gilliam 	}
291*b31b5de1SJerry Gilliam 
292*b31b5de1SJerry Gilliam 	return (no_err ? 0 : exitcode);
293*b31b5de1SJerry Gilliam }
294