xref: /illumos-gate/usr/src/cmd/sgs/libelf/common/error.c (revision 734b6a94890be549309b21156f8ed6d4561cac51)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2001-2003 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	<stdlib.h>
36 #include	<string.h>
37 #include	<stdio.h>
38 #include	<libelf.h>
39 #include	"msg.h"
40 #include	"decl.h"
41 
42 #define	ELFERRSHIFT	16
43 #define	SYSERRMASK	0xffff
44 
45 
46 /*
47  * _elf_err has two values encoded in it, both the _elf_err # and
48  * the system errno value (if relevant).  These values are encoded
49  * in the upper & lower 16 bits of the 4 byte integer.
50  */
51 static int		_elf_err = 0;
52 
53 static mutex_t		keylock;
54 static mutex_t		buflock;
55 static thread_key_t	errkey;
56 static thread_key_t	bufkey;
57 static int		keyonce = 0;
58 static int		bufonce = 0;
59 NOTE(DATA_READABLE_WITHOUT_LOCK(keyonce))
60 NOTE(DATA_READABLE_WITHOUT_LOCK(bufonce))
61 
62 
63 extern char *_dgettext(const char *, const char *);
64 
65 
66 const char *
67 _libelf_msg(Msg mid)
68 {
69 	return (_dgettext(MSG_ORIG(MSG_SUNW_OST_SGS), MSG_ORIG(mid)));
70 }
71 
72 
73 void
74 _elf_seterr(Msg lib_err, int sys_err)
75 {
76 	/*LINTED*/
77 	intptr_t encerr = ((int)lib_err << ELFERRSHIFT) |
78 	    (sys_err & SYSERRMASK);
79 
80 #ifndef	__lock_lint
81 	if (thr_main()) {
82 		_elf_err = (int)encerr;
83 		return;
84 	}
85 #endif
86 	if (keyonce == 0) {
87 		(void) mutex_lock(&keylock);
88 		if (keyonce == 0) {
89 			(void) thr_keycreate(&errkey, 0);
90 			keyonce++;
91 		}
92 		(void) mutex_unlock(&keylock);
93 	}
94 
95 	(void) thr_setspecific(errkey, (void *)encerr);
96 }
97 
98 int
99 _elf_geterr() {
100 	intptr_t	rc;
101 
102 #ifndef	__lock_lint
103 	if (thr_main())
104 		return (_elf_err);
105 #endif
106 	if (keyonce == 0)
107 		return (0);
108 
109 	(void) thr_getspecific(errkey, (void **)(&rc));
110 	return ((int)rc);
111 }
112 
113 const char *
114 elf_errmsg(int err)
115 {
116 	char			*errno_str;
117 	char			*elferr_str;
118 	char			*buffer = 0;
119 	int			syserr;
120 	int			elferr;
121 	static char		intbuf[MAXELFERR];
122 
123 	if (err == 0) {
124 		if ((err = _elf_geterr()) == 0)
125 			return (0);
126 	} else if (err == -1) {
127 		if ((err = _elf_geterr()) == 0)
128 			/*LINTED*/ /* MSG_INTL(EINF_NULLERROR) */
129 			err = (int)EINF_NULLERROR << ELFERRSHIFT;
130 	}
131 
132 	if (thr_main())
133 		buffer = intbuf;
134 	else {
135 		/*
136 		 * If this is a threaded APP then we store the
137 		 * errmsg buffer in Thread Specific Storage.
138 		 *
139 		 * Each thread has its own private buffer.
140 		 */
141 		if (bufonce == 0) {
142 			(void) mutex_lock(&buflock);
143 			if (bufonce == 0) {
144 				if (thr_keycreate(&bufkey, free) != 0) {
145 					(void) mutex_unlock(&buflock);
146 					return (MSG_INTL(EBUG_THRDKEY));
147 				}
148 				bufonce++;
149 			}
150 			(void) mutex_unlock(&buflock);
151 		}
152 
153 		(void) thr_getspecific(bufkey, (void **)&buffer);
154 
155 		if (!buffer) {
156 			if ((buffer = malloc(MAXELFERR)) == 0)
157 				return (MSG_INTL(EMEM_ERRMSG));
158 			if (thr_setspecific(bufkey, buffer) != 0) {
159 				free(buffer);
160 				return (MSG_INTL(EBUG_THRDSET));
161 			}
162 		}
163 	}
164 
165 	elferr = (int)((uint_t)err >> ELFERRSHIFT);
166 	syserr = err & SYSERRMASK;
167 	/*LINTED*/
168 	elferr_str = (char *)MSG_INTL(elferr);
169 	if (syserr && (errno_str = strerror(syserr)))
170 		(void) snprintf(buffer, MAXELFERR,
171 		    MSG_ORIG(MSG_FMT_ERR), elferr_str, errno_str);
172 	else {
173 		(void) strncpy(buffer, elferr_str, MAXELFERR - 1);
174 		buffer[MAXELFERR - 1] = '\0';
175 	}
176 
177 	return (buffer);
178 }
179 
180 int
181 elf_errno()
182 {
183 	int	rc = _elf_geterr();
184 
185 	_elf_seterr(0, 0);
186 	return (rc);
187 }
188