• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <stdbool.h>
35 #include <stdint.h>
36 #include <stdlib.h>
37 #include <errno.h>
38 
39 #include "libdwflP.h"
40 
41 
42 /* The error number.  */
43 static __thread int global_error;
44 
45 
46 int
dwfl_errno(void)47 dwfl_errno (void)
48 {
49   int result = global_error;
50   global_error = DWFL_E_NOERROR;
51   return result;
52 }
53 INTDEF (dwfl_errno)
54 
55 
56 struct msgtable
57 {
58 #define DWFL_ERROR(name, text) char msg_##name[sizeof text];
59   DWFL_ERRORS
60 #undef	DWFL_ERROR
61 };
62 
63 static const union
64 {
65   struct msgtable table;
66   char strings[
67 #define DWFL_ERROR(name, text)	+ sizeof text
68 	       DWFL_ERRORS
69 #undef	DWFL_ERROR
70 	       ];
71 } msgtable =
72   {
73     .table =
74     {
75 #define DWFL_ERROR(name, text) text,
76       DWFL_ERRORS
77 #undef	DWFL_ERROR
78     }
79   };
80 #define msgstr (msgtable.strings)
81 
82 static const uint_fast16_t msgidx[] =
83 {
84 #define DWFL_ERROR(name, text) \
85   [DWFL_E_##name] = offsetof (struct msgtable, msg_##name),
86   DWFL_ERRORS
87 #undef	DWFL_ERROR
88 };
89 #define nmsgidx (sizeof msgidx / sizeof msgidx[0])
90 
91 
92 static inline int
canonicalize(Dwfl_Error error)93 canonicalize (Dwfl_Error error)
94 {
95   unsigned int value;
96 
97   switch (error)
98     {
99     default:
100       value = error;
101       if ((value &~ 0xffff) != 0)
102 	break;
103       assert (value < nmsgidx);
104       break;
105     case DWFL_E_ERRNO:
106       value = DWFL_E (ERRNO, errno);
107       break;
108     case DWFL_E_LIBELF:
109       value = DWFL_E (LIBELF, elf_errno ());
110       break;
111     case DWFL_E_LIBDW:
112       value = DWFL_E (LIBDW, INTUSE(dwarf_errno) ());
113       break;
114 #if 0
115     DWFL_E_LIBEBL:
116       value = DWFL_E (LIBEBL, ebl_errno ());
117       break;
118 #endif
119     }
120 
121   return value;
122 }
123 
124 int
125 internal_function
__libdwfl_canon_error(Dwfl_Error error)126 __libdwfl_canon_error (Dwfl_Error error)
127 {
128   return canonicalize (error);
129 }
130 
131 void
132 internal_function
__libdwfl_seterrno(Dwfl_Error error)133 __libdwfl_seterrno (Dwfl_Error error)
134 {
135   global_error = canonicalize (error);
136 }
137 
138 
139 static const char *
errnomsg(int error)140 errnomsg(int error)
141 {
142   /* Won't be changed by strerror_r, but not const so compiler doesn't throw warning */
143   static char unknown[] = "unknown error";
144 
145 #ifdef STRERROR_R_CHAR_P
146   return strerror_r (error, unknown, 0);
147 #else
148   /* To store the error message from strerror_r in a thread-safe manner */
149   static __thread char msg[128];
150   return strerror_r (error, msg, sizeof (msg)) ? unknown : msg;
151 #endif
152 }
153 
154 const char *
dwfl_errmsg(int error)155 dwfl_errmsg (int error)
156 {
157   if (error == 0 || error == -1)
158     {
159       int last_error = global_error;
160 
161       if (error == 0 && last_error == 0)
162 	return NULL;
163 
164       error = last_error;
165       global_error = DWFL_E_NOERROR;
166     }
167 
168   switch (error &~ 0xffff)
169     {
170     case OTHER_ERROR (ERRNO):
171       return errnomsg (error & 0xffff);
172     case OTHER_ERROR (LIBELF):
173       return elf_errmsg (error & 0xffff);
174     case OTHER_ERROR (LIBDW):
175       return INTUSE(dwarf_errmsg) (error & 0xffff);
176 #if 0
177     case OTHER_ERROR (LIBEBL):
178       return ebl_errmsg (error & 0xffff);
179 #endif
180     }
181 
182   return _(&msgstr[msgidx[(unsigned int) error < nmsgidx
183 			  ? error : DWFL_E_UNKNOWN_ERROR]]);
184 }
185 INTDEF (dwfl_errmsg)
186