Home | History | Annotate | Download | only in libdw
      1 /* Unaligned memory access functionality.
      2    Copyright (C) 2000, 2001, 2002, 2003, 2004 Red Hat, Inc.
      3    Written by Ulrich Drepper <drepper (at) redhat.com>, 2001.
      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 #ifndef _MEMORY_ACCESS_H
     16 #define _MEMORY_ACCESS_H 1
     17 
     18 #include <byteswap.h>
     19 #include <limits.h>
     20 #include <stdint.h>
     21 
     22 
     23 /* Number decoding macros.  See 7.6 Variable Length Data.  */
     24 #define get_uleb128(var, addr) \
     25   do {									      \
     26     unsigned char __b = *((const unsigned char *) addr);		      \
     27     addr = (__typeof (addr)) (((uintptr_t) (addr)) + 1);		      \
     28     var = __b & 0x7f;							      \
     29     if (__b & 0x80)							      \
     30       {									      \
     31 	__b = *((const unsigned char *) addr);				      \
     32 	addr = (__typeof (addr)) (((uintptr_t) (addr)) + 1);		      \
     33 	var |= (__b & 0x7f) << 7;					      \
     34 	if (__b & 0x80)							      \
     35 	  {								      \
     36 	    __b = *((const unsigned char *) addr);			      \
     37 	    addr = (__typeof (addr)) (((uintptr_t) (addr)) + 1);	      \
     38 	    var |= (__b & 0x7f) << 14;					      \
     39 	    if (__b & 0x80)						      \
     40 	      {								      \
     41 		__b = *((const unsigned char *) addr);			      \
     42 		addr = (__typeof (addr)) (((uintptr_t) (addr)) + 1);	      \
     43 		var |= (__b & 0x7f) << 21;				      \
     44 		if (__b & 0x80)						      \
     45 		  /* Other implementation set VALUE to UINT_MAX in this	      \
     46 		     case.  So we better do this as well.  */		      \
     47 		  var = UINT_MAX;					      \
     48 	      }								      \
     49 	  }								      \
     50       }									      \
     51   } while (0)
     52 
     53 /* The signed case is a big more complicated.  */
     54 #define get_sleb128(var, addr) \
     55   do {									      \
     56     unsigned char __b = *((const unsigned char *) addr);		      \
     57     addr = (__typeof (addr)) (((uintptr_t) (addr)) + 1);		      \
     58     int32_t __res = __b & 0x7f;						      \
     59     if ((__b & 0x80) == 0)						      \
     60       {									      \
     61 	if (__b & 0x40)							      \
     62 	  __res |= 0xffffff80;						      \
     63       }									      \
     64     else								      \
     65       {									      \
     66 	__b = *((const unsigned char *) addr);				      \
     67 	addr = (__typeof (addr)) (((uintptr_t) (addr)) + 1);		      \
     68 	__res |= (__b & 0x7f) << 7;					      \
     69 	if ((__b & 0x80) == 0)						      \
     70 	  {								      \
     71 	    if (__b & 0x40)						      \
     72 	      __res |= 0xffffc000;					      \
     73 	  }								      \
     74 	else								      \
     75 	  {								      \
     76 	    __b = *((const unsigned char *) addr);			      \
     77 	    addr = (__typeof (addr)) (((uintptr_t) (addr)) + 1);	      \
     78 	    __res |= (__b & 0x7f) << 14;				      \
     79 	    if ((__b & 0x80) == 0)					      \
     80 	      {								      \
     81 		if (__b & 0x40)						      \
     82 		  __res |= 0xffe00000;					      \
     83 	      }								      \
     84 	    else							      \
     85 	      {								      \
     86 		__b = *((const unsigned char *) addr);			      \
     87 		addr = (__typeof (addr)) (((uintptr_t) (addr)) + 1);	      \
     88 		__res |= (__b & 0x7f) << 21;				      \
     89 		if ((__b & 0x80) == 0)					      \
     90 		  {							      \
     91 		    if (__b & 0x40)					      \
     92 		      __res |= 0xf0000000;				      \
     93 		  }							      \
     94 		else							      \
     95 		  /* Other implementation set VALUE to INT_MAX in this	      \
     96 		     case.  So we better do this as well.  */		      \
     97 		  __res = INT_MAX;					      \
     98 	      }								      \
     99 	  }								      \
    100       }									      \
    101     var = __res;							      \
    102   } while (0)
    103 
    104 
    105 /* We use simple memory access functions in case the hardware allows it.
    106    The caller has to make sure we don't have alias problems.  */
    107 #if ALLOW_UNALIGNED
    108 
    109 # define read_2ubyte_unaligned(Dbg, Addr) \
    110   (unlikely ((Dbg)->other_byte_order)					      \
    111    ? bswap_16 (*((const uint16_t *) (Addr)))				      \
    112    : *((const uint16_t *) (Addr)))
    113 # define read_2sbyte_unaligned(Dbg, Addr) \
    114   (unlikely ((Dbg)->other_byte_order)					      \
    115    ? (int16_t) bswap_16 (*((const int16_t *) (Addr)))			      \
    116    : *((const int16_t *) (Addr)))
    117 
    118 # define read_4ubyte_unaligned_noncvt(Addr) \
    119    *((const uint32_t *) (Addr))
    120 # define read_4ubyte_unaligned(Dbg, Addr) \
    121   (unlikely ((Dbg)->other_byte_order)					      \
    122    ? bswap_32 (*((const uint32_t *) (Addr)))				      \
    123    : *((const uint32_t *) (Addr)))
    124 # define read_4sbyte_unaligned(Dbg, Addr) \
    125   (unlikely ((Dbg)->other_byte_order)					      \
    126    ? (int32_t) bswap_32 (*((const int32_t *) (Addr)))			      \
    127    : *((const int32_t *) (Addr)))
    128 
    129 # define read_8ubyte_unaligned(Dbg, Addr) \
    130   (unlikely ((Dbg)->other_byte_order)					      \
    131    ? bswap_64 (*((const uint64_t *) (Addr)))				      \
    132    : *((const uint64_t *) (Addr)))
    133 # define read_8sbyte_unaligned(Dbg, Addr) \
    134   (unlikely ((Dbg)->other_byte_order)					      \
    135    ? (int64_t) bswap_64 (*((const int64_t *) (Addr)))			      \
    136    : *((const int64_t *) (Addr)))
    137 
    138 #else
    139 
    140 union unaligned
    141   {
    142     void *p;
    143     uint16_t u2;
    144     uint32_t u4;
    145     uint64_t u8;
    146     int16_t s2;
    147     int32_t s4;
    148     int64_t s8;
    149   } __attribute__ ((packed));
    150 
    151 static inline uint16_t
    152 read_2ubyte_unaligned (Dwarf *dbg, const void *p)
    153 {
    154   const union unaligned *up = p;
    155   if (dbg->other_byte_order)
    156     return bswap_16 (up->u2);
    157   return up->u2;
    158 }
    159 static inline int16_t
    160 read_2sbyte_unaligned (Dwarf *dbg, const void *p)
    161 {
    162   const union unaligned *up = p;
    163   if (dbg->other_byte_order)
    164     return (int16_t) bswap_16 (up->u2);
    165   return up->s2;
    166 }
    167 
    168 static inline uint32_t
    169 read_4ubyte_unaligned_noncvt (const void *p)
    170 {
    171   const union unaligned *up = p;
    172   return up->u4;
    173 }
    174 static inline uint32_t
    175 read_4ubyte_unaligned (Dwarf *dbg, const void *p)
    176 {
    177   const union unaligned *up = p;
    178   if (dbg->other_byte_order)
    179     return bswap_32 (up->u4);
    180   return up->u4;
    181 }
    182 static inline int32_t
    183 read_4sbyte_unaligned (Dwarf *dbg, const void *p)
    184 {
    185   const union unaligned *up = p;
    186   if (dbg->other_byte_order)
    187     return (int32_t) bswap_32 (up->u4);
    188   return up->s4;
    189 }
    190 
    191 static inline uint64_t
    192 read_8ubyte_unaligned (Dwarf *dbg, const void *p)
    193 {
    194   const union unaligned *up = p;
    195   if (dbg->other_byte_order)
    196     return bswap_64 (up->u8);
    197   return up->u8;
    198 }
    199 static inline int64_t
    200 read_8sbyte_unaligned (Dwarf *dbg, const void *p)
    201 {
    202   const union unaligned *up = p;
    203   if (dbg->other_byte_order)
    204     return (int64_t) bswap_64 (up->u8);
    205   return up->s8;
    206 }
    207 
    208 #endif	/* allow unaligned */
    209 
    210 
    211 #define read_2ubyte_unaligned_inc(Dbg, Addr) \
    212   ({ uint16_t t_ = read_2ubyte_unaligned (Dbg, Addr);			      \
    213      Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 2);		      \
    214      t_; })
    215 #define read_2sbyte_unaligned_inc(Dbg, Addr) \
    216   ({ int16_t t_ = read_2sbyte_unaligned (Dbg, Addr);			      \
    217      Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 2);		      \
    218      t_; })
    219 
    220 #define read_4ubyte_unaligned_inc(Dbg, Addr) \
    221   ({ uint32_t t_ = read_4ubyte_unaligned (Dbg, Addr);			      \
    222      Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 4);		      \
    223      t_; })
    224 #define read_4sbyte_unaligned_inc(Dbg, Addr) \
    225   ({ int32_t t_ = read_4sbyte_unaligned (Dbg, Addr);			      \
    226      Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 4);		      \
    227      t_; })
    228 
    229 #define read_8ubyte_unaligned_inc(Dbg, Addr) \
    230   ({ uint64_t t_ = read_8ubyte_unaligned (Dbg, Addr);			      \
    231      Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 8);		      \
    232      t_; })
    233 #define read_8sbyte_unaligned_inc(Dbg, Addr) \
    234   ({ int64_t t_ = read_8sbyte_unaligned (Dbg, Addr);			      \
    235      Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 8);		      \
    236      t_; })
    237 
    238 #endif	/* memory-access.h */
    239