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