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