• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Error handling in libasm.
2    Copyright (C) 2002, 2004 Red Hat, Inc.
3    Written by Ulrich Drepper <drepper@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
asm_errno(void)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
__libasm_seterrno(value)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 *
asm_errmsg(error)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
free_key_mem(void * mem)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
init(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