xref: /third_party/elfutils/libdwfl/dwfl_error.c (revision da0c48c4)
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.  */
43static __thread int global_error;
44
45
46int
47dwfl_errno (void)
48{
49  int result = global_error;
50  global_error = DWFL_E_NOERROR;
51  return result;
52}
53INTDEF (dwfl_errno)
54
55
56struct msgtable
57{
58#define DWFL_ERROR(name, text) char msg_##name[sizeof text];
59  DWFL_ERRORS
60#undef	DWFL_ERROR
61};
62
63static 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
82static 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
92static inline int
93canonicalize (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
124int
125internal_function
126__libdwfl_canon_error (Dwfl_Error error)
127{
128  return canonicalize (error);
129}
130
131void
132internal_function
133__libdwfl_seterrno (Dwfl_Error error)
134{
135  global_error = canonicalize (error);
136}
137
138
139static const char *
140errnomsg(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
154const char *
155dwfl_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}
185INTDEF (dwfl_errmsg)
186