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