Results: Implement namespaced, type-safe results.
Because I was working on multiple things at once, this commit also:
- Adds wrappers for/linker flags to wrap CXX exceptions to make them
abort. This saves ~0x8000 of memory in every system module.
- Broadly replaces lines of the pattern if (cond) { return ResultX; }
with R_UNLESS(!cond, ResultX());.
- Reworks the R_TRY_CATCH macros (and the result macros in general).
This commit is contained in:
@@ -49,29 +49,25 @@ namespace sts::ldr::args {
|
||||
}
|
||||
|
||||
Result Set(ncm::TitleId title_id, const void *args, size_t args_size) {
|
||||
if (args_size >= ArgumentSizeMax) {
|
||||
return ResultLoaderTooLongArgument;
|
||||
}
|
||||
R_UNLESS(args_size < ArgumentSizeMax, ldr::ResultTooLongArgument());
|
||||
|
||||
ArgumentInfo *arg_info = FindArgumentInfo(title_id);
|
||||
if (arg_info == nullptr) {
|
||||
arg_info = FindFreeArgumentInfo();
|
||||
}
|
||||
if (arg_info == nullptr) {
|
||||
return ResultLoaderTooManyArguments;
|
||||
}
|
||||
R_UNLESS(arg_info != nullptr, ldr::ResultTooManyArguments());
|
||||
|
||||
arg_info->title_id = title_id;
|
||||
arg_info->args_size = args_size;
|
||||
std::memcpy(arg_info->args, args, args_size);
|
||||
return ResultSuccess;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result Clear() {
|
||||
for (size_t i = 0; i < MaxArgumentInfos; i++) {
|
||||
g_argument_infos[i].title_id = FreeTitleId;
|
||||
}
|
||||
return ResultSuccess;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -339,9 +339,7 @@ namespace sts::ldr::caps {
|
||||
|
||||
#define VALIDATE_CASE(id) \
|
||||
case CapabilityId::id: \
|
||||
if (!Capability##id::Decode(cur_cap).IsValid(acid_caps, num_acid_caps)) { \
|
||||
return ResultLoaderInvalidCapability##id; \
|
||||
} \
|
||||
R_UNLESS(Capability##id::Decode(cur_cap).IsValid(acid_caps, num_acid_caps), ldr::ResultInvalidCapability##id()); \
|
||||
break
|
||||
switch (id) {
|
||||
VALIDATE_CASE(KernelFlags);
|
||||
@@ -356,21 +354,18 @@ namespace sts::ldr::caps {
|
||||
{
|
||||
/* Map Range needs extra logic because there it involves two sequential caps. */
|
||||
i++;
|
||||
if (i >= num_aci_caps || !CapabilityMapRange::Decode(cur_cap).IsValid(aci_caps[i], acid_caps, num_acid_caps)) {
|
||||
return ResultLoaderInvalidCapabilityMapRange;
|
||||
}
|
||||
R_UNLESS(i < num_aci_caps, ldr::ResultInvalidCapabilityMapRange());
|
||||
R_UNLESS(CapabilityMapRange::Decode(cur_cap).IsValid(aci_caps[i], acid_caps, num_acid_caps), ldr::ResultInvalidCapabilityMapRange());
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (id != CapabilityId::Empty) {
|
||||
return ResultLoaderUnknownCapability;
|
||||
}
|
||||
R_UNLESS(id == CapabilityId::Empty, ldr::ResultUnknownCapability());
|
||||
break;
|
||||
}
|
||||
#undef VALIDATE_CASE
|
||||
}
|
||||
|
||||
return ResultSuccess;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
u16 GetProgramInfoFlags(const void *kac, size_t kac_size) {
|
||||
|
||||
@@ -84,7 +84,7 @@ namespace sts::ldr {
|
||||
FsFileSystem fs;
|
||||
R_TRY(fsOpenFileSystemWithId(&fs, 0, FsFileSystemType_ApplicationPackage, path));
|
||||
STS_ASSERT(fsdevMountDevice(device_name, fs) >= 0);
|
||||
return ResultSuccess;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
FILE *OpenFile(const char *device_name, const char *relative_path) {
|
||||
@@ -180,7 +180,7 @@ namespace sts::ldr {
|
||||
|
||||
/* Note that we mounted code. */
|
||||
this->is_code_mounted = true;
|
||||
return ResultSuccess;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result ScopedCodeMount::MountSdCardCodeFileSystem(const ncm::TitleLocation &loc) {
|
||||
@@ -193,7 +193,7 @@ namespace sts::ldr {
|
||||
|
||||
/* Note that we mounted code. */
|
||||
this->is_code_mounted = true;
|
||||
return ResultSuccess;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result ScopedCodeMount::MountHblFileSystem() {
|
||||
@@ -206,7 +206,7 @@ namespace sts::ldr {
|
||||
|
||||
/* Note that we mounted HBL. */
|
||||
this->is_hbl_mounted = true;
|
||||
return ResultSuccess;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
|
||||
@@ -236,7 +236,7 @@ namespace sts::ldr {
|
||||
R_TRY(this->MountCodeFileSystem(loc));
|
||||
}
|
||||
|
||||
return ResultSuccess;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result OpenCodeFile(FILE *&out, ncm::TitleId title_id, const char *relative_path) {
|
||||
@@ -262,23 +262,19 @@ namespace sts::ldr {
|
||||
}
|
||||
|
||||
/* If nothing worked, we failed to find the path. */
|
||||
if (f == nullptr) {
|
||||
return ResultFsPathNotFound;
|
||||
}
|
||||
R_UNLESS(f != nullptr, fs::ResultPathNotFound());
|
||||
|
||||
out = f;
|
||||
return ResultSuccess;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result OpenCodeFileFromBaseExefs(FILE *&out, ncm::TitleId title_id, const char *relative_path) {
|
||||
/* Open the file. */
|
||||
FILE *f = OpenBaseExefsFile(title_id, relative_path);
|
||||
if (f == nullptr) {
|
||||
return ResultFsPathNotFound;
|
||||
}
|
||||
R_UNLESS(f != nullptr, fs::ResultPathNotFound());
|
||||
|
||||
out = f;
|
||||
return ResultSuccess;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
/* Redirection API. */
|
||||
@@ -291,7 +287,7 @@ namespace sts::ldr {
|
||||
ON_SCOPE_EXIT { serviceClose(®.s); };
|
||||
|
||||
R_TRY_CATCH(lrRegLrResolveProgramPath(®, static_cast<u64>(loc.title_id), path)) {
|
||||
R_CATCH(ResultLrProgramNotFound) {
|
||||
R_CATCH(lr::ResultProgramNotFound) {
|
||||
/* Program wasn't found via registered resolver, fall back to the normal resolver. */
|
||||
LrLocationResolver lr;
|
||||
R_TRY(lrOpenLocationResolver(static_cast<FsStorageId>(loc.storage_id), &lr));
|
||||
@@ -304,7 +300,7 @@ namespace sts::ldr {
|
||||
std::strncpy(out_path, path, FS_MAX_PATH);
|
||||
out_path[FS_MAX_PATH - 1] = '\0';
|
||||
FixFileSystemPath(out_path);
|
||||
return ResultSuccess;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result RedirectContentPath(const char *path, const ncm::TitleLocation &loc) {
|
||||
@@ -324,15 +320,13 @@ namespace sts::ldr {
|
||||
ON_SCOPE_EXIT { serviceClose(&lr.s); };
|
||||
|
||||
/* If there's already a Html Document path, we don't need to set one. */
|
||||
if (R_SUCCEEDED(lrLrResolveApplicationHtmlDocumentPath(&lr, static_cast<u64>(loc.title_id), path))) {
|
||||
return ResultSuccess;
|
||||
}
|
||||
R_UNLESS(R_FAILED(lrLrResolveApplicationHtmlDocumentPath(&lr, static_cast<u64>(loc.title_id), path)), ResultSuccess());
|
||||
|
||||
/* We just need to set this to any valid NCA path. Let's use the executable path. */
|
||||
R_TRY(lrLrResolveProgramPath(&lr, static_cast<u64>(loc.title_id), path));
|
||||
R_TRY(lrLrRedirectApplicationHtmlDocumentPath(&lr, static_cast<u64>(loc.title_id), static_cast<u64>(loc.title_id), path));
|
||||
|
||||
return ResultSuccess;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -60,10 +60,8 @@ namespace sts::ldr::ecs {
|
||||
}
|
||||
|
||||
Result Set(Handle *out, ncm::TitleId title_id) {
|
||||
if (g_map.size() >= MaxExternalContentSourceCount) {
|
||||
/* TODO: Is this an appropriate error? */
|
||||
return ResultLoaderTooManyArguments;
|
||||
}
|
||||
/* TODO: Is this an appropriate error? */
|
||||
R_UNLESS(g_map.size() < MaxExternalContentSourceCount, ldr::ResultTooManyArguments());
|
||||
|
||||
/* Clear any sources. */
|
||||
R_ASSERT(Clear(title_id));
|
||||
@@ -80,23 +78,22 @@ namespace sts::ldr::ecs {
|
||||
Service srv;
|
||||
serviceCreate(&srv, client.Move());
|
||||
FsFileSystem fs = { srv };
|
||||
auto fs_guard = SCOPE_GUARD { fsFsClose(&fs); };
|
||||
|
||||
/* Try to mount. */
|
||||
if (fsdevMountDevice(device_name, fs) == -1) {
|
||||
serviceClose(&srv);
|
||||
return ResultFsMountNameAlreadyExists;
|
||||
}
|
||||
R_UNLESS(fsdevMountDevice(device_name, fs) >= 0, fs::ResultMountNameAlreadyExists());
|
||||
fs_guard.Cancel();
|
||||
|
||||
/* Add to map. */
|
||||
g_map.emplace(static_cast<u64>(title_id), device_name);
|
||||
*out = server.Move();
|
||||
return ResultSuccess;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result Clear(ncm::TitleId title_id) {
|
||||
/* Delete if present. */
|
||||
g_map.erase(static_cast<u64>(title_id));
|
||||
return ResultSuccess;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ namespace sts::pm::info {
|
||||
|
||||
Result HasLaunchedTitle(bool *out, ncm::TitleId title_id) {
|
||||
*out = ldr::HasLaunchedTitle(title_id);
|
||||
return ResultSuccess;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ namespace sts::ldr {
|
||||
}
|
||||
}
|
||||
|
||||
return ResultSuccess;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result LoaderService::PinTitle(sf::Out<PinId> out_id, const ncm::TitleLocation &loc) {
|
||||
@@ -80,10 +80,7 @@ namespace sts::ldr {
|
||||
}
|
||||
|
||||
Result LoaderService::GetProcessModuleInfo(sf::Out<u32> count, const sf::OutPointerArray<ModuleInfo> &out, os::ProcessId process_id) {
|
||||
if (out.GetSize() > std::numeric_limits<s32>::max()) {
|
||||
return ResultLoaderInvalidSize;
|
||||
}
|
||||
|
||||
R_UNLESS(out.GetSize() <= std::numeric_limits<s32>::max(), ResultInvalidSize());
|
||||
return ldr::ro::GetProcessModuleInfo(count.GetPointer(), out.GetPointer(), out.GetSize(), process_id);
|
||||
}
|
||||
|
||||
|
||||
@@ -54,6 +54,12 @@ namespace sts::ams {
|
||||
|
||||
}
|
||||
|
||||
namespace sts::result {
|
||||
|
||||
bool CallFatalOnResultAssertion = false;
|
||||
|
||||
}
|
||||
|
||||
using namespace sts;
|
||||
|
||||
void __libnx_exception_handler(ThreadExceptionDump *ctx) {
|
||||
|
||||
@@ -40,29 +40,24 @@ namespace sts::ldr {
|
||||
|
||||
/* Helpers. */
|
||||
Result ValidateSubregion(size_t allowed_start, size_t allowed_end, size_t start, size_t size, size_t min_size = 0) {
|
||||
if (!(size >= min_size && allowed_start <= start && start <= allowed_end && start + size <= allowed_end)) {
|
||||
return ResultLoaderInvalidMeta;
|
||||
}
|
||||
return ResultSuccess;
|
||||
R_UNLESS(size >= min_size, ResultInvalidMeta());
|
||||
R_UNLESS(allowed_start <= start, ResultInvalidMeta());
|
||||
R_UNLESS(start <= allowed_end, ResultInvalidMeta());
|
||||
R_UNLESS(start + size <= allowed_end, ResultInvalidMeta());
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result ValidateNpdm(const Npdm *npdm, size_t size) {
|
||||
/* Validate magic. */
|
||||
if (npdm->magic != Npdm::Magic) {
|
||||
return ResultLoaderInvalidMeta;
|
||||
}
|
||||
R_UNLESS(npdm->magic == Npdm::Magic, ResultInvalidMeta());
|
||||
|
||||
/* Validate flags. */
|
||||
if (hos::GetVersion() >= hos::Version_700) {
|
||||
/* 7.0.0 added 0x10 as a valid bit to NPDM flags. */
|
||||
if (npdm->flags & ~0x1F) {
|
||||
return ResultLoaderInvalidMeta;
|
||||
}
|
||||
} else {
|
||||
if (npdm->flags & ~0xF) {
|
||||
return ResultLoaderInvalidMeta;
|
||||
}
|
||||
u32 mask = ~0x1F;
|
||||
if (hos::GetVersion() < hos::Version_700) {
|
||||
/* 7.0.0 added 0x10 as a valid bit to NPDM flags, so before that we only check 0xF. */
|
||||
mask = ~0xF;
|
||||
}
|
||||
R_UNLESS(!(npdm->flags & mask), ResultInvalidMeta());
|
||||
|
||||
/* Validate Acid extents. */
|
||||
R_TRY(ValidateSubregion(sizeof(Npdm), size, npdm->acid_offset, npdm->acid_size, sizeof(Acid)));
|
||||
@@ -70,14 +65,12 @@ namespace sts::ldr {
|
||||
/* Validate Aci extends. */
|
||||
R_TRY(ValidateSubregion(sizeof(Npdm), size, npdm->aci_offset, npdm->aci_size, sizeof(Aci)));
|
||||
|
||||
return ResultSuccess;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result ValidateAcid(const Acid *acid, size_t size) {
|
||||
/* Validate magic. */
|
||||
if (acid->magic != Acid::Magic) {
|
||||
return ResultLoaderInvalidMeta;
|
||||
}
|
||||
R_UNLESS(acid->magic == Acid::Magic, ResultInvalidMeta());
|
||||
|
||||
/* TODO: Check if retail flag is set if not development hardware. */
|
||||
|
||||
@@ -86,21 +79,19 @@ namespace sts::ldr {
|
||||
R_TRY(ValidateSubregion(sizeof(Acid), size, acid->sac_offset, acid->sac_size));
|
||||
R_TRY(ValidateSubregion(sizeof(Acid), size, acid->kac_offset, acid->kac_size));
|
||||
|
||||
return ResultSuccess;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result ValidateAci(const Aci *aci, size_t size) {
|
||||
/* Validate magic. */
|
||||
if (aci->magic != Aci::Magic) {
|
||||
return ResultLoaderInvalidMeta;
|
||||
}
|
||||
R_UNLESS(aci->magic == Aci::Magic, ResultInvalidMeta());
|
||||
|
||||
/* Validate Fah, Sac, Kac. */
|
||||
R_TRY(ValidateSubregion(sizeof(Aci), size, aci->fah_offset, aci->fah_size));
|
||||
R_TRY(ValidateSubregion(sizeof(Aci), size, aci->sac_offset, aci->sac_size));
|
||||
R_TRY(ValidateSubregion(sizeof(Aci), size, aci->kac_offset, aci->kac_size));
|
||||
|
||||
return ResultSuccess;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result LoadMetaFromFile(FILE *f, MetaCache *cache) {
|
||||
@@ -116,15 +107,12 @@ namespace sts::ldr {
|
||||
fseek(f, 0, SEEK_SET);
|
||||
|
||||
/* Read data into cache buffer. */
|
||||
if (npdm_size > MetaCacheBufferSize || fread(cache->buffer, npdm_size, 1, f) != 1) {
|
||||
return ResultLoaderTooLargeMeta;
|
||||
}
|
||||
R_UNLESS(npdm_size <= MetaCacheBufferSize, ResultTooLargeMeta());
|
||||
R_UNLESS(fread(cache->buffer, npdm_size, 1, f) == 1, ResultTooLargeMeta());
|
||||
}
|
||||
|
||||
/* Ensure size is big enough. */
|
||||
if (npdm_size < sizeof(Npdm)) {
|
||||
return ResultLoaderInvalidMeta;
|
||||
}
|
||||
R_UNLESS(npdm_size >= sizeof(Npdm), ResultInvalidMeta());
|
||||
|
||||
/* Validate the meta. */
|
||||
{
|
||||
@@ -152,7 +140,7 @@ namespace sts::ldr {
|
||||
meta->aci_kac = reinterpret_cast<u8 *>(aci) + aci->kac_offset;
|
||||
}
|
||||
|
||||
return ResultSuccess;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -198,7 +186,7 @@ namespace sts::ldr {
|
||||
g_cached_title_id = title_id;
|
||||
*out_meta = *meta;
|
||||
|
||||
return ResultSuccess;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result LoadMetaFromCache(Meta *out_meta, ncm::TitleId title_id) {
|
||||
@@ -206,7 +194,7 @@ namespace sts::ldr {
|
||||
return LoadMeta(out_meta, title_id);
|
||||
}
|
||||
*out_meta = g_meta_cache.meta;
|
||||
return ResultSuccess;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
void InvalidateMetaCache() {
|
||||
|
||||
@@ -196,38 +196,32 @@ namespace sts::ldr {
|
||||
constexpr size_t g_MinimumTitleVersionsCount900 = util::size(g_MinimumTitleVersions900);
|
||||
|
||||
Result ValidateTitleVersion(ncm::TitleId title_id, u32 version) {
|
||||
if (hos::GetVersion() < hos::Version_810) {
|
||||
return ResultSuccess;
|
||||
} else {
|
||||
R_UNLESS(hos::GetVersion() >= hos::Version_810, ResultSuccess());
|
||||
#ifdef LDR_VALIDATE_PROCESS_VERSION
|
||||
const MinimumTitleVersion *entries = nullptr;
|
||||
size_t num_entries = 0;
|
||||
switch (hos::GetVersion()) {
|
||||
case hos::Version_810:
|
||||
entries = g_MinimumTitleVersions810;
|
||||
num_entries = g_MinimumTitleVersionsCount810;
|
||||
break;
|
||||
case hos::Version_900:
|
||||
entries = g_MinimumTitleVersions900;
|
||||
num_entries = g_MinimumTitleVersionsCount900;
|
||||
break;
|
||||
default:
|
||||
entries = nullptr;
|
||||
num_entries = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < num_entries; i++) {
|
||||
if (entries[i].title_id == title_id && entries[i].version > version) {
|
||||
return ResultLoaderInvalidVersion;
|
||||
}
|
||||
}
|
||||
|
||||
return ResultSuccess;
|
||||
#else
|
||||
return ResultSuccess;
|
||||
#endif
|
||||
const MinimumTitleVersion *entries = nullptr;
|
||||
size_t num_entries = 0;
|
||||
switch (hos::GetVersion()) {
|
||||
case hos::Version_810:
|
||||
entries = g_MinimumTitleVersions810;
|
||||
num_entries = g_MinimumTitleVersionsCount810;
|
||||
break;
|
||||
case hos::Version_900:
|
||||
entries = g_MinimumTitleVersions900;
|
||||
num_entries = g_MinimumTitleVersionsCount900;
|
||||
break;
|
||||
default:
|
||||
entries = nullptr;
|
||||
num_entries = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < num_entries; i++) {
|
||||
if (entries[i].title_id == title_id) {
|
||||
R_UNLESS(entries[i].version <= version, ResultInvalidVersion());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
/* Helpers. */
|
||||
@@ -243,9 +237,7 @@ namespace sts::ldr {
|
||||
#define COPY_ACCESS_CONTROL(source, which) \
|
||||
({ \
|
||||
const size_t size = meta->source->which##_size; \
|
||||
if (offset + size > sizeof(out->ac_buffer)) { \
|
||||
return ResultLoaderInternalError; \
|
||||
} \
|
||||
R_UNLESS(offset + size <= sizeof(out->ac_buffer), ResultInternalError()); \
|
||||
out->source##_##which##_size = size; \
|
||||
std::memcpy(out->ac_buffer + offset, meta->source##_##which, size); \
|
||||
offset += size; \
|
||||
@@ -260,7 +252,7 @@ namespace sts::ldr {
|
||||
|
||||
/* Copy flags. */
|
||||
out->flags = caps::GetProgramInfoFlags(meta->acid_kac, meta->acid->kac_size);
|
||||
return ResultSuccess;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
bool IsApplet(const Meta *meta) {
|
||||
@@ -289,39 +281,31 @@ namespace sts::ldr {
|
||||
if (R_SUCCEEDED(OpenCodeFile(f, title_id, GetNsoName(i)))) {
|
||||
ON_SCOPE_EXIT { fclose(f); };
|
||||
/* Read NSO header. */
|
||||
if (fread(nso_headers + i, sizeof(*nso_headers), 1, f) != 1) {
|
||||
return ResultLoaderInvalidNso;
|
||||
}
|
||||
R_UNLESS(fread(nso_headers + i, sizeof(*nso_headers), 1, f) == 1, ResultInvalidNso());
|
||||
has_nso[i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
return ResultSuccess;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result ValidateNsoHeaders(const NsoHeader *nso_headers, const bool *has_nso) {
|
||||
/* We must always have a main. */
|
||||
if (!has_nso[Nso_Main]) {
|
||||
return ResultLoaderInvalidNso;
|
||||
}
|
||||
R_UNLESS(has_nso[Nso_Main], ResultInvalidNso());
|
||||
|
||||
/* If we don't have an RTLD, we must only have a main. */
|
||||
if (!has_nso[Nso_Rtld]) {
|
||||
for (size_t i = Nso_Main + 1; i < Nso_Count; i++) {
|
||||
if (has_nso[i]) {
|
||||
return ResultLoaderInvalidNso;
|
||||
}
|
||||
R_UNLESS(!has_nso[i], ResultInvalidNso());
|
||||
}
|
||||
}
|
||||
|
||||
/* All NSOs must have zero text offset. */
|
||||
for (size_t i = 0; i < Nso_Count; i++) {
|
||||
if (nso_headers[i].text_dst_offset != 0) {
|
||||
return ResultLoaderInvalidNso;
|
||||
}
|
||||
R_UNLESS(nso_headers[i].text_dst_offset == 0, ResultInvalidNso());
|
||||
}
|
||||
|
||||
return ResultSuccess;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result ValidateMeta(const Meta *meta, const ncm::TitleLocation &loc) {
|
||||
@@ -329,15 +313,14 @@ namespace sts::ldr {
|
||||
R_TRY(ValidateTitleVersion(loc.title_id, meta->npdm->version));
|
||||
|
||||
/* Validate title id. */
|
||||
if (meta->aci->title_id < meta->acid->title_id_min || meta->aci->title_id > meta->acid->title_id_max) {
|
||||
return ResultLoaderInvalidProgramId;
|
||||
}
|
||||
R_UNLESS(meta->aci->title_id >= meta->acid->title_id_min, ResultInvalidProgramId());
|
||||
R_UNLESS(meta->aci->title_id <= meta->acid->title_id_max, ResultInvalidProgramId());
|
||||
|
||||
/* Validate the kernel capabilities. */
|
||||
R_TRY(caps::ValidateCapabilities(meta->acid_kac, meta->acid->kac_size, meta->aci_kac, meta->aci->kac_size));
|
||||
|
||||
/* All good. */
|
||||
return ResultSuccess;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result GetCreateProcessFlags(u32 *out, const Meta *meta, const u32 ldr_flags) {
|
||||
@@ -365,7 +348,7 @@ namespace sts::ldr {
|
||||
flags |= svc::CreateProcessFlag_AddressSpace64Bit;
|
||||
break;
|
||||
default:
|
||||
return ResultLoaderInvalidMeta;
|
||||
return ResultInvalidMeta();
|
||||
}
|
||||
|
||||
/* Set Enable Debug. */
|
||||
@@ -410,7 +393,7 @@ namespace sts::ldr {
|
||||
flags |= svc::CreateProcessFlag_PoolPartitionSystemNonSecure;
|
||||
break;
|
||||
default:
|
||||
return ResultLoaderInvalidMeta;
|
||||
return ResultInvalidMeta();
|
||||
}
|
||||
} else if (hos::GetVersion() >= hos::Version_400) {
|
||||
/* On 4.0.0+, the corresponding bit was simply "UseSecureMemory". */
|
||||
@@ -420,7 +403,7 @@ namespace sts::ldr {
|
||||
}
|
||||
|
||||
*out = flags;
|
||||
return ResultSuccess;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result GetCreateProcessInfo(CreateProcessInfo *out, const Meta *meta, u32 flags, Handle reslimit_h) {
|
||||
@@ -439,30 +422,23 @@ namespace sts::ldr {
|
||||
/* 3.0.0+ System Resource Size. */
|
||||
if (hos::GetVersion() >= hos::Version_300) {
|
||||
/* Validate size is aligned. */
|
||||
if (meta->npdm->system_resource_size & (SystemResourceSizeAlignment - 1)) {
|
||||
return ResultLoaderInvalidSize;
|
||||
}
|
||||
R_UNLESS(util::IsAligned(meta->npdm->system_resource_size, SystemResourceSizeAlignment), ResultInvalidSize());
|
||||
|
||||
/* Validate system resource usage. */
|
||||
if (meta->npdm->system_resource_size) {
|
||||
/* Process must be 64-bit. */
|
||||
if (!(out->flags & svc::CreateProcessFlag_AddressSpace64Bit)) {
|
||||
return ResultLoaderInvalidMeta;
|
||||
}
|
||||
R_UNLESS((out->flags & svc::CreateProcessFlag_AddressSpace64Bit), ResultInvalidMeta());
|
||||
|
||||
/* Process must be application or applet. */
|
||||
if (!IsApplication(meta) && !IsApplet(meta)) {
|
||||
return ResultLoaderInvalidMeta;
|
||||
}
|
||||
R_UNLESS(IsApplication(meta) || IsApplet(meta), ResultInvalidMeta());
|
||||
|
||||
/* Size must be less than or equal to max. */
|
||||
if (meta->npdm->system_resource_size > SystemResourceSizeMax) {
|
||||
return ResultLoaderInvalidMeta;
|
||||
}
|
||||
R_UNLESS(meta->npdm->system_resource_size <= SystemResourceSizeMax, ResultInvalidMeta());
|
||||
}
|
||||
out->system_resource_num_pages = meta->npdm->system_resource_size >> 12;
|
||||
}
|
||||
|
||||
return ResultSuccess;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result DecideAddressSpaceLayout(ProcessInfo *out, CreateProcessInfo *out_cpi, const NsoHeader *nso_headers, const bool *has_nso, const args::ArgumentInfo *arg_info) {
|
||||
@@ -527,9 +503,7 @@ namespace sts::ldr {
|
||||
aslr_size = map::AslrSize32Bit;
|
||||
}
|
||||
}
|
||||
if (total_size > aslr_size) {
|
||||
return ResultKernelOutOfMemory;
|
||||
}
|
||||
R_UNLESS(total_size <= aslr_size, svc::ResultOutOfMemory());
|
||||
|
||||
/* Set Create Process output. */
|
||||
uintptr_t aslr_slide = 0;
|
||||
@@ -552,7 +526,7 @@ namespace sts::ldr {
|
||||
out_cpi->code_address = aslr_start;
|
||||
out_cpi->code_num_pages = total_size >> 12;
|
||||
|
||||
return ResultSuccess;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result CreateProcessImpl(ProcessInfo *out, const Meta *meta, const NsoHeader *nso_headers, const bool *has_nso, const args::ArgumentInfo *arg_info, u32 flags, Handle reslimit_h) {
|
||||
@@ -574,22 +548,18 @@ namespace sts::ldr {
|
||||
}
|
||||
|
||||
/* Validate size. */
|
||||
if (file_size > segment->size || file_size > std::numeric_limits<s32>::max() || segment->size > std::numeric_limits<s32>::max()) {
|
||||
return ResultLoaderInvalidNso;
|
||||
}
|
||||
R_UNLESS(file_size <= segment->size, ResultInvalidNso());
|
||||
R_UNLESS(segment->size <= std::numeric_limits<s32>::max(), ResultInvalidNso());
|
||||
|
||||
/* Load data from file. */
|
||||
uintptr_t load_address = is_compressed ? map_end - file_size : map_base;
|
||||
fseek(f, segment->file_offset, SEEK_SET);
|
||||
if (fread(reinterpret_cast<void *>(load_address), file_size, 1, f) != 1) {
|
||||
return ResultLoaderInvalidNso;
|
||||
}
|
||||
R_UNLESS(fread(reinterpret_cast<void *>(load_address), file_size, 1, f) == 1, ResultInvalidNso());
|
||||
|
||||
/* Uncompress if necessary. */
|
||||
if (is_compressed) {
|
||||
if (util::DecompressLZ4(reinterpret_cast<void *>(map_base), segment->size, reinterpret_cast<const void *>(load_address), file_size) != static_cast<int>(segment->size)) {
|
||||
return ResultLoaderInvalidNso;
|
||||
}
|
||||
bool decompressed = (util::DecompressLZ4(reinterpret_cast<void *>(map_base), segment->size, reinterpret_cast<const void *>(load_address), file_size) == static_cast<int>(segment->size));
|
||||
R_UNLESS(decompressed, ResultInvalidNso());
|
||||
}
|
||||
|
||||
/* Check hash if necessary. */
|
||||
@@ -597,12 +567,10 @@ namespace sts::ldr {
|
||||
u8 hash[SHA256_HASH_SIZE];
|
||||
sha256CalculateHash(hash, reinterpret_cast<void *>(map_base), segment->size);
|
||||
|
||||
if (std::memcmp(hash, file_hash, sizeof(hash)) != 0) {
|
||||
return ResultLoaderInvalidNso;
|
||||
}
|
||||
R_UNLESS(std::memcmp(hash, file_hash, sizeof(hash)) == 0, ResultInvalidNso());
|
||||
}
|
||||
|
||||
return ResultSuccess;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result LoadNsoIntoProcessMemory(Handle process_handle, FILE *f, uintptr_t map_address, const NsoHeader *nso_header, uintptr_t nso_address, size_t nso_size) {
|
||||
@@ -646,7 +614,7 @@ namespace sts::ldr {
|
||||
R_TRY(svcSetProcessMemoryPermission(process_handle, nso_address + nso_header->rw_dst_offset, rw_size, Perm_Rw));
|
||||
}
|
||||
|
||||
return ResultSuccess;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result LoadNsosIntoProcessMemory(const ProcessInfo *process_info, const ncm::TitleId title_id, const NsoHeader *nso_headers, const bool *has_nso, const args::ArgumentInfo *arg_info) {
|
||||
@@ -687,7 +655,7 @@ namespace sts::ldr {
|
||||
R_TRY(svcSetProcessMemoryPermission(process_handle, process_info->args_address, process_info->args_size, Perm_Rw));
|
||||
}
|
||||
|
||||
return ResultSuccess;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -754,7 +722,7 @@ namespace sts::ldr {
|
||||
*out = info.process_handle.Move();
|
||||
}
|
||||
|
||||
return ResultSuccess;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result GetProgramInfo(ProgramInfo *out, const ncm::TitleLocation &loc) {
|
||||
|
||||
@@ -81,9 +81,7 @@ namespace sts::ldr::ro {
|
||||
Result PinTitle(PinId *out, const ncm::TitleLocation &loc) {
|
||||
*out = InvalidPinId;
|
||||
ProcessInfo *info = GetFreeProcessInfo();
|
||||
if (info == nullptr) {
|
||||
return ResultLoaderTooManyProcesses;
|
||||
}
|
||||
R_UNLESS(info != nullptr, ldr::ResultTooManyProcesses());
|
||||
|
||||
static u64 s_cur_pin_id = 1;
|
||||
|
||||
@@ -92,46 +90,38 @@ namespace sts::ldr::ro {
|
||||
info->loc = loc;
|
||||
info->in_use = true;
|
||||
*out = info->pin_id;
|
||||
return ResultSuccess;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result UnpinTitle(PinId id) {
|
||||
ProcessInfo *info = GetProcessInfo(id);
|
||||
if (info == nullptr) {
|
||||
return ResultLoaderNotPinned;
|
||||
}
|
||||
R_UNLESS(info != nullptr, ldr::ResultNotPinned());
|
||||
|
||||
info->in_use = false;
|
||||
return ResultSuccess;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
|
||||
Result GetTitleLocation(ncm::TitleLocation *out, PinId id) {
|
||||
ProcessInfo *info = GetProcessInfo(id);
|
||||
if (info == nullptr) {
|
||||
return ResultLoaderNotPinned;
|
||||
}
|
||||
R_UNLESS(info != nullptr, ldr::ResultNotPinned());
|
||||
|
||||
*out = info->loc;
|
||||
return ResultSuccess;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result RegisterProcess(PinId id, os::ProcessId process_id, ncm::TitleId title_id) {
|
||||
ProcessInfo *info = GetProcessInfo(id);
|
||||
if (info == nullptr) {
|
||||
return ResultLoaderNotPinned;
|
||||
}
|
||||
R_UNLESS(info != nullptr, ldr::ResultNotPinned());
|
||||
|
||||
info->title_id = title_id;
|
||||
info->process_id = process_id;
|
||||
return ResultSuccess;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result RegisterModule(PinId id, const u8 *build_id, uintptr_t address, size_t size) {
|
||||
ProcessInfo *info = GetProcessInfo(id);
|
||||
if (info == nullptr) {
|
||||
return ResultLoaderNotPinned;
|
||||
}
|
||||
R_UNLESS(info != nullptr, ldr::ResultNotPinned());
|
||||
|
||||
/* Nintendo doesn't actually care about successful allocation. */
|
||||
for (size_t i = 0; i < ModuleCountMax; i++) {
|
||||
@@ -147,14 +137,12 @@ namespace sts::ldr::ro {
|
||||
break;
|
||||
}
|
||||
|
||||
return ResultSuccess;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result GetProcessModuleInfo(u32 *out_count, ldr::ModuleInfo *out, size_t max_out_count, os::ProcessId process_id) {
|
||||
const ProcessInfo *info = GetProcessInfo(process_id);
|
||||
if (info == nullptr) {
|
||||
return ResultLoaderNotPinned;
|
||||
}
|
||||
R_UNLESS(info != nullptr, ldr::ResultNotPinned());
|
||||
|
||||
size_t count = 0;
|
||||
for (size_t i = 0; i < ModuleCountMax && count < max_out_count; i++) {
|
||||
@@ -167,7 +155,7 @@ namespace sts::ldr::ro {
|
||||
}
|
||||
|
||||
*out_count = static_cast<u32>(count);
|
||||
return ResultSuccess;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user