LCOV - code coverage report
Current view: top level - libdw - memory-access.h (source / functions) Hit Total Coverage
Test: elfutils-0.172 Lines: 25 43 58.1 %
Date: 2018-06-11 22:52:14 Functions: 4 4 100.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      340620 :   const size_t pointer_len = likely (addr < end) ? end - addr : 0;
      47      340620 :   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      156016 :   const size_t type_len = len_leb128 (uint64_t);
      54      156016 :   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      184604 :   const size_t type_len = len_leb128 (int64_t) - 1;
      62      184604 :   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    83204835 : __libdw_get_uleb128 (const unsigned char **addrp, const unsigned char *end)
      75             : {
      76    83204835 :   uint64_t acc = 0;
      77             : 
      78             :   /* Unroll the first step to help the compiler optimize
      79             :      for the common single-byte case.  */
      80    83204835 :   get_uleb128_step (acc, *addrp, 0);
      81             : 
      82      312032 :   const size_t max = __libdw_max_len_uleb128 (*addrp - 1, end);
      83      193971 :   for (size_t i = 1; i < max; ++i)
      84      193971 :     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   467684746 : __libdw_get_uleb128_unchecked (const unsigned char **addrp)
      92             : {
      93   467684746 :   uint64_t acc = 0;
      94             : 
      95             :   /* Unroll the first step to help the compiler optimize
      96             :      for the common single-byte case.  */
      97   467684746 :   get_uleb128_step (acc, *addrp, 0);
      98             : 
      99             :   const size_t max = len_leb128 (uint64_t);
     100           0 :   for (size_t i = 1; i < max; ++i)
     101     4325733 :     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             :     if (likely ((__b & 0x80) == 0))                                       \
     117             :       {                                                                       \
     118             :         struct { signed int i:7; } __s = { .i = __b };                        \
     119             :         (var) |= (typeof (var)) __s.i * ((typeof (var)) 1 << ((nth) * 7));    \
     120             :         return (var);                                                         \
     121             :       }                                                                       \
     122             :     (var) |= (typeof (var)) (__b & 0x7f) << ((nth) * 7);                    \
     123             :   } while (0)
     124             : 
     125             : static inline int64_t
     126      423544 : __libdw_get_sleb128 (const unsigned char **addrp, const unsigned char *end)
     127             : {
     128      423544 :   int64_t acc = 0;
     129             : 
     130             :   /* Unroll the first step to help the compiler optimize
     131             :      for the common single-byte case.  */
     132      423544 :   get_sleb128_step (acc, *addrp, 0);
     133             : 
     134      369208 :   const size_t max = __libdw_max_len_sleb128 (*addrp - 1, end);
     135      196320 :   for (size_t i = 1; i < max; ++i)
     136      196298 :     get_sleb128_step (acc, *addrp, i);
     137             :   /* Other implementations set VALUE to INT_MAX in this
     138             :      case.  So we better do this as well.  */
     139             :   return INT64_MAX;
     140             : }
     141             : 
     142             : static inline int64_t
     143        1169 : __libdw_get_sleb128_unchecked (const unsigned char **addrp)
     144             : {
     145        1169 :   int64_t acc = 0;
     146             : 
     147             :   /* Unroll the first step to help the compiler optimize
     148             :      for the common single-byte case.  */
     149        1169 :   get_sleb128_step (acc, *addrp, 0);
     150             : 
     151             :   /* Subtract one step, so we don't shift into sign bit.  */
     152           0 :   const size_t max = len_leb128 (int64_t) - 1;
     153           0 :   for (size_t i = 1; i < max; ++i)
     154           0 :     get_sleb128_step (acc, *addrp, i);
     155             :   /* Other implementations set VALUE to INT_MAX in this
     156             :      case.  So we better do this as well.  */
     157             :   return INT64_MAX;
     158             : }
     159             : 
     160             : #define get_sleb128(var, addr, end) ((var) = __libdw_get_sleb128 (&(addr), end))
     161             : #define get_sleb128_unchecked(var, addr) ((var) = __libdw_get_sleb128_unchecked (&(addr)))
     162             : 
     163             : 
     164             : /* We use simple memory access functions in case the hardware allows it.
     165             :    The caller has to make sure we don't have alias problems.  */
     166             : #if ALLOW_UNALIGNED
     167             : 
     168             : # define read_2ubyte_unaligned(Dbg, Addr) \
     169             :   (unlikely ((Dbg)->other_byte_order)                                              \
     170             :    ? bswap_16 (*((const uint16_t *) (Addr)))                                  \
     171             :    : *((const uint16_t *) (Addr)))
     172             : # define read_2sbyte_unaligned(Dbg, Addr) \
     173             :   (unlikely ((Dbg)->other_byte_order)                                              \
     174             :    ? (int16_t) bswap_16 (*((const int16_t *) (Addr)))                         \
     175             :    : *((const int16_t *) (Addr)))
     176             : 
     177             : # define read_4ubyte_unaligned_noncvt(Addr) \
     178             :    *((const uint32_t *) (Addr))
     179             : # define read_4ubyte_unaligned(Dbg, Addr) \
     180             :   (unlikely ((Dbg)->other_byte_order)                                              \
     181             :    ? bswap_32 (*((const uint32_t *) (Addr)))                                  \
     182             :    : *((const uint32_t *) (Addr)))
     183             : # define read_4sbyte_unaligned(Dbg, Addr) \
     184             :   (unlikely ((Dbg)->other_byte_order)                                              \
     185             :    ? (int32_t) bswap_32 (*((const int32_t *) (Addr)))                         \
     186             :    : *((const int32_t *) (Addr)))
     187             : 
     188             : # define read_8ubyte_unaligned_noncvt(Addr) \
     189             :    *((const uint64_t *) (Addr))
     190             : # define read_8ubyte_unaligned(Dbg, Addr) \
     191             :   (unlikely ((Dbg)->other_byte_order)                                              \
     192             :    ? bswap_64 (*((const uint64_t *) (Addr)))                                  \
     193             :    : *((const uint64_t *) (Addr)))
     194             : # define read_8sbyte_unaligned(Dbg, Addr) \
     195             :   (unlikely ((Dbg)->other_byte_order)                                              \
     196             :    ? (int64_t) bswap_64 (*((const int64_t *) (Addr)))                         \
     197             :    : *((const int64_t *) (Addr)))
     198             : 
     199             : #else
     200             : 
     201             : union unaligned
     202             :   {
     203             :     void *p;
     204             :     uint16_t u2;
     205             :     uint32_t u4;
     206             :     uint64_t u8;
     207             :     int16_t s2;
     208             :     int32_t s4;
     209             :     int64_t s8;
     210             :   } attribute_packed;
     211             : 
     212             : # define read_2ubyte_unaligned(Dbg, Addr) \
     213             :   read_2ubyte_unaligned_1 ((Dbg)->other_byte_order, (Addr))
     214             : # define read_2sbyte_unaligned(Dbg, Addr) \
     215             :   read_2sbyte_unaligned_1 ((Dbg)->other_byte_order, (Addr))
     216             : # define read_4ubyte_unaligned(Dbg, Addr) \
     217             :   read_4ubyte_unaligned_1 ((Dbg)->other_byte_order, (Addr))
     218             : # define read_4sbyte_unaligned(Dbg, Addr) \
     219             :   read_4sbyte_unaligned_1 ((Dbg)->other_byte_order, (Addr))
     220             : # define read_8ubyte_unaligned(Dbg, Addr) \
     221             :   read_8ubyte_unaligned_1 ((Dbg)->other_byte_order, (Addr))
     222             : # define read_8sbyte_unaligned(Dbg, Addr) \
     223             :   read_8sbyte_unaligned_1 ((Dbg)->other_byte_order, (Addr))
     224             : 
     225             : static inline uint16_t
     226             : read_2ubyte_unaligned_1 (bool other_byte_order, const void *p)
     227             : {
     228             :   const union unaligned *up = p;
     229             :   if (unlikely (other_byte_order))
     230             :     return bswap_16 (up->u2);
     231             :   return up->u2;
     232             : }
     233             : static inline int16_t
     234             : read_2sbyte_unaligned_1 (bool other_byte_order, const void *p)
     235             : {
     236             :   const union unaligned *up = p;
     237             :   if (unlikely (other_byte_order))
     238             :     return (int16_t) bswap_16 (up->u2);
     239             :   return up->s2;
     240             : }
     241             : 
     242             : static inline uint32_t
     243             : read_4ubyte_unaligned_noncvt (const void *p)
     244             : {
     245             :   const union unaligned *up = p;
     246             :   return up->u4;
     247             : }
     248             : static inline uint32_t
     249             : read_4ubyte_unaligned_1 (bool other_byte_order, const void *p)
     250             : {
     251             :   const union unaligned *up = p;
     252             :   if (unlikely (other_byte_order))
     253             :     return bswap_32 (up->u4);
     254             :   return up->u4;
     255             : }
     256             : static inline int32_t
     257             : read_4sbyte_unaligned_1 (bool other_byte_order, const void *p)
     258             : {
     259             :   const union unaligned *up = p;
     260             :   if (unlikely (other_byte_order))
     261             :     return (int32_t) bswap_32 (up->u4);
     262             :   return up->s4;
     263             : }
     264             : 
     265             : static inline uint64_t
     266             : read_8ubyte_unaligned_noncvt (const void *p)
     267             : {
     268             :   const union unaligned *up = p;
     269             :   return up->u8;
     270             : }
     271             : static inline uint64_t
     272             : read_8ubyte_unaligned_1 (bool other_byte_order, const void *p)
     273             : {
     274             :   const union unaligned *up = p;
     275             :   if (unlikely (other_byte_order))
     276             :     return bswap_64 (up->u8);
     277             :   return up->u8;
     278             : }
     279             : static inline int64_t
     280             : read_8sbyte_unaligned_1 (bool other_byte_order, const void *p)
     281             : {
     282             :   const union unaligned *up = p;
     283             :   if (unlikely (other_byte_order))
     284             :     return (int64_t) bswap_64 (up->u8);
     285             :   return up->s8;
     286             : }
     287             : 
     288             : #endif  /* allow unaligned */
     289             : 
     290             : 
     291             : #define read_2ubyte_unaligned_inc(Dbg, Addr) \
     292             :   ({ uint16_t t_ = read_2ubyte_unaligned (Dbg, Addr);                         \
     293             :      Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 2);                     \
     294             :      t_; })
     295             : #define read_2sbyte_unaligned_inc(Dbg, Addr) \
     296             :   ({ int16_t t_ = read_2sbyte_unaligned (Dbg, Addr);                          \
     297             :      Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 2);                     \
     298             :      t_; })
     299             : 
     300             : #define read_4ubyte_unaligned_inc(Dbg, Addr) \
     301             :   ({ uint32_t t_ = read_4ubyte_unaligned (Dbg, Addr);                         \
     302             :      Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 4);                     \
     303             :      t_; })
     304             : #define read_4sbyte_unaligned_inc(Dbg, Addr) \
     305             :   ({ int32_t t_ = read_4sbyte_unaligned (Dbg, Addr);                          \
     306             :      Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 4);                     \
     307             :      t_; })
     308             : 
     309             : #define read_8ubyte_unaligned_inc(Dbg, Addr) \
     310             :   ({ uint64_t t_ = read_8ubyte_unaligned (Dbg, Addr);                         \
     311             :      Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 8);                     \
     312             :      t_; })
     313             : #define read_8sbyte_unaligned_inc(Dbg, Addr) \
     314             :   ({ int64_t t_ = read_8sbyte_unaligned (Dbg, Addr);                          \
     315             :      Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 8);                     \
     316             :      t_; })
     317             : 
     318             : /* 3ubyte reads are only used for DW_FORM_addrx3 and DW_FORM_strx3.
     319             :    And are probably very rare.  They are not optimized.  They are
     320             :    handled as if reading a 4byte value with the first (for big endian)
     321             :    or last (for little endian) byte zero.  */
     322             : 
     323             : static inline int
     324             : file_byte_order (bool other_byte_order)
     325             : {
     326             : #if __BYTE_ORDER == __LITTLE_ENDIAN
     327           0 :   return other_byte_order ? __BIG_ENDIAN : __LITTLE_ENDIAN;
     328             : #else
     329             :   return other_byte_order ? __LITTLE_ENDIAN : __BIG_ENDIAN;
     330             : #endif
     331             : }
     332             : 
     333             : static inline uint32_t
     334             : read_3ubyte_unaligned (Dwarf *dbg, const unsigned char *p)
     335             : {
     336             :   union
     337             :   {
     338             :     uint32_t u4;
     339             :     unsigned char c[4];
     340             :   } d;
     341           0 :   bool other_byte_order = dbg->other_byte_order;
     342             : 
     343           0 :   if (file_byte_order (other_byte_order) == __BIG_ENDIAN)
     344             :     {
     345           0 :       d.c[0] = 0x00;
     346           0 :       d.c[1] = p[0];
     347           0 :       d.c[2] = p[1];
     348           0 :       d.c[3] = p[2];
     349             :     }
     350             :   else
     351             :     {
     352           0 :       d.c[0] = p[0];
     353           0 :       d.c[1] = p[1];
     354           0 :       d.c[2] = p[2];
     355           0 :       d.c[3] = 0x00;
     356             :     }
     357             : 
     358           0 :   if (other_byte_order)
     359           0 :     return bswap_32 (d.u4);
     360             :   else
     361           0 :     return d.u4;
     362             : }
     363             : 
     364             : 
     365             : #define read_addr_unaligned_inc(Nbytes, Dbg, Addr)                      \
     366             :   (assert ((Nbytes) == 4 || (Nbytes) == 8),                             \
     367             :     ((Nbytes) == 4 ? read_4ubyte_unaligned_inc (Dbg, Addr)              \
     368             :      : read_8ubyte_unaligned_inc (Dbg, Addr)))
     369             : 
     370             : #endif  /* memory-access.h */

Generated by: LCOV version 1.13