15a63b2b3SAiden Grossman //===-- SubprocessMemory.cpp ------------------------------------*- C++ -*-===// 25a63b2b3SAiden Grossman // 35a63b2b3SAiden Grossman // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 45a63b2b3SAiden Grossman // See https://llvm.org/LICENSE.txt for license information. 55a63b2b3SAiden Grossman // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 65a63b2b3SAiden Grossman // 75a63b2b3SAiden Grossman //===----------------------------------------------------------------------===// 85a63b2b3SAiden Grossman 95a63b2b3SAiden Grossman #include "SubprocessMemory.h" 105a63b2b3SAiden Grossman #include "Error.h" 1174a5e778SAiden Grossman #include "llvm/ADT/ScopeExit.h" 125a63b2b3SAiden Grossman #include "llvm/Support/Error.h" 1350e62181SAiden Grossman #include "llvm/Support/FormatVariadic.h" 14e1b88a97SChristopher Di Bella #include <cerrno> 155a63b2b3SAiden Grossman 165a63b2b3SAiden Grossman #ifdef __linux__ 175a63b2b3SAiden Grossman #include <fcntl.h> 185a63b2b3SAiden Grossman #include <sys/mman.h> 1950e62181SAiden Grossman #include <sys/syscall.h> 205a63b2b3SAiden Grossman #include <unistd.h> 215a63b2b3SAiden Grossman #endif 225a63b2b3SAiden Grossman 235a63b2b3SAiden Grossman namespace llvm { 245a63b2b3SAiden Grossman namespace exegesis { 255a63b2b3SAiden Grossman 26a29e85d6SAiden Grossman #if defined(__linux__) 275a63b2b3SAiden Grossman 2861f40016SAiden Grossman // The SYS_* macros for system calls are provided by the libc whereas the 2961f40016SAiden Grossman // __NR_* macros are from the linux headers. This means that sometimes 3061f40016SAiden Grossman // SYS_* macros might not be available for certain system calls depending 3161f40016SAiden Grossman // upon the libc. This happens with the gettid syscall and bionic for 3261f40016SAiden Grossman // example, so we use __NR_gettid when no SYS_gettid is available. 3361f40016SAiden Grossman #ifndef SYS_gettid 3461f40016SAiden Grossman #define SYS_gettid __NR_gettid 3561f40016SAiden Grossman #endif 3661f40016SAiden Grossman 3750e62181SAiden Grossman long SubprocessMemory::getCurrentTID() { 3850e62181SAiden Grossman // We're using the raw syscall here rather than the gettid() function provided 3950e62181SAiden Grossman // by most libcs for compatibility as gettid() was only added to glibc in 4050e62181SAiden Grossman // version 2.30. 4150e62181SAiden Grossman return syscall(SYS_gettid); 4250e62181SAiden Grossman } 4350e62181SAiden Grossman 44a29e85d6SAiden Grossman #if !defined(__ANDROID__) 45a29e85d6SAiden Grossman 465a63b2b3SAiden Grossman Error SubprocessMemory::initializeSubprocessMemory(pid_t ProcessID) { 475a63b2b3SAiden Grossman // Add the PID to the shared memory name so that if we're running multiple 485a63b2b3SAiden Grossman // processes at the same time, they won't interfere with each other. 495a63b2b3SAiden Grossman // This comes up particularly often when running the exegesis tests with 5050e62181SAiden Grossman // llvm-lit. Additionally add the TID so that downstream consumers 5150e62181SAiden Grossman // using multiple threads don't run into conflicts. 5250e62181SAiden Grossman std::string AuxiliaryMemoryName = 5350e62181SAiden Grossman formatv("/{0}auxmem{1}", getCurrentTID(), ProcessID); 545a63b2b3SAiden Grossman int AuxiliaryMemoryFD = shm_open(AuxiliaryMemoryName.c_str(), 555a63b2b3SAiden Grossman O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); 565a63b2b3SAiden Grossman if (AuxiliaryMemoryFD == -1) 575a63b2b3SAiden Grossman return make_error<Failure>( 585a63b2b3SAiden Grossman "Failed to create shared memory object for auxiliary memory: " + 595a63b2b3SAiden Grossman Twine(strerror(errno))); 6074a5e778SAiden Grossman auto AuxiliaryMemoryFDClose = 6174a5e778SAiden Grossman make_scope_exit([AuxiliaryMemoryFD]() { close(AuxiliaryMemoryFD); }); 625a63b2b3SAiden Grossman if (ftruncate(AuxiliaryMemoryFD, AuxiliaryMemorySize) != 0) { 635a63b2b3SAiden Grossman return make_error<Failure>("Truncating the auxiliary memory failed: " + 645a63b2b3SAiden Grossman Twine(strerror(errno))); 655a63b2b3SAiden Grossman } 661048b7f8SAiden Grossman SharedMemoryNames.push_back(AuxiliaryMemoryName); 675a63b2b3SAiden Grossman return Error::success(); 685a63b2b3SAiden Grossman } 695a63b2b3SAiden Grossman 705a63b2b3SAiden Grossman Error SubprocessMemory::addMemoryDefinition( 715a63b2b3SAiden Grossman std::unordered_map<std::string, MemoryValue> MemoryDefinitions, 725a63b2b3SAiden Grossman pid_t ProcessPID) { 735a63b2b3SAiden Grossman SharedMemoryNames.reserve(MemoryDefinitions.size()); 745a63b2b3SAiden Grossman for (auto &[Name, MemVal] : MemoryDefinitions) { 7550e62181SAiden Grossman std::string SharedMemoryName = 7650e62181SAiden Grossman formatv("/{0}t{1}memdef{2}", ProcessPID, getCurrentTID(), MemVal.Index); 775a63b2b3SAiden Grossman SharedMemoryNames.push_back(SharedMemoryName); 785a63b2b3SAiden Grossman int SharedMemoryFD = 795a63b2b3SAiden Grossman shm_open(SharedMemoryName.c_str(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); 80fa90a0aaSAiden Grossman if (SharedMemoryFD == -1) 81fa90a0aaSAiden Grossman return make_error<Failure>( 82fa90a0aaSAiden Grossman "Failed to create shared memory object for memory definition: " + 83fa90a0aaSAiden Grossman Twine(strerror(errno))); 8474a5e778SAiden Grossman auto SharedMemoryFDClose = 8574a5e778SAiden Grossman make_scope_exit([SharedMemoryFD]() { close(SharedMemoryFD); }); 865a63b2b3SAiden Grossman if (ftruncate(SharedMemoryFD, MemVal.SizeBytes) != 0) { 875a63b2b3SAiden Grossman return make_error<Failure>("Truncating a memory definiton failed: " + 885a63b2b3SAiden Grossman Twine(strerror(errno))); 895a63b2b3SAiden Grossman } 905a63b2b3SAiden Grossman 915a63b2b3SAiden Grossman char *SharedMemoryMapping = 925a63b2b3SAiden Grossman (char *)mmap(NULL, MemVal.SizeBytes, PROT_READ | PROT_WRITE, MAP_SHARED, 935a63b2b3SAiden Grossman SharedMemoryFD, 0); 945a63b2b3SAiden Grossman // fill the buffer with the specified value 955a63b2b3SAiden Grossman size_t CurrentByte = 0; 965a63b2b3SAiden Grossman const size_t ValueWidthBytes = MemVal.Value.getBitWidth() / 8; 975a63b2b3SAiden Grossman while (CurrentByte < MemVal.SizeBytes - ValueWidthBytes) { 985a63b2b3SAiden Grossman memcpy(SharedMemoryMapping + CurrentByte, MemVal.Value.getRawData(), 995a63b2b3SAiden Grossman ValueWidthBytes); 1005a63b2b3SAiden Grossman CurrentByte += ValueWidthBytes; 1015a63b2b3SAiden Grossman } 1025a63b2b3SAiden Grossman // fill the last section 1035a63b2b3SAiden Grossman memcpy(SharedMemoryMapping + CurrentByte, MemVal.Value.getRawData(), 1045a63b2b3SAiden Grossman MemVal.SizeBytes - CurrentByte); 1055a63b2b3SAiden Grossman if (munmap(SharedMemoryMapping, MemVal.SizeBytes) != 0) { 1065a63b2b3SAiden Grossman return make_error<Failure>( 1075a63b2b3SAiden Grossman "Unmapping a memory definition in the parent failed: " + 1085a63b2b3SAiden Grossman Twine(strerror(errno))); 1095a63b2b3SAiden Grossman } 1105a63b2b3SAiden Grossman } 1115a63b2b3SAiden Grossman return Error::success(); 1125a63b2b3SAiden Grossman } 1135a63b2b3SAiden Grossman 1145a63b2b3SAiden Grossman Expected<int> SubprocessMemory::setupAuxiliaryMemoryInSubprocess( 1155a63b2b3SAiden Grossman std::unordered_map<std::string, MemoryValue> MemoryDefinitions, 11650e62181SAiden Grossman pid_t ParentPID, long ParentTID, int CounterFileDescriptor) { 11750e62181SAiden Grossman std::string AuxiliaryMemoryName = 11850e62181SAiden Grossman formatv("/{0}auxmem{1}", ParentTID, ParentPID); 1195a63b2b3SAiden Grossman int AuxiliaryMemoryFileDescriptor = 1205a63b2b3SAiden Grossman shm_open(AuxiliaryMemoryName.c_str(), O_RDWR, S_IRUSR | S_IWUSR); 1215a63b2b3SAiden Grossman if (AuxiliaryMemoryFileDescriptor == -1) 1225a63b2b3SAiden Grossman return make_error<Failure>( 123fa90a0aaSAiden Grossman "Getting file descriptor for auxiliary memory failed: " + 124fa90a0aaSAiden Grossman Twine(strerror(errno))); 1255a63b2b3SAiden Grossman // set up memory value file descriptors 1265a63b2b3SAiden Grossman int *AuxiliaryMemoryMapping = 1275a63b2b3SAiden Grossman (int *)mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, 1285a63b2b3SAiden Grossman AuxiliaryMemoryFileDescriptor, 0); 129*fac87b88SAiden Grossman if (reinterpret_cast<intptr_t>(AuxiliaryMemoryMapping) == -1) 1305a63b2b3SAiden Grossman return make_error<Failure>("Mapping auxiliary memory failed"); 1315a63b2b3SAiden Grossman AuxiliaryMemoryMapping[0] = CounterFileDescriptor; 1325a63b2b3SAiden Grossman for (auto &[Name, MemVal] : MemoryDefinitions) { 13350e62181SAiden Grossman std::string MemoryValueName = 13450e62181SAiden Grossman formatv("/{0}t{1}memdef{2}", ParentPID, ParentTID, MemVal.Index); 1355a63b2b3SAiden Grossman AuxiliaryMemoryMapping[AuxiliaryMemoryOffset + MemVal.Index] = 1365a63b2b3SAiden Grossman shm_open(MemoryValueName.c_str(), O_RDWR, S_IRUSR | S_IWUSR); 1375a63b2b3SAiden Grossman if (AuxiliaryMemoryMapping[AuxiliaryMemoryOffset + MemVal.Index] == -1) 1385a63b2b3SAiden Grossman return make_error<Failure>("Mapping shared memory failed"); 1395a63b2b3SAiden Grossman } 1405a63b2b3SAiden Grossman if (munmap(AuxiliaryMemoryMapping, 4096) == -1) 1415a63b2b3SAiden Grossman return make_error<Failure>("Unmapping auxiliary memory failed"); 1425a63b2b3SAiden Grossman return AuxiliaryMemoryFileDescriptor; 1435a63b2b3SAiden Grossman } 1445a63b2b3SAiden Grossman 1455a63b2b3SAiden Grossman SubprocessMemory::~SubprocessMemory() { 146ad2816e7SAiden Grossman for (const std::string &SharedMemoryName : SharedMemoryNames) { 1475a63b2b3SAiden Grossman if (shm_unlink(SharedMemoryName.c_str()) != 0) { 1485a63b2b3SAiden Grossman errs() << "Failed to unlink shared memory section: " << strerror(errno) 1495a63b2b3SAiden Grossman << "\n"; 1505a63b2b3SAiden Grossman } 1515a63b2b3SAiden Grossman } 1525a63b2b3SAiden Grossman } 1535a63b2b3SAiden Grossman 1545a63b2b3SAiden Grossman #else 1555a63b2b3SAiden Grossman 1565a63b2b3SAiden Grossman Error SubprocessMemory::initializeSubprocessMemory(pid_t ProcessPID) { 1575a63b2b3SAiden Grossman return make_error<Failure>( 1585a63b2b3SAiden Grossman "initializeSubprocessMemory is only supported on Linux"); 1595a63b2b3SAiden Grossman } 1605a63b2b3SAiden Grossman 1615a63b2b3SAiden Grossman Error SubprocessMemory::addMemoryDefinition( 1625a63b2b3SAiden Grossman std::unordered_map<std::string, MemoryValue> MemoryDefinitions, 1635a63b2b3SAiden Grossman pid_t ProcessPID) { 1645a63b2b3SAiden Grossman return make_error<Failure>("addMemoryDefinitions is only supported on Linux"); 1655a63b2b3SAiden Grossman } 1665a63b2b3SAiden Grossman 1675a63b2b3SAiden Grossman Expected<int> SubprocessMemory::setupAuxiliaryMemoryInSubprocess( 1685a63b2b3SAiden Grossman std::unordered_map<std::string, MemoryValue> MemoryDefinitions, 16950e62181SAiden Grossman pid_t ParentPID, long ParentTID, int CounterFileDescriptor) { 1705a63b2b3SAiden Grossman return make_error<Failure>( 1715a63b2b3SAiden Grossman "setupAuxiliaryMemoryInSubprocess is only supported on Linux"); 1725a63b2b3SAiden Grossman } 1735a63b2b3SAiden Grossman 1745a63b2b3SAiden Grossman SubprocessMemory::~SubprocessMemory() {} 1755a63b2b3SAiden Grossman 176a29e85d6SAiden Grossman #endif // !defined(__ANDROID__) 177a29e85d6SAiden Grossman #endif // defined(__linux__) 1785a63b2b3SAiden Grossman 1795a63b2b3SAiden Grossman } // namespace exegesis 1805a63b2b3SAiden Grossman } // namespace llvm 181