mirror of
https://github.com/DynamoRIO/dynamorio.git
synced 2026-10-12 02:02:04 +00:00
As we are trying to build DR files with the Linux kernel build system (Kbuild), which has `-Wstrict-prototypes` turned on by default, we are turning it on in this project as well. Also, the [coding style conventions](https://dynamorio.org/page_code_style.html#autotoc_md106) of this project already requires that declarations of functions that take no argument should have the explicit `void` keyword in their signatures. - Enable `-Wstrict-prototypes` when compiling C files. - Add explicit `void` to the signatures of functions that take no argument. For global functions whose declarations already have `void` (or were added `void` in this PR), this PR also adds `void` to their definitions. This is an optional cosmetic match, not required by the style guide or `-Wstrict-prototypes`. Fixed #7975
732 lines
33 KiB
C
732 lines
33 KiB
C
/* **********************************************************
|
|
* Copyright (c) 2010-2026 Google, Inc. All rights reserved.
|
|
* Copyright (c) 2002-2010 VMware, 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 _DR_PROC_H_
|
|
#define _DR_PROC_H_
|
|
|
|
/****************************************************************************
|
|
* PROCESSOR-SPECIFIC UTILITY ROUTINES AND CONSTANTS
|
|
*/
|
|
/**
|
|
* @file dr_proc.h
|
|
* @brief Utility routines for identifying features of the processor.
|
|
*/
|
|
|
|
/**
|
|
* The maximum possible required size of floating point state buffer for
|
|
* processors with different features (i.e., the processors with the FXSR
|
|
* feature on x86, or the processors with the VFPv3 feature on ARM).
|
|
* \note The actual required buffer size may vary depending on the processor
|
|
* feature. \note proc_fpstate_save_size() can be used to determine the
|
|
* particular size needed.
|
|
*/
|
|
#ifdef X86
|
|
# define DR_FPSTATE_BUF_SIZE 512
|
|
#elif defined(ARM) || defined(AARCH64) || defined(RISCV64)
|
|
/* On ARM/AArch64/RISCV64 proc_save_fpstate saves nothing, so use the smallest
|
|
* legal size for an array.
|
|
*/
|
|
# define DR_FPSTATE_BUF_SIZE 1
|
|
#endif
|
|
|
|
/** The alignment requirements of floating point state buffer. */
|
|
#if defined(X86) || defined(AARCH64)
|
|
# define DR_FPSTATE_ALIGN 16
|
|
#elif defined(RISCV64)
|
|
# define DR_FPSTATE_ALIGN 1
|
|
#elif defined(ARM)
|
|
# define DR_FPSTATE_ALIGN 1
|
|
#endif
|
|
/** Constants returned by proc_get_vendor(). */
|
|
enum {
|
|
VENDOR_INTEL, /**< proc_get_vendor() processor identification: Intel */
|
|
VENDOR_AMD, /**< proc_get_vendor() processor identification: AMD */
|
|
VENDOR_ARM, /**< proc_get_vendor() processor identification: ARM */
|
|
VENDOR_UNKNOWN, /**< proc_get_vendor() processor identification: unknown */
|
|
};
|
|
|
|
/* Family and Model
|
|
* Intel 486 Family 4
|
|
* Intel Pentium Family 5
|
|
* Intel Pentium Pro Family 6, Model 0 and 1
|
|
* Intel Pentium 2 Family 6, Model 3, 5, and 6
|
|
* Intel Celeron Family 6, Model 5 and 6
|
|
* Intel Pentium 3 Family 6, Model 7, 8, 10, 11
|
|
* Intel Pentium 4 Family 15, Extended 0
|
|
* Intel Itanium Family 7
|
|
* Intel Itanium 2 Family 15, Extended 1 and 2
|
|
* Intel Pentium M Family 6, Model 9 and 13
|
|
* Intel Core Family 6, Model 14
|
|
* Intel Core 2 Family 6, Model 15
|
|
* Intel Nehalem Family 6, Models 26 (0x1a), 30 (0x1e), 31 (0x1f)
|
|
* Intel SandyBridge Family 6, Models 37 (0x25), 42 (0x2a), 44 (0x2c),
|
|
* 45 (0x2d), 47 (0x2f)
|
|
* Intel IvyBridge Family 6, Model 58 (0x3a)
|
|
* Intel Atom Family 6, Model 28 (0x1c), 38 (0x26), 54 (0x36)
|
|
*/
|
|
/* Remember that we add extended family to family as Intel suggests */
|
|
#define FAMILY_LLANO 18 /**< proc_get_family() processor family: AMD Llano */
|
|
#define FAMILY_ITANIUM_2_DC 17 /**< proc_get_family() processor family: Itanium 2 DC */
|
|
#define FAMILY_K8_MOBILE 17 /**< proc_get_family() processor family: AMD K8 Mobile */
|
|
#define FAMILY_ITANIUM_2 16 /**< proc_get_family() processor family: Itanium 2 */
|
|
#define FAMILY_K8L 16 /**< proc_get_family() processor family: AMD K8L */
|
|
#define FAMILY_K8 15 /**< proc_get_family() processor family: AMD K8 */
|
|
#define FAMILY_PENTIUM_4 15 /**< proc_get_family() processor family: Pentium 4 */
|
|
#define FAMILY_P4 15 /**< proc_get_family() processor family: P4 family */
|
|
#define FAMILY_ITANIUM 7 /**< proc_get_family() processor family: Itanium */
|
|
/* Pentium Pro, Pentium II, Pentium III, Athlon, Pentium M, Core, Core 2+ */
|
|
#define FAMILY_P6 6 /**< proc_get_family() processor family: P6 family */
|
|
#define FAMILY_IVYBRIDGE 6 /**< proc_get_family() processor family: IvyBridge */
|
|
#define FAMILY_SANDYBRIDGE 6 /**< proc_get_family() processor family: SandyBridge */
|
|
#define FAMILY_NEHALEM 6 /**< proc_get_family() processor family: Nehalem */
|
|
#define FAMILY_CORE_I7 6 /**< proc_get_family() processor family: Core i7 */
|
|
#define FAMILY_CORE_2 6 /**< proc_get_family() processor family: Core 2 */
|
|
#define FAMILY_CORE 6 /**< proc_get_family() processor family: Core */
|
|
#define FAMILY_PENTIUM_M 6 /**< proc_get_family() processor family: Pentium M */
|
|
#define FAMILY_PENTIUM_3 6 /**< proc_get_family() processor family: Pentium 3 */
|
|
#define FAMILY_PENTIUM_2 6 /**< proc_get_family() processor family: Pentium 2 */
|
|
#define FAMILY_PENTIUM_PRO 6 /**< proc_get_family() processor family: Pentium Pro */
|
|
#define FAMILY_ATHLON 6 /**< proc_get_family() processor family: Athlon */
|
|
#define FAMILY_K7 6 /**< proc_get_family() processor family: AMD K7 */
|
|
/* Pentium (586) */
|
|
#define FAMILY_P5 5 /**< proc_get_family() processor family: P5 family */
|
|
#define FAMILY_PENTIUM 5 /**< proc_get_family() processor family: Pentium */
|
|
#define FAMILY_K6 5 /**< proc_get_family() processor family: K6 */
|
|
#define FAMILY_K5 5 /**< proc_get_family() processor family: K5 */
|
|
/* 486 */
|
|
#define FAMILY_486 4 /**< proc_get_family() processor family: 486 */
|
|
|
|
/* We do not enumerate all models; just relevant ones needed to distinguish
|
|
* major processors in the same family.
|
|
*/
|
|
#define MODEL_HASWELL 60 /**< proc_get_model(): Haswell */
|
|
#define MODEL_IVYBRIDGE 58 /**< proc_get_model(): Ivybridge */
|
|
#define MODEL_I7_WESTMERE_EX 47 /**< proc_get_model(): Sandybridge Westmere Ex */
|
|
#define MODEL_SANDYBRIDGE_E 45 /**< proc_get_model(): Sandybridge-E, -EN, -EP */
|
|
#define MODEL_I7_WESTMERE 44 /**< proc_get_model(): Westmere */
|
|
#define MODEL_SANDYBRIDGE 42 /**< proc_get_model(): Sandybridge */
|
|
#define MODEL_I7_CLARKDALE 37 /**< proc_get_model(): Westmere Clarkdale/Arrandale */
|
|
#define MODEL_I7_HAVENDALE 31 /**< proc_get_model(): Core i7 Havendale/Auburndale */
|
|
#define MODEL_I7_CLARKSFIELD 30 /**< proc_get_model(): Core i7 Clarksfield/Lynnfield */
|
|
#define MODEL_ATOM_CEDARVIEW 54 /**< proc_get_model(): Atom Cedarview */
|
|
#define MODEL_ATOM_LINCROFT 38 /**< proc_get_model(): Atom Lincroft */
|
|
#define MODEL_ATOM 28 /**< proc_get_model(): Atom */
|
|
#define MODEL_I7_GAINESTOWN 26 /**< proc_get_model(): Core i7 Gainestown (Nehalem) */
|
|
#define MODEL_CORE_PENRYN 23 /**< proc_get_model(): Core 2 Penryn */
|
|
#define MODEL_CORE_2 15 /**< proc_get_model(): Core 2 Merom/Conroe */
|
|
#define MODEL_CORE_MEROM 15 /**< proc_get_model(): Core 2 Merom */
|
|
#define MODEL_CORE 14 /**< proc_get_model(): Core Yonah */
|
|
#define MODEL_PENTIUM_M 13 /**< proc_get_model(): Pentium M 2MB L2 */
|
|
#define MODEL_PENTIUM_M_1MB 9 /**< proc_get_model(): Pentium M 1MB L2 */
|
|
|
|
#ifdef X86
|
|
/**
|
|
* For X86 this struct holds all 4 32-bit feature values returned by cpuid.
|
|
* Used by proc_get_all_feature_bits().
|
|
*/
|
|
typedef struct {
|
|
uint flags_edx; /**< X86 feature flags stored in edx */
|
|
uint flags_ecx; /**< X86 feature flags stored in ecx */
|
|
uint ext_flags_edx; /**< X86 extended feature flags stored in edx */
|
|
uint ext_flags_ecx; /**< X86 extended feature flags stored in ecx */
|
|
uint sext_flags_ebx; /**< structured X86 extended feature flags stored in ebx */
|
|
} features_t;
|
|
#endif
|
|
/* We avoid using #elif here because otherwise doxygen will be unable to
|
|
* document both defines, for X86 and for AARCHXX. See also i#5496.
|
|
*/
|
|
#ifdef AARCHXX
|
|
|
|
/**
|
|
* For AArch64 this enum represents the feature registers read by MRS
|
|
* instructions. Used by proc_has_feature().
|
|
*/
|
|
typedef enum {
|
|
AA64ISAR0, /**< AArch64 Instruction Set Attribute Register 0. */
|
|
AA64ISAR1, /**< AArch64 Instruction Set Attribute Register 1. */
|
|
AA64PFR0, /**< AArch64 Processor Feature Register 0. */
|
|
AA64MMFR1, /**< AArch64 Memory Model Feature Register 1. */
|
|
AA64DFR0, /**< AArch64 Debug Feature Register 0. */
|
|
AA64ZFR0, /**< SVE Feature ID Register 0. */
|
|
AA64PFR1, /**< AArch64 Processor Feature Register 1. */
|
|
AA64ISAR2, /**< AArch64 Instruction Set Attribute Register 2. */
|
|
AA64MMFR2, /**< AArch64 Memory Model Feature Register 2. */
|
|
AA64_NUM_FEAT_REGS /**< Number of feature registers. */
|
|
} feature_reg_idx_t;
|
|
|
|
/**
|
|
* For AArch64 this struct contains an array of ints which cache the values of AArch64
|
|
* attribute registers.
|
|
*/
|
|
typedef struct {
|
|
/** Array of ints representing attribute registers. */
|
|
uint64 isa_features[AA64_NUM_FEAT_REGS];
|
|
} features_t;
|
|
|
|
#endif
|
|
#ifdef RISCV64
|
|
/**
|
|
* For RISC-V64 there are no features readable from userspace, so we mimic this ourselves,
|
|
* see signal_arch_init(). Used by proc_get_all_feature_bits().
|
|
*/
|
|
typedef struct {
|
|
uint64 isa_features[1];
|
|
} features_t;
|
|
#endif
|
|
|
|
#ifdef X86
|
|
/**
|
|
* Feature bits returned by cpuid for X86 and mrs for AArch64. Pass one of
|
|
* these values to proc_has_feature() to determine whether the underlying
|
|
* processor has the feature.
|
|
*/
|
|
typedef enum {
|
|
/* features returned in edx */
|
|
FEATURE_FPU = 0, /**< Floating-point unit on chip (X86) */
|
|
FEATURE_VME = 1, /**< Virtual Mode Extension (X86) */
|
|
FEATURE_DE = 2, /**< Debugging Extension (X86) */
|
|
FEATURE_PSE = 3, /**< Page Size Extension (X86) */
|
|
FEATURE_TSC = 4, /**< Time-Stamp Counter (X86) */
|
|
FEATURE_MSR = 5, /**< Model Specific Registers (X86) */
|
|
FEATURE_PAE = 6, /**< Physical Address Extension (X86) */
|
|
FEATURE_MCE = 7, /**< Machine Check Exception (X86) */
|
|
FEATURE_CX8 = 8, /**< #OP_cmpxchg8b supported (X86) */
|
|
FEATURE_APIC = 9, /**< On-chip APIC Hardware supported (X86) */
|
|
FEATURE_SEP = 11, /**< Fast System Call (X86) */
|
|
FEATURE_MTRR = 12, /**< Memory Type Range Registers (X86) */
|
|
FEATURE_PGE = 13, /**< Page Global Enable (X86) */
|
|
FEATURE_MCA = 14, /**< Machine Check Architecture (X86) */
|
|
FEATURE_CMOV = 15, /**< Conditional Move Instruction (X86) */
|
|
FEATURE_PAT = 16, /**< Page Attribute Table (X86) */
|
|
FEATURE_PSE_36 = 17, /**< 36-bit Page Size Extension (X86) */
|
|
FEATURE_PSN = 18, /**< Processor serial # present & enabled (X86) */
|
|
FEATURE_CLFSH = 19, /**< #OP_clflush supported (X86) */
|
|
FEATURE_DS = 21, /**< Debug Store (X86) */
|
|
FEATURE_ACPI = 22, /**< Thermal monitor & SCC supported (X86) */
|
|
FEATURE_MMX = 23, /**< MMX technology supported (X86) */
|
|
FEATURE_FXSR = 24, /**< Fast FP save and restore (X86) */
|
|
FEATURE_SSE = 25, /**< SSE Extensions supported (X86) */
|
|
FEATURE_SSE2 = 26, /**< SSE2 Extensions supported (X86) */
|
|
FEATURE_SS = 27, /**< Self-snoop (X86) */
|
|
FEATURE_HTT = 28, /**< Hyper-threading Technology (X86) */
|
|
FEATURE_TM = 29, /**< Thermal Monitor supported (X86) */
|
|
FEATURE_IA64 = 30, /**< IA64 Capabilities (X86) */
|
|
FEATURE_PBE = 31, /**< Pending Break Enable (X86) */
|
|
/* features returned in ecx */
|
|
FEATURE_SSE3 = 0 + 32, /**< SSE3 Extensions supported (X86) */
|
|
FEATURE_PCLMULQDQ = 1 + 32, /**< #OP_pclmulqdq supported (X86) */
|
|
FEATURE_DTES64 = 2 + 32, /**< 64-bit debug store supported (X86) */
|
|
FEATURE_MONITOR = 3 + 32, /**< #OP_monitor/#OP_mwait supported (X86) */
|
|
FEATURE_DS_CPL = 4 + 32, /**< CPL Qualified Debug Store (X86) */
|
|
FEATURE_VMX = 5 + 32, /**< Virtual Machine Extensions (X86) */
|
|
FEATURE_SMX = 6 + 32, /**< Safer Mode Extensions (X86) */
|
|
FEATURE_EST = 7 + 32, /**< Enhanced Speedstep Technology (X86) */
|
|
FEATURE_TM2 = 8 + 32, /**< Thermal Monitor 2 (X86) */
|
|
FEATURE_SSSE3 = 9 + 32, /**< SSSE3 Extensions supported (X86) */
|
|
FEATURE_CID = 10 + 32, /**< Context ID (X86) */
|
|
FEATURE_FMA = 12 + 32, /**< FMA instructions supported (X86) */
|
|
FEATURE_CX16 = 13 + 32, /**< #OP_cmpxchg16b supported (X86) */
|
|
FEATURE_xTPR = 14 + 32, /**< Send Task Priority Messages (X86) */
|
|
FEATURE_PDCM = 15 + 32, /**< Perfmon and Debug Capability (X86) */
|
|
FEATURE_PCID = 17 + 32, /**< Process-context identifiers (X86) */
|
|
FEATURE_DCA = 18 + 32, /**< Prefetch from memory-mapped devices (X86) */
|
|
FEATURE_SSE41 = 19 + 32, /**< SSE4.1 Extensions supported (X86) */
|
|
FEATURE_SSE42 = 20 + 32, /**< SSE4.2 Extensions supported (X86) */
|
|
FEATURE_x2APIC = 21 + 32, /**< x2APIC supported (X86) */
|
|
FEATURE_MOVBE = 22 + 32, /**< #OP_movbe supported (X86) */
|
|
FEATURE_POPCNT = 23 + 32, /**< #OP_popcnt supported (X86) */
|
|
FEATURE_AES = 25 + 32, /**< AES instructions supported (X86) */
|
|
FEATURE_XSAVE = 26 + 32, /**< OP_xsave* supported (X86) */
|
|
FEATURE_OSXSAVE = 27 + 32, /**< #OP_xgetbv supported in user mode (X86) */
|
|
FEATURE_AVX = 28 + 32, /**< AVX instructions supported (X86) */
|
|
FEATURE_F16C = 29 + 32, /**< 16-bit floating-point conversion supported (X86) */
|
|
FEATURE_RDRAND = 30 + 32, /**< #OP_rdrand supported (X86) */
|
|
/* extended features returned in edx */
|
|
FEATURE_SYSCALL = 11 + 64, /**< #OP_syscall/#OP_sysret supported (X86) */
|
|
FEATURE_XD_Bit = 20 + 64, /**< Execution Disable bit (X86) */
|
|
FEATURE_MMX_EXT = 22 + 64, /**< AMD MMX Extensions (X86) */
|
|
FEATURE_PDPE1GB = 26 + 64, /**< Gigabyte pages (X86) */
|
|
FEATURE_RDTSCP = 27 + 64, /**< #OP_rdtscp supported (X86) */
|
|
FEATURE_EM64T = 29 + 64, /**< Extended Memory 64 Technology (X86) */
|
|
FEATURE_3DNOW_EXT = 30 + 64, /**< AMD 3DNow! Extensions (X86) */
|
|
FEATURE_3DNOW = 31 + 64, /**< AMD 3DNow! instructions supported (X86) */
|
|
/* extended features returned in ecx */
|
|
FEATURE_LAHF = 0 + 96, /**< #OP_lahf/#OP_sahf available in 64-bit mode (X86) */
|
|
FEATURE_SVM = 2 + 96, /**< AMD Secure Virtual Machine (X86) */
|
|
FEATURE_LZCNT = 5 + 96, /**< #OP_lzcnt supported (X86) */
|
|
FEATURE_SSE4A = 6 + 96, /**< AMD SSE4A Extensions supported (X86) */
|
|
FEATURE_PRFCHW = 8 + 96, /**< #OP_prefetchw supported (X86) */
|
|
FEATURE_XOP = 11 + 96, /**< AMD XOP supported (X86) */
|
|
FEATURE_SKINIT = 12 + 96, /**< AMD #OP_skinit/#OP_stgi supported (X86) */
|
|
FEATURE_FMA4 = 16 + 96, /**< AMD FMA4 supported (X86) */
|
|
FEATURE_TBM = 21 + 96, /**< AMD Trailing Bit Manipulation supported (X86) */
|
|
/* structured extended features returned in ebx */
|
|
FEATURE_FSGSBASE = 0 + 128, /**< #OP_rdfsbase, etc. supported (X86) */
|
|
FEATURE_BMI1 = 3 + 128, /**< BMI1 instructions supported (X86) */
|
|
FEATURE_HLE = 4 + 128, /**< Hardware Lock Elision supported (X86) */
|
|
FEATURE_AVX2 = 5 + 128, /**< AVX2 instructions supported (X86) */
|
|
FEATURE_BMI2 = 8 + 128, /**< BMI2 instructions supported (X86) */
|
|
FEATURE_ERMSB = 9 + 128, /**< Enhanced rep movsb/stosb supported (X86) */
|
|
FEATURE_INVPCID = 10 + 128, /**< #OP_invpcid supported (X86) */
|
|
FEATURE_RTM = 11 + 128, /**< Restricted Transactional Memory supported (X86) */
|
|
FEATURE_AVX512F = 16 + 128, /**< AVX-512F instructions supported (X86) */
|
|
FEATURE_AVX512BW = 30 + 128, /**< AVX-512BW instructions supported (X86) */
|
|
} feature_bit_t;
|
|
#endif
|
|
/* We avoid using #elif here because otherwise doxygen will be unable to
|
|
* document both defines, for X86 and for AARCHXX. See also i#5496.
|
|
*/
|
|
#ifdef AARCHXX
|
|
/* On Arm, architectural features are defined and stored very differently from
|
|
* X86. Specifically:
|
|
* - There are multiple 64 bit system registers for features storage only, FREG.
|
|
* - Each register is divided into nibbles representing a feature, NIBPOS.
|
|
* - The value of a nibble represents a certain level of support for that feature, FVAL.
|
|
* - The values can range from 0 to 15. In most cases 0 means a feature is not
|
|
* supported at all but in some cases 15 means a feature is not supported at
|
|
* all, NSFLAG.
|
|
* - If FEAT_EQ is set then the nibble value should match exactly, otherwise reg
|
|
* values greater than or equal to the feature nibble are considered a match. The helper
|
|
* macro below packs feature data into 16 bits (ushort).
|
|
*
|
|
* Bit 15: Set if a nibble value of 15 indicates feature not set.
|
|
* Bit 14: Exact match flag.
|
|
* Bits 8-13: Register ID in feature_reg_idx_t.
|
|
* Bits 4-7: Nibble index in register.
|
|
* Bits 0-3: Value to check for.
|
|
*/
|
|
# define DEF_FEAT(FREG, NIBPOS, FVAL, flags) \
|
|
((ushort)((flags) | (FREG << 8) | (NIBPOS << 4) | FVAL))
|
|
# define FEAT_NS (1 << 15)
|
|
# define FEAT_EQ (1 << 14)
|
|
# define FEAT_GR_EQ 0
|
|
/**
|
|
* Feature bits returned by mrs for AArch64. Pass one of these values to
|
|
* proc_has_feature() to determine whether the underlying processor has the feature.
|
|
*/
|
|
typedef enum {
|
|
/* Register NibblePos FeatVal Flags */
|
|
FEATURE_AESX = DEF_FEAT(AA64ISAR0, 1, 1, FEAT_GR_EQ), /**< AES<x> (AArch64) */
|
|
FEATURE_PMULL = DEF_FEAT(AA64ISAR0, 1, 2, FEAT_EQ), /**< PMULL/PMULL2 (AArch64) */
|
|
FEATURE_SHA1 = DEF_FEAT(AA64ISAR0, 2, 1, FEAT_EQ), /**< SHA1<x> (AArch64) */
|
|
FEATURE_SHA256 = DEF_FEAT(AA64ISAR0, 3, 1, FEAT_GR_EQ), /**< SHA256<x> (AArch64) */
|
|
FEATURE_SHA512 = DEF_FEAT(AA64ISAR0, 3, 2, FEAT_EQ), /**< SHA512<x> (AArch64) */
|
|
FEATURE_CRC32 = DEF_FEAT(AA64ISAR0, 4, 1, FEAT_EQ), /**< CRC32<x> (AArch64) */
|
|
FEATURE_LSE = DEF_FEAT(AA64ISAR0, 5, 1, FEAT_GR_EQ), /**< Atomics (AArch64) */
|
|
FEATURE_RDM = DEF_FEAT(AA64ISAR0, 7, 1, FEAT_EQ), /**< SQRDMLAH,SQRDMLSH (AArch64) */
|
|
FEATURE_SHA3 =
|
|
DEF_FEAT(AA64ISAR0, 8, 1, FEAT_EQ), /**< EOR3,RAX1,XAR,BCAX (AArch64) */
|
|
FEATURE_SM3 = DEF_FEAT(AA64ISAR0, 9, 1, FEAT_EQ), /**< SM3<x> (AArch64) */
|
|
FEATURE_SM4 = DEF_FEAT(AA64ISAR0, 10, 1, FEAT_EQ), /**< SM4E, SM4EKEY (AArch64) */
|
|
FEATURE_DotProd = DEF_FEAT(AA64ISAR0, 11, 1, FEAT_EQ), /**< UDOT, SDOT (AArch64) */
|
|
FEATURE_FHM = DEF_FEAT(AA64ISAR0, 12, 1, FEAT_EQ), /**< FMLAL, FMLSL (AArch64) */
|
|
FEATURE_FlagM =
|
|
DEF_FEAT(AA64ISAR0, 13, 1, FEAT_GR_EQ), /**< CFINV,RMIF,SETF<x> (AArch64) */
|
|
FEATURE_FlagM2 = DEF_FEAT(AA64ISAR0, 13, 2, FEAT_EQ), /**< AXFLAG, XAFLAG (AArch64) */
|
|
FEATURE_RNG = DEF_FEAT(AA64ISAR0, 15, 1, FEAT_EQ), /**< RNDR, RNDRRS (AArch64) */
|
|
FEATURE_DPB = DEF_FEAT(AA64ISAR1, 0, 1, FEAT_GR_EQ), /**< DC CVAP (AArch64) */
|
|
FEATURE_DPB2 = DEF_FEAT(AA64ISAR1, 0, 2, FEAT_EQ), /**< DC CVAP, DC CVADP (AArch64) */
|
|
FEATURE_JSCVT = DEF_FEAT(AA64ISAR1, 3, 1, FEAT_EQ), /**< FJCVTZS (AArch64) */
|
|
FEATURE_FP16 = DEF_FEAT(AA64PFR0, 4, 1, FEAT_NS), /**< Half-precision FP (AArch64) */
|
|
FEATURE_RAS = DEF_FEAT(AA64PFR0, 7, 1, FEAT_GR_EQ), /**< RAS extension (AArch64) */
|
|
FEATURE_SVE = DEF_FEAT(AA64PFR0, 8, 1, FEAT_EQ), /**< Scalable Vectors (AArch64) */
|
|
FEATURE_LOR =
|
|
DEF_FEAT(AA64MMFR1, 4, 1, FEAT_EQ), /**< Limited order regions (AArch64) */
|
|
FEATURE_SPE =
|
|
DEF_FEAT(AA64DFR0, 8, 1, FEAT_GR_EQ), /**< Profiling extension (AArch64) */
|
|
FEATURE_PAUTH =
|
|
DEF_FEAT(AA64ISAR1, 2, 1, FEAT_GR_EQ), /**< PAuth extension (AArch64) */
|
|
FEATURE_LRCPC =
|
|
DEF_FEAT(AA64ISAR1, 5, 1, FEAT_GR_EQ), /**< LDAPR, LDAPRB, LDAPRH (AArch64) */
|
|
FEATURE_LRCPC2 =
|
|
DEF_FEAT(AA64ISAR1, 5, 2, FEAT_GR_EQ), /**< LDAPUR*, STLUR* (AArch64) */
|
|
FEATURE_FRINTTS =
|
|
DEF_FEAT(AA64ISAR1, 8, 1, FEAT_EQ), /**< FRINT(32/64)(X/Z) (AArch64) */
|
|
FEATURE_LS64 = DEF_FEAT(AA64ISAR1, 15, 1, FEAT_GR_EQ), /**< LD64B, ST64B (AArch64) */
|
|
FEATURE_LS64V = DEF_FEAT(AA64ISAR1, 15, 2, FEAT_GR_EQ), /**< ST64BV (AArch64) */
|
|
FEATURE_LS64ACCDATA =
|
|
DEF_FEAT(AA64ISAR1, 15, 3, FEAT_GR_EQ), /**< ST64BV0 (AArch64) */
|
|
FEATURE_BF16 = DEF_FEAT(AA64ZFR0, 5, 1, FEAT_GR_EQ), /**< SVE BFloat16 (AArch64) */
|
|
FEATURE_I8MM = DEF_FEAT(AA64ZFR0, 11, 1,
|
|
FEAT_EQ), /**< SVE Int8 matrix multiplication (AArch64) */
|
|
FEATURE_F64MM = DEF_FEAT(AA64ZFR0, 14, 1,
|
|
FEAT_EQ), /**< SVE FP64 matrix multiplication (AArch64) */
|
|
FEATURE_SVE2 =
|
|
DEF_FEAT(AA64ZFR0, 0, 1, FEAT_GR_EQ), /**< Scalable vectors 2 (AArch64) */
|
|
FEATURE_SVEAES = DEF_FEAT(AA64ZFR0, 1, 1, FEAT_GR_EQ), /**< SVE2 + AES (AArch64) */
|
|
FEATURE_SVESHA3 = DEF_FEAT(AA64ZFR0, 8, 1, FEAT_EQ), /**< SVE2 + SHA3 (AArch64) */
|
|
FEATURE_SVESM4 = DEF_FEAT(AA64ZFR0, 10, 1, FEAT_EQ), /**< SVE2 + SM4 (AArch64) */
|
|
FEATURE_SVEBitPerm =
|
|
DEF_FEAT(AA64ZFR0, 4, 1, FEAT_EQ), /**< SVE2 + BitPerm (AArch64) */
|
|
FEATURE_MTE = DEF_FEAT(AA64PFR1, 2, 1,
|
|
FEAT_GR_EQ), /**< Instruction-only Memory Tagging (AArch64) */
|
|
FEATURE_MTE2 =
|
|
DEF_FEAT(AA64PFR1, 2, 2, FEAT_GR_EQ), /**< Full Memory Tagging (AArch64) */
|
|
FEATURE_BTI =
|
|
DEF_FEAT(AA64PFR1, 0, 1, FEAT_EQ), /**< Branch Target Identification (AArch64) */
|
|
FEATURE_PAUTH2 =
|
|
DEF_FEAT(AA64ISAR2, 3, 3, FEAT_GR_EQ), /**< PAuth2 extension (AArch64) */
|
|
FEATURE_CONSTPACFIELD =
|
|
DEF_FEAT(AA64ISAR2, 6, 1, FEAT_EQ), /**< PAC algorithm enhancement (AArch64) */
|
|
FEATURE_SSBS = DEF_FEAT(AA64PFR1, 1, 1,
|
|
FEAT_GR_EQ), /**< Speculative Store Bypass Safe (AArch64) */
|
|
FEATURE_SSBS2 = DEF_FEAT(AA64PFR1, 1, 2,
|
|
FEAT_EQ), /**< MRS and MSR instructions for SSBS (AArch64) */
|
|
FEATURE_DIT = DEF_FEAT(
|
|
AA64PFR0, 12, 1, FEAT_EQ), /**< Data Independent Timing instructions (AArch64) */
|
|
FEATURE_LSE2 =
|
|
DEF_FEAT(AA64MMFR2, 8, 1,
|
|
FEAT_EQ), /**< Atomicity requirements for loads and stores (AArch64) */
|
|
FEATURE_WFxT =
|
|
DEF_FEAT(AA64ISAR2, 0, 2,
|
|
FEAT_EQ), /**< Wait for event / interrupt with timeout (AArch64) */
|
|
FEATURE_FPAC = DEF_FEAT(AA64ISAR2, 3, 4,
|
|
FEAT_GR_EQ), /**< Faulting on AUTI* instructions (AArch64) */
|
|
FEATURE_FPACCOMBINE =
|
|
DEF_FEAT(AA64ISAR2, 3, 5, FEAT_GR_EQ), /**< Faulting on combined branch pointer
|
|
authentication instructions (AArch64) */
|
|
} feature_bit_t;
|
|
|
|
#endif
|
|
|
|
#ifdef RISCV64
|
|
/**
|
|
* Feature bits passed to proc_has_feature() to determine whether the underlying
|
|
* processor has the feature.
|
|
* XXX: The enum definitions here and the bitmask of hwprobe in the kernel are kept
|
|
* consistent to facilitate possible switching in the future, refer to
|
|
* https://github.com/torvalds/linux/blob/v6.9/arch/riscv/include/uapi/asm/hwprobe.h.
|
|
*/
|
|
typedef enum {
|
|
FEATURE_VECTOR = 2, /**< Vector extension. */
|
|
} feature_bit_t;
|
|
#endif
|
|
|
|
/* Make sure to keep this in sync with proc_get_cache_size_str() in proc.c. */
|
|
/**
|
|
* L1 and L2 cache sizes, used by proc_get_L1_icache_size(),
|
|
* proc_get_L1_dcache_size(), proc_get_L2_cache_size(), and
|
|
* proc_get_cache_size_str().
|
|
*/
|
|
typedef enum {
|
|
CACHE_SIZE_8_KB, /**< L1 or L2 cache size of 8 KB. */
|
|
CACHE_SIZE_16_KB, /**< L1 or L2 cache size of 16 KB. */
|
|
CACHE_SIZE_32_KB, /**< L1 or L2 cache size of 32 KB. */
|
|
CACHE_SIZE_64_KB, /**< L1 or L2 cache size of 64 KB. */
|
|
CACHE_SIZE_128_KB, /**< L1 or L2 cache size of 128 KB. */
|
|
CACHE_SIZE_256_KB, /**< L1 or L2 cache size of 256 KB. */
|
|
CACHE_SIZE_512_KB, /**< L1 or L2 cache size of 512 KB. */
|
|
CACHE_SIZE_1_MB, /**< L1 or L2 cache size of 1 MB. */
|
|
CACHE_SIZE_2_MB, /**< L1 or L2 cache size of 2 MB. */
|
|
CACHE_SIZE_UNKNOWN, /**< Unknown L1 or L2 cache size. */
|
|
CACHE_SIZE_48_KB, /**< L1 or L2 cache size of 48 KB. */
|
|
} cache_size_t;
|
|
|
|
DR_API
|
|
/** Returns the cache line size in bytes of the processor. */
|
|
size_t
|
|
proc_get_cache_line_size(void);
|
|
|
|
DR_API
|
|
/** Returns true only if \p addr is cache-line-aligned. */
|
|
bool
|
|
proc_is_cache_aligned(void *addr);
|
|
|
|
DR_API
|
|
/** Returns n >= \p sz such that n is a multiple of the cache line size. */
|
|
ptr_uint_t
|
|
proc_bump_to_end_of_cache_line(ptr_uint_t sz);
|
|
|
|
DR_API
|
|
/** Returns n <= \p addr such that n is a multiple of the page size. */
|
|
void *
|
|
proc_get_containing_page(void *addr);
|
|
|
|
DR_API
|
|
/** Returns one of the VENDOR_ constants. */
|
|
uint
|
|
proc_get_vendor(void);
|
|
|
|
DR_API
|
|
/**
|
|
* Sets the vendor to the given VENDOR_ constant.
|
|
* This function is supplied to support decoding or encoding with respect to
|
|
* other than the current processor being executed on. The change in vendor
|
|
* will be seen by the decoder and encoder, as well as the rest of the
|
|
* system.
|
|
* \return the prior vendor, or -1 on an invalid argument.
|
|
*/
|
|
int
|
|
proc_set_vendor(uint new_vendor);
|
|
|
|
DR_API
|
|
/**
|
|
* Returns the processor family as given by the cpuid instruction,
|
|
* adjusted by the extended family as described in the Intel documentation.
|
|
* The FAMILY_ constants identify important family values.
|
|
*/
|
|
uint
|
|
proc_get_family(void);
|
|
|
|
DR_API
|
|
/** Returns the processor type as given by the cpuid instruction. */
|
|
uint
|
|
proc_get_type(void);
|
|
|
|
DR_API
|
|
/**
|
|
* Returns the processor model as given by the cpuid instruction,
|
|
* adjusted by the extended model as described in the Intel documentation.
|
|
* The MODEL_ constants identify important model values.
|
|
*/
|
|
uint
|
|
proc_get_model(void);
|
|
|
|
DR_API
|
|
/** Returns the processor stepping ID. */
|
|
uint
|
|
proc_get_stepping(void);
|
|
|
|
DR_API
|
|
/** Tests if processor has selected feature. */
|
|
bool
|
|
proc_has_feature(feature_bit_t feature);
|
|
|
|
#if defined(AARCH64) && defined(BUILD_TESTS)
|
|
DR_API
|
|
/**
|
|
* Allows overriding the available state of CPU features.
|
|
* This is only for unit testing and offline decode, and must be called after
|
|
* proc_init_arch() (e.g. after dr_standalone_init() or dr_app_setup()).
|
|
*/
|
|
void
|
|
proc_set_feature(feature_bit_t f, bool enable);
|
|
|
|
DR_API
|
|
/**
|
|
* Uses proc_set_feature() to forcibly enable CPU features for unit testing and offline
|
|
* decode.
|
|
*/
|
|
void
|
|
enable_all_test_cpu_features(void);
|
|
#endif
|
|
|
|
DR_API
|
|
/**
|
|
* Returns all 4 32-bit feature values on X86 and architectural feature
|
|
* registers' values on AArch64. Use proc_has_feature() to test for specific
|
|
* features.
|
|
*/
|
|
features_t *
|
|
proc_get_all_feature_bits(void);
|
|
|
|
DR_API
|
|
/** Returns the processor brand string as given by the cpuid instruction. */
|
|
char *
|
|
proc_get_brand_string(void);
|
|
|
|
DR_API
|
|
/** Returns the size of the L1 instruction cache. */
|
|
cache_size_t
|
|
proc_get_L1_icache_size(void);
|
|
|
|
DR_API
|
|
/** Returns the size of the L1 data cache. */
|
|
cache_size_t
|
|
proc_get_L1_dcache_size(void);
|
|
|
|
DR_API
|
|
/** Returns the size of the L2 cache. */
|
|
cache_size_t
|
|
proc_get_L2_cache_size(void);
|
|
|
|
DR_API
|
|
/** Converts a cache_size_t type to a string. */
|
|
const char *
|
|
proc_get_cache_size_str(cache_size_t size);
|
|
|
|
#if defined(AARCHXX)
|
|
DR_API
|
|
/**
|
|
* Returns the size in bytes of the SVE registers' vector length set by the
|
|
* AArch64 hardware implementor. Length can be from 128 to 2048 bits in
|
|
* multiples of 128 bits:
|
|
* 128 256 384 512 640 768 896 1024 1152 1280 1408 1536 1664 1792 1920 2048
|
|
* Currently DynamoRIO supports implementations of up to 512 bits.
|
|
*/
|
|
uint
|
|
proc_get_vector_length_bytes(void);
|
|
#elif defined(RISCV64)
|
|
DR_API
|
|
/**
|
|
* Returns the size in bytes of the RVV registers' vector length which is a design-time
|
|
* constant set by the hardware implementor. Length can be from 64 to 65536 bits
|
|
* in the power of 2.
|
|
* Currently DynamoRIO supports implementations of up to 256 bits.
|
|
*/
|
|
uint
|
|
proc_get_vector_length_bytes(void);
|
|
#endif
|
|
|
|
DR_API
|
|
/**
|
|
* Returns the size in bytes needed for a buffer for saving the x87 floating point state.
|
|
*/
|
|
size_t
|
|
proc_fpstate_save_size(void);
|
|
|
|
DR_API
|
|
/**
|
|
* Returns the number of SIMD registers preserved for a context switch. DynamoRIO
|
|
* may decide to optimize the number of registers saved, in which case this number
|
|
* may be less than proc_num_simd_registers(). For x86 this only includes xmm/ymm/zmm.
|
|
*
|
|
* The number of saved SIMD registers may be variable. For example, we may decide
|
|
* to optimize the number of saved registers in a context switch to avoid frequency
|
|
* scaling (https://github.com/DynamoRIO/dynamorio/issues/3169).
|
|
*/
|
|
/* PR 306394: for 32-bit xmm0-7 are caller-saved, and are touched by
|
|
* libc routines invoked by DR in some Linux systems (xref i#139),
|
|
* so they should be saved in 32-bit Linux.
|
|
*
|
|
* Xref i#139:
|
|
* XMM register preservation will cause extra runtime overhead.
|
|
* We test it over 32-bit SPEC2006 on a 64-bit Debian Linux, which shows
|
|
* that DR with xmm preservation adds negligible overhead over DR without
|
|
* xmm preservation.
|
|
* It means xmm preservation would have little performance impact over
|
|
* DR base system. This is mainly because DR's own operations' overhead
|
|
* is much higher than the context switch overhead.
|
|
* However, if a program is running with a DR client which performs many
|
|
* clean calls (one or more per basic block), xmm preservation may
|
|
* have noticable impacts, i.e. pushing bbs over the max size limit,
|
|
* and could have a noticeable performance hit.
|
|
*/
|
|
int
|
|
proc_num_simd_saved(void);
|
|
|
|
DR_API
|
|
/**
|
|
* Returns the number of SIMD registers. The number returned here depends on the
|
|
* processor and OS feature bits on a given machine. For x86 this only includes
|
|
* xmm/ymm/zmm.
|
|
*
|
|
*/
|
|
int
|
|
proc_num_simd_registers(void);
|
|
|
|
DR_API
|
|
/**
|
|
* Returns the number of AVX-512 mask registers. The number returned here depends on the
|
|
* processor and OS feature bits on a given machine.
|
|
*
|
|
*/
|
|
int
|
|
proc_num_opmask_registers(void);
|
|
|
|
DR_API
|
|
/**
|
|
* Saves the x87 floating point state into the buffer \p buf.
|
|
*
|
|
* On x86, the buffer must be 16-byte-aligned, and it must be
|
|
* 512 (#DR_FPSTATE_BUF_SIZE) bytes for processors with the FXSR feature,
|
|
* and 108 bytes for those without (where this routine does not support
|
|
* 16-bit operand sizing). On ARM/AArch64, nothing needs to be saved as the
|
|
* SIMD/FP registers are saved together with the general-purpose registers.
|
|
*
|
|
* \note proc_fpstate_save_size() can be used to determine the particular
|
|
* size needed.
|
|
*
|
|
* When the FXSR feature is present, the fxsave format matches the bitwidth
|
|
* of the ISA mode of the current thread (see dr_get_isa_mode()).
|
|
*
|
|
* The last floating-point instruction address is left in an
|
|
* untranslated state (i.e., it may point into the code cache).
|
|
*
|
|
* DR does NOT save the application's x87 floating-point or MMX state
|
|
* on context switches! Thus if a client performs any floating-point
|
|
* operations in its main routines called by DR and cannot prove that its
|
|
* compiler will not use x87 operations, the client must save
|
|
* and restore the x87 floating-point/MMX state.
|
|
* If the client needs to do so inside the code cache the client should implement
|
|
* that itself.
|
|
* \note Floating-point state handling applies only to managed DynamoRIO modes.
|
|
* In standalone decoder mode, this routine is stubbed out and does not save
|
|
* any state; standalone decoding does not execute application code and does not
|
|
* manage x87/SSE state.
|
|
* Returns number of bytes written.
|
|
*/
|
|
size_t
|
|
proc_save_fpstate(byte *buf);
|
|
|
|
DR_API
|
|
/**
|
|
* Restores the x87 floating point state from the buffer \p buf.
|
|
* On x86, the buffer must be 16-byte-aligned, and it must be
|
|
* 512 (#DR_FPSTATE_BUF_SIZE) bytes for processors with the FXSR feature,
|
|
* and 108 bytes for those without (where this routine does not support
|
|
* 16-bit operand sizing). On ARM/AArch64, nothing needs to be restored as the
|
|
* SIMD/FP registers are restored together with the general-purpose registers.
|
|
*
|
|
* \note proc_fpstate_save_size() can be used to determine the particular
|
|
* size needed.
|
|
*
|
|
* When the FXSR feature is present, the fxsave format matches the bitwidth
|
|
* of the ISA mode of the current thread (see dr_get_isa_mode()).
|
|
* \note Floating-point state handling applies only to managed DynamoRIO modes.
|
|
* In standalone decoder mode, this routine is stubbed out and does not restore
|
|
* any state.
|
|
*/
|
|
void
|
|
proc_restore_fpstate(byte *buf);
|
|
|
|
DR_API
|
|
/**
|
|
* Returns whether AVX (or AVX2) is enabled by both the processor and the OS.
|
|
* Even if the processor supports AVX, if the OS does not enable AVX, then
|
|
* AVX instructions will fault.
|
|
*/
|
|
bool
|
|
proc_avx_enabled(void);
|
|
|
|
DR_API
|
|
/**
|
|
* Returns whether AVX-512 is enabled by both the processor and the OS.
|
|
* Even if the processor supports AVX-512, if the OS does not enable AVX-512,
|
|
* then AVX-512 instructions will fault.
|
|
*/
|
|
bool
|
|
proc_avx512_enabled(void);
|
|
|
|
#endif /* _DR_PROC_H_ */
|