ldr: Implement DebugMonitor GetNsoInfos
Returns an array of NSO Info entries, which contain information on address, size, and build ID.
This commit is contained in:
@@ -8,7 +8,10 @@
|
||||
|
||||
#include "common/alignment.h"
|
||||
#include "common/hex_util.h"
|
||||
#include "core/file_sys/program_metadata.h"
|
||||
#include "core/file_sys/romfs_factory.h"
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/process.h"
|
||||
#include "core/hle/service/ldr/ldr.h"
|
||||
#include "core/hle/service/service.h"
|
||||
@@ -16,6 +19,11 @@
|
||||
|
||||
namespace Service::LDR {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr ResultCode ERROR_ALREADY_REGISTERED{ErrorModule::Loader, 7};
|
||||
constexpr ResultCode ERROR_TITLE_NOT_FOUND{ErrorModule::Loader, 8};
|
||||
|
||||
constexpr ResultCode ERROR_INVALID_MEMORY_STATE{ErrorModule::Loader, 51};
|
||||
constexpr ResultCode ERROR_INVALID_NRO{ErrorModule::Loader, 52};
|
||||
constexpr ResultCode ERROR_INVALID_NRR{ErrorModule::Loader, 53};
|
||||
@@ -31,19 +39,138 @@ constexpr ResultCode ERROR_NOT_INITIALIZED{ErrorModule::Loader, 87};
|
||||
|
||||
constexpr u64 MAXIMUM_LOADED_RO = 0x40;
|
||||
|
||||
constexpr u64 NSO_BUILD_ID_OFFSET = 0x40;
|
||||
|
||||
enum class ApplicationType : u8 {
|
||||
Sysmodule = 0,
|
||||
Application = 1,
|
||||
Applet = 2,
|
||||
};
|
||||
|
||||
struct NSOInfo {
|
||||
std::array<u8, 0x20> build_id;
|
||||
VAddr map_address;
|
||||
u64 map_size;
|
||||
};
|
||||
static_assert(sizeof(NSOInfo) == 0x30, "NSOInfo has incorrect size.");
|
||||
|
||||
struct ProgramInfoHeader {
|
||||
u8 main_thread_priority;
|
||||
u8 default_cpu_id;
|
||||
ApplicationType application_type;
|
||||
INSERT_PADDING_BYTES(0x1);
|
||||
u32_le main_thread_stack_size;
|
||||
u64_le title_id;
|
||||
u32_le acid_sac_size;
|
||||
u32_le aci0_sac_size;
|
||||
u32_le acid_fac_size;
|
||||
u32_le aci0_fac_size;
|
||||
};
|
||||
static_assert(sizeof(ProgramInfoHeader) == 0x20, "ProgramInfoHeader has incorrect size.");
|
||||
|
||||
std::vector<NSOInfo> GetNSOInfo(const std::map<VAddr, std::shared_ptr<std::vector<u8>>>& modules) {
|
||||
std::vector<NSOInfo> out;
|
||||
|
||||
for (const auto& [base_addr, memory] : modules) {
|
||||
out.emplace_back();
|
||||
out.back().map_address = base_addr;
|
||||
out.back().map_size = memory->size();
|
||||
std::memcpy(out.back().build_id.data(), memory->data() + NSO_BUILD_ID_OFFSET,
|
||||
out.back().build_id.size());
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
std::vector<u8> GetProgramInfoFromProcess(const Kernel::Process& process) {
|
||||
const auto& meta = process.GetProgramMetadata();
|
||||
|
||||
ProgramInfoHeader header{};
|
||||
header.main_thread_priority = meta.GetMainThreadPriority();
|
||||
header.default_cpu_id = meta.GetMainThreadCore();
|
||||
header.application_type = ApplicationType::Application;
|
||||
header.main_thread_stack_size = meta.GetMainThreadStackSize();
|
||||
header.title_id = meta.GetTitleID();
|
||||
|
||||
const auto acid_file_access = meta.GetACIDFileAccessControl();
|
||||
const auto aci0_file_access = meta.GetACI0FileAccessControl();
|
||||
const auto acid_service_access = meta.GetACIDServiceAccessControl();
|
||||
const auto aci0_service_access = meta.GetACI0ServiceAccessControl();
|
||||
|
||||
header.acid_fac_size = acid_file_access.size();
|
||||
header.aci0_fac_size = aci0_file_access.size();
|
||||
header.acid_sac_size = acid_service_access.size();
|
||||
header.aci0_sac_size = aci0_service_access.size();
|
||||
|
||||
std::vector<u8> out(sizeof(ProgramInfoHeader) + acid_file_access.size() +
|
||||
aci0_file_access.size() + acid_service_access.size() +
|
||||
aci0_service_access.size());
|
||||
|
||||
u64 offset = 0;
|
||||
std::memcpy(out.data() + offset, &header, sizeof(ProgramInfoHeader));
|
||||
offset += sizeof(ProgramInfoHeader);
|
||||
std::memcpy(out.data() + offset, acid_service_access.data(), acid_service_access.size());
|
||||
offset += acid_service_access.size();
|
||||
std::memcpy(out.data() + offset, aci0_service_access.data(), aci0_service_access.size());
|
||||
offset += aci0_service_access.size();
|
||||
std::memcpy(out.data() + offset, acid_file_access.data(), acid_file_access.size());
|
||||
offset += acid_file_access.size();
|
||||
std::memcpy(out.data() + offset, aci0_file_access.data(), aci0_file_access.size());
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
} // Anonymous namespace
|
||||
|
||||
class DebugMonitor final : public ServiceFramework<DebugMonitor> {
|
||||
public:
|
||||
explicit DebugMonitor() : ServiceFramework{"ldr:dmnt"} {
|
||||
explicit DebugMonitor(const std::vector<Kernel::SharedPtr<Kernel::Process>>& process_list)
|
||||
: ServiceFramework{"ldr:dmnt"}, process_list(process_list) {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "AddProcessToDebugLaunchQueue"},
|
||||
{1, nullptr, "ClearDebugLaunchQueue"},
|
||||
{2, nullptr, "GetNsoInfos"},
|
||||
{2, &DebugMonitor::GetNsoInfos, "GetNsoInfos"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
private:
|
||||
void GetNsoInfos(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto process_id = rp.PopRaw<u64>();
|
||||
|
||||
auto write_size = ctx.GetWriteBufferSize() / sizeof(NSOInfo);
|
||||
|
||||
LOG_DEBUG(Service_LDR, "called, process_id={:016X}, write_size={:08X}", process_id,
|
||||
write_size);
|
||||
|
||||
const auto iter = std::find_if(
|
||||
process_list.begin(), process_list.end(),
|
||||
[process_id](const auto& process) { return process->GetProcessID() == process_id; });
|
||||
|
||||
if (iter == process_list.end()) {
|
||||
LOG_ERROR(Service_LDR, "Cannot find process with given process ID!");
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ERROR_TITLE_NOT_FOUND);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& modules = (*iter)->GetModules();
|
||||
const auto nso_infos = GetNSOInfo(modules);
|
||||
|
||||
write_size = std::min<std::size_t>(write_size, nso_infos.size());
|
||||
|
||||
ctx.WriteBuffer(nso_infos.data(), write_size * sizeof(NSOInfo));
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push(write_size);
|
||||
}
|
||||
|
||||
const std::vector<Kernel::SharedPtr<Kernel::Process>>& process_list;
|
||||
};
|
||||
|
||||
class ProcessManager final : public ServiceFramework<ProcessManager> {
|
||||
@@ -518,11 +645,14 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
void InstallInterfaces(SM::ServiceManager& sm) {
|
||||
std::make_shared<DebugMonitor>()->InstallAsService(sm);
|
||||
std::make_shared<ProcessManager>()->InstallAsService(sm);
|
||||
std::make_shared<Shell>()->InstallAsService(sm);
|
||||
std::make_shared<RelocatableObject>()->InstallAsService(sm);
|
||||
void InstallInterfaces(Core::System& system) {
|
||||
std::make_shared<DebugMonitor>(system.Kernel().GetProcessList())
|
||||
->InstallAsService(system.ServiceManager());
|
||||
std::make_shared<ProcessManager>(system.Kernel().GetProcessList())
|
||||
->InstallAsService(system.ServiceManager());
|
||||
std::make_shared<Shell>()->InstallAsService(system.ServiceManager());
|
||||
std::make_shared<RelocatableObject>("ldr:ro")->InstallAsService(system.ServiceManager());
|
||||
std::make_shared<RelocatableObject>("ro:1")->InstallAsService(system.ServiceManager());
|
||||
}
|
||||
|
||||
} // namespace Service::LDR
|
||||
|
||||
@@ -11,6 +11,6 @@ class ServiceManager;
|
||||
namespace Service::LDR {
|
||||
|
||||
/// Registers all LDR services with the specified service manager.
|
||||
void InstallInterfaces(SM::ServiceManager& sm);
|
||||
void InstallInterfaces(Core::System& system);
|
||||
|
||||
} // namespace Service::LDR
|
||||
|
||||
@@ -225,7 +225,7 @@ void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system) {
|
||||
HID::InstallInterfaces(*sm);
|
||||
LBL::InstallInterfaces(*sm);
|
||||
LDN::InstallInterfaces(*sm);
|
||||
LDR::InstallInterfaces(*sm);
|
||||
LDR::InstallInterfaces(system);
|
||||
LM::InstallInterfaces(*sm);
|
||||
Migration::InstallInterfaces(*sm);
|
||||
Mii::InstallInterfaces(*sm);
|
||||
|
||||
Reference in New Issue
Block a user