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.  */
44static __thread int global_error;
45
46
47int
48dwfl_errno (void)
49{
50  int result = global_error;
51  global_error = DWFL_E_NOERROR;
52  return result;
53}
54INTDEF (dwfl_errno)
55
56
57struct msgtable
58{
59#define DWFL_ERROR(name, text) char msg_##name[sizeof text];
60  DWFL_ERRORS
61#undef	DWFL_ERROR
62};
63
64static 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
83static 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
93static inline int
94canonicalize (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
125int
126internal_function
127__libdwfl_canon_error (Dwfl_Error error)
128{
129  return canonicalize (error);
130}
131
132void
133internal_function
134__libdwfl_seterrno (Dwfl_Error error)
135{
136  global_error = canonicalize (error);
137}
138
139
140const char *
141dwfl_errmsg (int error)
142{
143  if (error == 0 || error == -1)
144    {
145      int last_error = global_error;
146
147      if (error == 0 && last_error == 0)
148	return NULL;
149
150      error = last_error;
151      global_error = DWFL_E_NOERROR;
152    }
153
154  switch (error &~ 0xffff)
155    {
156    case OTHER_ERROR (ERRNO):
157      return strerror_r (error & 0xffff, "bad", 0);
158    case OTHER_ERROR (LIBELF):
159      return elf_errmsg (error & 0xffff);
160    case OTHER_ERROR (LIBDW):
161      return INTUSE(dwarf_errmsg) (error & 0xffff);
162#if 0
163    case OTHER_ERROR (LIBEBL):
164      return ebl_errmsg (error & 0xffff);
165#endif
166    }
167
168  return _(&msgstr[msgidx[(unsigned int) error < nmsgidx
169			  ? error : DWFL_E_UNKNOWN_ERROR]]);
170}
171INTDEF (dwfl_errmsg)
172