1 /* Error handling in libasm. 2 Copyright (C) 2002, 2004 Red Hat, Inc. 3 Written by Ulrich Drepper <drepper (at) redhat.com>, 2002. 4 5 This program is Open Source software; you can redistribute it and/or 6 modify it under the terms of the Open Software License version 1.0 as 7 published by the Open Source Initiative. 8 9 You should have received a copy of the Open Software License along 10 with this program; if not, you may obtain a copy of the Open Software 11 License version 1.0 from http://www.opensource.org/licenses/osl.php or 12 by writing the Open Source Initiative c/o Lawrence Rosen, Esq., 13 3001 King Ranch Road, Ukiah, CA 95482. */ 14 15 #ifdef HAVE_CONFIG_H 16 # include <config.h> 17 #endif 18 19 #include <libintl.h> 20 #include <stdbool.h> 21 #include <stdlib.h> 22 23 #include "libasmP.h" 24 25 26 /* This is the key for the thread specific memory. */ 27 static tls_key_t key; 28 29 /* The error number. Used in non-threaded programs. */ 30 static int global_error; 31 static bool threaded; 32 /* We need to initialize the thread-specific data. */ 33 once_define (static, once); 34 35 /* The initialization and destruction functions. */ 36 static void init (void); 37 static void free_key_mem (void *mem); 38 39 40 int 41 asm_errno (void) 42 { 43 int result; 44 45 /* If we have not yet initialized the buffer do it now. */ 46 once_execute (once, init); 47 48 if (threaded) 49 { 50 /* We have a key. Use it to get the thread-specific buffer. */ 51 int *buffer = getspecific (key); 52 if (buffer == NULL) 53 { 54 /* No buffer allocated so far. */ 55 buffer = (int *) malloc (sizeof (int)); 56 if (buffer == NULL) 57 /* No more memory available. We use the static buffer. */ 58 buffer = &global_error; 59 60 setspecific (key, buffer); 61 62 *buffer = 0; 63 } 64 65 result = *buffer; 66 *buffer = ASM_E_NOERROR; 67 return result; 68 } 69 70 result = global_error; 71 global_error = ASM_E_NOERROR; 72 return result; 73 } 74 75 76 void 77 __libasm_seterrno (value) 78 int value; 79 { 80 /* If we have not yet initialized the buffer do it now. */ 81 once_execute (once, init); 82 83 if (threaded) 84 { 85 /* We have a key. Use it to get the thread-specific buffer. */ 86 int *buffer = getspecific (key); 87 if (buffer == NULL) 88 { 89 /* No buffer allocated so far. */ 90 buffer = malloc (sizeof (int)); 91 if (buffer == NULL) 92 /* No more memory available. We use the static buffer. */ 93 buffer = &global_error; 94 95 setspecific (key, buffer); 96 } 97 98 *buffer = value; 99 } 100 101 global_error = value; 102 } 103 104 105 /* Return the appropriate message for the error. */ 106 static const char *msgs[ASM_E_NUM] = 107 { 108 [ASM_E_NOERROR] = N_("no error"), 109 [ASM_E_NOMEM] = N_("out of memory"), 110 [ASM_E_CANNOT_CREATE] = N_("cannot create output file"), 111 [ASM_E_INVALID] = N_("invalid parameter"), 112 [ASM_E_CANNOT_CHMOD] = N_("cannot change mode of output file"), 113 [ASM_E_CANNOT_RENAME] = N_("cannot rename output file"), 114 [ASM_E_DUPLSYM] = N_("duplicate symbol"), 115 [ASM_E_TYPE] = N_("invalid section type for operation") 116 }; 117 118 const char * 119 asm_errmsg (error) 120 int error; 121 { 122 int last_error; 123 124 /* If we have not yet initialized the buffer do it now. */ 125 once_execute (once, init); 126 127 if ((error == 0 || error == -1) && threaded) 128 { 129 /* We have a key. Use it to get the thread-specific buffer. */ 130 int *buffer = (int *) getspecific (key); 131 if (buffer == NULL) 132 { 133 /* No buffer allocated so far. */ 134 buffer = (int *) malloc (sizeof (int)); 135 if (buffer == NULL) 136 /* No more memory available. We use the static buffer. */ 137 buffer = &global_error; 138 139 setspecific (key, buffer); 140 *buffer = 0; 141 } 142 143 last_error = *buffer; 144 } 145 else 146 last_error = global_error; 147 148 if (error < -1) 149 return _("Unknown error"); 150 if (error == 0 && last_error == 0) 151 /* No error. */ 152 return NULL; 153 154 if (error != -1) 155 last_error = error; 156 157 if (last_error == ASM_E_LIBELF) 158 return elf_errmsg (-1); 159 160 return _(msgs[last_error]); 161 } 162 163 164 /* Free the thread specific data, this is done if a thread terminates. */ 165 static void 166 free_key_mem (void *mem) 167 { 168 free (mem); 169 setspecific (key, NULL); 170 } 171 172 173 /* Initialize the key for the global variable. */ 174 static void 175 init (void) 176 { 177 // XXX Screw you, gcc4, the unused function attribute does not work. 178 __asm ("" :: "r" (free_key_mem)); 179 180 if (key_create (&key, free_key_mem) == 0) 181 /* Creating the key succeeded. */ 182 threaded = true; 183 } 184