LCOV - code coverage report
Current view: top level - libdw - memory-access.h (source / functions) Hit Total Coverage
Test: elfutils-0.182 Lines: 32 55 58.2 %
Date: 2020-10-31 23:45:54 Functions: 4 5 80.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* Unaligned memory access functionality.
       2             :    Copyright (C) 2000-2014, 2018 Red Hat, Inc.
       3             :    This file is part of elfutils.
       4             : 
       5             :    This file is free software; you can redistribute it and/or modify
       6             :    it under the terms of either
       7             : 
       8             :      * the GNU Lesser General Public License as published by the Free
       9             :        Software Foundation; either version 3 of the License, or (at
      10             :        your option) any later version
      11             : 
      12             :    or
      13             : 
      14             :      * the GNU General Public License as published by the Free
      15             :        Software Foundation; either version 2 of the License, or (at
      16             :        your option) any later version
      17             : 
      18             :    or both in parallel, as here.
      19             : 
      20             :    elfutils is distributed in the hope that it will be useful, but
      21             :    WITHOUT ANY WARRANTY; without even the implied warranty of
      22             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      23             :    General Public License for more details.
      24             : 
      25             :    You should have received copies of the GNU General Public License and
      26             :    the GNU Lesser General Public License along with this program.  If
      27             :    not, see <http://www.gnu.org/licenses/>.  */
      28             : 
      29             : #ifndef _MEMORY_ACCESS_H
      30             : #define _MEMORY_ACCESS_H 1
      31             : 
      32             : #include <byteswap.h>
      33             : #include <endian.h>
      34             : #include <limits.h>
      35             : #include <stdint.h>
      36             : 
      37             : 
      38             : /* Number decoding macros.  See 7.6 Variable Length Data.  */
      39             : 
      40             : #define len_leb128(var) ((8 * sizeof (var) + 6) / 7)
      41             : 
      42             : static inline size_t
      43             : __libdw_max_len_leb128 (const size_t type_len,
      44             :                         const unsigned char *addr, const unsigned char *end)
      45             : {
      46      969638 :   const size_t pointer_len = likely (addr < end) ? end - addr : 0;
      47      484819 :   return likely (type_len <= pointer_len) ? type_len : pointer_len;
      48             : }
      49             : 
      50             : static inline size_t
      51             : __libdw_max_len_uleb128 (const unsigned char *addr, const unsigned char *end)
      52             : {
      53      196751 :   const size_t type_len = len_leb128 (uint64_t);
      54      393502 :   return __libdw_max_len_leb128 (type_len, addr, end);
      55             : }
      56             : 
      57             : static inline size_t
      58             : __libdw_max_len_sleb128 (const unsigned char *addr, const unsigned char *end)
      59             : {
      60             :   /* Subtract one step, so we don't shift into sign bit.  */
      61      288068 :   const size_t type_len = len_leb128 (int64_t) - 1;
      62      576136 :   return __libdw_max_len_leb128 (type_len, addr, end);
      63             : }
      64             : 
      65             : #define get_uleb128_step(var, addr, nth)                                      \
      66             :   do {                                                                        \
      67             :     unsigned char __b = *(addr)++;                                            \
      68             :     (var) |= (typeof (var)) (__b & 0x7f) << ((nth) * 7);                    \
      69             :     if (likely ((__b & 0x80) == 0))                                       \
      70             :       return (var);                                                           \
      71             :   } while (0)
      72             : 
      73             : static inline uint64_t
      74    56773323 : __libdw_get_uleb128 (const unsigned char **addrp, const unsigned char *end)
      75             : {
      76    56773323 :   uint64_t acc = 0;
      77             : 
      78             :   /* Unroll the first step to help the compiler optimize
      79             :      for the common single-byte case.  */
      80    56773323 :   get_uleb128_step (acc, *addrp, 0);
      81             : 
      82      196751 :   const size_t max = __libdw_max_len_uleb128 (*addrp - 1, end);
      83      243400 :   for (size_t i = 1; i < max; ++i)
      84      243400 :     get_uleb128_step (acc, *addrp, i);
      85             :   /* Other implementations set VALUE to UINT_MAX in this
      86             :      case.  So we better do this as well.  */
      87             :   return UINT64_MAX;
      88             : }
      89             : 
      90             : static inline uint64_t
      91   381580814 : __libdw_get_uleb128_unchecked (const unsigned char **addrp)
      92             : {
      93   381580814 :   uint64_t acc = 0;
      94             : 
      95             :   /* Unroll the first step to help the compiler optimize
      96             :      for the common single-byte case.  */
      97   381580814 :   get_uleb128_step (acc, *addrp, 0);
      98             : 
      99             :   const size_t max = len_leb128 (uint64_t);
     100     6269045 :   for (size_t i = 1; i < max; ++i)
     101     6269045 :     get_uleb128_step (acc, *addrp, i);
     102             :   /* Other implementations set VALUE to UINT_MAX in this
     103             :      case.  So we better do this as well.  */
     104             :   return UINT64_MAX;
     105             : }
     106             : 
     107             : /* Note, addr needs to me smaller than end. */
     108             : #define get_uleb128(var, addr, end) ((var) = __libdw_get_uleb128 (&(addr), end))
     109             : #define get_uleb128_unchecked(var, addr) ((var) = __libdw_get_uleb128_unchecked (&(addr)))
     110             : 
     111             : /* The signed case is similar, but we sign-extend the result.  */
     112             : 
     113             : #define get_sleb128_step(var, addr, nth)                                      \
     114             :   do {                                                                        \
     115             :     unsigned char __b = *(addr)++;                                            \
     116             :     (var) |= (typeof (var)) (__b & 0x7f) << ((nth) * 7);                    \
     117             :     if (likely ((__b & 0x80) == 0))                                       \
     118             :       {                                                                       \
     119             :         if ((__b & 0x40) != 0)                                                    \
     120             :           (var) |= - ((typeof (var)) 1 << (((nth) + 1) * 7));                   \
     121             :         return (var);                                                         \
     122             :       }                                                                       \
     123             :   } while (0)
     124             : 
     125             : static inline int64_t
     126      669820 : __libdw_get_sleb128 (const unsigned char **addrp, const unsigned char *end)
     127             : {
     128             :   /* Do the work in an unsigned type, but use implementation-defined
     129             :      behavior to cast to signed on return.  This avoids some undefined
     130             :      behavior when shifting.  */
     131      669820 :   uint64_t acc = 0;
     132             : 
     133             :   /* Unroll the first step to help the compiler optimize
     134             :      for the common single-byte case.  */
     135      669820 :   get_sleb128_step (acc, *addrp, 0);
     136             : 
     137      288068 :   const size_t max = __libdw_max_len_sleb128 (*addrp - 1, end);
     138      296455 :   for (size_t i = 1; i < max; ++i)
     139      296437 :     get_sleb128_step (acc, *addrp, i);
     140          18 :   if (*addrp == end)
     141             :     return INT64_MAX;
     142             : 
     143             :   /* There might be one extra byte.  */
     144          18 :   unsigned char b = **addrp;
     145          18 :   ++*addrp;
     146          18 :   if (likely ((b & 0x80) == 0))
     147             :     {
     148             :       /* We only need the low bit of the final byte, and as it is the
     149             :          sign bit, we don't need to do anything else here.  */
     150          18 :       acc |= ((typeof (acc)) b) << 7 * max;
     151          18 :       return acc;
     152             :     }
     153             : 
     154             :   /* Other implementations set VALUE to INT_MAX in this
     155             :      case.  So we better do this as well.  */
     156             :   return INT64_MAX;
     157             : }
     158             : 
     159             : static inline int64_t
     160        1200 : __libdw_get_sleb128_unchecked (const unsigned char **addrp)
     161             : {
     162             :   /* Do the work in an unsigned type, but use implementation-defined
     163             :      behavior to cast to signed on return.  This avoids some undefined
     164             :      behavior when shifting.  */
     165        1200 :   uint64_t acc = 0;
     166             : 
     167             :   /* Unroll the first step to help the compiler optimize
     168             :      for the common single-byte case.  */
     169        1200 :   get_sleb128_step (acc, *addrp, 0);
     170             : 
     171             :   /* Subtract one step, so we don't shift into sign bit.  */
     172             :   const size_t max = len_leb128 (int64_t) - 1;
     173           0 :   for (size_t i = 1; i < max; ++i)
     174           0 :     get_sleb128_step (acc, *addrp, i);
     175             : 
     176             :   /* There might be one extra byte.  */
     177           0 :   unsigned char b = **addrp;
     178           0 :   ++*addrp;
     179           0 :   if (likely ((b & 0x80) == 0))
     180             :     {
     181             :       /* We only need the low bit of the final byte, and as it is the
     182             :          sign bit, we don't need to do anything else here.  */
     183           0 :       acc |= ((typeof (acc)) b) << 7 * max;
     184           0 :       return acc;
     185             :     }
     186             : 
     187             :   /* Other implementations set VALUE to INT_MAX in this
     188             :      case.  So we better do this as well.  */
     189             :   return INT64_MAX;
     190             : }
     191             : 
     192             : #define get_sleb128(var, addr, end) ((var) = __libdw_get_sleb128 (&(addr), end))
     193             : #define get_sleb128_unchecked(var, addr) ((var) = __libdw_get_sleb128_unchecked (&(addr)))
     194             : 
     195             : 
     196             : /* We use simple memory access functions in case the hardware allows it.
     197             :    The caller has to make sure we don't have alias problems.  */
     198             : #if ALLOW_UNALIGNED
     199             : 
     200             : # define read_2ubyte_unaligned(Dbg, Addr) \
     201             :   (unlikely ((Dbg)->other_byte_order)                                              \
     202             :    ? bswap_16 (*((const uint16_t *) (Addr)))                                  \
     203             :    : *((const uint16_t *) (Addr)))
     204             : # define read_2sbyte_unaligned(Dbg, Addr) \
     205             :   (unlikely ((Dbg)->other_byte_order)                                              \
     206             :    ? (int16_t) bswap_16 (*((const int16_t *) (Addr)))                         \
     207             :    : *((const int16_t *) (Addr)))
     208             : 
     209             : # define read_4ubyte_unaligned_noncvt(Addr) \
     210             :    *((const uint32_t *) (Addr))
     211             : # define read_4ubyte_unaligned(Dbg, Addr) \
     212             :   (unlikely ((Dbg)->other_byte_order)                                              \
     213             :    ? bswap_32 (*((const uint32_t *) (Addr)))                                  \
     214             :    : *((const uint32_t *) (Addr)))
     215             : # define read_4sbyte_unaligned(Dbg, Addr) \
     216             :   (unlikely ((Dbg)->other_byte_order)                                              \
     217             :    ? (int32_t) bswap_32 (*((const int32_t *) (Addr)))                         \
     218             :    : *((const int32_t *) (Addr)))
     219             : 
     220             : # define read_8ubyte_unaligned_noncvt(Addr) \
     221             :    *((const uint64_t *) (Addr))
     222             : # define read_8ubyte_unaligned(Dbg, Addr) \
     223             :   (unlikely ((Dbg)->other_byte_order)                                              \
     224             :    ? bswap_64 (*((const uint64_t *) (Addr)))                                  \
     225             :    : *((const uint64_t *) (Addr)))
     226             : # define read_8sbyte_unaligned(Dbg, Addr) \
     227             :   (unlikely ((Dbg)->other_byte_order)                                              \
     228             :    ? (int64_t) bswap_64 (*((const int64_t *) (Addr)))                         \
     229             :    : *((const int64_t *) (Addr)))
     230             : 
     231             : #else
     232             : 
     233             : union unaligned
     234             :   {
     235             :     void *p;
     236             :     uint16_t u2;
     237             :     uint32_t u4;
     238             :     uint64_t u8;
     239             :     int16_t s2;
     240             :     int32_t s4;
     241             :     int64_t s8;
     242             :   } attribute_packed;
     243             : 
     244             : # define read_2ubyte_unaligned(Dbg, Addr) \
     245             :   read_2ubyte_unaligned_1 ((Dbg)->other_byte_order, (Addr))
     246             : # define read_2sbyte_unaligned(Dbg, Addr) \
     247             :   read_2sbyte_unaligned_1 ((Dbg)->other_byte_order, (Addr))
     248             : # define read_4ubyte_unaligned(Dbg, Addr) \
     249             :   read_4ubyte_unaligned_1 ((Dbg)->other_byte_order, (Addr))
     250             : # define read_4sbyte_unaligned(Dbg, Addr) \
     251             :   read_4sbyte_unaligned_1 ((Dbg)->other_byte_order, (Addr))
     252             : # define read_8ubyte_unaligned(Dbg, Addr) \
     253             :   read_8ubyte_unaligned_1 ((Dbg)->other_byte_order, (Addr))
     254             : # define read_8sbyte_unaligned(Dbg, Addr) \
     255             :   read_8sbyte_unaligned_1 ((Dbg)->other_byte_order, (Addr))
     256             : 
     257             : static inline uint16_t
     258             : read_2ubyte_unaligned_1 (bool other_byte_order, const void *p)
     259             : {
     260             :   const union unaligned *up = p;
     261             :   if (unlikely (other_byte_order))
     262             :     return bswap_16 (up->u2);
     263             :   return up->u2;
     264             : }
     265             : static inline int16_t
     266             : read_2sbyte_unaligned_1 (bool other_byte_order, const void *p)
     267             : {
     268             :   const union unaligned *up = p;
     269             :   if (unlikely (other_byte_order))
     270             :     return (int16_t) bswap_16 (up->u2);
     271             :   return up->s2;
     272             : }
     273             : 
     274             : static inline uint32_t
     275             : read_4ubyte_unaligned_noncvt (const void *p)
     276             : {
     277             :   const union unaligned *up = p;
     278             :   return up->u4;
     279             : }
     280             : static inline uint32_t
     281             : read_4ubyte_unaligned_1 (bool other_byte_order, const void *p)
     282             : {
     283             :   const union unaligned *up = p;
     284             :   if (unlikely (other_byte_order))
     285             :     return bswap_32 (up->u4);
     286             :   return up->u4;
     287             : }
     288             : static inline int32_t
     289             : read_4sbyte_unaligned_1 (bool other_byte_order, const void *p)
     290             : {
     291             :   const union unaligned *up = p;
     292             :   if (unlikely (other_byte_order))
     293             :     return (int32_t) bswap_32 (up->u4);
     294             :   return up->s4;
     295             : }
     296             : 
     297             : static inline uint64_t
     298             : read_8ubyte_unaligned_noncvt (const void *p)
     299             : {
     300             :   const union unaligned *up = p;
     301             :   return up->u8;
     302             : }
     303             : static inline uint64_t
     304             : read_8ubyte_unaligned_1 (bool other_byte_order, const void *p)
     305             : {
     306             :   const union unaligned *up = p;
     307             :   if (unlikely (other_byte_order))
     308             :     return bswap_64 (up->u8);
     309             :   return up->u8;
     310             : }
     311             : static inline int64_t
     312             : read_8sbyte_unaligned_1 (bool other_byte_order, const void *p)
     313             : {
     314             :   const union unaligned *up = p;
     315             :   if (unlikely (other_byte_order))
     316             :     return (int64_t) bswap_64 (up->u8);
     317             :   return up->s8;
     318             : }
     319             : 
     320             : #endif  /* allow unaligned */
     321             : 
     322             : 
     323             : #define read_2ubyte_unaligned_inc(Dbg, Addr) \
     324             :   ({ uint16_t t_ = read_2ubyte_unaligned (Dbg, Addr);                         \
     325             :      Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 2);                     \
     326             :      t_; })
     327             : #define read_2sbyte_unaligned_inc(Dbg, Addr) \
     328             :   ({ int16_t t_ = read_2sbyte_unaligned (Dbg, Addr);                          \
     329             :      Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 2);                     \
     330             :      t_; })
     331             : 
     332             : #define read_4ubyte_unaligned_inc(Dbg, Addr) \
     333             :   ({ uint32_t t_ = read_4ubyte_unaligned (Dbg, Addr);                         \
     334             :      Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 4);                     \
     335             :      t_; })
     336             : #define read_4sbyte_unaligned_inc(Dbg, Addr) \
     337             :   ({ int32_t t_ = read_4sbyte_unaligned (Dbg, Addr);                          \
     338             :      Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 4);                     \
     339             :      t_; })
     340             : 
     341             : #define read_8ubyte_unaligned_inc(Dbg, Addr) \
     342             :   ({ uint64_t t_ = read_8ubyte_unaligned (Dbg, Addr);                         \
     343             :      Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 8);                     \
     344             :      t_; })
     345             : #define read_8sbyte_unaligned_inc(Dbg, Addr) \
     346             :   ({ int64_t t_ = read_8sbyte_unaligned (Dbg, Addr);                          \
     347             :      Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 8);                     \
     348             :      t_; })
     349             : 
     350             : /* 3ubyte reads are only used for DW_FORM_addrx3 and DW_FORM_strx3.
     351             :    And are probably very rare.  They are not optimized.  They are
     352             :    handled as if reading a 4byte value with the first (for big endian)
     353             :    or last (for little endian) byte zero.  */
     354             : 
     355             : static inline int
     356             : file_byte_order (bool other_byte_order)
     357             : {
     358             : #if __BYTE_ORDER == __LITTLE_ENDIAN
     359           0 :   return other_byte_order ? __BIG_ENDIAN : __LITTLE_ENDIAN;
     360             : #else
     361             :   return other_byte_order ? __LITTLE_ENDIAN : __BIG_ENDIAN;
     362             : #endif
     363             : }
     364             : 
     365             : static inline uint32_t
     366           0 : read_3ubyte_unaligned (Dwarf *dbg, const unsigned char *p)
     367             : {
     368           0 :   union
     369             :   {
     370             :     uint32_t u4;
     371             :     unsigned char c[4];
     372             :   } d;
     373           0 :   bool other_byte_order = dbg->other_byte_order;
     374             : 
     375           0 :   if (file_byte_order (other_byte_order) == __BIG_ENDIAN)
     376             :     {
     377           0 :       d.c[0] = 0x00;
     378           0 :       d.c[1] = p[0];
     379           0 :       d.c[2] = p[1];
     380           0 :       d.c[3] = p[2];
     381             :     }
     382             :   else
     383             :     {
     384           0 :       d.c[0] = p[0];
     385           0 :       d.c[1] = p[1];
     386           0 :       d.c[2] = p[2];
     387           0 :       d.c[3] = 0x00;
     388             :     }
     389             : 
     390           0 :   if (other_byte_order)
     391           0 :     return bswap_32 (d.u4);
     392             :   else
     393           0 :     return d.u4;
     394             : }
     395             : 
     396             : 
     397             : #define read_3ubyte_unaligned_inc(Dbg, Addr) \
     398             :   ({ uint32_t t_ = read_3ubyte_unaligned (Dbg, Addr);                         \
     399             :      Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 3);                     \
     400             :      t_; })
     401             : 
     402             : #define read_addr_unaligned_inc(Nbytes, Dbg, Addr)                      \
     403             :   (assert ((Nbytes) == 4 || (Nbytes) == 8),                             \
     404             :     ((Nbytes) == 4 ? read_4ubyte_unaligned_inc (Dbg, Addr)              \
     405             :      : read_8ubyte_unaligned_inc (Dbg, Addr)))
     406             : 
     407             : #endif  /* memory-access.h */

Generated by: LCOV version 1.13