blob: 73fcb2533d03d20b09cb1d6072bbcc714c02f300 [file] [log] [blame]
/* ******************************************************
* Copyright (c) 2014-2021 Google, Inc. All rights reserved.
* ******************************************************/
/*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of VMware, Inc. nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL VMWARE, INC. OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
#ifndef _DYNAMORIO_ANNOTATIONS_ASM_H_
#define _DYNAMORIO_ANNOTATIONS_ASM_H_ 1
/* This header defines the annotation functions and code sequences. For a high-level
* overview, see https://dynamorio.org/page_annotations.html.
*/
/* To simplify project configuration, this pragma excludes the file from GCC warnings. */
#ifdef __GNUC__
# pragma GCC system_header
#endif
#include <stddef.h>
#ifdef _MSC_VER
# include <intrin.h>
# pragma warning(disable : 4100) /* disable "unreferenced formal parameter" warning \
*/
#endif
#ifndef DYNAMORIO_ANNOTATIONS_X86
# if defined(__x86_64__) || defined(__i386__) || defined(_M_X64) || defined(_M_IX86)
# define DYNAMORIO_ANNOTATIONS_X86 1
# endif
#endif
#ifndef DYNAMORIO_ANNOTATIONS_X64
# ifdef _MSC_VER
# ifdef _WIN64
# define DYNAMORIO_ANNOTATIONS_X64 1
# endif
# else
# ifdef __LP64__
# define DYNAMORIO_ANNOTATIONS_X64 1
# endif
# endif
#endif
#ifdef _MSC_VER
# ifdef __cplusplus
# define EXTERN extern "C"
# else
# define EXTERN extern
# endif
#else
# ifdef __cplusplus
# define EXTERN_C extern "C"
# else
# define EXTERN_C
# endif
#endif
#if !defined(DYNAMORIO_ANNOTATIONS_X86) || defined(__clang__)
/* TODO i#1672: Add annotation support to AArchXX.
* For now, we provide a fallback so we can build the annotation-concurrency
* app for use with drcachesim tests.
* We do the same for clang, which has no "asm goto".
*/
# define DR_ANNOTATION_OR_NATIVE(annotation, native_version, ...) /* Nothing. */
# define DR_DECLARE_ANNOTATION(return_type, annotation, parameters) \
return_type annotation parameters
# define DR_DEFINE_ANNOTATION(return_type, annotation, parameters, body) \
return_type annotation parameters \
{ \
body; \
}
#elif defined(_MSC_VER) /* Microsoft Visual Studio */
# define PASTE1(x, y) x##y
# define PASTE(x, y) PASTE1(x, y)
# ifdef DYNAMORIO_ANNOTATIONS_X64
/* The value of this intrinsic is assumed to be non-zero. In the rare case of
* annotations occurring within managed code (i.e., C# or VB), it may not properly
* be the address of the return address on the stack, but it still should never be
* zero.
*/
# pragma intrinsic(_AddressOfReturnAddress, __debugbreak, __int2c, _m_prefetchw)
# define GET_RETURN_PTR _AddressOfReturnAddress
# define DR_DEFINE_ANNOTATION_LABELS(annotation, return_type) \
const char *annotation##_expression_label = \
"dynamorio-annotation:expression:" #return_type ":" #annotation; \
const char *annotation##_statement_label = \
"dynamorio-annotation:statement:" #return_type ":" #annotation;
# define DR_EXTERN_ANNOTATION_LABELS(annotation, return_type) \
EXTERN const char *annotation##_expression_label; \
EXTERN const char *annotation##_statement_label;
/* The magic numbers for the head and tail are specially selected to establish
* immovable "bookends" on the annotation around which the compiler and optimizers
* will not reorder instructions. The values 0xfffffffffffffff0 and
* 0xfffffffffffffff1 are chosen because: (1) the stack can never appear in this
* address range in Windows x64, and (2) there is a little space below
* 0xffffffffffffffff to prevent optimizations based on the number of possible
* values greater than the magic number. The factor of 2 prevents optimizers from
* sharing a single instance of the conditional expression between the tail of one
* annotation and the head of the next when they appear on subsequent lines. The
* compiler will always reduce the magic number expression to a single constant,
* even in a debug build with all optimizations disabled.
*/
# define DR_ANNOTATION_STATEMENT_HEAD (0xfffffffffffffff1 - (2 * __LINE__))
# define DR_ANNOTATION_STATEMENT_TAIL (0xfffffffffffffff0 - (2 * __LINE__))
# define DR_ANNOTATION_OR_NATIVE(annotation, native_version, ...) \
do { \
if ((unsigned __int64)GET_RETURN_PTR() > DR_ANNOTATION_STATEMENT_HEAD) { \
__int2c(); \
_m_prefetchw(annotation##_statement_label); \
__debugbreak(); \
annotation(__VA_ARGS__); \
} else { \
native_version; \
} \
} while ((unsigned __int64)GET_RETURN_PTR() > DR_ANNOTATION_STATEMENT_TAIL)
# define DR_ANNOTATION_FUNCTION(annotation, body) \
if (GET_RETURN_PTR() == (void *)0) { \
__int2c(); \
_m_prefetchw(annotation##_expression_label); \
__debugbreak(); \
} else { \
body; \
}
# else
/* The assembly sequence for this platform begins with absolute bytes "0xeb 0x06"
* (jmp +6) to facilitate an optimized detection algorithm in the DR interpreter.
* The target of this jump is always the following jump, i.e. (mov=5 + pop/nop=1)
* => 6.
*/
# define DR_DEFINE_ANNOTATION_LABELS(annotation, return_type) \
const char *annotation##_label = \
"dynamorio-annotation:" #return_type ":" #annotation;
# define DR_EXTERN_ANNOTATION_LABELS(annotation, return_type) \
EXTERN const char *annotation##_label;
# define DR_ANNOTATION_OR_NATIVE_INSTANCE(unique_id, annotation, native_version, \
...) \
{ \
__asm { \
__asm _emit 0xeb \
__asm _emit 0x06 \
__asm mov eax, annotation##_label \
__asm pop eax \
__asm jmp PASTE(native_run, unique_id) } \
annotation(__VA_ARGS__); \
goto PASTE(native_end_marker, unique_id); \
PASTE(native_run, unique_id) \
: native_version; \
PASTE(native_end_marker, unique_id) \
:; \
}
# define DR_ANNOTATION_OR_NATIVE(annotation, native_version, ...) \
DR_ANNOTATION_OR_NATIVE_INSTANCE(__COUNTER__, annotation, native_version, \
__VA_ARGS__)
# define DR_ANNOTATION_FUNCTION_INSTANCE(unique_id, annotation, body) \
__asm { \
__asm _emit 0xeb \
__asm _emit 0x06 \
__asm mov eax, annotation##_label \
__asm nop \
__asm jmp PASTE(native_run, unique_id) } \
goto PASTE(native_end_marker, unique_id); \
PASTE(native_run, unique_id) \
: body; \
PASTE(native_end_marker, unique_id) \
:;
# define DR_ANNOTATION_FUNCTION(annotation, body) \
DR_ANNOTATION_FUNCTION_INSTANCE(__COUNTER__, annotation, body)
# endif
# define DR_DECLARE_ANNOTATION(return_type, annotation, parameters) \
DR_EXTERN_ANNOTATION_LABELS(annotation, return_type) \
return_type __fastcall annotation parameters
# define DR_DEFINE_ANNOTATION(return_type, annotation, parameters, body) \
DR_DEFINE_ANNOTATION_LABELS(annotation, return_type) \
return_type __fastcall annotation parameters \
{ \
DR_ANNOTATION_FUNCTION(annotation, body) \
}
#else /* GCC or Intel (Unix or Windows) */
/* *************************************************************************************
* The assembly sequence for this platform begins with absolute bytes "0xeb 0xNN"
* (jmp +LABEL_REFERENCE_LENGTH) to facilitate an optimized detection algorithm in
* the DR interpreter. The target of this jump is always the following jump.
* Each reference to _GLOBAL_OFFSET_TABLE_ is adjusted by the linker to be
* XIP-relative, and no relocations are generated for the operand.
*/
# ifdef DYNAMORIO_ANNOTATIONS_X64
/* (mov=8 + bsf/bsr=9) => 0x11 */
# define LABEL_REFERENCE_LENGTH "0x11"
# define LABEL_REFERENCE_REGISTER "%rax"
/* Defensive clobber list: only rax is actually clobbered, but all
* argument-passing registers are included to discourage optimizers from using
* them prior to the annotation. Note that optimizations should be disabled for
* files that define annotation functions, so this is just an extra precaution.
*/
# define ANNOTATION_FUNCTION_CLOBBER_LIST \
"%rax", "%rcx", "%rdx", "%rsi", "%rdi", "%r8", "%r9"
# define _CALL_TYPE
# define ANNOT_LBL(annot, base) # annot "_label@GOT"
# else
/* (mov=5 + bsf/bsr=7) => 0xc */
# define LABEL_REFERENCE_LENGTH "0xc"
# define LABEL_REFERENCE_REGISTER "%eax"
/* Defensive clobber list: only rax is actually clobbered, but all
* argument-passing registers are included to discourage optimizers from using
* them prior to the annotation. Note that optimizations should be disabled for
* files that define annotation functions, so this is just an extra precaution.
*/
# define ANNOTATION_FUNCTION_CLOBBER_LIST "%rax", "%rcx", "%rdx"
# define _CALL_TYPE , fastcall
/* i#2050: i386 ABI forces us to use the base register as an offset into GOT, which is
* not the case for 64-bit.
*/
# define ANNOT_LBL(annot, base) # annot "_label@GOT(%" base ")"
# endif
# define DR_ANNOTATION_ATTRIBUTES \
__attribute__((noinline, visibility("hidden") _CALL_TYPE))
# define DR_WEAK_DECLARATION __attribute__((weak))
/* GCC extension "__label__" confines the named label to the block scope. */
# define DR_ANNOTATION_OR_NATIVE(annotation, native_version, ...) \
({ \
__label__ native_run, native_end_marker; \
extern const char *annotation##_label; \
__asm__ volatile goto(".byte 0xeb; .byte " LABEL_REFERENCE_LENGTH "; \
mov _GLOBAL_OFFSET_TABLE_,%" LABEL_REFERENCE_REGISTER "; \
bsf " ANNOT_LBL(annotation, LABEL_REFERENCE_REGISTER) ", \
%" LABEL_REFERENCE_REGISTER "; \
jmp %l0;" :: \
: LABEL_REFERENCE_REGISTER \
: native_run); \
annotation(__VA_ARGS__); \
goto native_end_marker; \
native_run: \
native_version; \
native_end_marker:; \
})
# define DR_DECLARE_ANNOTATION(return_type, annotation, parameters) \
DR_ANNOTATION_ATTRIBUTES return_type annotation parameters DR_WEAK_DECLARATION
# define DR_DEFINE_ANNOTATION(return_type, annotation, parameters, body) \
EXTERN_C const char *annotation##_label = \
"dynamorio-annotation:" #return_type ":" #annotation; \
DR_ANNOTATION_ATTRIBUTES return_type annotation parameters \
{ \
__label__ native_run, native_end_marker; \
extern const char *annotation##_label; \
__asm__ volatile goto(".byte 0xeb; .byte " LABEL_REFERENCE_LENGTH "; \
mov _GLOBAL_OFFSET_TABLE_,%" LABEL_REFERENCE_REGISTER \
"; \
bsr " ANNOT_LBL(annotation, \
LABEL_REFERENCE_REGISTER) ", \
%" LABEL_REFERENCE_REGISTER "; \
jmp %l0;" :: \
: ANNOTATION_FUNCTION_CLOBBER_LIST \
: native_run); \
goto native_end_marker; \
native_run: \
body; \
native_end_marker:; \
}
#endif
#define DR_ANNOTATION(annotation, ...) DR_ANNOTATION_OR_NATIVE(annotation, , __VA_ARGS__)
#endif