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 | |