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 | // +--------------------+ 0x440000008000 |
44 | // | allocator | |
45 | // +--------------------+ 0x400000000000 (kHeapMemBeg) |
46 | // | shadow memory | |
47 | // +--------------------+ 0x200000000000 (kShadowAddr) |
48 | // | shadow types | |
49 | // +--------------------+ 0x100000000000 (kTypesAddr) |
50 | // | reserved by kernel | |
51 | // +--------------------+ 0x000000000000 |
52 | // |
53 | // |
54 | // To derive a shadow memory address from an application memory address, |
55 | // bits 44-46 are cleared to bring the address into the range |
56 | // [0x000000000000,0x100000000000). We scale to account for the fact that a |
57 | // shadow value takes twice as much space as the original value. |
58 | // Then we add kShadowAddr to put the shadow relative offset into the shadow |
59 | // memory. See getShadowAddrFor(). |
60 | // The process is similar for the shadow types. |
61 | |
62 | // The ratio of app to shadow memory. |
63 | enum { kShadowScale = 2 }; |
64 | |
65 | // The original value type of a byte in app memory. Uses LLVM terminology: |
66 | // https://llvm.org/docs/LangRef.html#floating-point-types |
67 | // FIXME: support half and bfloat. |
68 | enum ValueType { |
69 | kUnknownValueType = 0, |
70 | kFloatValueType = 1, // LLVM float, shadow type double. |
71 | kDoubleValueType = 2, // LLVM double, shadow type fp128. |
72 | kFp80ValueType = 3, // LLVM x86_fp80, shadow type fp128. |
73 | }; |
74 | |
75 | // The size of ValueType encoding, in bits. |
76 | enum { |
77 | kValueSizeSizeBits = 2, |
78 | }; |
79 | |
80 | #if defined(__x86_64__) |
81 | struct Mapping { |
82 | // FIXME: kAppAddr == 0x700000000000 ? |
83 | static const uptr kAppAddr = 0x700000008000; |
84 | static const uptr kHeapMemBeg = 0x400000000000; |
85 | static const uptr kShadowAddr = 0x200000000000; |
86 | static const uptr kTypesAddr = 0x100000000000; |
87 | static const uptr kShadowMask = ~0x700000000000; |
88 | }; |
89 | #else |
90 | #error "NSan not supported for this platform!" |
91 | #endif |
92 | |
93 | enum MappingType { |
94 | MAPPING_APP_ADDR, |
95 | MAPPING_ALLOCATOR_ADDR, |
96 | MAPPING_SHADOW_ADDR, |
97 | MAPPING_TYPES_ADDR, |
98 | MAPPING_SHADOW_MASK |
99 | }; |
100 | |
101 | template <typename Mapping, int Type> uptr MappingImpl() { |
102 | switch (Type) { |
103 | case MAPPING_APP_ADDR: |
104 | return Mapping::kAppAddr; |
105 | case MAPPING_ALLOCATOR_ADDR: |
106 | return Mapping::kHeapMemBeg; |
107 | case MAPPING_SHADOW_ADDR: |
108 | return Mapping::kShadowAddr; |
109 | case MAPPING_TYPES_ADDR: |
110 | return Mapping::kTypesAddr; |
111 | case MAPPING_SHADOW_MASK: |
112 | return Mapping::kShadowMask; |
113 | } |
114 | } |
115 | |
116 | template <int Type> uptr MappingArchImpl() { |
117 | return MappingImpl<Mapping, Type>(); |
118 | } |
119 | |
120 | ALWAYS_INLINE |
121 | uptr AppAddr() { return MappingArchImpl<MAPPING_APP_ADDR>(); } |
122 | |
123 | ALWAYS_INLINE |
124 | uptr AllocatorAddr() { return MappingArchImpl<MAPPING_ALLOCATOR_ADDR>(); } |
125 | |
126 | ALWAYS_INLINE |
127 | uptr ShadowAddr() { return MappingArchImpl<MAPPING_SHADOW_ADDR>(); } |
128 | |
129 | ALWAYS_INLINE |
130 | uptr TypesAddr() { return MappingArchImpl<MAPPING_TYPES_ADDR>(); } |
131 | |
132 | ALWAYS_INLINE |
133 | uptr ShadowMask() { return MappingArchImpl<MAPPING_SHADOW_MASK>(); } |
134 | |
135 | } // end namespace __nsan |
136 | |
137 | #endif |
138 | |