1 /* Error handling in libdwfl.
2 Copyright (C) 2005-2015 Red Hat, Inc.
3 This file is part of elfutils.
4
5 This file is free software; you can redistribute it and/or modify
6 it under the terms of either
7
8 * the GNU Lesser General Public License as published by the Free
9 Software Foundation; either version 3 of the License, or (at
10 your option) any later version
11
12 or
13
14 * the GNU General Public License as published by the Free
15 Software Foundation; either version 2 of the License, or (at
16 your option) any later version
17
18 or both in parallel, as here.
19
20 elfutils is distributed in the hope that it will be useful, but
21 WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 General Public License for more details.
24
25 You should have received copies of the GNU General Public License and
26 the GNU Lesser General Public License along with this program. If
27 not, see <http://www.gnu.org/licenses/>. */
28
29 #ifdef HAVE_CONFIG_H
30 # include <config.h>
31 #endif
32
33 #include <assert.h>
34 #include <libintl.h>
35 #include <stdbool.h>
36 #include <stdint.h>
37 #include <stdlib.h>
38 #include <errno.h>
39
40 #include "libdwflP.h"
41
42
43 /* The error number. */
44 static __thread int global_error;
45
46
47 int
dwfl_errno(void)48 dwfl_errno (void)
49 {
50 int result = global_error;
51 global_error = DWFL_E_NOERROR;
52 return result;
53 }
54 INTDEF (dwfl_errno)
55
56
57 struct msgtable
58 {
59 #define DWFL_ERROR(name, text) char msg_##name[sizeof text];
60 DWFL_ERRORS
61 #undef DWFL_ERROR
62 };
63
64 static const union
65 {
66 struct msgtable table;
67 char strings[
68 #define DWFL_ERROR(name, text) + sizeof text
69 DWFL_ERRORS
70 #undef DWFL_ERROR
71 ];
72 } msgtable =
73 {
74 .table =
75 {
76 #define DWFL_ERROR(name, text) text,
77 DWFL_ERRORS
78 #undef DWFL_ERROR
79 }
80 };
81 #define msgstr (msgtable.strings)
82
83 static const uint_fast16_t msgidx[] =
84 {
85 #define DWFL_ERROR(name, text) \
86 [DWFL_E_##name] = offsetof (struct msgtable, msg_##name),
87 DWFL_ERRORS
88 #undef DWFL_ERROR
89 };
90 #define nmsgidx (sizeof msgidx / sizeof msgidx[0])
91
92
93 static inline int
canonicalize(Dwfl_Error error)94 canonicalize (Dwfl_Error error)
95 {
96 unsigned int value;
97
98 switch (error)
99 {
100 default:
101 value = error;
102 if ((value &~ 0xffff) != 0)
103 break;
104 assert (value < nmsgidx);
105 break;
106 case DWFL_E_ERRNO:
107 value = DWFL_E (ERRNO, errno);
108 break;
109 case DWFL_E_LIBELF:
110 value = DWFL_E (LIBELF, elf_errno ());
111 break;
112 case DWFL_E_LIBDW:
113 value = DWFL_E (LIBDW, INTUSE(dwarf_errno) ());
114 break;
115 #if 0
116 DWFL_E_LIBEBL:
117 value = DWFL_E (LIBEBL, ebl_errno ());
118 break;
119 #endif
120 }
121
122 return value;
123 }
124
125 int
126 internal_function
__libdwfl_canon_error(Dwfl_Error error)127 __libdwfl_canon_error (Dwfl_Error error)
128 {
129 return canonicalize (error);
130 }
131
132 void
133 internal_function
__libdwfl_seterrno(Dwfl_Error error)134 __libdwfl_seterrno (Dwfl_Error error)
135 {
136 global_error = canonicalize (error);
137 }
138
139
140 static const char *
errnomsg(int error)141 errnomsg(int error)
142 {
143 /* Won't be changed by strerror_r, but not const so compiler doesn't throw warning */
144 static char unknown[] = "unknown error";
145
146 #ifdef STRERROR_R_CHAR_P
147 return strerror_r (error, unknown, 0);
148 #else
149 /* To store the error message from strerror_r in a thread-safe manner */
150 static __thread char msg[128];
151 return strerror_r (error, msg, sizeof (msg)) ? unknown : msg;
152 #endif
153 }
154
155 const char *
dwfl_errmsg(int error)156 dwfl_errmsg (int error)
157 {
158 if (error == 0 || error == -1)
159 {
160 int last_error = global_error;
161
162 if (error == 0 && last_error == 0)
163 return NULL;
164
165 error = last_error;
166 global_error = DWFL_E_NOERROR;
167 }
168
169 switch (error &~ 0xffff)
170 {
171 case OTHER_ERROR (ERRNO):
172 return errnomsg (error & 0xffff);
173 case OTHER_ERROR (LIBELF):
174 return elf_errmsg (error & 0xffff);
175 case OTHER_ERROR (LIBDW):
176 return INTUSE(dwarf_errmsg) (error & 0xffff);
177 #if 0
178 case OTHER_ERROR (LIBEBL):
179 return ebl_errmsg (error & 0xffff);
180 #endif
181 }
182
183 return _(&msgstr[msgidx[(unsigned int) error < nmsgidx
184 ? error : DWFL_E_UNKNOWN_ERROR]]);
185 }
186 INTDEF (dwfl_errmsg)
187