blob: babe976fcaca19e24a1d1dde76e4e5d073d14aa4 [file] [log] [blame]
/* Unaligned memory access functionality.
Copyright (C) 2000, 2001, 2002, 2003, 2004 Red Hat, Inc.
Written by Ulrich Drepper <drepper@redhat.com>, 2001.
This program is Open Source software; you can redistribute it and/or
modify it under the terms of the Open Software License version 1.0 as
published by the Open Source Initiative.
You should have received a copy of the Open Software License along
with this program; if not, you may obtain a copy of the Open Software
License version 1.0 from http://www.opensource.org/licenses/osl.php or
by writing the Open Source Initiative c/o Lawrence Rosen, Esq.,
3001 King Ranch Road, Ukiah, CA 95482. */
#ifndef _MEMORY_ACCESS_H
#define _MEMORY_ACCESS_H 1
#include <byteswap.h>
#include <limits.h>
#include <stdint.h>
/* Number decoding macros. See 7.6 Variable Length Data. */
#define get_uleb128(var, addr) \
do { \
unsigned char __b = *((const unsigned char *) addr); \
addr = (__typeof (addr)) (((uintptr_t) (addr)) + 1); \
var = __b & 0x7f; \
if (__b & 0x80) \
{ \
__b = *((const unsigned char *) addr); \
addr = (__typeof (addr)) (((uintptr_t) (addr)) + 1); \
var |= (__b & 0x7f) << 7; \
if (__b & 0x80) \
{ \
__b = *((const unsigned char *) addr); \
addr = (__typeof (addr)) (((uintptr_t) (addr)) + 1); \
var |= (__b & 0x7f) << 14; \
if (__b & 0x80) \
{ \
__b = *((const unsigned char *) addr); \
addr = (__typeof (addr)) (((uintptr_t) (addr)) + 1); \
var |= (__b & 0x7f) << 21; \
if (__b & 0x80) \
/* Other implementation set VALUE to UINT_MAX in this \
case. So we better do this as well. */ \
var = UINT_MAX; \
} \
} \
} \
} while (0)
/* The signed case is a big more complicated. */
#define get_sleb128(var, addr) \
do { \
unsigned char __b = *((const unsigned char *) addr); \
addr = (__typeof (addr)) (((uintptr_t) (addr)) + 1); \
int32_t __res = __b & 0x7f; \
if ((__b & 0x80) == 0) \
{ \
if (__b & 0x40) \
__res |= 0xffffff80; \
} \
else \
{ \
__b = *((const unsigned char *) addr); \
addr = (__typeof (addr)) (((uintptr_t) (addr)) + 1); \
__res |= (__b & 0x7f) << 7; \
if ((__b & 0x80) == 0) \
{ \
if (__b & 0x40) \
__res |= 0xffffc000; \
} \
else \
{ \
__b = *((const unsigned char *) addr); \
addr = (__typeof (addr)) (((uintptr_t) (addr)) + 1); \
__res |= (__b & 0x7f) << 14; \
if ((__b & 0x80) == 0) \
{ \
if (__b & 0x40) \
__res |= 0xffe00000; \
} \
else \
{ \
__b = *((const unsigned char *) addr); \
addr = (__typeof (addr)) (((uintptr_t) (addr)) + 1); \
__res |= (__b & 0x7f) << 21; \
if ((__b & 0x80) == 0) \
{ \
if (__b & 0x40) \
__res |= 0xf0000000; \
} \
else \
/* Other implementation set VALUE to INT_MAX in this \
case. So we better do this as well. */ \
__res = INT_MAX; \
} \
} \
} \
var = __res; \
} while (0)
/* We use simple memory access functions in case the hardware allows it.
The caller has to make sure we don't have alias problems. */
#if ALLOW_UNALIGNED
# define read_2ubyte_unaligned(Dbg, Addr) \
(unlikely ((Dbg)->other_byte_order) \
? bswap_16 (*((const uint16_t *) (Addr))) \
: *((const uint16_t *) (Addr)))
# define read_2sbyte_unaligned(Dbg, Addr) \
(unlikely ((Dbg)->other_byte_order) \
? (int16_t) bswap_16 (*((const int16_t *) (Addr))) \
: *((const int16_t *) (Addr)))
# define read_4ubyte_unaligned_noncvt(Addr) \
*((const uint32_t *) (Addr))
# define read_4ubyte_unaligned(Dbg, Addr) \
(unlikely ((Dbg)->other_byte_order) \
? bswap_32 (*((const uint32_t *) (Addr))) \
: *((const uint32_t *) (Addr)))
# define read_4sbyte_unaligned(Dbg, Addr) \
(unlikely ((Dbg)->other_byte_order) \
? (int32_t) bswap_32 (*((const int32_t *) (Addr))) \
: *((const int32_t *) (Addr)))
# define read_8ubyte_unaligned(Dbg, Addr) \
(unlikely ((Dbg)->other_byte_order) \
? bswap_64 (*((const uint64_t *) (Addr))) \
: *((const uint64_t *) (Addr)))
# define read_8sbyte_unaligned(Dbg, Addr) \
(unlikely ((Dbg)->other_byte_order) \
? (int64_t) bswap_64 (*((const int64_t *) (Addr))) \
: *((const int64_t *) (Addr)))
#else
union unaligned
{
void *p;
uint16_t u2;
uint32_t u4;
uint64_t u8;
int16_t s2;
int32_t s4;
int64_t s8;
} __attribute__ ((packed));
static inline uint16_t
read_2ubyte_unaligned (Dwarf *dbg, const void *p)
{
const union unaligned *up = p;
if (dbg->other_byte_order)
return bswap_16 (up->u2);
return up->u2;
}
static inline int16_t
read_2sbyte_unaligned (Dwarf *dbg, const void *p)
{
const union unaligned *up = p;
if (dbg->other_byte_order)
return (int16_t) bswap_16 (up->u2);
return up->s2;
}
static inline uint32_t
read_4ubyte_unaligned_noncvt (const void *p)
{
const union unaligned *up = p;
return up->u4;
}
static inline uint32_t
read_4ubyte_unaligned (Dwarf *dbg, const void *p)
{
const union unaligned *up = p;
if (dbg->other_byte_order)
return bswap_32 (up->u4);
return up->u4;
}
static inline int32_t
read_4sbyte_unaligned (Dwarf *dbg, const void *p)
{
const union unaligned *up = p;
if (dbg->other_byte_order)
return (int32_t) bswap_32 (up->u4);
return up->s4;
}
static inline uint64_t
read_8ubyte_unaligned (Dwarf *dbg, const void *p)
{
const union unaligned *up = p;
if (dbg->other_byte_order)
return bswap_64 (up->u8);
return up->u8;
}
static inline int64_t
read_8sbyte_unaligned (Dwarf *dbg, const void *p)
{
const union unaligned *up = p;
if (dbg->other_byte_order)
return (int64_t) bswap_64 (up->u8);
return up->s8;
}
#endif /* allow unaligned */
#define read_2ubyte_unaligned_inc(Dbg, Addr) \
({ uint16_t t_ = read_2ubyte_unaligned (Dbg, Addr); \
Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 2); \
t_; })
#define read_2sbyte_unaligned_inc(Dbg, Addr) \
({ int16_t t_ = read_2sbyte_unaligned (Dbg, Addr); \
Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 2); \
t_; })
#define read_4ubyte_unaligned_inc(Dbg, Addr) \
({ uint32_t t_ = read_4ubyte_unaligned (Dbg, Addr); \
Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 4); \
t_; })
#define read_4sbyte_unaligned_inc(Dbg, Addr) \
({ int32_t t_ = read_4sbyte_unaligned (Dbg, Addr); \
Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 4); \
t_; })
#define read_8ubyte_unaligned_inc(Dbg, Addr) \
({ uint64_t t_ = read_8ubyte_unaligned (Dbg, Addr); \
Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 8); \
t_; })
#define read_8sbyte_unaligned_inc(Dbg, Addr) \
({ int64_t t_ = read_8sbyte_unaligned (Dbg, Addr); \
Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 8); \
t_; })
#endif /* memory-access.h */