|
| 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 |
0 commit comments