1 /**
2 * Copyright (c) 2022-2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #ifndef PANDA_VERIFICATION_UTIL_MEM_H
16 #define PANDA_VERIFICATION_UTIL_MEM_H
17
18 #include <cstdint>
19 #include "libpandabase/macros.h"
20
21 namespace ark::verifier {
22
23 /* We are using the fact that on every operating system some of the process's virtual memory space
24 is unavailable for allocation -- for example, it may be reserved for kernel memory.
25
26 For Linux:
27 https://linux-kernel-labs.github.io/refs/heads/master/lectures/address-space.html
28
29 Linux is using a split address space for 32 bit systems, although in the past there
30 were options for supporting 4/4s split or dedicated kernel address space (on those
31 architecture that supports it, e.g. x86). Linux always uses split address space for 64 bit systems.
32
33 [For 32-bit Linux, the split is usually 3/1, i.e. 0x00000000-0xc0000000 is user space,
34 0xc0000000-0xffffffff is kernel space]
35
36 For Windows: https://learn.microsoft.com/en-us/windows-hardware/drivers/gettingstarted/virtual-address-spaces
37
38 For a 32-bit process, the virtual address space is usually the 2-gigabyte range 0x00000000
39 through 0x7FFFFFFF.
40 For a 64-bit process on 64-bit Windows, the virtual address space is the 128-terabyte range
41 0x000'00000000 through 0x7FFF'FFFFFFFF.
42 */
43
44 /* Works on Linux and Windows. Might need adjustment for other OSes */
45
46 size_t constexpr POINTER_CHECK_SHIFT = sizeof(uintptr_t) * 8 - 4;
47 // NOLINTNEXTLINE(hicpp-signed-bitwise)
48 uintptr_t constexpr POINTER_CHECK_MASK = 0xfL << POINTER_CHECK_SHIFT;
49 uintptr_t constexpr NOT_POINTER = POINTER_CHECK_MASK;
50
51 size_t constexpr TAG_SHIFT = sizeof(uintptr_t) * 8 - 8;
52 // NOLINTNEXTLINE(hicpp-signed-bitwise)
53 uintptr_t constexpr TAG_MASK = 0xfL << TAG_SHIFT;
54
55 uintptr_t constexpr PAYLOAD_MASK = ~(POINTER_CHECK_MASK | TAG_MASK);
56
IsNotPointer(uintptr_t x)57 ALWAYS_INLINE inline bool IsNotPointer(uintptr_t x)
58 {
59 return (x & POINTER_CHECK_MASK) == NOT_POINTER;
60 }
61
IsPointer(uintptr_t x)62 ALWAYS_INLINE inline bool IsPointer(uintptr_t x)
63 {
64 return !IsNotPointer(x);
65 }
66
GetTag(uintptr_t x)67 ALWAYS_INLINE inline int GetTag(uintptr_t x)
68 {
69 ASSERT(IsNotPointer(x));
70 return (x & TAG_MASK) >> TAG_SHIFT;
71 }
72
GetPayload(uintptr_t x)73 ALWAYS_INLINE inline uintptr_t GetPayload(uintptr_t x)
74 {
75 ASSERT(IsNotPointer(x));
76 return x & PAYLOAD_MASK;
77 }
78
GetPointer(uintptr_t x)79 ALWAYS_INLINE inline uintptr_t GetPointer(uintptr_t x)
80 {
81 ASSERT(IsPointer(x));
82 return x;
83 }
84
ConstructWithTag(int tag, uintptr_t v)85 ALWAYS_INLINE inline uintptr_t ConstructWithTag(int tag, uintptr_t v)
86 {
87 // NOLINTNEXTLINE(hicpp-signed-bitwise)
88 ASSERT(tag < (1 << 4U));
89 ASSERT(v < (1UL << TAG_SHIFT));
90 return NOT_POINTER | (static_cast<uintptr_t>(tag) << TAG_SHIFT) | v;
91 }
92
93 } // namespace ark::verifier
94
95 #endif /* PANDA_VERIFICATION_UTIL_MEM_H */
96