181 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9#include "SubprocessMemory.h"10#include "Error.h"11#include "llvm/ADT/ScopeExit.h"12#include "llvm/Support/Error.h"13#include "llvm/Support/FormatVariadic.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#endif22 23namespace llvm {24namespace exegesis {25 26#if defined(__linux__)27 28// The SYS_* macros for system calls are provided by the libc whereas the29// __NR_* macros are from the linux headers. This means that sometimes30// SYS_* macros might not be available for certain system calls depending31// upon the libc. This happens with the gettid syscall and bionic for32// example, so we use __NR_gettid when no SYS_gettid is available.33#ifndef SYS_gettid34#define SYS_gettid __NR_gettid35#endif36 37long SubprocessMemory::getCurrentTID() {38 // We're using the raw syscall here rather than the gettid() function provided39 // by most libcs for compatibility as gettid() was only added to glibc in40 // version 2.30.41 return syscall(SYS_gettid);42}43 44#if !defined(__ANDROID__)45 46Error SubprocessMemory::initializeSubprocessMemory(pid_t ProcessID) {47 // Add the PID to the shared memory name so that if we're running multiple48 // processes at the same time, they won't interfere with each other.49 // This comes up particularly often when running the exegesis tests with50 // llvm-lit. Additionally add the TID so that downstream consumers51 // using multiple threads don't run into conflicts.52 std::string AuxiliaryMemoryName =53 formatv("/{0}auxmem{1}", getCurrentTID(), ProcessID);54 int AuxiliaryMemoryFD = shm_open(AuxiliaryMemoryName.c_str(),55 O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);56 if (AuxiliaryMemoryFD == -1)57 return make_error<Failure>(58 "Failed to create shared memory object for auxiliary memory: " +59 Twine(strerror(errno)));60 auto AuxiliaryMemoryFDClose =61 make_scope_exit([AuxiliaryMemoryFD]() { close(AuxiliaryMemoryFD); });62 if (ftruncate(AuxiliaryMemoryFD, AuxiliaryMemorySize) != 0) {63 return make_error<Failure>("Truncating the auxiliary memory failed: " +64 Twine(strerror(errno)));65 }66 SharedMemoryNames.push_back(AuxiliaryMemoryName);67 return Error::success();68}69 70Error SubprocessMemory::addMemoryDefinition(71 std::unordered_map<std::string, MemoryValue> MemoryDefinitions,72 pid_t ProcessPID) {73 SharedMemoryNames.reserve(MemoryDefinitions.size());74 for (auto &[Name, MemVal] : MemoryDefinitions) {75 std::string SharedMemoryName =76 formatv("/{0}t{1}memdef{2}", ProcessPID, getCurrentTID(), MemVal.Index);77 SharedMemoryNames.push_back(SharedMemoryName);78 int SharedMemoryFD =79 shm_open(SharedMemoryName.c_str(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);80 if (SharedMemoryFD == -1)81 return make_error<Failure>(82 "Failed to create shared memory object for memory definition: " +83 Twine(strerror(errno)));84 auto SharedMemoryFDClose =85 make_scope_exit([SharedMemoryFD]() { close(SharedMemoryFD); });86 if (ftruncate(SharedMemoryFD, MemVal.SizeBytes) != 0) {87 return make_error<Failure>("Truncating a memory definiton failed: " +88 Twine(strerror(errno)));89 }90 91 char *SharedMemoryMapping =92 (char *)mmap(NULL, MemVal.SizeBytes, PROT_READ | PROT_WRITE, MAP_SHARED,93 SharedMemoryFD, 0);94 // fill the buffer with the specified value95 size_t CurrentByte = 0;96 const size_t ValueWidthBytes = MemVal.Value.getBitWidth() / 8;97 while (CurrentByte < MemVal.SizeBytes - ValueWidthBytes) {98 memcpy(SharedMemoryMapping + CurrentByte, MemVal.Value.getRawData(),99 ValueWidthBytes);100 CurrentByte += ValueWidthBytes;101 }102 // fill the last section103 memcpy(SharedMemoryMapping + CurrentByte, MemVal.Value.getRawData(),104 MemVal.SizeBytes - CurrentByte);105 if (munmap(SharedMemoryMapping, MemVal.SizeBytes) != 0) {106 return make_error<Failure>(107 "Unmapping a memory definition in the parent failed: " +108 Twine(strerror(errno)));109 }110 }111 return Error::success();112}113 114Expected<int> SubprocessMemory::setupAuxiliaryMemoryInSubprocess(115 std::unordered_map<std::string, MemoryValue> MemoryDefinitions,116 pid_t ParentPID, long ParentTID, int CounterFileDescriptor) {117 std::string AuxiliaryMemoryName =118 formatv("/{0}auxmem{1}", ParentTID, ParentPID);119 int AuxiliaryMemoryFileDescriptor =120 shm_open(AuxiliaryMemoryName.c_str(), O_RDWR, S_IRUSR | S_IWUSR);121 if (AuxiliaryMemoryFileDescriptor == -1)122 return make_error<Failure>(123 "Getting file descriptor for auxiliary memory failed: " +124 Twine(strerror(errno)));125 // set up memory value file descriptors126 int *AuxiliaryMemoryMapping =127 (int *)mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED,128 AuxiliaryMemoryFileDescriptor, 0);129 if (reinterpret_cast<intptr_t>(AuxiliaryMemoryMapping) == -1)130 return make_error<Failure>("Mapping auxiliary memory failed");131 AuxiliaryMemoryMapping[0] = CounterFileDescriptor;132 for (auto &[Name, MemVal] : MemoryDefinitions) {133 std::string MemoryValueName =134 formatv("/{0}t{1}memdef{2}", ParentPID, ParentTID, MemVal.Index);135 AuxiliaryMemoryMapping[AuxiliaryMemoryOffset + MemVal.Index] =136 shm_open(MemoryValueName.c_str(), O_RDWR, S_IRUSR | S_IWUSR);137 if (AuxiliaryMemoryMapping[AuxiliaryMemoryOffset + MemVal.Index] == -1)138 return make_error<Failure>("Mapping shared memory failed");139 }140 if (munmap(AuxiliaryMemoryMapping, 4096) == -1)141 return make_error<Failure>("Unmapping auxiliary memory failed");142 return AuxiliaryMemoryFileDescriptor;143}144 145SubprocessMemory::~SubprocessMemory() {146 for (const std::string &SharedMemoryName : SharedMemoryNames) {147 if (shm_unlink(SharedMemoryName.c_str()) != 0) {148 errs() << "Failed to unlink shared memory section: " << strerror(errno)149 << "\n";150 }151 }152}153 154#else155 156Error SubprocessMemory::initializeSubprocessMemory(pid_t ProcessPID) {157 return make_error<Failure>(158 "initializeSubprocessMemory is only supported on Linux");159}160 161Error SubprocessMemory::addMemoryDefinition(162 std::unordered_map<std::string, MemoryValue> MemoryDefinitions,163 pid_t ProcessPID) {164 return make_error<Failure>("addMemoryDefinitions is only supported on Linux");165}166 167Expected<int> SubprocessMemory::setupAuxiliaryMemoryInSubprocess(168 std::unordered_map<std::string, MemoryValue> MemoryDefinitions,169 pid_t ParentPID, long ParentTID, int CounterFileDescriptor) {170 return make_error<Failure>(171 "setupAuxiliaryMemoryInSubprocess is only supported on Linux");172}173 174SubprocessMemory::~SubprocessMemory() {}175 176#endif // !defined(__ANDROID__)177#endif // defined(__linux__)178 179} // namespace exegesis180} // namespace llvm181