1 //===------------------------ nsan_platform.h -------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // Platform specific information for NSan. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #ifndef NSAN_PLATFORM_H 14 #define NSAN_PLATFORM_H 15 16 namespace __nsan { 17 18 // NSan uses two regions of memory to store information: 19 // - 'shadow memory' stores the shadow copies of numerical values stored in 20 // application memory. 21 // - 'shadow types' is used to determine which value type each byte of memory 22 // belongs to. This makes sure that we always know whether a shadow value is 23 // valid. Shadow values may be tampered with using access through other 24 // pointer types (type punning). Each byte stores: 25 // - bit 1-0: whether the corresponding value is of unknown (00), 26 // float (01), double (10), or long double (11) type. 27 // - bit 5-2: the index of this byte in the value, or 0000 if type is 28 // unknown. 29 // This allows handling unaligned loat load/stores by checking that a load 30 // with a given alignment corresponds to the alignment of the store. 31 // Any store of a non-floating point type invalidates the corresponding 32 // bytes, so that subsequent overlapping loads (aligned or not) know that 33 // the corresponding shadow value is no longer valid. 34 35 // On Linux/x86_64, memory is laid out as follows: 36 // 37 // +--------------------+ 0x800000000000 (top of memory) 38 // | application memory | 39 // +--------------------+ 0x700000008000 (kAppAddr) 40 // | | 41 // | unused | 42 // | | 43 // +--------------------+ 0x400000000000 (kUnusedAddr) 44 // | shadow memory | 45 // +--------------------+ 0x200000000000 (kShadowAddr) 46 // | shadow types | 47 // +--------------------+ 0x100000000000 (kTypesAddr) 48 // | reserved by kernel | 49 // +--------------------+ 0x000000000000 50 // 51 // 52 // To derive a shadow memory address from an application memory address, 53 // bits 44-46 are cleared to bring the address into the range 54 // [0x000000000000,0x100000000000). We scale to account for the fact that a 55 // shadow value takes twice as much space as the original value. 56 // Then we add kShadowAddr to put the shadow relative offset into the shadow 57 // memory. See getShadowAddrFor(). 58 // The process is similar for the shadow types. 59 60 // The ratio of app to shadow memory. 61 enum { kShadowScale = 2 }; 62 63 // The original value type of a byte in app memory. Uses LLVM terminology: 64 // https://llvm.org/docs/LangRef.html#floating-point-types 65 // FIXME: support half and bfloat. 66 enum ValueType { 67 kUnknownValueType = 0, 68 kFloatValueType = 1, // LLVM float, shadow type double. 69 kDoubleValueType = 2, // LLVM double, shadow type fp128. 70 kFp80ValueType = 3, // LLVM x86_fp80, shadow type fp128. 71 }; 72 73 // The size of ValueType encoding, in bits. 74 enum { 75 kValueSizeSizeBits = 2, 76 }; 77 78 #if defined(__x86_64__) 79 struct Mapping { 80 // FIXME: kAppAddr == 0x700000000000 ? 81 static const uptr kAppAddr = 0x700000008000; 82 static const uptr kUnusedAddr = 0x400000000000; 83 static const uptr kShadowAddr = 0x200000000000; 84 static const uptr kTypesAddr = 0x100000000000; 85 static const uptr kShadowMask = ~0x700000000000; 86 }; 87 #else 88 #error "NSan not supported for this platform!" 89 #endif 90 91 enum MappingType { 92 MAPPING_APP_ADDR, 93 MAPPING_UNUSED_ADDR, 94 MAPPING_SHADOW_ADDR, 95 MAPPING_TYPES_ADDR, 96 MAPPING_SHADOW_MASK 97 }; 98 99 template <typename Mapping, int Type> uptr MappingImpl() { 100 switch (Type) { 101 case MAPPING_APP_ADDR: 102 return Mapping::kAppAddr; 103 case MAPPING_UNUSED_ADDR: 104 return Mapping::kUnusedAddr; 105 case MAPPING_SHADOW_ADDR: 106 return Mapping::kShadowAddr; 107 case MAPPING_TYPES_ADDR: 108 return Mapping::kTypesAddr; 109 case MAPPING_SHADOW_MASK: 110 return Mapping::kShadowMask; 111 } 112 } 113 114 template <int Type> uptr MappingArchImpl() { 115 return MappingImpl<Mapping, Type>(); 116 } 117 118 ALWAYS_INLINE 119 uptr AppAddr() { return MappingArchImpl<MAPPING_APP_ADDR>(); } 120 121 ALWAYS_INLINE 122 uptr UnusedAddr() { return MappingArchImpl<MAPPING_UNUSED_ADDR>(); } 123 124 ALWAYS_INLINE 125 uptr ShadowAddr() { return MappingArchImpl<MAPPING_SHADOW_ADDR>(); } 126 127 ALWAYS_INLINE 128 uptr TypesAddr() { return MappingArchImpl<MAPPING_TYPES_ADDR>(); } 129 130 ALWAYS_INLINE 131 uptr ShadowMask() { return MappingArchImpl<MAPPING_SHADOW_MASK>(); } 132 133 } // end namespace __nsan 134 135 #endif 136