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