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