336 lines
11 KiB
C++
336 lines
11 KiB
C++
/***
|
|
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
|
|
|
File: AuProcessSectionView.Unix.hpp
|
|
Date: 2022-08-10
|
|
Author: Reece
|
|
***/
|
|
#include <Source/RuntimeInternal.hpp>
|
|
#include "AuProcessSectionView.Unix.hpp"
|
|
#include "Process.hpp"
|
|
#include <Source/IO/FS/FileStream.Unix.hpp>
|
|
#include "AuProcessSectionFileMapView.Unix.hpp"
|
|
#include <Source/IO/IPC/AuIPCHandle.hpp>
|
|
#include <Source/IO/IPC/AuIPCMemory.Unix.hpp>
|
|
#include <sys/mman.h>
|
|
#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
|
|
namespace Aurora::Process
|
|
{
|
|
AuUInt ProcessSectionView::GetStart()
|
|
{
|
|
return AuNumericLimits<AuUInt>::min();
|
|
}
|
|
|
|
AuUInt ProcessSectionView::GetEnd()
|
|
{
|
|
return AuNumericLimits<AuUInt>::max();
|
|
}
|
|
|
|
AuSPtr<IProcessSectionMapView> ProcessSectionView::Allocate(AuUInt uLength)
|
|
{
|
|
if (!uLength)
|
|
{
|
|
SysPushErrorArg("invalid uLength");
|
|
return {};
|
|
}
|
|
|
|
auto map = ::mmap(nullptr, uLength, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
|
|
if (map == MAP_FAILED)
|
|
{
|
|
SysPushErrorIO();
|
|
return {};
|
|
}
|
|
|
|
auto newObject = AuMakeShared<ProcessSectionFileMapView>(AuUInt(map),
|
|
uLength,
|
|
false);
|
|
if (!newObject)
|
|
{
|
|
SysPushErrorMem();
|
|
::munmap(map, uLength);
|
|
return {};
|
|
}
|
|
|
|
return newObject;
|
|
}
|
|
|
|
AuSPtr<IProcessSectionMapView> ProcessSectionView::MapFileByPath(const AuString &str,
|
|
AuUInt64 uOffset,
|
|
AuUInt uLength,
|
|
AuFS::EFileOpenMode mode,
|
|
AuFS::EFileAdvisoryLockLevel sectionLock)
|
|
{
|
|
return this->MapFileByPathEx(0, str, uOffset, uLength, mode, sectionLock);
|
|
}
|
|
|
|
AuSPtr<IProcessSectionMapView> ProcessSectionView::MapFileByObject(const AuSPtr<IO::IIOHandle> &pIOHandle,
|
|
AuUInt64 uOffset,
|
|
AuUInt uLength,
|
|
AuFS::EFileOpenMode mode,
|
|
AuFS::EFileAdvisoryLockLevel processLockLevel)
|
|
{
|
|
return this->MapFileByObjectEx(0, pIOHandle, uOffset, uLength, mode, processLockLevel);
|
|
}
|
|
|
|
AuSPtr<IProcessSectionMapView> ProcessSectionView::MapIPCMemory(const AuString &handleString,
|
|
AuUInt64 uOffset,
|
|
AuUInt uLength,
|
|
AuFS::EFileOpenMode mode)
|
|
{
|
|
return this->MapIPCMemoryEx(0, handleString, uOffset, uLength, mode);
|
|
}
|
|
|
|
AuSPtr<IProcessSectionMapView> ProcessSectionView::AllocateEx(AuUInt uLength, AuUInt uOffset)
|
|
{
|
|
PageTable table {};
|
|
table.NX = true;
|
|
table.readable = true;
|
|
table.writable = true;
|
|
return this->AllocateEx2(uLength, uOffset, table);
|
|
}
|
|
|
|
AuSPtr<IProcessSectionMapView> ProcessSectionView::AllocateEx2(AuUInt uLength, AuUInt uOffset, PageTable permissions)
|
|
{
|
|
if (!uLength)
|
|
{
|
|
SysPushErrorArg("invalid uLength");
|
|
return {};
|
|
}
|
|
|
|
AuUInt32 uProtFlags {};
|
|
|
|
if (!permissions.NX)
|
|
{
|
|
uProtFlags |= PROT_EXEC;
|
|
}
|
|
|
|
if (permissions.writable)
|
|
{
|
|
uProtFlags |= PROT_WRITE;
|
|
}
|
|
|
|
if (permissions.readable)
|
|
{
|
|
uProtFlags |= PROT_READ;
|
|
}
|
|
|
|
auto map = ::mmap((void *)uOffset, uLength, uProtFlags, MAP_ANONYMOUS | MAP_PRIVATE | (uOffset ? MAP_FIXED : 0), 0, 0);
|
|
if (map == MAP_FAILED)
|
|
{
|
|
SysPushErrorIO();
|
|
return {};
|
|
}
|
|
|
|
auto newObject = AuMakeShared<ProcessSectionFileMapView>(AuUInt(map),
|
|
uLength,
|
|
false);
|
|
if (!newObject)
|
|
{
|
|
SysPushErrorMem();
|
|
::munmap(map, uLength);
|
|
return {};
|
|
}
|
|
|
|
return newObject;
|
|
}
|
|
|
|
AuSPtr<IProcessSectionMapView> ProcessSectionView::MapFileByPathEx(AuUInt viewOffset,
|
|
const AuString &str,
|
|
AuUInt64 uOffset,
|
|
AuUInt uLength,
|
|
Aurora::IO::FS::EFileOpenMode mode,
|
|
Aurora::IO::FS::EFileAdvisoryLockLevel processLockLevel)
|
|
{
|
|
|
|
auto pHandle = AuIO::IOHandleShared();
|
|
if (!pHandle)
|
|
{
|
|
SysPushErrorMemory();
|
|
return nullptr;
|
|
}
|
|
|
|
AuIO::IIOHandle::HandleCreate createhandle(str);
|
|
createhandle.eAdvisoryLevel = AuFS::EFileAdvisoryLockLevel::eNoSafety;
|
|
createhandle.eMode = mode;
|
|
createhandle.bFailIfNonEmptyFile = false;
|
|
createhandle.bDirectIOMode = false;
|
|
createhandle.bAsyncHandle = false;
|
|
|
|
if (!pHandle->InitFromPath(createhandle))
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
return this->MapFileByObjectEx(viewOffset, pHandle, uOffset, uLength, mode, processLockLevel);
|
|
}
|
|
|
|
AuSPtr<IProcessSectionMapView> ProcessSectionView::MapFileByObjectEx(AuUInt viewOffset,
|
|
const AuSPtr<IO::IIOHandle> &pIOHandle,
|
|
AuUInt64 uOffset,
|
|
AuUInt uLength,
|
|
Aurora::IO::FS::EFileOpenMode mode,
|
|
Aurora::IO::FS::EFileAdvisoryLockLevel processLockLevel)
|
|
{
|
|
if (!pIOHandle)
|
|
{
|
|
return {};
|
|
}
|
|
|
|
if (!uLength)
|
|
{
|
|
SysPushErrorArg("invalid uLength");
|
|
return {};
|
|
}
|
|
|
|
int fd = ::dup(pIOHandle->GetOSHandle());
|
|
if (fd == -1)
|
|
{
|
|
SysPushErrorIO();
|
|
return {};
|
|
}
|
|
|
|
// TODO (Reece): lock garbage
|
|
|
|
int prot {};
|
|
switch (mode)
|
|
{
|
|
case AuFS::EFileOpenMode::eRead:
|
|
{
|
|
prot = PROT_READ;
|
|
break;
|
|
}
|
|
case AuFS::EFileOpenMode::eWrite:
|
|
case AuFS::EFileOpenMode::eReadWrite:
|
|
{
|
|
prot = PROT_READ | PROT_WRITE;
|
|
break;
|
|
}
|
|
default:
|
|
SysPushErrorGeneric();
|
|
return {};
|
|
};
|
|
|
|
auto map = ::mmap((void *)viewOffset, uLength, prot, MAP_SHARED | (viewOffset ? MAP_FIXED : 0), fd, uOffset);
|
|
if (map == MAP_FAILED)
|
|
{
|
|
SysPushErrorIO();
|
|
::close(fd);
|
|
return {};
|
|
}
|
|
|
|
auto newObject = AuMakeShared<ProcessSectionFileMapView>(AuUInt(map),
|
|
uLength,
|
|
true,
|
|
fd);
|
|
if (!newObject)
|
|
{
|
|
SysPushErrorMem();
|
|
::close(fd);
|
|
::munmap(map, uLength);
|
|
return {};
|
|
}
|
|
|
|
return newObject;
|
|
}
|
|
|
|
AuSPtr<IProcessSectionMapView> ProcessSectionView::MapIPCMemoryEx(AuUInt viewOffset,
|
|
const AuString &handleString,
|
|
AuUInt64 uOffset,
|
|
AuUInt uLength,
|
|
Aurora::IO::FS::EFileOpenMode mode)
|
|
{
|
|
AuIPC::IPCHandle handle;
|
|
|
|
if (!uLength)
|
|
{
|
|
SysPushErrorArg("invalid uLength");
|
|
return {};
|
|
}
|
|
|
|
if (!handle.FromString(handleString))
|
|
{
|
|
SysPushErrorParseError("Invalid handle: {}", handleString);
|
|
return {};
|
|
}
|
|
|
|
auto val = handle.GetToken(AuIPC::EIPCHandleType::eIPCMemory, 0);
|
|
if (!val)
|
|
{
|
|
SysPushErrorParseError("Invalid handle: {}", handleString);
|
|
return {};
|
|
}
|
|
|
|
auto actualLength = val->token.word;
|
|
auto path = AuIPC::GetServerPath(val->token);
|
|
|
|
if (actualLength < uOffset + uLength)
|
|
{
|
|
SysPushErrorIO("Out of range");
|
|
return {};
|
|
}
|
|
|
|
int fd = ::shm_open(path.c_str(), O_RDWR, S_IRUSR | S_IWUSR);
|
|
if (fd == -1)
|
|
{
|
|
SysPushErrorIO();
|
|
return {};
|
|
}
|
|
|
|
// TODO (Reece): lock garbage ( ??? )
|
|
|
|
int prot {};
|
|
switch (mode)
|
|
{
|
|
case AuFS::EFileOpenMode::eRead:
|
|
{
|
|
prot = PROT_READ;
|
|
break;
|
|
}
|
|
case AuFS::EFileOpenMode::eWrite:
|
|
case AuFS::EFileOpenMode::eReadWrite:
|
|
{
|
|
prot = PROT_READ | PROT_WRITE;
|
|
break;
|
|
}
|
|
default:
|
|
SysPushErrorGeneric();
|
|
return {};
|
|
};
|
|
|
|
auto map = ::mmap((void *)viewOffset, uLength, prot, MAP_SHARED | (viewOffset ? MAP_FIXED : 0), fd, uOffset);
|
|
if (map == MAP_FAILED)
|
|
{
|
|
SysPushErrorIO();
|
|
::close(fd);
|
|
return {};
|
|
}
|
|
|
|
auto newObject = AuMakeShared<ProcessSectionFileMapView>(AuUInt(map),
|
|
uLength,
|
|
true,
|
|
fd);
|
|
if (!newObject)
|
|
{
|
|
SysPushErrorMem();
|
|
::close(fd);
|
|
::munmap(map, val->token.word);
|
|
return {};
|
|
}
|
|
|
|
return newObject;
|
|
}
|
|
|
|
AuList<AuPair<AuUInt, AuUInt>> ProcessSectionView::GetAllocations()
|
|
{
|
|
AU_LOCK_GUARD(this->spinlock);
|
|
return allocations;
|
|
}
|
|
|
|
AUKN_SYM AuSPtr<IProcessSectionView> GetGlobalProcessSpace()
|
|
{
|
|
static ProcessSectionView gSingleton;
|
|
return AuUnsafeRaiiToShared(&gSingleton);
|
|
}
|
|
} |