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 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 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 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