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