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