From 3ef9673360089b1729ff174eefad9195d8eaf97f Mon Sep 17 00:00:00 2001
From: Liam <byteslice@airmail.cc>
Date: Thu, 14 Sep 2023 14:34:05 -0400
Subject: [PATCH] core: improve debug workflow

---
 src/core/file_sys/patch_manager.cpp             | 4 ++--
 src/core/file_sys/patch_manager.h               | 2 +-
 src/core/hle/kernel/k_process.cpp               | 5 ++++-
 src/core/hle/kernel/k_process.h                 | 8 +++++++-
 src/core/hle/kernel/svc/svc_debug_string.cpp    | 2 +-
 src/core/hle/kernel/svc/svc_exception.cpp       | 6 +++++-
 src/core/loader/deconstructed_rom_directory.cpp | 8 ++++----
 src/core/loader/deconstructed_rom_directory.h   | 4 +++-
 src/core/loader/kip.cpp                         | 3 ++-
 src/core/loader/nro.cpp                         | 3 ++-
 src/core/loader/nso.cpp                         | 5 +++--
 src/core/loader/nsp.cpp                         | 3 ++-
 12 files changed, 36 insertions(+), 17 deletions(-)

diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp
index a4baddb15a..8e475f25a3 100644
--- a/src/core/file_sys/patch_manager.cpp
+++ b/src/core/file_sys/patch_manager.cpp
@@ -294,11 +294,11 @@ std::vector<u8> PatchManager::PatchNSO(const std::vector<u8>& nso, const std::st
     return out;
 }
 
