Home | History | Annotate | Download | only in libasm
      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