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/* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27#pragma ident "@(#)error.c 1.22 08/06/03 SMI" 28 29#include <pthread.h> /* In lieu of Solaris <thread.h> */ 30#define thr_keycreate pthread_key_create /* In lieu of Solaris <thread.h> */ 31#define thr_getspecific(key, pval) (*pval = pthread_getspecific( key )) /* In lieu of Solaris <thread.h> */ 32#define thr_setspecific pthread_setspecific /* In lieu of Solaris <thread.h> */ 33 34/* Solaris thr_main() is used to detect the possibility that libelf is being used in a 35 threaded application and is subject to re-entrancy. There is no Posix cognate. 36 For safety, always indicate threading is live. */ 37#define thr_main() 0 /* In lieu of Solaris <thread.h> */ 38int __libc_threaded = 1; /* In lieu of Solaris <thread.h> */ 39 40#include <stdlib.h> 41#include <string.h> 42#include <stdio.h> 43#include <libelf.h> 44#include "msg.h" 45#undef _elf_seterr 46 47#define EINF_NULLERROR 0 48#define EBUG_THRDKEY 0 49 50#define MSG_SUNW_OST_SGS -2 51#define MSG_FMT_ERR -1 52#define MSG_INTL(x) "libelf internal error" 53#define MSG_ORIG(x) (x == MSG_FMT_ERR ? "%s %s" : NULL) 54 55char *_dgettext(const char *x, const char *y) { return "libelf internal error"; } 56#define dgettext(x,y) _dgettext(x,y) 57#define NATIVE_BUILD 1 58 59#include "decl.h" 60 61#define ELFERRSHIFT 16 62#define SYSERRMASK 0xffff 63 64 65/* 66 * _elf_err has two values encoded in it, both the _elf_err # and 67 * the system errno value (if relevant). These values are encoded 68 * in the upper & lower 16 bits of the 4 byte integer. 69 */ 70static int _elf_err = 0; 71 72#if !defined(NATIVE_BUILD) 73 74static thread_key_t errkey = THR_ONCE_KEY; 75static thread_key_t bufkey = THR_ONCE_KEY; 76 77#else /* NATIVE_BUILD */ 78 79/* 80 * This code is here to enable the building of a native version 81 * of libelf.so when the build machine has not yet been upgraded 82 * to a version of libc that provides thr_keycreate_once(). 83 * It should be deleted when solaris_nevada ships. 84 * The code is not MT-safe in a relaxed memory model. 85 */ 86 87static thread_key_t errkey = 0; 88static thread_key_t bufkey = 0; 89 90int 91thr_keycreate_once(thread_key_t *keyp, void (*destructor)(void *)) 92{ 93 static mutex_t key_lock = DEFAULTMUTEX; 94 thread_key_t key; 95 int error; 96 97 if (*keyp == 0) { 98 mutex_lock(&key_lock); 99 if (*keyp == 0) { 100 error = thr_keycreate(&key, destructor); 101 if (error) { 102 mutex_unlock(&key_lock); 103 return (error); 104 } 105 *keyp = key; 106 } 107 mutex_unlock(&key_lock); 108 } 109 110 return (0); 111} 112 113#endif /* NATIVE_BUILD */ 114 115 116const char * 117_libelf_msg(Msg mid) 118{ 119 return (dgettext(MSG_ORIG(MSG_SUNW_OST_SGS), MSG_ORIG(mid))); 120} 121 122 123void 124_elf_seterr(Msg lib_err, int sys_err) 125{ 126 /*LINTED*/ 127 intptr_t encerr = ((int)lib_err << ELFERRSHIFT) | 128 (sys_err & SYSERRMASK); 129 130#ifndef __lock_lint 131 if (thr_main()) { 132 _elf_err = (int)encerr; 133 return; 134 } 135#endif 136 (void) thr_keycreate_once(&errkey, 0); 137 (void) thr_setspecific(errkey, (void *)encerr); 138} 139 140int 141_elf_geterr() { 142#ifndef __lock_lint 143 if (thr_main()) 144 return (_elf_err); 145#endif 146 return ((uintptr_t)pthread_getspecific(errkey)); 147} 148 149const char * 150elf_errmsg(int err) 151{ 152 char *errno_str; 153 char *elferr_str; 154 char *buffer = 0; 155 int syserr; 156 int elferr; 157 static char intbuf[MAXELFERR]; 158 159 if (err == 0) { 160 if ((err = _elf_geterr()) == 0) 161 return (0); 162 } else if (err == -1) { 163 if ((err = _elf_geterr()) == 0) 164 /*LINTED*/ /* MSG_INTL(EINF_NULLERROR) */ 165 err = (int)EINF_NULLERROR << ELFERRSHIFT; 166 } 167 168 if (thr_main()) 169 buffer = intbuf; 170 else { 171 /* 172 * If this is a threaded APP then we store the 173 * errmsg buffer in Thread Specific Storage. 174 * 175 * Each thread has its own private buffer. 176 */ 177 if (thr_keycreate_once(&bufkey, free) != 0) 178 return (MSG_INTL(EBUG_THRDKEY)); 179 buffer = pthread_getspecific(bufkey); 180 181 if (!buffer) { 182 if ((buffer = malloc(MAXELFERR)) == 0) 183 return (MSG_INTL(EMEM_ERRMSG)); 184 if (thr_setspecific(bufkey, buffer) != 0) { 185 free(buffer); 186 return (MSG_INTL(EBUG_THRDSET)); 187 } 188 } 189 } 190 191 elferr = (int)((uint_t)err >> ELFERRSHIFT); 192 syserr = err & SYSERRMASK; 193 /*LINTED*/ 194 elferr_str = (char *)MSG_INTL(elferr); 195 if (syserr && (errno_str = strerror(syserr))) 196 (void) snprintf(buffer, MAXELFERR, 197 MSG_ORIG(MSG_FMT_ERR), elferr_str, errno_str); 198 else { 199 (void) strncpy(buffer, elferr_str, MAXELFERR - 1); 200 buffer[MAXELFERR - 1] = '\0'; 201 } 202 203 return (buffer); 204} 205 206int 207elf_errno() 208{ 209 int rc = _elf_geterr(); 210 211 _elf_seterr(0, 0); 212 return (rc); 213} 214