blob: 0127a5da5cc7bca84008fbda1f3f8ed91545c73d [file] [edit]
/* **********************************************************
* Copyright (c) 2010-2024 Google, Inc. All rights reserved.
* Copyright (c) 2007-2010 VMware, Inc. All rights reserved.
* **********************************************************/
/* Dr. Memory: the memory debugger
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License, and no later version.
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "dr_api.h"
#include "drmemory.h"
#include "utils.h"
#include "shadow.h"
#include "umbra.h"
#include "spill.h"
#include "instru.h"
#include <limits.h> /* UINT_MAX */
#include <stddef.h>
#ifdef TOOL_DR_HEAPSTAT
# include "../drheapstat/staleness.h"
#endif
#include "slowpath.h" /* get_own_seg_base */
#ifdef TOOL_DR_MEMORY /* around whole shadow table */
/***************************************************************************
* BITMAP SUPPORT
*/
typedef uint* bitmap_t;
/* 1 bit per byte */
#define BITMAP_UNIT 32
#define BITMAP_MASK(i) (1 << ((i) % BITMAP_UNIT))
#define BITMAP_IDX(i) ((i) / BITMAP_UNIT)
/* if a shadow memory type is special shared block, could be redzone */
#define SHADOW_IS_SHARED(type) TEST(UMBRA_SHADOW_MEMORY_TYPE_SHARED, type)
/* if a shadow memory type is special shared block, but not redzone */
#define SHADOW_IS_SHARED_ONLY(type) (UMBRA_SHADOW_MEMORY_TYPE_SHARED == type)
/* 2 bits of shadow per real byte: or 4 real bytes shadowed by one shadow byte */
#define BITMAPx2_UNIT 16 /* one uint shadows 16 real bytes */
#define BITMAPx2_SHIFT(i) (((i) % BITMAPx2_UNIT) * 2)
#define BITMAPx2_MASK(i) (3 << BITMAPx2_SHIFT)
#define BITMAPx2_IDX(i) ((i) / BITMAPx2_UNIT)
#define BLOCK_AS_BYTE_ARRAY_IDX(i) (BITMAPx2_IDX(i*sizeof(uint)))
/* returns the two bits corresponding to offset i */
static inline uint
bitmapx2_get(bitmap_t bm, uint i)
{
LOG(6, "bitmapx2_get 0x%04x [%d] => "PFX" == %d\n", i, BITMAPx2_IDX(i),
bm[BITMAPx2_IDX(i)], ((bm[BITMAPx2_IDX(i)] >> BITMAPx2_SHIFT(i)) & 3));
return ((bm[BITMAPx2_IDX(i)] >> BITMAPx2_SHIFT(i)) & 3);
}
/* SHADOW_DWORD2BYTE() == "get_2bits" */
static inline uint
set_2bits_inline(uint orig, uint val, uint shift)
{
ASSERT(val <= 3, "set_2bits usage error");
ASSERT(shift % 2 == 0, "set_2bits usage error");
orig &= (((0xfffffffc | val) << shift) | (~(0xffffffff << shift)));
orig |= (val << shift);
return orig;
}
/* SHADOW_DWORD2BYTE() == "get_2bits" */
uint
set_2bits(uint orig, uint val, uint shift)
{
return set_2bits_inline(orig, val, shift);
}
static inline void
bitmapx2_set(bitmap_t bm, uint i, uint val)
{
uint shift = BITMAPx2_SHIFT(i);
ASSERT(val <= 3, "internal error");
/* It's a pain to set 2 bits: first we have to clear in case either
* of the two is a zero; then we have to set in case either is a 1.
*/
LOG(6, "bitmapx2_set 0x%04x [%d] to %d: from "PFX" ", i, BITMAPx2_IDX(i),
val, bm[BITMAPx2_IDX(i)]);
bm[BITMAPx2_IDX(i)] = set_2bits_inline(bm[BITMAPx2_IDX(i)], val, shift);
LOG(6, "to "PFX"\n", bm[BITMAPx2_IDX(i)]);
}
/* returns the byte corresponding to offset i */
static inline uint
bitmapx2_byte(bitmap_t bm, uint i)
{
ASSERT(BITMAPx2_SHIFT(i) %8 == 0, "bitmapx2_byte: index not aligned");
return (bm[BITMAPx2_IDX(i)] >> BITMAPx2_SHIFT(i)) & 0xff;
}
#ifdef X64
/* returns the ushort corresponding to offset i */
static inline uint
bitmapx2_ushort(bitmap_t bm, uint i)
{
ASSERT(BITMAPx2_SHIFT(i) %16 == 0, "bitmapx2_ushort: index not aligned");
return (bm[BITMAPx2_IDX(i)] >> BITMAPx2_SHIFT(i)) & 0xffff;
}
#endif
/***************************************************************************
* BYTE-TO-BYTE SHADOWING SUPPORT
*/
/* It would be simpler to use a char[] for shadow_block_t but for simpler
* runtime parametrization we stick with uint[] and extract bytes.
*/
static inline void
bytemap_4to1_set(bitmap_t bm, uint i, uint val)
{
char *bytes = (char *) bm;
ASSERT(val <= UCHAR_MAX, "internal error");
bytes[BLOCK_AS_BYTE_ARRAY_IDX(i)] = val;
}
/* returns the byte corresponding to offset i */
static inline uint
bytemap_4to1_byte(bitmap_t bm, uint i)
{
char *bytes = (char *) bm;
return bytes[BLOCK_AS_BYTE_ARRAY_IDX(i)];
}
#ifdef X64
/* returns the ushort corresponding to offset i */
static inline uint
bytemap_4to1_ushort(bitmap_t bm, uint i)
{
char *bytes = (char *) bm;
return *(ushort*)(&bytes[BLOCK_AS_BYTE_ARRAY_IDX(i)]);
}
#endif
/***************************************************************************
* MEMORY SHADOWING DATA STRUCTURES
*/
umbra_map_t *umbra_map;
/* 2 shadow bits per app byte */
/* we use Umbra's 4B-to-1B and layer 1B-to-2b on top of that */
#define SHADOW_MAP_SCALE UMBRA_MAP_SCALE_DOWN_4X
#define SHADOW_DEFAULT_VALUE SHADOW_DWORD_UNADDRESSABLE
#define SHADOW_DEFAULT_VALUE_SIZE 1
#define SHADOW_REDZONE_VALUE SHADOW_DWORD_BITLEVEL
#define SHADOW_REDZONE_VALUE_SIZE 1
#define REDZONE_SIZE 512
typedef struct _saved_region_t {
app_pc start;
size_t size;
bitmap_t shadow;
} saved_region_t;
/* extend size to uint boundary if the exact required size is not already aligned */
#define SIZEOF_SAVED_BUFFER_SHADOW(size) \
(ALIGN_FORWARD((size), SHADOW_GRANULARITY) / SHADOW_GRANULARITY)
/* single allocation for saved_region_t and its shadow buffer */
#define SIZEOF_SAVED_BUFFER(size) \
(sizeof(saved_region_t) + SIZEOF_SAVED_BUFFER_SHADOW(size))
#ifndef X64
static byte *special_unaddressable;
static byte *special_undefined;
static byte *special_defined;
static byte *special_bitlevel;
#endif
#ifdef STATISTICS
uint shadow_block_alloc;
/* b/c of PR 580017 we no longer free any non-specials so this is always 0 */
uint shadow_block_free;
uint num_special_unaddressable;
uint num_special_undefined;
uint num_special_defined;
#endif
/* these are filled in in shadow_table_init() b/c the consts vary dynamically */
uint val_to_dword[4];
uint val_to_qword[4];
uint val_to_dqword[4];
#ifdef X64
# define VAL_TO_PTRSZ val_to_qword
#else
# define VAL_TO_PTRSZ val_to_dword
#endif
const char * const shadow_name[] = {
"defined",
"unaddressable",
"bitlevel",
"undefined",
"mixed", /* SHADOW_MIXED */
"unknown", /* SHADOW_UNKNOWN */
};
static inline uint
shadow_value_byte_2_dword(uint val)
{
if (val == SHADOW_UNADDRESSABLE)
return SHADOW_DWORD_UNADDRESSABLE;
if (val == SHADOW_UNDEFINED)
return SHADOW_DWORD_UNDEFINED;
if (val == SHADOW_DEFINED)
return SHADOW_DWORD_DEFINED;
if (val == SHADOW_DEFINED_BITLEVEL)
return SHADOW_DWORD_BITLEVEL;
ASSERT(false, "wrong shadow value");
return SHADOW_DWORD_UNADDRESSABLE;
}
bool
is_in_special_shadow_block(app_pc pc)
{
umbra_shadow_memory_type_t shadow_type;
if (umbra_shadow_memory_is_shared(umbra_map, pc,
&shadow_type) != DRMF_SUCCESS)
ASSERT(false, "fail to get shadow memory type");
/* excluding redzone */
return SHADOW_IS_SHARED_ONLY(shadow_type);
}
/* we can call umbra_scale_app_to_shadow, which would be slower */
static inline ptr_uint_t
shadow_scale_app_to_shadow(ptr_uint_t value)
{
return (value >> 2);
}
static void
shadow_table_init(void)
{
umbra_map_options_t umbra_map_ops;
LOG(2, "shadow_table_init\n");
val_to_dword[0] = SHADOW_DWORD_DEFINED;
val_to_dword[1] = SHADOW_DWORD_UNADDRESSABLE;
val_to_dword[2] = SHADOW_DWORD_BITLEVEL;
val_to_dword[3] = SHADOW_DWORD_UNDEFINED;
val_to_qword[0] = SHADOW_QWORD_DEFINED;
val_to_qword[1] = SHADOW_QWORD_UNADDRESSABLE;
val_to_qword[2] = SHADOW_QWORD_BITLEVEL;
val_to_qword[3] = SHADOW_QWORD_UNDEFINED;
val_to_dqword[0] = SHADOW_DQWORD_DEFINED;
val_to_dqword[1] = SHADOW_DQWORD_UNADDRESSABLE;
val_to_dqword[2] = SHADOW_DQWORD_BITLEVEL;
val_to_dqword[3] = SHADOW_DQWORD_UNDEFINED;
memset(&umbra_map_ops, 0, sizeof(umbra_map_ops));
umbra_map_ops.flags =
UMBRA_MAP_CREATE_SHADOW_ON_TOUCH |
UMBRA_MAP_SHADOW_SHARED_READONLY;
umbra_map_ops.scale = SHADOW_MAP_SCALE;
umbra_map_ops.default_value = SHADOW_DEFAULT_VALUE;
umbra_map_ops.default_value_size = SHADOW_DEFAULT_VALUE_SIZE;
#ifndef X64
umbra_map_ops.redzone_size = REDZONE_SIZE;
umbra_map_ops.redzone_value = SHADOW_REDZONE_VALUE;
umbra_map_ops.redzone_value_size = 1;
#endif
if (umbra_create_mapping(&umbra_map_ops, &umbra_map) != DRMF_SUCCESS)
ASSERT(false, "fail to create shadow memory mapping");
#ifndef X64
umbra_create_shared_shadow_block(umbra_map, SHADOW_DWORD_UNADDRESSABLE,
1, &special_unaddressable);
umbra_create_shared_shadow_block(umbra_map, SHADOW_DWORD_UNDEFINED,
1, &special_undefined);
umbra_create_shared_shadow_block(umbra_map, SHADOW_DWORD_DEFINED,
1, &special_defined);
umbra_create_shared_shadow_block(umbra_map, SHADOW_DWORD_BITLEVEL,
1, &special_bitlevel);
#endif
}
static void
shadow_table_exit(void)
{
LOG(2, "shadow_table_exit\n");
if (umbra_destroy_mapping(umbra_map) != DRMF_SUCCESS)
ASSERT(false, "fail to destroy shadow memory");
}
bool
shadow_create_shadow_memory(app_pc base, size_t size, uint value)
{
uint flags = UMBRA_CREATE_SHADOW_SHARED_READONLY; /* allow special block */
if (umbra_create_shadow_memory(umbra_map, flags,
base, size, value, 1) == DRMF_SUCCESS)
return true;
return false;
}
size_t
get_shadow_block_size(void)
{
size_t size;
if (umbra_get_shadow_block_size(umbra_map, &size) != DRMF_SUCCESS) {
ASSERT(false, "fail to get shadow block size");
return PAGE_SIZE;
}
return size;
}
bool
shadow_get_special(app_pc addr, uint *val)
{
umbra_shadow_memory_info_t info;
uint value;
umbra_shadow_memory_info_init(&info);
value = shadow_get_byte(&info, addr);
if (val != NULL)
*val = value;
/* the shadow memory is get from application address, so shadow_type
* should has no redzone set.
*/
return SHADOW_IS_SHARED_ONLY(info.shadow_type);
}
/* return the two bits for the byte at the passed-in address */
/* umbra_shadow_memory_info must be first zeroed out by the caller prior to
* calling the first time for any series of calls. It will be filled out
* and can be used for a series of calls for better performance.
* On the subsequent calls, if the passed in umbra_shadow_memory_info has
* the right range, we assume the the shadow memory info is correct and
* will access the cached shadow memory directly without querying
* Umbra.
* However, the info may have stale info as Umbra may replace it, and
* the caller must be able to handle or tolerate that situation.
*/
/* it also has the racy problem on accessing partial byte, xref i#271 */
uint
shadow_get_byte(DR_PARAM_INOUT umbra_shadow_memory_info_t *info, app_pc addr)
{
ptr_uint_t idx;
if (addr < info->app_base || addr >= info->app_base + info->app_size) {
ASSERT(info->struct_size == sizeof(*info),
"shadow memory info is not initialized properly");
if (umbra_get_shadow_memory(umbra_map, addr,
NULL, info) != DRMF_SUCCESS) {
ASSERT(false, "fail to get shadow memory info");
return 0;
}
}
/* avoid a fault: if no shadow yet, it's unaddr */
if (info->shadow_type == UMBRA_SHADOW_MEMORY_TYPE_SHADOW_NOT_ALLOC)
return SHADOW_UNADDRESSABLE;
/* if non-app-memory (no shadow supported there for x64), it's unaddr */
if (info->shadow_type == UMBRA_SHADOW_MEMORY_TYPE_NOT_SHADOW)
return SHADOW_UNADDRESSABLE;
idx = addr - info->app_base;
if (!MAP_4B_TO_1B)
return bitmapx2_get((bitmap_t)info->shadow_base, idx);
else
return bytemap_4to1_byte((bitmap_t)info->shadow_base, idx);
}
/* Returns the byte that shadows the 4-byte-aligned address */
/* see comment in shadow_get_byte about using umbra_shadow_memory_info_t */
uint
shadow_get_dword(DR_PARAM_INOUT umbra_shadow_memory_info_t *info, app_pc addr)
{
ptr_uint_t idx;
if (addr < info->app_base || addr >= info->app_base + info->app_size) {
ASSERT(info->struct_size == sizeof(*info),
"shadow memory info is not initialized properly");
if (umbra_get_shadow_memory(umbra_map, addr,
NULL, info) != DRMF_SUCCESS) {
ASSERT(false, "fail to get shadow memory info");
return 0;
}
}
/* avoid a fault: if no shadow yet, it's unaddr */
if (info->shadow_type == UMBRA_SHADOW_MEMORY_TYPE_SHADOW_NOT_ALLOC)
return SHADOW_DWORD_UNADDRESSABLE;
/* if non-app-memory (no shadow supported there for x64), it's unaddr */
if (info->shadow_type == UMBRA_SHADOW_MEMORY_TYPE_NOT_SHADOW)
return SHADOW_DWORD_UNADDRESSABLE;
idx = ((ptr_uint_t)ALIGN_BACKWARD(addr, 4)) - (ptr_uint_t)info->app_base;
if (!MAP_4B_TO_1B)
return bitmapx2_byte((bitmap_t)info->shadow_base, idx);
else /* just return byte */
return bytemap_4to1_byte((bitmap_t)info->shadow_base, idx);
}
#ifdef X64
uint
shadow_get_qword(DR_PARAM_INOUT umbra_shadow_memory_info_t *info, app_pc addr)
{
ptr_uint_t idx;
if (addr < info->app_base || addr >= info->app_base + info->app_size) {
ASSERT(info->struct_size == sizeof(*info),
"shadow memory info is not initialized properly");
if (umbra_get_shadow_memory(umbra_map, addr,
NULL, info) != DRMF_SUCCESS) {
ASSERT(false, "fail to get shadow memory info");
return 0;
}
}
/* avoid a fault: if no shadow yet, it's unaddr */
if (info->shadow_type == UMBRA_SHADOW_MEMORY_TYPE_SHADOW_NOT_ALLOC)
return SHADOW_DWORD_UNADDRESSABLE;
/* if non-app-memory (no shadow supported there for x64), it's unaddr */
if (info->shadow_type == UMBRA_SHADOW_MEMORY_TYPE_NOT_SHADOW)
return SHADOW_DWORD_UNADDRESSABLE;
idx = ((ptr_uint_t)ALIGN_BACKWARD(addr, 8)) - (ptr_uint_t)info->app_base;
if (!MAP_4B_TO_1B)
return bitmapx2_ushort((bitmap_t)info->shadow_base, idx);
else /* just return byte */
return bytemap_4to1_ushort((bitmap_t)info->shadow_base, idx);
}
#endif
uint
shadow_get_ptrsz(DR_PARAM_INOUT umbra_shadow_memory_info_t *info, app_pc addr)
{
#ifdef X64
return shadow_get_qword(info, addr);
#else
return shadow_get_dword(info, addr);
#endif
}
/* Sets the two bits for the byte at the passed-in address */
/* see comment in shadow_get_byte about using umbra_shadow_memory_info_t */
void
shadow_set_byte(DR_PARAM_INOUT umbra_shadow_memory_info_t *info, app_pc addr, uint val)
{
ASSERT(val <= 4, "invalid shadow value");
if (addr < info->app_base || addr >= info->app_base + info->app_size) {
ASSERT(info->struct_size == sizeof(*info),
"shadow memory info is not initialized properly");
if (umbra_get_shadow_memory(umbra_map, addr,
NULL, info) != DRMF_SUCCESS) {
ASSERT(false, "fail to get shadow memory info");
}
}
/* If non-app-memory (no shadow supported there for x64), we can't recover
* (FIXME i#1640: umbra should be more robust).
*/
if (info->shadow_type == UMBRA_SHADOW_MEMORY_TYPE_NOT_SHADOW) {
NOTIFY_ERROR("unhandled application memory @"PFX NL, addr);
dr_abort();
}
/* Note that we can come here for SHADOW_SPECIAL_DEFINED, for mmap
* regions used for calloc (we mark headers as unaddressable), etc.
*/
if (info->shadow_type == UMBRA_SHADOW_MEMORY_TYPE_SHARED ||
/* Lazily allocated */
info->shadow_type == UMBRA_SHADOW_MEMORY_TYPE_SHADOW_NOT_ALLOC) {
/* Avoid replacing special on nop write */
if (val == shadow_get_byte(info, addr)) {
LOG(5, "writing "PFX" => nop (already special %d)\n", addr, val);
return;
}
/* If it's special shared shadow memory, recreate normal shadow memory.
* If it's lazily allocated, allocate the shadow (umbra_write_shadow_memory()
* would do that for us).
*/
if (umbra_create_shadow_memory(umbra_map, 0,
info->app_base, info->app_size,
(info->shadow_type ==
UMBRA_SHADOW_MEMORY_TYPE_SHARED) ?
(ptr_uint_t)*(info->shadow_base) :
SHADOW_DEFAULT_VALUE,
SHADOW_DEFAULT_VALUE_SIZE) != DRMF_SUCCESS) {
NOTIFY_ERROR("unhandled application memory @"PFX NL, addr);
dr_abort();
}
if (umbra_get_shadow_memory(umbra_map, addr,
NULL, info) != DRMF_SUCCESS)
ASSERT(false, "fail to get shadow memory info");
}
ASSERT(info->shadow_type != UMBRA_SHADOW_MEMORY_TYPE_SHADOW_NOT_ALLOC, "will fault");
LOG(5, "writing "PFX" ("PIFX") => %d\n", addr, addr - info->app_base, val);
if (!MAP_4B_TO_1B) {
bitmapx2_set((bitmap_t)info->shadow_base,
addr - info->app_base,
val);
} else {
bytemap_4to1_set((bitmap_t)info->shadow_base,
addr - info->app_base,
val);
}
}
byte *
shadow_translation_addr(app_pc addr)
{
umbra_shadow_memory_info_t info;
byte *shadow_addr;
info.struct_size = sizeof(info);
if (umbra_get_shadow_memory(umbra_map, addr,
&shadow_addr, &info) != DRMF_SUCCESS) {
ASSERT(false, "fail to get shadow memory");
return NULL;
}
return shadow_addr;
}
/* Returns a pointer to an always-bitlevel shadow block */
byte *
shadow_bitlevel_addr(void)
{
/* For PR 493257 we need this pointer to have redzone bitlevel on both sides */
#ifdef X64
return NULL;
#else
return special_bitlevel + SHADOW_REDZONE_SIZE;
#endif
}
byte *
shadow_replace_special(app_pc addr)
{
byte *shadow_addr;
if (umbra_replace_shared_shadow_memory(umbra_map, addr,
&shadow_addr) != DRMF_SUCCESS) {
ASSERT(false, "fail to replace special shadow memory");
return NULL;
}
return shadow_addr;
}
/* Saves the shadow values for the specified app memory region into a newly allocated
* buffer. The caller must free the returned shadow buffer using shadow_free_buffer(),
*/
shadow_buffer_t *
shadow_save_region(app_pc start, size_t size)
{
uint i, shadow_value;
size_t saved_buffer_size = SIZEOF_SAVED_BUFFER(size);
saved_region_t *saved = global_alloc(saved_buffer_size, HEAPSTAT_SHADOW);
umbra_shadow_memory_info_t shadow_info;
if (MAP_4B_TO_1B) {
ASSERT_NOT_IMPLEMENTED();
return NULL;
}
/* single allocation: struct at the front, buffer at the back */
saved->start = start;
saved->size = size;
saved->shadow = (bitmap_t)((byte *) saved + sizeof(saved_region_t));
/* XXX i#1734: this can be optimized for better performance on large buffers */
umbra_shadow_memory_info_init(&shadow_info);
for (i = 0; i < saved->size; i++) {
shadow_value = shadow_get_byte(&shadow_info, (byte *) start + i);
bitmapx2_set(saved->shadow, i, shadow_value);
}
return (shadow_buffer_t *) saved;
}
/* Restore the shadow state for a region that was saved using shadow_save_buffer(). */
void
shadow_restore_region(shadow_buffer_t *shadow_buffer)
{
uint i;
saved_region_t *saved = (saved_region_t *) shadow_buffer;
umbra_shadow_memory_info_t shadow_info;
umbra_shadow_memory_info_init(&shadow_info);
for (i = 0; i < saved->size; i++)
shadow_set_byte(&shadow_info, saved->start + i, bitmapx2_get(saved->shadow, i));
}
/* Free a shadow buffer that was allocated in shadow_save_buffer(). */
void
shadow_free_buffer(shadow_buffer_t *shadow_buffer)
{
saved_region_t *saved = (saved_region_t *) shadow_buffer;
global_free(saved, SIZEOF_SAVED_BUFFER(saved->size), HEAPSTAT_SHADOW);
}
/* Sets the two bits for each byte in the range [start, end) */
void
shadow_set_range(app_pc start, app_pc end, uint val)
{
umbra_shadow_memory_info_t info;
app_pc aligned_start, aligned_end;
app_pc pc;
size_t shadow_size;
ASSERT(options.shadowing, "shadowing disabled");
ASSERT(val <= 4, "invalid shadow value");
LOG(2, "set range "PFX"-"PFX" => 0x%x\n", start, end, val);
umbra_shadow_memory_info_init(&info);
DOLOG(2, {
if (end - start > 0x10000000)
LOG(2, "WARNING: set range of very large range "PFX"-"PFX"\n",
start, end);
});
if (start >= end)
return;
/* for case like [0x1001, 0x1003]: align_start=0x1004, align_end=0x1000 */
aligned_start = (app_pc)ALIGN_FORWARD(start, SHADOW_GRANULARITY);
aligned_end = (app_pc)ALIGN_BACKWARD(end, SHADOW_GRANULARITY);
/* set unaligned start */
pc = start;
while (pc < aligned_start && pc < end) {
shadow_set_byte(&info, pc, val);
LOG(4, "\tset byte "PFX"\n", pc);
if (POINTER_OVERFLOW_ON_ADD(pc, 1))
break;
pc++;
}
/* set aligned byte */
if (aligned_end > aligned_start &&
umbra_shadow_set_range(umbra_map,
aligned_start,
aligned_end-aligned_start,
&shadow_size,
shadow_value_byte_2_dword(val),
1) != DRMF_SUCCESS) {
ASSERT(false, "fail to set shadow memory");
}
/* set unaligned end */
if (aligned_end >= aligned_start) {
pc = aligned_end;
while (pc < end) {
shadow_set_byte(&info, pc, val);
LOG(4, "\tset byte "PFX"\n", pc);
if (POINTER_OVERFLOW_ON_ADD(pc, 1))
break;
pc++;
}
}
}
/* Copies the values for each byte in the range [old_start, old_start+size) to
* [new_start, new_start+size). The two ranges can overlap.
*/
void
shadow_copy_range(app_pc old_start, app_pc new_start, size_t size)
{
size_t shdw_size;
app_pc old_pc, new_pc, old_end;
umbra_shadow_memory_info_t info_src;
umbra_shadow_memory_info_t info_dst;
uint head_val[SHADOW_GRANULARITY], tail_val[SHADOW_GRANULARITY];
uint head_bit, tail_bit, i;
LOG(2, "copy range "PFX"-"PFX" to "PFX"-"PFX"\n",
old_start, old_start+size, new_start, new_start+size);
umbra_shadow_memory_info_init(&info_src);
umbra_shadow_memory_info_init(&info_dst);
head_bit = (ptr_uint_t)old_start % SHADOW_GRANULARITY;
if (head_bit != ((ptr_uint_t)new_start % SHADOW_GRANULARITY)) {
/* Alignments don't match (e.g., 0x...3 and 0x...1). We use a slow,
* brute-force appraoch as this should be rare. We handle overlap by
* copying to a temp, with the assumption that anything big like an mmap
* will be page-aligned and won't come here.
*
* XXX: we should add a unit test framework so we can easily write
* a test for this.
*/
/* For simplicity we store each pair of 2 bits in one byte */
byte *temp = global_alloc(size, HEAPSTAT_SHADOW);
for (i = 0; i < size; i++)
temp[i] = (byte) shadow_get_byte(&info_src, old_start + i);
for (i = 0; i < size; i++)
shadow_set_byte(&info_dst, new_start + i, temp[i]);
global_free(temp, size, HEAPSTAT_SHADOW);
return;
}
old_end = old_start + size;
tail_bit = (ptr_uint_t)old_end % SHADOW_GRANULARITY;
/* It is 1B-2-2b mapping and umbra only support full byte copy, so we have
* to handle the unaligned byte copy.
*/
/* XXX: maybe umbra should support partial byte update and the code can be
* moved into umbra.
*/
if (head_bit != 0) {
for (i = 0; i+head_bit < SHADOW_GRANULARITY; i++)
head_val[i+head_bit] = shadow_get_byte(&info_src, old_start+i);
}
if (tail_bit != 0) {
old_end = (app_pc)ALIGN_BACKWARD(old_end, SHADOW_GRANULARITY);
for (i = 0; i < tail_bit; i++)
tail_val[i] = shadow_get_byte(&info_src, old_end+i);
}
old_pc = (app_pc)ALIGN_FORWARD(old_start, SHADOW_GRANULARITY);
if (old_end > old_pc) {
size_t copy_size = old_end - old_pc;
new_pc = (app_pc)ALIGN_FORWARD(new_start, SHADOW_GRANULARITY);
if (umbra_shadow_copy_range(umbra_map, old_pc, new_pc, copy_size,
&shdw_size) != DRMF_SUCCESS ||
shdw_size != shadow_scale_app_to_shadow(copy_size))
ASSERT(false, "fail to copy shadow memory");
}
if (head_bit != 0) {
for (i = 0; i+head_bit < SHADOW_GRANULARITY; i++)
shadow_set_byte(&info_dst, new_start+i, head_val[i+head_bit]);
}
if (tail_bit != 0) {
app_pc new_end =
(app_pc)ALIGN_BACKWARD(new_start + size, SHADOW_GRANULARITY);
for (i = 0; i < tail_bit; i++)
shadow_set_byte(&info_dst, new_end+i, tail_val[i]);
}
}
void
shadow_set_non_matching_range(app_pc start, size_t size, uint val, uint val_not)
{
umbra_shadow_memory_info_t info;
app_pc end = start + size;
app_pc cur;
ASSERT(!MAP_4B_TO_1B, "invalid shadow mode");
LOG(2, "Marking non-%s bytes in range "PFX"-"PFX" as %s\n",
shadow_name[val_not], start, end, shadow_name[val]);
/* XXX: We could try to be clever for perf, but these calls are rare, so we
* go byte by byte.
*/
umbra_shadow_memory_info_init(&info);
for (cur = start; cur != end; cur++) {
uint shadow = shadow_get_byte(&info, cur);
if (shadow != val_not) {
shadow_set_byte(&info, cur, val);
}
}
}
static uint dqword_to_val(uint dqword)
{
if (dqword == SHADOW_DQWORD_UNADDRESSABLE)
return SHADOW_UNADDRESSABLE;
if (dqword == SHADOW_DQWORD_UNDEFINED)
return SHADOW_UNDEFINED;
if (dqword == SHADOW_DQWORD_DEFINED)
return SHADOW_DEFINED;
if (dqword == SHADOW_DQWORD_BITLEVEL)
return SHADOW_DEFINED_BITLEVEL;
return UINT_MAX;
}
const char *
shadow_dqword_name(uint dqword)
{
if (dqword == SHADOW_DQWORD_UNADDRESSABLE)
return shadow_name[SHADOW_UNADDRESSABLE];
if (dqword == SHADOW_DQWORD_UNDEFINED)
return shadow_name[SHADOW_UNDEFINED];
if (dqword == SHADOW_DQWORD_DEFINED)
return shadow_name[SHADOW_DEFINED];
if (dqword == SHADOW_DQWORD_BITLEVEL)
return shadow_name[SHADOW_DEFINED_BITLEVEL];
return "<mixed>";
}
/* Compares every byte in [start, start+size) to expect.
* Stops and returns the pc of the first non-matching value.
* If all bytes match, returns start+size.
* bad_state is a dqword value.
*/
bool
shadow_check_range(app_pc start, size_t size, uint expect,
app_pc *bad_start, app_pc *bad_end, uint *bad_state)
{
umbra_shadow_memory_info_t info;
app_pc pc = start;
uint val;
uint bad_val = 0;
bool res = true;
size_t incr;
ASSERT(expect <= 4, "invalid shadow value");
ASSERT(start+size > start, "invalid param");
umbra_shadow_memory_info_init(&info);
while (pc < start+size) {
val = shadow_get_byte(&info, pc);
if (!ALIGNED(pc, 16)) {
incr = 1;
} else if (SHADOW_IS_SHARED_ONLY(info.shadow_type)) {
incr = info.app_base + info.app_size - pc;
} else {
val = shadow_get_byte(&info, pc);
val = dqword_to_val(val);
if (val == UINT_MAX) {
/* mixed: have to drop to per-byte */
val = shadow_get_byte(&info, pc);
incr = 1;
} else /* all identical */
incr = 16;
}
if (!res) {
/* we know we have some non-matching bytes, but we want to know
* the full extent of them (if identical) (if bad_end is non-NULL)
*/
if (val != bad_val || bad_end == NULL) {
if (bad_end != NULL)
*bad_end = pc;
break;
}
} else if (val != expect) {
res = false;
bad_val = val;
if (bad_start != NULL)
*bad_start = pc;
if (bad_state != NULL)
*bad_state = val;
}
pc += incr;
}
if (!res && val == bad_val && bad_end != NULL)
*bad_end = pc;
return res;
}
/* Walks backward from start comparing each byte to expect.
* If a non-matching value is reached, stops and returns false with the
* non-matching addr in bad_addr.
* If all bytes match when it reaches start-size, returns true.
* N.B.: if this finds more important uses, should generalize and give
* all the features of the forward version.
*/
bool
shadow_check_range_backward(app_pc start, size_t size, uint expect,
app_pc *bad_addr)
{
umbra_shadow_memory_info_t info;
app_pc pc = start;
uint val;
bool res = true;
ASSERT(expect <= 4, "invalid shadow value");
ASSERT(size < (size_t)start, "invalid param");
umbra_shadow_memory_info_init(&info);
while (pc > start-size) {
/* For simplicity and since performance is not critical for current
* callers, walking one byte at a time
*/
val = shadow_get_byte(&info, pc);
if (val != expect) {
res = false;
if (bad_addr != NULL)
*bad_addr = pc;
break;
}
pc--;
}
return res;
}
/* Finds the next aligned dword, starting at start and stopping at
* end, whose shadow equals expect expanded to a dword.
*/
app_pc
shadow_next_dword(app_pc start, app_pc end, uint expect)
{
bool found;
app_pc app_addr = start;
uint expect_dword = val_to_dword[expect];
if (umbra_value_in_shadow_memory(umbra_map,
(app_pc *)&app_addr,
end - app_addr,
expect_dword, 1,
&found) != DRMF_SUCCESS)
ASSERT(false, "failed to check value in shadow memory");
if (found)
return app_addr;
return NULL;
}
/* Finds the previous aligned dword, starting at start and stopping at
* end (end < start), whose shadow equals expect expanded to a dword.
*/
app_pc
shadow_prev_dword(app_pc start, app_pc end, uint expect)
{
umbra_shadow_memory_info_t info;
app_pc pc = start;
uint expect_dword = val_to_dword[expect];
ASSERT(expect <= 4, "invalid shadow value");
ASSERT(ALIGNED(start, 4), "invalid start pc");
ASSERT(end < start, "invalid end pc");
umbra_shadow_memory_info_init(&info);
while (pc > end) {
uint blockval = shadow_get_byte(&info, pc);
LOG(5, "shadow_prev_dword: checking "PFX"\n", pc);
if (SHADOW_IS_SHARED_ONLY(info.shadow_type)) {
uint dwordval = val_to_dword[blockval];
if (dwordval == expect_dword)
return pc;
} else {
byte *base = info.shadow_base;
size_t mod = pc - info.app_base;
byte *start_shadow = base + BLOCK_AS_BYTE_ARRAY_IDX(mod);
byte *shadow = start_shadow;
while (shadow >= base && *shadow != expect_dword)
shadow--;
if (shadow >= base) {
pc = pc - ((start_shadow - shadow)*4);
if (pc > end)
return pc;
else
return NULL;
}
}
ASSERT(!POINTER_UNDERFLOW_ON_SUB(info.app_base, 1),
"application address underflow");
pc = info.app_base - 1;
}
return NULL;
}
/* Finds the next pointer-sized aligned address, starting at start and stopping at
* end, whose shadow equals expect expanded to a pointer.
*/
app_pc
shadow_next_ptrsz(app_pc start, app_pc end, uint expect)
{
bool found;
app_pc app_addr = start;
uint expect_val = VAL_TO_PTRSZ[expect];
if (end < start)
return NULL;
if (umbra_value_in_shadow_memory(umbra_map,
(app_pc *)&app_addr,
end - app_addr,
expect_val, sizeof(void*)/SHADOW_GRANULARITY,
&found) != DRMF_SUCCESS)
ASSERT(false, "failed to check value in shadow memory");
if (found)
return app_addr;
return NULL;
}
/* Caller does a lea or equivalent:
* 0x4d1cd047 8d 8e 84 00 00 00 lea 0x00000084(%esi) -> %ecx
* And this routine adds:
* 0x4d1cd04d 8b d1 mov %ecx -> %edx
* 0x4d1cd04f c1 ea 10 shr $0x00000010 %edx -> %edx
* 0x4d1cd052 c1 e9 02 shr $0x00000002 %ecx -> %ecx
* 0x4d1cd055 03 0c 95 40 26 96 73 add 0x73962640(,%edx,4) %ecx -> %ecx
* And now the shadow addr is in %ecx.
*/
void
shadow_gen_translation_addr(void *drcontext, instrlist_t *bb, instr_t *inst,
reg_id_t addr_reg, reg_id_t scratch_reg)
{
#ifdef DEBUG
int num_regs;
#endif
ASSERT(umbra_num_scratch_regs_for_translation(&num_regs) == DRMF_SUCCESS &&
num_regs <= 1, "not enough scratch registers");
umbra_insert_app_to_shadow(drcontext, umbra_map, bb, inst, addr_reg,
&scratch_reg, 1);
}
bool
shadow_memory_is_shadow(app_pc addr)
{
umbra_shadow_memory_type_t shadow_type;
umbra_shadow_memory_type_t match_shadow =
UMBRA_SHADOW_MEMORY_TYPE_NORMAL |
UMBRA_SHADOW_MEMORY_TYPE_SHARED |
#ifndef X64
UMBRA_SHADOW_MEMORY_TYPE_REDZONE |
#endif
UMBRA_SHADOW_MEMORY_TYPE_SHADOW_NOT_ALLOC;
if (!options.shadowing)
return false;
if (umbra_get_shadow_memory_type(umbra_map, addr,
&shadow_type) == DRMF_SUCCESS &&
TESTANY(match_shadow, shadow_type))
return true;
return false;
}
/***************************************************************************
* TABLES
*
* Table lookup is most performant way to do many operations, when we're
* instrumenting so much code that code size is a bottleneck.
*/
/*
0000
0001
0010
0011
0100
0101
0110
0111
1000
1001
1010
1011
1100
1101
1110
1111
*/
/* If any 2-bit sequence is 01, return 0 */
const byte shadow_dword_is_addressable[256] = {
1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, /* 0 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1 */
1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, /* 2 */
1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, /* 3 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 4 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 5 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 6 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7 */
1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, /* 8 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9 */
1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, /* A */
1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, /* B */
1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, /* C */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* D */
1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, /* E */
1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, /* F */
};
/* If any 2-bit sequence is 01 or 10, return 0 */
const byte shadow_dword_is_addr_not_bit[256] = {
1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, /* 0 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2 */
1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, /* 3 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 4 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 5 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 6 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* B */
1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, /* C */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* D */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* E */
1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, /* F */
};
/* Expand a 2-bit sequence, with the other bits 0 */
const byte shadow_2_to_dword[256] = {
0x00,0x55,0xaa,0xff, 0x55,0,0,0, 0xaa,0,0,0, 0xff,0,0,0, /* 0 */
0x55,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* 1 */
0xaa,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* 2 */
0xff,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* 3 */
0x55,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* 4 */
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* 5 */
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* 6 */
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* 7 */
0xaa,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* 8 */
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* 9 */
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* A */
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* B */
0xff,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* C */
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* D */
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* E */
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* F */
};
/* Expand a 4-bit sequence, with the other bits 0, for movsx.
* The higher 2-bit propagates, the lower stays.
* The other half being non-0 is an error so we return bitlevel 0xaa.
*/
const byte shadow_4_to_dword[256] = {
0x00,0x01,0x02,0x03,0x54,0x55,0x56,0x57,0xa8,0xa9,0xaa,0xab,0xfc,0xfd,0xfe,0xff,/*0*/
0x01,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,/*1*/
0x02,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,/*2*/
0x03,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,/*3*/
0x54,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,/*4*/
0x55,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,/*5*/
0x56,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,/*6*/
0x57,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,/*7*/
0xa8,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,/*8*/
0xa9,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,/*9*/
0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,/*A*/
0xab,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,/*B*/
0xfc,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,/*C*/
0xfd,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,/*D*/
0xfe,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,/*E*/
0xff,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,/*F*/
};
/* Returns 1 iff the selected 2-bit sequence is 00 */
const byte shadow_byte_defined[4][256] = {
{ /* offs = 0 => bits 0-1 */
1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, /* 0 */
1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, /* 1 */
1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, /* 2 */
1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, /* 3 */
1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, /* 4 */
1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, /* 5 */
1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, /* 6 */
1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, /* 7 */
1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, /* 8 */
1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, /* 9 */
1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, /* A */
1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, /* B */
1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, /* C */
1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, /* D */
1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, /* E */
1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, /* F */
},
{ /* offs = 1 => bits 2-3 */
1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0 */
1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1 */
1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2 */
1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 3 */
1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 4 */
1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 5 */
1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 6 */
1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7 */
1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8 */
1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9 */
1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A */
1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* B */
1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* C */
1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* D */
1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* E */
1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* F */
},
{ /* offs = 2 => bits 4-5 */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 3 */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 4 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 5 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 6 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7 */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 8 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* B */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* C */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* D */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* E */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* F */
},
{ /* offs = 3 => bits 6-7 */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0 */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 1 */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 2 */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 3 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 4 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 5 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 6 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* B */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* C */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* D */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* E */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* F */
},
};
/* Returns 1 iff the selected 4-bit sequence is 0000.
* We should already be checking alignment so we expect
* either 0 or 2 for the offs.
*/
const byte shadow_word_defined[4][256] = {
{ /* offs = 0 => bits 0-3 */
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0 */
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1 */
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2 */
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 3 */
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 4 */
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 5 */
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 6 */
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7 */
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8 */
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9 */
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A */
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* B */
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* C */
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* D */
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* E */
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* F */
},
{ /* offs = 1 => unaligned */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 3 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 4 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 5 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 6 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* B */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* C */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* D */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* E */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* F */
},
{ /* offs = 2 => bits 4-7 */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 3 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 4 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 5 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 6 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* B */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* C */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* D */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* E */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* F */
},
{ /* offs = 3 => unaligned */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 3 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 4 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 5 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 6 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* B */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* C */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* D */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* E */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* F */
},
};
/* Returns 1 iff the selected 2-bit sequence is 00 or 11 */
const byte shadow_byte_addr_not_bit[4][256] = {
{ /* offs = 0 => bits 0-1 */
1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, /* 0 */
1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, /* 1 */
1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, /* 2 */
1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, /* 3 */
1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, /* 4 */
1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, /* 5 */
1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, /* 6 */
1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, /* 7 */
1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, /* 8 */
1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, /* 9 */
1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, /* A */
1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, /* B */
1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, /* C */
1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, /* D */
1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, /* E */
1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, /* F */
},
{ /* offs = 1 => bits 2-3 */
1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, /* 0 */
1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, /* 1 */
1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, /* 2 */
1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, /* 3 */
1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, /* 4 */
1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, /* 5 */
1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, /* 6 */
1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, /* 7 */
1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, /* 8 */
1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, /* 9 */
1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, /* A */
1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, /* B */
1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, /* C */
1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, /* D */
1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, /* E */
1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, /* F */
},
{ /* offs = 2 => bits 4-5 */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2 */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 3 */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 4 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 5 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 6 */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 7 */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 8 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* B */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* C */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* D */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* E */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* F */
},
{ /* offs = 3 => bits 6-7 */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0 */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 1 */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 2 */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 3 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 4 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 5 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 6 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* B */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* C */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* D */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* E */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* F */
},
};
/* Returns 1 iff the selected 4-bit sequence is 0000, 1100, 0011, or 1111.
* We should already be checking alignment so we expect
* either 0 or 2 for the offs.
*/
const byte shadow_word_addr_not_bit[4][256] = {
{ /* offs = 0 => bits 0-3 */
1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, /* 0 */
1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, /* 1 */
1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, /* 2 */
1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, /* 3 */
1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, /* 4 */
1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, /* 5 */
1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, /* 6 */
1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, /* 7 */
1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, /* 8 */
1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, /* 9 */
1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, /* A */
1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, /* B */
1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, /* C */
1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, /* D */
1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, /* E */
1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, /* F */
},
{ /* offs = 1 => unaligned */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 3 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 4 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 5 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 6 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* B */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* C */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* D */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* E */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* F */
},
{ /* offs = 2 => bits 4-7 */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2 */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 3 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 4 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 5 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 6 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* B */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* C */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* D */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* E */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* F */
},
{ /* offs = 3 => unaligned */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 3 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 4 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 5 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 6 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* B */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* C */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* D */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* E */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* F */
},
};
#endif /* TOOL_DR_MEMORY around whole shadow table */
/***************************************************************************
* SHADOWING THE GPR REGISTERS
*/
#ifdef X64
# define NUM_XMM_REGS 16
#else
# define NUM_XMM_REGS 8
#endif
#define NUM_MMX_REGS 8
typedef struct _shadow_aux_registers_t {
/* i#243: shadow xmm registers */
int xmm[NUM_XMM_REGS];
int ymmh[NUM_XMM_REGS];
/* i#1473: shadow mmx registers */
short mm[NUM_MMX_REGS];
/* XXX i#471: add floating-point registers here as well */
} shadow_aux_registers_t;
#ifdef X64
typedef unsigned short shadow_reg_type_t;
#else
typedef byte shadow_reg_type_t;
#endif
/* We keep our shadow register bits in TLS */
typedef struct _shadow_registers_t {
#ifdef TOOL_DR_MEMORY
/* First 8-byte TLS slot */
shadow_reg_type_t xax;
shadow_reg_type_t xcx;
shadow_reg_type_t xdx;
shadow_reg_type_t xbx;
/* Second 8-byte TLS slot */
shadow_reg_type_t xsp;
shadow_reg_type_t xbp;
shadow_reg_type_t xsi;
shadow_reg_type_t xdi;
# ifdef X64
/* Third 8-byte TLS slot */
shadow_reg_type_t r8;
shadow_reg_type_t r9;
shadow_reg_type_t r10;
shadow_reg_type_t r11;
/* Fourth 8-byte TLS slot */
shadow_reg_type_t r12;
shadow_reg_type_t r13;
shadow_reg_type_t r14;
shadow_reg_type_t r15;
# endif
/* Third/fifth TLS slot. We go ahead and write GPR-sized values here
* for simplicity in our fastpath even though we treat this as
* a single tracked value.
*/
shadow_reg_type_t eflags;
/* Used for PR 578892. Should remain a very small integer so byte is fine. */
byte in_heap_routine;
byte padding[IF_X64_ELSE(4,2)];
/* Fourth/sixth TLS slot, which provides indirection to additional
* shadow memory.
*/
shadow_aux_registers_t *aux;
#else
/* Avoid empty struct. FIXME: this is a waste of a tls slot */
void *bogus;
#endif
} shadow_registers_t;
#define NUM_SHADOW_TLS_SLOTS (sizeof(shadow_registers_t)/sizeof(reg_t))
static reg_id_t tls_shadow_seg;
static uint tls_shadow_base;
/* we store a pointer for finding shadow regs for other threads */
static int tls_idx_shadow = -1;
#ifdef TOOL_DR_MEMORY
/* For xmm this points at the shadow aux ptr: need a de-ref */
opnd_t
opnd_create_shadow_reg_slot(reg_id_t reg)
{
uint offs;
opnd_size_t opsz;
ASSERT(options.shadowing, "incorrectly called");
if (reg_is_gpr(reg)) {
reg_id_t r = reg_to_pointer_sized(reg);
offs = (r - DR_REG_START_GPR) * sizeof(shadow_reg_type_t);
opsz = IF_X64(!reg_is_64bit(reg) ? OPSZ_1 :) SHADOW_GPR_OPSZ;
} else {
ASSERT(reg_is_xmm(reg) || reg_is_mmx(reg), "internal shadow reg error");
offs = offsetof(shadow_registers_t, aux);
opsz = OPSZ_PTR;
}
return opnd_create_far_base_disp_ex
(tls_shadow_seg, REG_NULL, REG_NULL, 1, tls_shadow_base + offs, opsz,
/* we do NOT want an addr16 prefix since most likely going to run on
* Core or Core2, and P4 doesn't care that much */
false, true, false);
}
#ifdef X64
opnd_t
opnd_create_shadow_reg_slot_high_dword(reg_id_t reg)
{
uint offs;
reg_id_t r = reg_to_pointer_sized(reg);
ASSERT(options.shadowing && reg_is_gpr(reg), "incorrectly called");
offs = (r - DR_REG_START_GPR) * sizeof(shadow_reg_type_t) + 1/*little-endian*/;
return opnd_create_far_base_disp_ex
(tls_shadow_seg, REG_NULL, REG_NULL, 1, tls_shadow_base + offs, OPSZ_1,
false, true, false);
}
#endif
uint
get_shadow_xmm_offs(reg_id_t reg)
{
#ifdef X86
if (reg_is_ymm(reg))
return offsetof(shadow_aux_registers_t, ymmh) + sizeof(int)*(reg - DR_REG_YMM0);
if (reg_is_xmm(reg))
return offsetof(shadow_aux_registers_t, xmm) + sizeof(int)*(reg - DR_REG_XMM0);
else {
ASSERT(reg_is_mmx(reg), "invalid reg");
return offsetof(shadow_aux_registers_t, mm) + sizeof(short)*(reg - DR_REG_MM0);
}
#else
/* FIXME i#1726: port to ARM: shadow SIMD regs */
ASSERT_NOT_IMPLEMENTED();
return 0;
#endif
}
opnd_t
opnd_create_shadow_eflags_slot(void)
{
ASSERT(options.shadowing, "incorrectly called");
return opnd_create_far_base_disp_ex
(tls_shadow_seg, REG_NULL, REG_NULL, 1, tls_shadow_base +
offsetof(shadow_registers_t, eflags), SHADOW_GPR_OPSZ,
/* we do NOT want an addr16 prefix since most likely going to run on
* Core or Core2, and P4 doesn't care that much */
false, true, false);
}
/* Opnd to acquire in_heap_routine TLS counter. Used for PR 578892. */
opnd_t
opnd_create_shadow_inheap_slot(void)
{
ASSERT(options.shadowing, "incorrectly called");
return opnd_create_far_base_disp_ex
(tls_shadow_seg, REG_NULL, REG_NULL, 1, tls_shadow_base +
offsetof(shadow_registers_t, in_heap_routine), OPSZ_1,
/* we do NOT want an addr16 prefix since most likely going to run on
* Core or Core2, and P4 doesn't care that much */
false, true, false);
}
#endif /* TOOL_DR_MEMORY */
#if defined(TOOL_DR_MEMORY) || defined(WINDOWS)
static shadow_registers_t *
get_shadow_registers(void)
{
byte *seg_base;
ASSERT(options.shadowing, "incorrectly called");
seg_base = get_own_seg_base();
return (shadow_registers_t *)(seg_base + tls_shadow_base);
}
#endif /* TOOL_DR_MEMORY || WINDOWS */
static void
shadow_registers_thread_init(void *drcontext)
{
#ifdef TOOL_DR_MEMORY
static bool first_thread = true;
shadow_aux_registers_t *aux;
#endif
shadow_registers_t *sr;
#ifdef UNIX
sr = (shadow_registers_t *)
(dr_get_dr_segment_base(tls_shadow_seg) + tls_shadow_base);
#else
sr = get_shadow_registers();
#endif
#ifdef TOOL_DR_MEMORY
aux = thread_alloc(drcontext, sizeof(*sr->aux), HEAPSTAT_SHADOW);
if (first_thread ||
/* If the app created other threads early before DR took over, we
* have to treat everything as defined.
*/
!first_bb) {
first_thread = false;
/* since we're in late, we consider everything defined
* (if we were in at init APC, only stack pointer would be defined) */
memset(sr, SHADOW_DWORD_DEFINED, sizeof(*sr));
sr->aux = aux;
memset(sr->aux, SHADOW_DWORD_DEFINED, sizeof(*sr->aux));
sr->eflags = SHADOW_DEFINED;
} else {
/* we are in at start for new threads */
uint init_shadow = SHADOW_DWORD_UNDEFINED;
#ifdef MACOS
/* With current late thread takeover (DRi#1403 covers moving it earlier),
* we have to mark all as defined.
*/
init_shadow = SHADOW_DWORD_DEFINED;
#endif
memset(sr, init_shadow, sizeof(*sr));
sr->aux = aux;
memset(sr->aux, init_shadow, sizeof(*sr->aux));
sr->eflags = init_shadow;
#ifdef LINUX
/* PR 426162: post-clone, esp and eax are defined */
sr->xsp = SHADOW_PTRSZ_DEFINED;
sr->xax = SHADOW_PTRSZ_DEFINED;
#elif defined(WINDOWS)
/* new thread on Windows has esp defined */
sr->xsp = SHADOW_PTRSZ_DEFINED;
#endif
}
sr->in_heap_routine = 0;
#endif /* TOOL_DR_MEMORY */
/* store in per-thread data struct so we can access from another thread */
drmgr_set_tls_field(drcontext, tls_idx_shadow, (void *) sr);
}
static void
shadow_registers_thread_exit(void *drcontext)
{
#ifdef TOOL_DR_MEMORY
shadow_registers_t *sr = (shadow_registers_t *)
drmgr_get_tls_field(drcontext, tls_idx_shadow);
thread_free(drcontext, sr->aux, sizeof(*sr->aux), HEAPSTAT_SHADOW);
#endif
drmgr_set_tls_field(drcontext, tls_idx_shadow, NULL);
}
static void
shadow_registers_init(void)
{
/* XXX: could save space by not allocating shadow regs for -no_check_uninitialized */
IF_DEBUG(bool ok =)
dr_raw_tls_calloc(&tls_shadow_seg, &tls_shadow_base, NUM_SHADOW_TLS_SLOTS, 0);
tls_idx_shadow = drmgr_register_tls_field();
ASSERT(tls_idx_shadow > -1, "failed to reserve TLS slot");
LOG(2, "TLS shadow base: "PIFX"\n", tls_shadow_base);
ASSERT(ok, "fatal error: unable to reserve tls slots");
#ifdef X86
ASSERT(tls_shadow_seg == EXPECTED_SEG_TLS, "unexpected tls segment");
#endif
}
static void
shadow_registers_exit(void)
{
IF_DEBUG(bool ok =)
dr_raw_tls_cfree(tls_shadow_base, NUM_SHADOW_TLS_SLOTS);
ASSERT(ok, "WARNING: unable to free tls slots");
drmgr_unregister_tls_field(tls_idx_shadow);
}
#ifdef TOOL_DR_MEMORY
void
print_shadow_registers(void)
{
uint i;
IF_DEBUG(shadow_registers_t *sr = get_shadow_registers());
ASSERT(options.shadowing, "shouldn't be called");
#ifdef X64
LOG(0, " rax=%04x rcx=%04x rdx=%04x rbx=%04x "
"rsp=%04x rbp=%04x rsi=%04x rdi=%04x\n"
" r8 =%04x r9 =%04x r10=%04x r11=%04x "
"r12=%04x r13=%04x r14=%04x r15=%04x efl=%04x\n",
sr->xax, sr->xcx, sr->xdx, sr->xbx, sr->xsp, sr->xbp, sr->xsi, sr->xdi,
sr->r8, sr->r9, sr->r10, sr->r11, sr->r12, sr->r13, sr->r14, sr->r15,
sr->eflags);
#else
LOG(0, " eax=%02x ecx=%02x edx=%02x ebx=%02x "
"esp=%02x ebp=%02x esi=%02x edi=%02x efl=%x\n",
sr->xax, sr->xcx, sr->xdx, sr->xbx, sr->xsp, sr->xbp,
sr->xsi, sr->xdi, sr->eflags);
#endif
for (i = 0; i < NUM_XMM_REGS; i++) {
if (i % 4 == 0)
LOG(0, " ");
LOG(0, "xmm%d=%08x ", i, sr->aux->xmm[i]);
if (i % 4 == 3)
LOG(0, "\n");
}
LOG(0, " ");
for (i = 0; i < NUM_MMX_REGS; i++) {
LOG(0, "mm%d=%04x ", i, (unsigned short)sr->aux->mm[i]);
}
LOG(0, "\n");
}
static byte *
reg_shadow_addr(shadow_registers_t *sr, reg_id_t reg)
{
/* REG_NULL means eflags */
if (reg == REG_NULL)
return ((byte *)sr) + offsetof(shadow_registers_t, eflags);
else if (reg_is_gpr(reg)) {
return ((byte *)sr) +
(reg_to_pointer_sized(reg) - DR_REG_START_GPR)*sizeof(shadow_reg_type_t);
} else {
#ifdef X86
/* Caller must ask for xmm to get low bits (won't all fit in uint) */
if (reg_is_ymm(reg))
return (byte *) &sr->aux->ymmh[reg - DR_REG_YMM0];
if (reg_is_xmm(reg))
return (byte *) &sr->aux->xmm[reg - DR_REG_XMM0];
else {
ASSERT(reg_is_mmx(reg), "invalid reg");
return (byte *) &sr->aux->mm[reg - DR_REG_MM0];
}
#else
/* FIXME i#1726: port to ARM: shadow SIMD regs */
ASSERT_NOT_IMPLEMENTED();
return NULL;
#endif
}
}
static uint
get_shadow_register_common(shadow_registers_t *sr, reg_id_t reg)
{
uint val;
opnd_size_t sz = reg_get_size(reg);
byte *addr = reg_shadow_addr(sr, reg);
ASSERT(options.shadowing, "incorrectly called");
if (reg_is_xmm(reg) || reg_is_mmx(reg))
return *(uint *)addr;
ASSERT(reg_is_gpr(reg), "internal shadow reg error");
if (sz == OPSZ_1) {
val = *addr;
if (reg_is_8bit_high(reg))
val = (val & 0xc) >> 2;
else
val &= 0x3;
} else if (sz == OPSZ_2) {
val = *addr;
val &= 0xf;
} else if (sz == OPSZ_4) {
val = *addr;
} else if (sz == OPSZ_8) {
IF_NOT_X86(ASSERT_NOT_REACHED());
val = *(ushort*)addr;
} else {
val = 0;
ASSERT_NOT_REACHED();
}
return val;
}
/* Note that any SHADOW_UNADDRESSABLE bit pairs simply mean it's
* a sub-register.
* For ymm registers, returns only the shadow for the high 128 bits --
* ask for the corresponding xmm to get the low bits.
*/
uint
get_shadow_register(reg_id_t reg)
{
shadow_registers_t *sr = get_shadow_registers();
ASSERT(options.shadowing, "incorrectly called");
return get_shadow_register_common(sr, reg);
}
/* Note that any SHADOW_UNADDRESSABLE bit pairs simply mean it's
* a sub-register
*/
uint
get_thread_shadow_register(void *drcontext, reg_id_t reg)
{
shadow_registers_t *sr = (shadow_registers_t *)
drmgr_get_tls_field(drcontext, tls_idx_shadow);
ASSERT(options.shadowing, "incorrectly called");
return get_shadow_register_common(sr, reg);
}
void
register_shadow_set_byte(reg_id_t reg, uint bytenum, uint val)
{
shadow_registers_t *sr = get_shadow_registers();
uint shift = bytenum*2;
byte *addr = reg_shadow_addr(sr, reg);
ASSERT(options.shadowing, "incorrectly called");
while (shift > 7) {
ASSERT(reg_is_xmm(reg) ||
(shift < 16 IF_NOT_X64(&& reg_is_mmx(reg))), "shift too big for reg");
addr++;
shift -= 8;
}
*addr = set_2bits_inline(*addr, val, shift);
}
void
register_shadow_set_dword(reg_id_t reg, uint val)
{
shadow_registers_t *sr = get_shadow_registers();
byte *addr = reg_shadow_addr(sr, reg);
ASSERT(options.shadowing, "incorrectly called");
ASSERT(reg_is_gpr(reg), "internal shadow reg error");
*addr = (byte) val;
}
#ifdef X64
void
register_shadow_set_qword(reg_id_t reg, uint val)
{
shadow_registers_t *sr = get_shadow_registers();
byte *addr = reg_shadow_addr(sr, reg);
ASSERT(options.shadowing, "incorrectly called");
ASSERT(reg_is_gpr(reg), "internal shadow reg error");
*(ushort *)addr = (ushort) val;
}
void
register_shadow_set_high_dword(reg_id_t reg, uint val)
{
shadow_registers_t *sr = get_shadow_registers();
byte *addr = reg_shadow_addr(sr, reg);
ASSERT(options.shadowing, "incorrectly called");
ASSERT(reg_is_gpr(reg), "internal shadow reg error");
*(addr+1) = (byte) val; /* little-endian */
}
#endif
void
register_shadow_set_ptrsz(reg_id_t reg, uint val)
{
#ifdef X64
register_shadow_set_qword(reg, val);
#else
register_shadow_set_dword(reg, val);
#endif
}
void
register_shadow_set_dqword(reg_id_t reg, uint val)
{
shadow_registers_t *sr = get_shadow_registers();
byte *addr = reg_shadow_addr(sr, reg);
ASSERT(options.shadowing, "incorrectly called");
ASSERT(reg_is_xmm(reg), "internal shadow reg error");
*(uint *)addr = val;
}
uint
get_shadow_eflags(void)
{
shadow_registers_t *sr = get_shadow_registers();
ASSERT(options.shadowing, "incorrectly called");
return sr->eflags;
}
void
set_shadow_eflags(uint val)
{
shadow_registers_t *sr = get_shadow_registers();
ASSERT(options.shadowing, "incorrectly called");
sr->eflags = (byte) val;
}
byte
get_shadow_inheap(void)
{
shadow_registers_t *sr;
ASSERT(options.shadowing, "incorrectly called");
sr = get_shadow_registers();
return sr->in_heap_routine;
}
void
set_shadow_inheap(uint val)
{
shadow_registers_t *sr;
ASSERT(options.shadowing, "incorrectly called");
sr = get_shadow_registers();
sr->in_heap_routine = (byte) val;
}
/* assumes val was obtained from get_shadow_register(),
* but should never have unaddressable anyway
*/
bool
is_shadow_register_defined(uint val)
{
ASSERT(SHADOW_DEFINED == SHADOW_WORD_DEFINED &&
SHADOW_DEFINED == SHADOW_DWORD_DEFINED &&
SHADOW_DEFINED == SHADOW_QWORD_DEFINED &&
SHADOW_DEFINED == SHADOW_DQWORD_DEFINED,
"if change bit patterns, change here");
return (val == SHADOW_DEFINED);
}
#endif /* TOOL_DR_MEMORY */
/***************************************************************************/
void
shadow_thread_init(void *drcontext)
{
shadow_registers_thread_init(drcontext);
}
void
shadow_thread_exit(void *drcontext)
{
shadow_registers_thread_exit(drcontext);
}
void
shadow_init(void)
{
ASSERT(options.shadowing, "shadowing disabled");
shadow_registers_init();
shadow_table_init();
}
void
shadow_exit(void)
{
shadow_registers_exit();
shadow_table_exit();
}