Branch data Line data Source code
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 48 : 2643 : dwfl_errno (void) 49 : : { 50 : 2643 : int result = global_error; 51 : 2643 : global_error = DWFL_E_NOERROR; 52 : 2643 : 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 94 : 4004 : canonicalize (Dwfl_Error error) 95 : : { 96 : 4004 : unsigned int value; 97 : : 98 [ + + - + ]: 4004 : switch (error) 99 : : { 100 : 3902 : default: 101 : 3902 : value = error; 102 [ + + ]: 3902 : if ((value &~ 0xffff) != 0) 103 : : break; 104 [ - + ]: 3886 : assert (value < nmsgidx); 105 : : break; 106 : 1 : case DWFL_E_ERRNO: 107 : 1 : value = DWFL_E (ERRNO, errno); 108 : 1 : break; 109 : 0 : case DWFL_E_LIBELF: 110 : 0 : value = DWFL_E (LIBELF, elf_errno ()); 111 : 0 : break; 112 : 101 : case DWFL_E_LIBDW: 113 : 101 : value = DWFL_E (LIBDW, INTUSE(dwarf_errno) ()); 114 : 101 : break; 115 : : #if 0 116 : : DWFL_E_LIBEBL: 117 : : value = DWFL_E (LIBEBL, ebl_errno ()); 118 : : break; 119 : : #endif 120 : : } 121 : : 122 : 16 : return value; 123 : : } 124 : : 125 : : int 126 : : internal_function 127 : 1 : __libdwfl_canon_error (Dwfl_Error error) 128 : : { 129 : 1 : return canonicalize (error); 130 : : } 131 : : 132 : : void 133 : : internal_function 134 : 4003 : __libdwfl_seterrno (Dwfl_Error error) 135 : : { 136 : 4003 : global_error = canonicalize (error); 137 : 4003 : } 138 : : 139 : : 140 : : static const char * 141 : 0 : errnomsg(int error) 142 : : { 143 : : /* Won't be changed by strerror_r, but not const so compiler doesn't throw warning */ 144 : 0 : static char unknown[] = "unknown error"; 145 : : 146 : : #ifdef STRERROR_R_CHAR_P 147 : 0 : 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 * 156 : 18 : dwfl_errmsg (int error) 157 : : { 158 [ + + ]: 18 : if (error == 0 || error == -1) 159 : : { 160 : 16 : int last_error = global_error; 161 : : 162 [ + - ]: 16 : if (error == 0 && last_error == 0) 163 : : return NULL; 164 : : 165 : 16 : error = last_error; 166 : 16 : global_error = DWFL_E_NOERROR; 167 : : } 168 : : 169 [ - - + + ]: 18 : switch (error &~ 0xffff) 170 : : { 171 : 0 : case OTHER_ERROR (ERRNO): 172 : 0 : return errnomsg (error & 0xffff); 173 : 0 : case OTHER_ERROR (LIBELF): 174 : 0 : return elf_errmsg (error & 0xffff); 175 : 7 : case OTHER_ERROR (LIBDW): 176 : 7 : 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 [ - + ]: 11 : return _(&msgstr[msgidx[(unsigned int) error < nmsgidx 184 : : ? error : DWFL_E_UNKNOWN_ERROR]]); 185 : : } 186 : : INTDEF (dwfl_errmsg)