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