Home | History | Annotate | Download | only in libdw
      1 /* Retrieve ELF descriptor used for DWARF access.
      2    Copyright (C) 2002, 2003, 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 <assert.h>
     20 #include <stddef.h>
     21 
     22 #include "libdwP.h"
     23 
     24 
     25 #ifdef USE_TLS
     26 /* The error number.  */
     27 static int global_error;
     28 #else
     29 /* This is the key for the thread specific memory.  */
     30 static tls_key_t key;
     31 
     32 /* The error number.  Used in non-threaded programs.  */
     33 static int global_error;
     34 static bool threaded;
     35 /* We need to initialize the thread-specific data.  */
     36 once_define (static, once);
     37 
     38 /* The initialization and destruction functions.  */
     39 static void init (void);
     40 static void free_key_mem (void *mem);
     41 #endif	/* TLS */
     42 
     43 
     44 int
     45 dwarf_errno (void)
     46 {
     47   int result;
     48 
     49 #ifndef USE_TLS
     50   /* If we have not yet initialized the buffer do it now.  */
     51   once_execute (once, init);
     52 
     53   if (threaded)
     54     {
     55     /* We do not allocate memory for the data.  It is only a word.
     56        We can store it in place of the pointer.  */
     57       result = (intptr_t) getspecific (key);
     58 
     59       setspecific (key, (void *) (intptr_t) DWARF_E_NOERROR);
     60       return result;
     61     }
     62 #endif	/* TLS */
     63 
     64   result = global_error;
     65   global_error = DWARF_E_NOERROR;
     66   return result;
     67 }
     68 
     69 
     70 /* XXX For now we use string pointers.  Once the table stablelizes
     71    make it more DSO-friendly.  */
     72 static const char *errmsgs[] =
     73   {
     74     [DWARF_E_NOERROR] = N_("no error"),
     75     [DWARF_E_UNKNOWN_ERROR] = N_("unknown error"),
     76     [DWARF_E_INVALID_ACCESS] = N_("invalid access"),
     77     [DWARF_E_NO_REGFILE] = N_("no regular file"),
     78     [DWARF_E_IO_ERROR] = N_("I/O error"),
     79     [DWARF_E_INVALID_ELF] = N_("invalid ELF file"),
     80     [DWARF_E_NO_DWARF] = N_("no DWARF information"),
     81     [DWARF_E_NOELF] = N_("no ELF file"),
     82     [DWARF_E_GETEHDR_ERROR] = N_("cannot get ELF header"),
     83     [DWARF_E_NOMEM] = N_("out of memory"),
     84     [DWARF_E_UNIMPL] = N_("not implemented"),
     85     [DWARF_E_INVALID_CMD] = N_("invalid command"),
     86     [DWARF_E_INVALID_VERSION] = N_("invalid version"),
     87     [DWARF_E_INVALID_FILE] = N_("invalid file"),
     88     [DWARF_E_NO_ENTRY] = N_("no entries found"),
     89     [DWARF_E_INVALID_DWARF] = N_("invalid DWARF"),
     90     [DWARF_E_NO_STRING] = N_("no string data"),
     91     [DWARF_E_NO_ADDR] = N_("no address value"),
     92     [DWARF_E_NO_CONSTANT] = N_("no constant value"),
     93     [DWARF_E_NO_REFERENCE] = N_("no reference value"),
     94     [DWARF_E_INVALID_REFERENCE] = N_("invalid reference value"),
     95     [DWARF_E_NO_DEBUG_LINE] = N_(".debug_line section missing"),
     96     [DWARF_E_INVALID_DEBUG_LINE] = N_("invalid .debug_line section"),
     97     [DWARF_E_TOO_BIG] = N_("debug information too big"),
     98     [DWARF_E_VERSION] = N_("invalid DWARF version"),
     99     [DWARF_E_INVALID_DIR_IDX] = N_("invalid directory index"),
    100     [DWARF_E_ADDR_OUTOFRANGE] = N_("address out of range"),
    101     [DWARF_E_NO_LOCLIST] = N_("no location list value"),
    102     [DWARF_E_NO_BLOCK] = N_("no block data"),
    103     [DWARF_E_INVALID_LINE_IDX] = N_("invalid line index"),
    104     [DWARF_E_INVALID_ARANGE_IDX] = N_("invalid address range index"),
    105     [DWARF_E_NO_MATCH] = N_("no matching address range"),
    106     [DWARF_E_NO_FLAG] = N_("no flag value"),
    107   };
    108 #define nerrmsgs (sizeof (errmsgs) / sizeof (errmsgs[0]))
    109 
    110 
    111 void
    112 __libdw_seterrno (value)
    113      int value;
    114 {
    115 #ifndef USE_TLS
    116   /* If we have not yet initialized the buffer do it now.  */
    117   once_execute (once, init);
    118 
    119   if (threaded)
    120     /* We do not allocate memory for the data.  It is only a word.
    121        We can store it in place of the pointer.  */
    122     setspecific (key, (void *) (intptr_t) value);
    123 #endif	/* TLS */
    124 
    125   global_error = (value >= 0 && value < (int) nerrmsgs
    126 		  ? value : DWARF_E_UNKNOWN_ERROR);
    127 }
    128 
    129 
    130 const char *
    131 dwarf_errmsg (error)
    132      int error;
    133 {
    134   int last_error;
    135 
    136 #ifndef USE_TLS
    137   /* If we have not yet initialized the buffer do it now.  */
    138   once_execute (once, init);
    139 
    140   if ((error == 0 || error == -1) && threaded)
    141     /* We do not allocate memory for the data.  It is only a word.
    142        We can store it in place of the pointer.  */
    143     last_error = (intptr_t) getspecific (key);
    144   else
    145 #endif	/* TLS */
    146     last_error = global_error;
    147 
    148   if (error == 0)
    149     return last_error != 0 ? _(errmsgs[last_error]) : NULL;
    150   else if (error < -1 || error >= (int) nerrmsgs)
    151     return _(errmsgs[DWARF_E_UNKNOWN_ERROR]);
    152 
    153   return _(errmsgs[error == -1 ? last_error : error]);
    154 }
    155 
    156 
    157 #ifndef USE_TLS
    158 /* Free the thread specific data, this is done if a thread terminates.  */
    159 static void
    160 free_key_mem (void *mem)
    161 {
    162   setspecific (key, NULL);
    163 }
    164 
    165 
    166 /* Initialize the key for the global variable.  */
    167 static void
    168 init (void)
    169 {
    170   // XXX Screw you, gcc4, the unused function attribute does not work.
    171   __asm ("" :: "r" (free_key_mem));
    172 
    173   if (key_create (&key, free_key_mem) == 0)
    174     /* Creating the key succeeded.  */
    175     threaded = true;
    176 }
    177 #endif	/* TLS */
    178