| //===-- SubprocessMemory.cpp ------------------------------------*- C++ -*-===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "SubprocessMemory.h" |
| #include "Error.h" |
| #include "llvm/Support/Error.h" |
| #include <cerrno> |
| |
| #ifdef __linux__ |
| #include <fcntl.h> |
| #include <sys/mman.h> |
| #include <unistd.h> |
| #endif |
| |
| namespace llvm { |
| namespace exegesis { |
| |
| #if defined(__linux__) && !defined(__ANDROID__) |
| |
| Error SubprocessMemory::initializeSubprocessMemory(pid_t ProcessID) { |
| // Add the PID to the shared memory name so that if we're running multiple |
| // processes at the same time, they won't interfere with each other. |
| // This comes up particularly often when running the exegesis tests with |
| // llvm-lit |
| std::string AuxiliaryMemoryName = "/auxmem" + std::to_string(ProcessID); |
| int AuxiliaryMemoryFD = shm_open(AuxiliaryMemoryName.c_str(), |
| O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); |
| if (AuxiliaryMemoryFD == -1) |
| return make_error<Failure>( |
| "Failed to create shared memory object for auxiliary memory: " + |
| Twine(strerror(errno))); |
| if (ftruncate(AuxiliaryMemoryFD, AuxiliaryMemorySize) != 0) { |
| return make_error<Failure>("Truncating the auxiliary memory failed: " + |
| Twine(strerror(errno))); |
| } |
| SharedMemoryNames.push_back(AuxiliaryMemoryName); |
| return Error::success(); |
| } |
| |
| Error SubprocessMemory::addMemoryDefinition( |
| std::unordered_map<std::string, MemoryValue> MemoryDefinitions, |
| pid_t ProcessPID) { |
| SharedMemoryNames.reserve(MemoryDefinitions.size()); |
| for (auto &[Name, MemVal] : MemoryDefinitions) { |
| std::string SharedMemoryName = "/" + std::to_string(ProcessPID) + "memdef" + |
| std::to_string(MemVal.Index); |
| SharedMemoryNames.push_back(SharedMemoryName); |
| int SharedMemoryFD = |
| shm_open(SharedMemoryName.c_str(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); |
| if (ftruncate(SharedMemoryFD, MemVal.SizeBytes) != 0) { |
| return make_error<Failure>("Truncating a memory definiton failed: " + |
| Twine(strerror(errno))); |
| } |
| |
| char *SharedMemoryMapping = |
| (char *)mmap(NULL, MemVal.SizeBytes, PROT_READ | PROT_WRITE, MAP_SHARED, |
| SharedMemoryFD, 0); |
| // fill the buffer with the specified value |
| size_t CurrentByte = 0; |
| const size_t ValueWidthBytes = MemVal.Value.getBitWidth() / 8; |
| while (CurrentByte < MemVal.SizeBytes - ValueWidthBytes) { |
| memcpy(SharedMemoryMapping + CurrentByte, MemVal.Value.getRawData(), |
| ValueWidthBytes); |
| CurrentByte += ValueWidthBytes; |
| } |
| // fill the last section |
| memcpy(SharedMemoryMapping + CurrentByte, MemVal.Value.getRawData(), |
| MemVal.SizeBytes - CurrentByte); |
| if (munmap(SharedMemoryMapping, MemVal.SizeBytes) != 0) { |
| return make_error<Failure>( |
| "Unmapping a memory definition in the parent failed: " + |
| Twine(strerror(errno))); |
| } |
| } |
| return Error::success(); |
| } |
| |
| Expected<int> SubprocessMemory::setupAuxiliaryMemoryInSubprocess( |
| std::unordered_map<std::string, MemoryValue> MemoryDefinitions, |
| pid_t ParentPID, int CounterFileDescriptor) { |
| std::string AuxiliaryMemoryName = "/auxmem" + std::to_string(ParentPID); |
| int AuxiliaryMemoryFileDescriptor = |
| shm_open(AuxiliaryMemoryName.c_str(), O_RDWR, S_IRUSR | S_IWUSR); |
| if (AuxiliaryMemoryFileDescriptor == -1) |
| return make_error<Failure>( |
| "Getting file descriptor for auxiliary memory failed"); |
| // set up memory value file descriptors |
| int *AuxiliaryMemoryMapping = |
| (int *)mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, |
| AuxiliaryMemoryFileDescriptor, 0); |
| if ((intptr_t)AuxiliaryMemoryMapping == -1) |
| return make_error<Failure>("Mapping auxiliary memory failed"); |
| AuxiliaryMemoryMapping[0] = CounterFileDescriptor; |
| for (auto &[Name, MemVal] : MemoryDefinitions) { |
| std::string MemoryValueName = "/" + std::to_string(ParentPID) + "memdef" + |
| std::to_string(MemVal.Index); |
| AuxiliaryMemoryMapping[AuxiliaryMemoryOffset + MemVal.Index] = |
| shm_open(MemoryValueName.c_str(), O_RDWR, S_IRUSR | S_IWUSR); |
| if (AuxiliaryMemoryMapping[AuxiliaryMemoryOffset + MemVal.Index] == -1) |
| return make_error<Failure>("Mapping shared memory failed"); |
| } |
| if (munmap(AuxiliaryMemoryMapping, 4096) == -1) |
| return make_error<Failure>("Unmapping auxiliary memory failed"); |
| return AuxiliaryMemoryFileDescriptor; |
| } |
| |
| SubprocessMemory::~SubprocessMemory() { |
| for (std::string SharedMemoryName : SharedMemoryNames) { |
| if (shm_unlink(SharedMemoryName.c_str()) != 0) { |
| errs() << "Failed to unlink shared memory section: " << strerror(errno) |
| << "\n"; |
| } |
| } |
| } |
| |
| #else |
| |
| Error SubprocessMemory::initializeSubprocessMemory(pid_t ProcessPID) { |
| return make_error<Failure>( |
| "initializeSubprocessMemory is only supported on Linux"); |
| } |
| |
| Error SubprocessMemory::addMemoryDefinition( |
| std::unordered_map<std::string, MemoryValue> MemoryDefinitions, |
| pid_t ProcessPID) { |
| return make_error<Failure>("addMemoryDefinitions is only supported on Linux"); |
| } |
| |
| Expected<int> SubprocessMemory::setupAuxiliaryMemoryInSubprocess( |
| std::unordered_map<std::string, MemoryValue> MemoryDefinitions, |
| pid_t ParentPID, int CounterFileDescriptor) { |
| return make_error<Failure>( |
| "setupAuxiliaryMemoryInSubprocess is only supported on Linux"); |
| } |
| |
| SubprocessMemory::~SubprocessMemory() {} |
| |
| #endif // defined(__linux__) && !defined(__ANDROID__) |
| |
| } // namespace exegesis |
| } // namespace llvm |