-bool PatchManager::HasNSOPatch(const BuildID& build_id_) const {
+bool PatchManager::HasNSOPatch(const BuildID& build_id_, std::string_view name) const {
     const auto build_id_raw = Common::HexToString(build_id_);
     const auto build_id = build_id_raw.substr(0, build_id_raw.find_last_not_of('0') + 1);
 
-    LOG_INFO(Loader, "Querying NSO patch existence for build_id={}", build_id);
+    LOG_INFO(Loader, "Querying NSO patch existence for build_id={}, name={}", build_id, name);
 
     const auto load_dir = fs_controller.GetModificationLoadRoot(title_id);
     if (load_dir == nullptr) {
diff --git a/src/core/file_sys/patch_manager.h b/src/core/file_sys/patch_manager.h
index adcde7b7d6..03e9c7301d 100644
--- a/src/core/file_sys/patch_manager.h
+++ b/src/core/file_sys/patch_manager.h
@@ -52,7 +52,7 @@ public:
 
     // Checks to see if PatchNSO() will have any effect given the NSO's build ID.
     // Used to prevent expensive copies in NSO loader.
-    [[nodiscard]] bool HasNSOPatch(const BuildID& build_id) const;
+    [[nodiscard]] bool HasNSOPatch(const BuildID& build_id, std::string_view name) const;
 
     // Creates a CheatList object with all
     [[nodiscard]] std::vector<Core::Memory::CheatEntry> CreateCheatList(
diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp
index 703049ede9..4a099286b5 100644
--- a/src/core/hle/kernel/k_process.cpp
+++ b/src/core/hle/kernel/k_process.cpp
@@ -96,6 +96,7 @@ Result KProcess::Initialize(KProcess* process, Core::System& system, std::string
     process->m_is_suspended = false;
     process->m_schedule_count = 0;
     process->m_is_handle_table_initialized = false;
+    process->m_is_hbl = false;
 
     // Open a reference to the resource limit.
     process->m_resource_limit->Open();
@@ -351,12 +352,14 @@ Result KProcess::SetActivity(ProcessActivity activity) {
     R_SUCCEED();
 }
 
-Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std::size_t code_size) {
+Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std::size_t code_size,
+                                  bool is_hbl) {
     m_program_id = metadata.GetTitleID();
     m_ideal_core = metadata.GetMainThreadCore();
     m_is_64bit_process = metadata.Is64BitProgram();
     m_system_resource_size = metadata.GetSystemResourceSize();
     m_image_size = code_size;
+    m_is_hbl = is_hbl;
 
     if (metadata.GetAddressSpaceType() == FileSys::ProgramAddressSpaceType::Is39Bit) {
         // For 39-bit processes, the ASLR region starts at 0x800'0000 and is ~512GiB large.
diff --git a/src/core/hle/kernel/k_process.h b/src/core/hle/kernel/k_process.h
index 4fdeaf11a0..146e07a57b 100644
--- a/src/core/hle/kernel/k_process.h
+++ b/src/core/hle/kernel/k_process.h
@@ -338,7 +338,8 @@ public:
      * @returns ResultSuccess if all relevant metadata was able to be
      *          loaded and parsed. Otherwise, an error code is returned.
      */
-    Result LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std::size_t code_size);
+    Result LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std::size_t code_size,
+                            bool is_hbl);
 
     /**
      * Starts the main application thread for this process.
@@ -368,6 +369,10 @@ public:
         return GetProcessId();
     }
 
+    bool IsHbl() const {
+        return m_is_hbl;
+    }
+
     bool IsSignaled() const override;
 
     void DoWorkerTaskImpl();
@@ -525,6 +530,7 @@ private:
     bool m_is_immortal{};
     bool m_is_handle_table_initialized{};
     bool m_is_initialized{};
+    bool m_is_hbl{};
 
     std::atomic<u16> m_num_running_threads{};
 
diff --git a/src/core/hle/kernel/svc/svc_debug_string.cpp b/src/core/hle/kernel/svc/svc_debug_string.cpp
index 4c14ce6683..00b65429be 100644
--- a/src/core/hle/kernel/svc/svc_debug_string.cpp
+++ b/src/core/hle/kernel/svc/svc_debug_string.cpp
@@ -14,7 +14,7 @@ Result OutputDebugString(Core::System& system, u64 address, u64 len) {
 
     std::string str(len, '\0');
     GetCurrentMemory(system.Kernel()).ReadBlock(address, str.data(), str.size());
-    LOG_DEBUG(Debug_Emulated, "{}", str);
+    LOG_INFO(Debug_Emulated, "{}", str);
 
     R_SUCCEED();
 }
diff --git a/src/core/hle/kernel/svc/svc_exception.cpp b/src/core/hle/kernel/svc/svc_exception.cpp
index 580cf2f75c..c581c086b8 100644
--- a/src/core/hle/kernel/svc/svc_exception.cpp
+++ b/src/core/hle/kernel/svc/svc_exception.cpp
@@ -3,6 +3,7 @@
 
 #include "core/core.h"
 #include "core/debugger/debugger.h"
+#include "core/hle/kernel/k_process.h"
 #include "core/hle/kernel/k_thread.h"
 #include "core/hle/kernel/svc.h"
 #include "core/hle/kernel/svc_types.h"
@@ -107,7 +108,10 @@ void Break(Core::System& system, BreakReason reason, u64 info1, u64 info2) {
         system.ArmInterface(static_cast<std::size_t>(thread_processor_id)).LogBacktrace();
     }
 
-    if (system.DebuggerEnabled()) {
+    const bool is_hbl = GetCurrentProcess(system.Kernel()).IsHbl();
+    const bool should_break = is_hbl || !notification_only;
+
+    if (system.DebuggerEnabled() && should_break) {
         auto* thread = system.Kernel().GetCurrentEmuThread();
         system.GetDebugger().NotifyThreadStopped(thread);
         thread->RequestSuspend(Kernel::SuspendType::Debug);
diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp
index f4eaf3331f..5a42dea486 100644
--- a/src/core/loader/deconstructed_rom_directory.cpp
+++ b/src/core/loader/deconstructed_rom_directory.cpp
@@ -18,7 +18,7 @@ namespace Loader {
 
 AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(FileSys::VirtualFile file_,
                                                                          bool override_update_)
-    : AppLoader(std::move(file_)), override_update(override_update_) {
+    : AppLoader(std::move(file_)), override_update(override_update_), is_hbl(false) {
     const auto file_dir = file->GetContainingDirectory();
 
     // Title ID
@@ -69,9 +69,9 @@ AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(FileSys
 }
 
 AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(
-    FileSys::VirtualDir directory, bool override_update_)
+    FileSys::VirtualDir directory, bool override_update_, bool is_hbl_)
     : AppLoader(directory->GetFile("main")), dir(std::move(directory)),
-      override_update(override_update_) {}
+      override_update(override_update_), is_hbl(is_hbl_) {}
 
 FileType AppLoader_DeconstructedRomDirectory::IdentifyType(const FileSys::VirtualFile& dir_file) {
     if (FileSys::IsDirectoryExeFS(dir_file->GetContainingDirectory())) {
@@ -147,7 +147,7 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect
     }
 
     // Setup the process code layout
-    if (process.LoadFromMetadata(metadata, code_size).IsError()) {
+    if (process.LoadFromMetadata(metadata, code_size, is_hbl).IsError()) {
         return {ResultStatus::ErrorUnableToParseKernelMetadata, {}};
     }
 
diff --git a/src/core/loader/deconstructed_rom_directory.h b/src/core/loader/deconstructed_rom_directory.h
index f7702225ef..1e9f765c9d 100644
--- a/src/core/loader/deconstructed_rom_directory.h
+++ b/src/core/loader/deconstructed_rom_directory.h
@@ -27,7 +27,8 @@ public:
 
     // Overload to accept exefs directory. Must contain 'main' and 'main.npdm'
     explicit AppLoader_DeconstructedRomDirectory(FileSys::VirtualDir directory,
-                                                 bool override_update_ = false);
+                                                 bool override_update_ = false,
+                                                 bool is_hbl_ = false);
 
     /**
      * Identifies whether or not the given file is a deconstructed ROM directory.
@@ -62,6 +63,7 @@ private:
     std::string name;
     u64 title_id{};
     bool override_update;
+    bool is_hbl;
 
     Modules modules;
 };
diff --git a/src/core/loader/kip.cpp b/src/core/loader/kip.cpp
index d722459c64..bf56a08b40 100644
--- a/src/core/loader/kip.cpp
+++ b/src/core/loader/kip.cpp
@@ -90,7 +90,8 @@ AppLoader::LoadResult AppLoader_KIP::Load(Kernel::KProcess& process,
     codeset.DataSegment().size += kip->GetBSSSize();
 
     // Setup the process code layout
-    if (process.LoadFromMetadata(FileSys::ProgramMetadata::GetDefault(), program_image.size())
+    if (process
+            .LoadFromMetadata(FileSys::ProgramMetadata::GetDefault(), program_image.size(), false)
             .IsError()) {
         return {ResultStatus::ErrorNotInitialized, {}};
     }
diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp
index d7562b4bc1..69f1a54ed6 100644
--- a/src/core/loader/nro.cpp
+++ b/src/core/loader/nro.cpp
@@ -196,7 +196,8 @@ static bool LoadNroImpl(Kernel::KProcess& process, const std::vector<u8>& data)
     program_image.resize(static_cast<u32>(program_image.size()) + bss_size);
 
     // Setup the process code layout
-    if (process.LoadFromMetadata(FileSys::ProgramMetadata::GetDefault(), program_image.size())
+    if (process
+            .LoadFromMetadata(FileSys::ProgramMetadata::GetDefault(), program_image.size(), false)
             .IsError()) {
         return false;
     }
diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp
index 549822506b..1350da8dca 100644
--- a/src/core/loader/nso.cpp
+++ b/src/core/loader/nso.cpp
@@ -127,13 +127,14 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::KProcess& process, Core::
     }
 
     // Apply patches if necessary
-    if (pm && (pm->HasNSOPatch(nso_header.build_id) || Settings::values.dump_nso)) {
+    const auto name = nso_file.GetName();
+    if (pm && (pm->HasNSOPatch(nso_header.build_id, name) || Settings::values.dump_nso)) {
         std::vector<u8> pi_header(sizeof(NSOHeader) + program_image.size());
         std::memcpy(pi_header.data(), &nso_header, sizeof(NSOHeader));
         std::memcpy(pi_header.data() + sizeof(NSOHeader), program_image.data(),
                     program_image.size());
 
-        pi_header = pm->PatchNSO(pi_header, nso_file.GetName());
+        pi_header = pm->PatchNSO(pi_header, name);
 
         std::copy(pi_header.begin() + sizeof(NSOHeader), pi_header.end(), program_image.data());
     }
diff --git a/src/core/loader/nsp.cpp b/src/core/loader/nsp.cpp
index fe2af1ae6f..f4ab75b770 100644
--- a/src/core/loader/nsp.cpp
+++ b/src/core/loader/nsp.cpp
@@ -30,7 +30,8 @@ AppLoader_NSP::AppLoader_NSP(FileSys::VirtualFile file_,
     }
 
     if (nsp->IsExtractedType()) {
-        secondary_loader = std::make_unique<AppLoader_DeconstructedRomDirectory>(nsp->GetExeFS());
+        secondary_loader = std::make_unique<AppLoader_DeconstructedRomDirectory>(
+            nsp->GetExeFS(), false, file->GetName() == "hbl.nsp");
     } else {
         const auto control_nca =
             nsp->GetNCA(nsp->GetProgramTitleID(), FileSys::ContentRecordType::Control);