1 | //===-- SubprocessMemory.cpp ------------------------------------*- 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 | #include "SubprocessMemory.h" |
10 | #include "Error.h" |
11 | #include "llvm/ADT/ScopeExit.h" |
12 | #include "llvm/Support/Error.h" |
13 | #include "llvm/Support/FormatVariadic.h" |
14 | #include <cerrno> |
15 | |
16 | #ifdef __linux__ |
17 | #include <fcntl.h> |
18 | #include <sys/mman.h> |
19 | #include <sys/syscall.h> |
20 | #include <unistd.h> |
21 | #endif |
22 | |
23 | namespace llvm { |
24 | namespace exegesis { |
25 | |
26 | #if defined(__linux__) |
27 | |
28 | // The SYS_* macros for system calls are provided by the libc whereas the |
29 | // __NR_* macros are from the linux headers. This means that sometimes |
30 | // SYS_* macros might not be available for certain system calls depending |
31 | // upon the libc. This happens with the gettid syscall and bionic for |
32 | // example, so we use __NR_gettid when no SYS_gettid is available. |
33 | #ifndef SYS_gettid |
34 | #define SYS_gettid __NR_gettid |
35 | #endif |
36 | |
37 | long SubprocessMemory::getCurrentTID() { |
38 | // We're using the raw syscall here rather than the gettid() function provided |
39 | // by most libcs for compatibility as gettid() was only added to glibc in |
40 | // version 2.30. |
41 | return syscall(SYS_gettid); |
42 | } |
43 | |
44 | #if !defined(__ANDROID__) |
45 | |
46 | Error SubprocessMemory::initializeSubprocessMemory(pid_t ProcessID) { |
47 | // Add the PID to the shared memory name so that if we're running multiple |
48 | // processes at the same time, they won't interfere with each other. |
49 | // This comes up particularly often when running the exegesis tests with |
50 | // llvm-lit. Additionally add the TID so that downstream consumers |
51 | // using multiple threads don't run into conflicts. |
52 | std::string AuxiliaryMemoryName = |
53 | formatv(Fmt: "/{0}auxmem{1}" , Vals: getCurrentTID(), Vals&: ProcessID); |
54 | int AuxiliaryMemoryFD = shm_open(name: AuxiliaryMemoryName.c_str(), |
55 | O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); |
56 | if (AuxiliaryMemoryFD == -1) |
57 | return make_error<Failure>( |
58 | Args: "Failed to create shared memory object for auxiliary memory: " + |
59 | Twine(strerror(errno))); |
60 | auto AuxiliaryMemoryFDClose = |
61 | make_scope_exit(F: [AuxiliaryMemoryFD]() { close(fd: AuxiliaryMemoryFD); }); |
62 | if (ftruncate(fd: AuxiliaryMemoryFD, length: AuxiliaryMemorySize) != 0) { |
63 | return make_error<Failure>(Args: "Truncating the auxiliary memory failed: " + |
64 | Twine(strerror(errno))); |
65 | } |
66 | SharedMemoryNames.push_back(x: AuxiliaryMemoryName); |
67 | return Error::success(); |
68 | } |
69 | |
70 | Error SubprocessMemory::addMemoryDefinition( |
71 | std::unordered_map<std::string, MemoryValue> MemoryDefinitions, |
72 | pid_t ProcessPID) { |
73 | SharedMemoryNames.reserve(n: MemoryDefinitions.size()); |
74 | for (auto &[Name, MemVal] : MemoryDefinitions) { |
75 | std::string SharedMemoryName = |
76 | formatv(Fmt: "/{0}t{1}memdef{2}" , Vals&: ProcessPID, Vals: getCurrentTID(), Vals&: MemVal.Index); |
77 | SharedMemoryNames.push_back(x: SharedMemoryName); |
78 | int SharedMemoryFD = |
79 | shm_open(name: SharedMemoryName.c_str(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); |
80 | if (SharedMemoryFD == -1) |
81 | return make_error<Failure>( |
82 | Args: "Failed to create shared memory object for memory definition: " + |
83 | Twine(strerror(errno))); |
84 | auto SharedMemoryFDClose = |
85 | make_scope_exit(F: [SharedMemoryFD]() { close(fd: SharedMemoryFD); }); |
86 | if (ftruncate(fd: SharedMemoryFD, length: MemVal.SizeBytes) != 0) { |
87 | return make_error<Failure>(Args: "Truncating a memory definiton failed: " + |
88 | Twine(strerror(errno))); |
89 | } |
90 | |
91 | char *SharedMemoryMapping = |
92 | (char *)mmap(NULL, len: MemVal.SizeBytes, PROT_READ | PROT_WRITE, MAP_SHARED, |
93 | fd: SharedMemoryFD, offset: 0); |
94 | // fill the buffer with the specified value |
95 | size_t CurrentByte = 0; |
96 | const size_t ValueWidthBytes = MemVal.Value.getBitWidth() / 8; |
97 | while (CurrentByte < MemVal.SizeBytes - ValueWidthBytes) { |
98 | memcpy(dest: SharedMemoryMapping + CurrentByte, src: MemVal.Value.getRawData(), |
99 | n: ValueWidthBytes); |
100 | CurrentByte += ValueWidthBytes; |
101 | } |
102 | // fill the last section |
103 | memcpy(dest: SharedMemoryMapping + CurrentByte, src: MemVal.Value.getRawData(), |
104 | n: MemVal.SizeBytes - CurrentByte); |
105 | if (munmap(addr: SharedMemoryMapping, len: MemVal.SizeBytes) != 0) { |
106 | return make_error<Failure>( |
107 | Args: "Unmapping a memory definition in the parent failed: " + |
108 | Twine(strerror(errno))); |
109 | } |
110 | } |
111 | return Error::success(); |
112 | } |
113 | |
114 | Expected<int> SubprocessMemory::setupAuxiliaryMemoryInSubprocess( |
115 | std::unordered_map<std::string, MemoryValue> MemoryDefinitions, |
116 | pid_t ParentPID, long ParentTID, int CounterFileDescriptor) { |
117 | std::string AuxiliaryMemoryName = |
118 | formatv(Fmt: "/{0}auxmem{1}" , Vals&: ParentTID, Vals&: ParentPID); |
119 | int AuxiliaryMemoryFileDescriptor = |
120 | shm_open(name: AuxiliaryMemoryName.c_str(), O_RDWR, S_IRUSR | S_IWUSR); |
121 | if (AuxiliaryMemoryFileDescriptor == -1) |
122 | return make_error<Failure>( |
123 | Args: "Getting file descriptor for auxiliary memory failed: " + |
124 | Twine(strerror(errno))); |
125 | // set up memory value file descriptors |
126 | int *AuxiliaryMemoryMapping = |
127 | (int *)mmap(NULL, len: 4096, PROT_READ | PROT_WRITE, MAP_SHARED, |
128 | fd: AuxiliaryMemoryFileDescriptor, offset: 0); |
129 | if ((intptr_t)AuxiliaryMemoryMapping == -1) |
130 | return make_error<Failure>(Args: "Mapping auxiliary memory failed" ); |
131 | AuxiliaryMemoryMapping[0] = CounterFileDescriptor; |
132 | for (auto &[Name, MemVal] : MemoryDefinitions) { |
133 | std::string MemoryValueName = |
134 | formatv(Fmt: "/{0}t{1}memdef{2}" , Vals&: ParentPID, Vals&: ParentTID, Vals&: MemVal.Index); |
135 | AuxiliaryMemoryMapping[AuxiliaryMemoryOffset + MemVal.Index] = |
136 | shm_open(name: MemoryValueName.c_str(), O_RDWR, S_IRUSR | S_IWUSR); |
137 | if (AuxiliaryMemoryMapping[AuxiliaryMemoryOffset + MemVal.Index] == -1) |
138 | return make_error<Failure>(Args: "Mapping shared memory failed" ); |
139 | } |
140 | if (munmap(addr: AuxiliaryMemoryMapping, len: 4096) == -1) |
141 | return make_error<Failure>(Args: "Unmapping auxiliary memory failed" ); |
142 | return AuxiliaryMemoryFileDescriptor; |
143 | } |
144 | |
145 | SubprocessMemory::~SubprocessMemory() { |
146 | for (const std::string &SharedMemoryName : SharedMemoryNames) { |
147 | if (shm_unlink(name: SharedMemoryName.c_str()) != 0) { |
148 | errs() << "Failed to unlink shared memory section: " << strerror(errno) |
149 | << "\n" ; |
150 | } |
151 | } |
152 | } |
153 | |
154 | #else |
155 | |
156 | Error SubprocessMemory::initializeSubprocessMemory(pid_t ProcessPID) { |
157 | return make_error<Failure>( |
158 | "initializeSubprocessMemory is only supported on Linux" ); |
159 | } |
160 | |
161 | Error SubprocessMemory::addMemoryDefinition( |
162 | std::unordered_map<std::string, MemoryValue> MemoryDefinitions, |
163 | pid_t ProcessPID) { |
164 | return make_error<Failure>("addMemoryDefinitions is only supported on Linux" ); |
165 | } |
166 | |
167 | Expected<int> SubprocessMemory::setupAuxiliaryMemoryInSubprocess( |
168 | std::unordered_map<std::string, MemoryValue> MemoryDefinitions, |
169 | pid_t ParentPID, long ParentTID, int CounterFileDescriptor) { |
170 | return make_error<Failure>( |
171 | "setupAuxiliaryMemoryInSubprocess is only supported on Linux" ); |
172 | } |
173 | |
174 | SubprocessMemory::~SubprocessMemory() {} |
175 | |
176 | #endif // !defined(__ANDROID__) |
177 | #endif // defined(__linux__) |
178 | |
179 | } // namespace exegesis |
180 | } // namespace llvm |
181 | |