xref: /llvm-project/llvm/tools/llvm-exegesis/lib/SubprocessMemory.cpp (revision fac87b889c50f493ba332950f613fa15a45be9a9)
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