blob: 4bd1a50fcfc9f794b07d096d20a537bdf7e214be [file] [log] [blame]
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001/* Error handling in libdwfl.
2 Copyright (C) 2005 Red Hat, Inc.
3
4 This program is Open Source software; you can redistribute it and/or
5 modify it under the terms of the Open Software License version 1.0 as
6 published by the Open Source Initiative.
7
8 You should have received a copy of the Open Software License along
9 with this program; if not, you may obtain a copy of the Open Software
10 License version 1.0 from http://www.opensource.org/licenses/osl.php or
11 by writing the Open Source Initiative c/o Lawrence Rosen, Esq.,
12 3001 King Ranch Road, Ukiah, CA 95482. */
13
14#ifdef HAVE_CONFIG_H
15# include <config.h>
16#endif
17
18#include <assert.h>
19#include <libintl.h>
20#include <stdbool.h>
21#include <stdint.h>
22#include <stdlib.h>
23#include <errno.h>
24
25#include "libdwflP.h"
26
27
28#ifdef USE_TLS
29/* The error number. */
30static __thread int global_error;
31#else
32/* This is the key for the thread specific memory. */
33static tls_key_t key;
34
35/* The error number. Used in non-threaded programs. */
36static int global_error;
37static bool threaded;
38/* We need to initialize the thread-specific data. */
39once_define (static, once);
40
41/* The initialization and destruction functions. */
42static void init (void);
43static void free_key_mem (void *mem);
44#endif /* TLS */
45
46
47int
48dwfl_errno (void)
49{
50 int result;
51
52#ifndef USE_TLS
53 /* If we have not yet initialized the buffer do it now. */
54 once_execute (once, init);
55
56 if (threaded)
57 {
58 /* We do not allocate memory for the data. It is only a word.
59 We can store it in place of the pointer. */
60 result = (intptr_t) getspecific (key);
61
62 setspecific (key, (void *) (intptr_t) DWFL_E_NOERROR);
63 return result;
64 }
65#endif /* TLS */
66
67 result = global_error;
68 global_error = DWFL_E_NOERROR;
69 return result;
70}
71
72
73static const struct msgtable
74{
75#define DWFL_ERROR(name, text) char msg_##name[sizeof text];
76 DWFL_ERRORS
77#undef DWFL_ERROR
78} msgtable =
79 {
80#define DWFL_ERROR(name, text) text,
81 DWFL_ERRORS
82#undef DWFL_ERROR
83 };
84#define msgstr (&msgtable.msg_NOERROR[0])
85
86static const uint_fast16_t msgidx[] =
87{
88#define DWFL_ERROR(name, text) \
89 [DWFL_E_##name] = offsetof (struct msgtable, msg_##name),
90 DWFL_ERRORS
91#undef DWFL_ERROR
92};
93#define nmsgidx (sizeof msgidx / sizeof msgidx[0])
94
95
96static inline int
97canonicalize (Dwfl_Error error)
98{
99 unsigned int value;
100
101 switch (error)
102 {
103 default:
104 value = error;
105 if ((value &~ 0xffff) != 0)
106 break;
107 assert (value < nmsgidx);
108 break;
109 case DWFL_E_ERRNO:
110 value = DWFL_E (ERRNO, errno);
111 break;
112 case DWFL_E_LIBELF:
113 value = DWFL_E (LIBELF, elf_errno ());
114 break;
115 case DWFL_E_LIBDW:
116 value = DWFL_E (LIBDW, dwarf_errno ());
117 break;
118#if 0
119 DWFL_E_LIBEBL:
120 value = DWFL_E (LIBEBL, ebl_errno ());
121 break;
122#endif
123 }
124
125 return value;
126}
127
128int
129internal_function_def
130__libdwfl_canon_error (Dwfl_Error error)
131{
132 return canonicalize (error);
133}
134
135void
136internal_function_def
137__libdwfl_seterrno (Dwfl_Error error)
138{
139 int value = canonicalize (error);
140
141#ifndef USE_TLS
142 /* If we have not yet initialized the buffer do it now. */
143 once_execute (once, init);
144
145 if (threaded)
146 /* We do not allocate memory for the data. It is only a word.
147 We can store it in place of the pointer. */
148 setspecific (key, (void *) (intptr_t) value);
149#endif /* TLS */
150
151 global_error = value;
152}
153
154
155const char *
156dwfl_errmsg (error)
157 int error;
158{
159 if (error == 0 || error == -1)
160 {
161 int last_error;
162
163#ifndef USE_TLS
164 /* If we have not yet initialized the buffer do it now. */
165 once_execute (once, init);
166
167 if (threaded)
168 /* We do not allocate memory for the data. It is only a word.
169 We can store it in place of the pointer. */
170 last_error = (intptr_t) getspecific (key);
171 else
172#endif /* TLS */
173 last_error = global_error;
174
175 if (error == 0 && last_error == 0)
176 return NULL;
177
178 error = last_error;
179 global_error = DWFL_E_NOERROR;
180 }
181
182 switch (error &~ 0xffff)
183 {
184 case OTHER_ERROR (ERRNO):
185 return strerror_r (error & 0xffff, "bad", 0);
186 case OTHER_ERROR (LIBELF):
187 return elf_errmsg (error & 0xffff);
188 case OTHER_ERROR (LIBDW):
189 return dwarf_errmsg (error & 0xffff);
190#if 0
191 case OTHER_ERROR (LIBEBL):
192 return ebl_errmsg (error & 0xffff);
193#endif
194 }
195
196 return _(&msgstr[msgidx[(unsigned int) error < nmsgidx
197 ? error : DWFL_E_UNKNOWN_ERROR]]);
198}
199INTDEF (dwfl_errmsg)
200
201
202#ifndef USE_TLS
203/* Free the thread specific data, this is done if a thread terminates. */
204static void
205free_key_mem (void *mem __attribute__ ((unused)))
206{
207 setspecific (key, NULL);
208}
209
210
211/* Initialize the key for the global variable. */
212static void
213init (void)
214{
215 // XXX Screw you, gcc4, the unused function attribute does not work.
216 __asm ("" :: "r" (free_key_mem));
217
218 if (key_create (&key, free_key_mem) == 0)
219 /* Creating the key succeeded. */
220 threaded = true;
221}
222#endif /* TLS */