#ifndef TOOLS_MEMORY_PARTITION_ALLOCATOR_INSPECT_UTILS_H_
#define TOOLS_MEMORY_PARTITION_ALLOCATOR_INSPECT_UTILS_H_
#include <fcntl.h>
#include <signal.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <optional>
#include "base/files/file.h"
#include "build/build_config.h"
#if BUILDFLAG(IS_MAC)
#include <mach/mach.h>
#endif
namespace partition_alloc::tools {
class ScopedSigStopper {
public:
explicit ScopedSigStopper(pid_t pid) : pid_(pid) { kill(pid_, SIGSTOP); }
~ScopedSigStopper() { kill(pid_, SIGCONT); }
private:
const pid_t pid_;
};
base::ScopedFD OpenProcMem(pid_t pid);
base::ScopedFD OpenPagemap(pid_t pid);
char* CreateMappingAtAddress(uintptr_t address, size_t size);
class RemoteProcessMemoryReader {
public:
explicit RemoteProcessMemoryReader(pid_t pid);
~RemoteProcessMemoryReader();
bool IsValid() const;
bool ReadMemory(uintptr_t remote_address, size_t size, char* buffer);
char* ReadAtSameAddressInLocalMemory(uintptr_t address, size_t size);
pid_t pid() const { return pid_; }
private:
const pid_t pid_;
bool is_valid_;
#if BUILDFLAG(IS_LINUX)
base::ScopedFD mem_fd_;
#elif BUILDFLAG(IS_MAC)
task_t task_;
#endif
};
uintptr_t IndexThreadCacheNeedleArray(RemoteProcessMemoryReader& reader,
size_t index);
template <typename T>
class RawBuffer {
public:
RawBuffer() = default;
const T* get() const { return reinterpret_cast<const T*>(buffer_); }
char* get_buffer() { return buffer_; }
static std::optional<RawBuffer<T>> ReadFromProcessMemory(
RemoteProcessMemoryReader& reader,
uintptr_t address) {
RawBuffer<T> buf;
bool ok = reader.ReadMemory(reinterpret_cast<unsigned long>(address),
sizeof(T), buf.get_buffer());
if (!ok)
return std::nullopt;
return {buf};
}
static RawBuffer<T> FromData(const void* data) {
RawBuffer<T> ret;
memcpy(ret.buffer_, data, sizeof(T));
return ret;
}
private:
alignas(T) char buffer_[sizeof(T)];
};
}
#endif