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 (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 #pragma ident   "%Z%%M% %I%     %E% SMI"
  27 
  28 /*
  29  * Utility functions
  30  */
  31 
  32 #include <stdio.h>
  33 #include <stdlib.h>
  34 #include <string.h>
  35 #include <libelf.h>
  36 #include <gelf.h>
  37 #include <errno.h>
  38 #include <stdarg.h>
  39 #include <pthread.h>
  40 #include <unistd.h>
  41 #include <sys/param.h>
  42 
  43 #include "ctftools.h"
  44 #include "memory.h"
  45 
  46 static void (*terminate_cleanup)() = NULL;
  47 
  48 /* returns 1 if s1 == s2, 0 otherwise */
  49 int
  50 streq(const char *s1, const char *s2)
  51 {
  52         if (s1 == NULL) {
  53                 if (s2 != NULL)
  54                         return (0);
  55         } else if (s2 == NULL)
  56                 return (0);
  57         else if (strcmp(s1, s2) != 0)
  58                 return (0);
  59 
  60         return (1);
  61 }
  62 
  63 int
  64 findelfsecidx(Elf *elf, const char *file, const char *tofind)
  65 {
  66         Elf_Scn *scn = NULL;
  67         GElf_Ehdr ehdr;
  68         GElf_Shdr shdr;
  69 
  70         if (gelf_getehdr(elf, &ehdr) == NULL)
  71                 elfterminate(file, "Couldn't read ehdr");
  72 
  73         while ((scn = elf_nextscn(elf, scn)) != NULL) {
  74                 char *name;
  75 
  76                 if (gelf_getshdr(scn, &shdr) == NULL) {
  77                         elfterminate(file,
  78                             "Couldn't read header for section %d",
  79                             elf_ndxscn(scn));
  80                 }
  81 
  82                 if ((name = elf_strptr(elf, ehdr.e_shstrndx,
  83                     (size_t)shdr.sh_name)) == NULL) {
  84                         elfterminate(file,
  85                             "Couldn't get name for section %d",
  86                             elf_ndxscn(scn));
  87                 }
  88 
  89                 if (strcmp(name, tofind) == 0)
  90                         return (elf_ndxscn(scn));
  91         }
  92 
  93         return (-1);
  94 }
  95 
  96 size_t
  97 elf_ptrsz(Elf *elf)
  98 {
  99         GElf_Ehdr ehdr;
 100 
 101         if (gelf_getehdr(elf, &ehdr) == NULL) {
 102                 terminate("failed to read ELF header: %s\n",
 103                     elf_errmsg(-1));
 104         }
 105 
 106         if (ehdr.e_ident[EI_CLASS] == ELFCLASS32)
 107                 return (4);
 108         else if (ehdr.e_ident[EI_CLASS] == ELFCLASS64)
 109                 return (8);
 110         else
 111                 terminate("unknown ELF class %d\n", ehdr.e_ident[EI_CLASS]);
 112 
 113         /*NOTREACHED*/
 114         return (0);
 115 }
 116 
 117 /*PRINTFLIKE2*/
 118 static void
 119 whine(char *type, char *format, va_list ap)
 120 {
 121         int error = errno;
 122 
 123         fprintf(stderr, "%s: %s: ", type, progname);
 124         vfprintf(stderr, format, ap);
 125 
 126         if (format[strlen(format) - 1] != '\n')
 127                 fprintf(stderr, ": %s\n", strerror(error));
 128 }
 129 
 130 void
 131 set_terminate_cleanup(void (*cleanup)())
 132 {
 133         terminate_cleanup = cleanup;
 134 }
 135 
 136 /*PRINTFLIKE1*/
 137 void
 138 terminate(char *format, ...)
 139 {
 140         va_list ap;
 141 
 142         va_start(ap, format);
 143         whine("ERROR", format, ap);
 144         va_end(ap);
 145 
 146         if (terminate_cleanup)
 147                 terminate_cleanup();
 148 
 149         if (getenv("CTF_ABORT_ON_TERMINATE") != NULL)
 150                 abort();
 151         exit(1);
 152 }
 153 
 154 /*PRINTFLIKE1*/
 155 void
 156 aborterr(char *format, ...)
 157 {
 158         va_list ap;
 159 
 160         va_start(ap, format);
 161         whine("ERROR", format, ap);
 162         va_end(ap);
 163 
 164         abort();
 165 }
 166 
 167 /*PRINTFLIKE1*/
 168 void
 169 warning(char *format, ...)
 170 {
 171         va_list ap;
 172 
 173         va_start(ap, format);
 174         whine("WARNING", format, ap);
 175         va_end(ap);
 176 
 177         if (debug_level >= 3)
 178                 terminate("Termination due to warning\n");
 179 }
 180 
 181 /*PRINTFLIKE2*/
 182 void
 183 vadebug(int level, char *format, va_list ap)
 184 {
 185         if (level > debug_level)
 186                 return;
 187 
 188         (void) fprintf(DEBUG_STREAM, "DEBUG: ");
 189         (void) vfprintf(DEBUG_STREAM, format, ap);
 190         fflush(DEBUG_STREAM);
 191 }
 192 
 193 /*PRINTFLIKE2*/
 194 void
 195 debug(int level, char *format, ...)
 196 {
 197         va_list ap;
 198 
 199         if (level > debug_level)
 200                 return;
 201 
 202         va_start(ap, format);
 203         (void) vadebug(level, format, ap);
 204         va_end(ap);
 205 }
 206 
 207 char *
 208 mktmpname(const char *origname, const char *suffix)
 209 {
 210         char *newname;
 211 
 212         newname = xmalloc(strlen(origname) + strlen(suffix) + 1);
 213         (void) strcpy(newname, origname);
 214         (void) strcat(newname, suffix);
 215         return (newname);
 216 }
 217 
 218 /*PRINTFLIKE2*/
 219 void
 220 elfterminate(const char *file, const char *fmt, ...)
 221 {
 222         static char msgbuf[BUFSIZ];
 223         va_list ap;
 224 
 225         va_start(ap, fmt);
 226         vsnprintf(msgbuf, sizeof (msgbuf), fmt, ap);
 227         va_end(ap);
 228 
 229         terminate("%s: %s: %s\n", file, msgbuf, elf_errmsg(-1));
 230 }
 231 
 232 const char *
 233 tdesc_name(tdesc_t *tdp)
 234 {
 235         return (tdp->t_name == NULL ? "(anon)" : tdp->t_name);
 236 }