Merge pull request #2482 from DarkLordZach/prepo
core: Add detailed local reporting feature for development
This commit is contained in:
commit
96412848a9
34 changed files with 825 additions and 54 deletions
|
@ -38,6 +38,7 @@
|
|||
#include "core/hle/result.h"
|
||||
#include "core/hle/service/service.h"
|
||||
#include "core/memory.h"
|
||||
#include "core/reporter.h"
|
||||
|
||||
namespace Kernel {
|
||||
namespace {
|
||||
|
@ -594,6 +595,7 @@ struct BreakReason {
|
|||
static void Break(Core::System& system, u32 reason, u64 info1, u64 info2) {
|
||||
BreakReason break_reason{reason};
|
||||
bool has_dumped_buffer{};
|
||||
std::vector<u8> debug_buffer;
|
||||
|
||||
const auto handle_debug_buffer = [&](VAddr addr, u64 sz) {
|
||||
if (sz == 0 || addr == 0 || has_dumped_buffer) {
|
||||
|
@ -605,7 +607,7 @@ static void Break(Core::System& system, u32 reason, u64 info1, u64 info2) {
|
|||
LOG_CRITICAL(Debug_Emulated, "debug_buffer_err_code={:X}", Memory::Read32(addr));
|
||||
} else {
|
||||
// We don't know what's in here so we'll hexdump it
|
||||
std::vector<u8> debug_buffer(sz);
|
||||
debug_buffer.resize(sz);
|
||||
Memory::ReadBlock(addr, debug_buffer.data(), sz);
|
||||
std::string hexdump;
|
||||
for (std::size_t i = 0; i < debug_buffer.size(); i++) {
|
||||
|
@ -664,6 +666,10 @@ static void Break(Core::System& system, u32 reason, u64 info1, u64 info2) {
|
|||
break;
|
||||
}
|
||||
|
||||
system.GetReporter().SaveSvcBreakReport(
|
||||
static_cast<u32>(break_reason.break_type.Value()), break_reason.signal_debugger, info1,
|
||||
info2, has_dumped_buffer ? std::make_optional(debug_buffer) : std::nullopt);
|
||||
|
||||
if (!break_reason.signal_debugger) {
|
||||
LOG_CRITICAL(
|
||||
Debug_Emulated,
|
||||
|
|
|
@ -35,12 +35,28 @@ AppletDataBroker::AppletDataBroker() {
|
|||
|
||||
AppletDataBroker::~AppletDataBroker() = default;
|
||||
|
||||
AppletDataBroker::RawChannelData AppletDataBroker::PeekDataToAppletForDebug() const {
|
||||
std::vector<std::vector<u8>> out_normal;
|
||||
|
||||
for (const auto& storage : in_channel) {
|
||||
out_normal.push_back(storage->GetData());
|
||||
}
|
||||
|
||||
std::vector<std::vector<u8>> out_interactive;
|
||||
|
||||
for (const auto& storage : in_interactive_channel) {
|
||||
out_interactive.push_back(storage->GetData());
|
||||
}
|
||||
|
||||
return {std::move(out_normal), std::move(out_interactive)};
|
||||
}
|
||||
|
||||
std::unique_ptr<IStorage> AppletDataBroker::PopNormalDataToGame() {
|
||||
if (out_channel.empty())
|
||||
return nullptr;
|
||||
|
||||
auto out = std::move(out_channel.front());
|
||||
out_channel.pop();
|
||||
out_channel.pop_front();
|
||||
return out;
|
||||
}
|
||||
|
||||
|
@ -49,7 +65,7 @@ std::unique_ptr<IStorage> AppletDataBroker::PopNormalDataToApplet() {
|
|||
return nullptr;
|
||||
|
||||
auto out = std::move(in_channel.front());
|
||||
in_channel.pop();
|
||||
in_channel.pop_front();
|
||||
return out;
|
||||
}
|
||||
|
||||
|
@ -58,7 +74,7 @@ std::unique_ptr<IStorage> AppletDataBroker::PopInteractiveDataToGame() {
|
|||
return nullptr;
|
||||
|
||||
auto out = std::move(out_interactive_channel.front());
|
||||
out_interactive_channel.pop();
|
||||
out_interactive_channel.pop_front();
|
||||
return out;
|
||||
}
|
||||
|
||||
|
@ -67,25 +83,25 @@ std::unique_ptr<IStorage> AppletDataBroker::PopInteractiveDataToApplet() {
|
|||
return nullptr;
|
||||
|
||||
auto out = std::move(in_interactive_channel.front());
|
||||
in_interactive_channel.pop();
|
||||
in_interactive_channel.pop_front();
|
||||
return out;
|
||||
}
|
||||
|
||||
void AppletDataBroker::PushNormalDataFromGame(IStorage storage) {
|
||||
in_channel.push(std::make_unique<IStorage>(storage));
|
||||
in_channel.push_back(std::make_unique<IStorage>(storage));
|
||||
}
|
||||
|
||||
void AppletDataBroker::PushNormalDataFromApplet(IStorage storage) {
|
||||
out_channel.push(std::make_unique<IStorage>(storage));
|
||||
out_channel.push_back(std::make_unique<IStorage>(storage));
|
||||
pop_out_data_event.writable->Signal();
|
||||
}
|
||||
|
||||
void AppletDataBroker::PushInteractiveDataFromGame(IStorage storage) {
|
||||
in_interactive_channel.push(std::make_unique<IStorage>(storage));
|
||||
in_interactive_channel.push_back(std::make_unique<IStorage>(storage));
|
||||
}
|
||||
|
||||
void AppletDataBroker::PushInteractiveDataFromApplet(IStorage storage) {
|
||||
out_interactive_channel.push(std::make_unique<IStorage>(storage));
|
||||
out_interactive_channel.push_back(std::make_unique<IStorage>(storage));
|
||||
pop_interactive_out_data_event.writable->Signal();
|
||||
}
|
||||
|
||||
|
@ -204,7 +220,7 @@ std::shared_ptr<Applet> AppletManager::GetApplet(AppletId id) const {
|
|||
UNIMPLEMENTED_MSG(
|
||||
"No backend implementation exists for applet_id={:02X}! Falling back to stub applet.",
|
||||
static_cast<u8>(id));
|
||||
return std::make_shared<StubApplet>();
|
||||
return std::make_shared<StubApplet>(id);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -54,6 +54,14 @@ public:
|
|||
AppletDataBroker();
|
||||
~AppletDataBroker();
|
||||
|
||||
struct RawChannelData {
|
||||
std::vector<std::vector<u8>> normal;
|
||||
std::vector<std::vector<u8>> interactive;
|
||||
};
|
||||
|
||||
// Retrieves but does not pop the data sent to applet.
|
||||
RawChannelData PeekDataToAppletForDebug() const;
|
||||
|
||||
std::unique_ptr<IStorage> PopNormalDataToGame();
|
||||
std::unique_ptr<IStorage> PopNormalDataToApplet();
|
||||
|
||||
|
@ -76,16 +84,16 @@ private:
|
|||
// Queues are named from applet's perspective
|
||||
|
||||
// PopNormalDataToApplet and PushNormalDataFromGame
|
||||
std::queue<std::unique_ptr<IStorage>> in_channel;
|
||||
std::deque<std::unique_ptr<IStorage>> in_channel;
|
||||
|
||||
// PopNormalDataToGame and PushNormalDataFromApplet
|
||||
std::queue<std::unique_ptr<IStorage>> out_channel;
|
||||
std::deque<std::unique_ptr<IStorage>> out_channel;
|
||||
|
||||
// PopInteractiveDataToApplet and PushInteractiveDataFromGame
|
||||
std::queue<std::unique_ptr<IStorage>> in_interactive_channel;
|
||||
std::deque<std::unique_ptr<IStorage>> in_interactive_channel;
|
||||
|
||||
// PopInteractiveDataToGame and PushInteractiveDataFromApplet
|
||||
std::queue<std::unique_ptr<IStorage>> out_interactive_channel;
|
||||
std::deque<std::unique_ptr<IStorage>> out_interactive_channel;
|
||||
|
||||
Kernel::EventPair state_changed_event;
|
||||
|
||||
|
|
|
@ -9,8 +9,10 @@
|
|||
#include "common/string_util.h"
|
||||
#include "core/core.h"
|
||||
#include "core/frontend/applets/error.h"
|
||||
#include "core/hle/kernel/process.h"
|
||||
#include "core/hle/service/am/am.h"
|
||||
#include "core/hle/service/am/applets/error.h"
|
||||
#include "core/reporter.h"
|
||||
|
||||
namespace Service::AM::Applets {
|
||||
|
||||
|
@ -143,9 +145,12 @@ void Error::Execute() {
|
|||
}
|
||||
|
||||
const auto callback = [this] { DisplayCompleted(); };
|
||||
const auto title_id = Core::CurrentProcess()->GetTitleID();
|
||||
const auto& reporter{Core::System::GetInstance().GetReporter()};
|
||||
|
||||
switch (mode) {
|
||||
case ErrorAppletMode::ShowError:
|
||||
reporter.SaveErrorReport(title_id, error_code);
|
||||
frontend.ShowError(error_code, callback);
|
||||
break;
|
||||
case ErrorAppletMode::ShowSystemError:
|
||||
|
@ -156,14 +161,18 @@ void Error::Execute() {
|
|||
const auto& detail_text =
|
||||
system ? args->system_error.detail_text : args->application_error.detail_text;
|
||||
|
||||
frontend.ShowCustomErrorText(
|
||||
error_code,
|
||||
Common::StringFromFixedZeroTerminatedBuffer(main_text.data(), main_text.size()),
|
||||
Common::StringFromFixedZeroTerminatedBuffer(detail_text.data(), detail_text.size()),
|
||||
callback);
|
||||
const auto main_text_string =
|
||||
Common::StringFromFixedZeroTerminatedBuffer(main_text.data(), main_text.size());
|
||||
const auto detail_text_string =
|
||||
Common::StringFromFixedZeroTerminatedBuffer(detail_text.data(), detail_text.size());
|
||||
|
||||
reporter.SaveErrorReport(title_id, error_code, main_text_string, detail_text_string);
|
||||
frontend.ShowCustomErrorText(error_code, main_text_string, detail_text_string, callback);
|
||||
break;
|
||||
}
|
||||
case ErrorAppletMode::ShowErrorRecord:
|
||||
reporter.SaveErrorReport(title_id, error_code,
|
||||
fmt::format("{:016X}", args->error_record.posix_time));
|
||||
frontend.ShowErrorWithTimestamp(
|
||||
error_code, std::chrono::seconds{args->error_record.posix_time}, callback);
|
||||
break;
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "core/hle/result.h"
|
||||
#include "core/hle/service/am/am.h"
|
||||
#include "core/hle/service/am/applets/general_backend.h"
|
||||
#include "core/reporter.h"
|
||||
|
||||
namespace Service::AM::Applets {
|
||||
|
||||
|
@ -83,13 +84,20 @@ void PhotoViewer::ViewFinished() {
|
|||
broker.SignalStateChanged();
|
||||
}
|
||||
|
||||
StubApplet::StubApplet() = default;
|
||||
StubApplet::StubApplet(AppletId id) : id(id) {}
|
||||
|
||||
StubApplet::~StubApplet() = default;
|
||||
|
||||
void StubApplet::Initialize() {
|
||||
LOG_WARNING(Service_AM, "called (STUBBED)");
|
||||
Applet::Initialize();
|
||||
|
||||
const auto data = broker.PeekDataToAppletForDebug();
|
||||
Core::System::GetInstance().GetReporter().SaveUnimplementedAppletReport(
|
||||
static_cast<u32>(id), common_args.arguments_version, common_args.library_version,
|
||||
common_args.theme_color, common_args.play_startup_sound, common_args.system_tick,
|
||||
data.normal, data.interactive);
|
||||
|
||||
LogCurrentStorage(broker, "Initialize");
|
||||
}
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ private:
|
|||
|
||||
class StubApplet final : public Applet {
|
||||
public:
|
||||
StubApplet();
|
||||
explicit StubApplet(AppletId id);
|
||||
~StubApplet() override;
|
||||
|
||||
void Initialize() override;
|
||||
|
@ -43,6 +43,9 @@ public:
|
|||
ResultCode GetStatus() const override;
|
||||
void ExecuteInteractive() override;
|
||||
void Execute() override;
|
||||
|
||||
private:
|
||||
AppletId id;
|
||||
};
|
||||
|
||||
} // namespace Service::AM::Applets
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "core/hle/service/fatal/fatal.h"
|
||||
#include "core/hle/service/fatal/fatal_p.h"
|
||||
#include "core/hle/service/fatal/fatal_u.h"
|
||||
#include "core/reporter.h"
|
||||
|
||||
namespace Service::Fatal {
|
||||
|
||||
|
@ -100,27 +101,10 @@ static void GenerateErrorReport(ResultCode error_code, const FatalInfo& info) {
|
|||
|
||||
LOG_ERROR(Service_Fatal, "{}", crash_report);
|
||||
|
||||
const std::string crashreport_dir =
|
||||
FileUtil::GetUserPath(FileUtil::UserPath::LogDir) + "crash_logs";
|
||||
|
||||
if (!FileUtil::CreateFullPath(crashreport_dir)) {
|
||||
LOG_ERROR(
|
||||
Service_Fatal,
|
||||
"Unable to create crash report directory. Possible log directory permissions issue.");
|
||||
return;
|
||||
}
|
||||
|
||||
const std::time_t t = std::time(nullptr);
|
||||
const std::string crashreport_filename =
|
||||
fmt::format("{}/{:016x}-{:%F-%H%M%S}.log", crashreport_dir, title_id, *std::localtime(&t));
|
||||
|
||||
auto file = FileUtil::IOFile(crashreport_filename, "wb");
|
||||
if (file.IsOpen()) {
|
||||
file.WriteString(crash_report);
|
||||
LOG_ERROR(Service_Fatal, "Saving error report to {}", crashreport_filename);
|
||||
} else {
|
||||
LOG_ERROR(Service_Fatal, "Failed to save error report to {}", crashreport_filename);
|
||||
}
|
||||
Core::System::GetInstance().GetReporter().SaveCrashReport(
|
||||
title_id, error_code, info.set_flags, info.program_entry_point, info.sp, info.pc,
|
||||
info.pstate, info.afsr0, info.afsr1, info.esr, info.far, info.registers, info.backtrace,
|
||||
info.backtrace_size, info.ArchAsString(), info.unk10);
|
||||
}
|
||||
|
||||
static void ThrowFatalError(ResultCode error_code, FatalType fatal_type, const FatalInfo& info) {
|
||||
|
|
|
@ -2,10 +2,18 @@
|
|||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <json.hpp>
|
||||
#include "common/file_util.h"
|
||||
#include "common/hex_util.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/scm_rev.h"
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/kernel/process.h"
|
||||
#include "core/hle/service/acc/profile_manager.h"
|
||||
#include "core/hle/service/prepo/prepo.h"
|
||||
#include "core/hle/service/service.h"
|
||||
#include "core/reporter.h"
|
||||
#include "core/settings.h"
|
||||
|
||||
namespace Service::PlayReport {
|
||||
|
||||
|
@ -40,8 +48,21 @@ public:
|
|||
|
||||
private:
|
||||
void SaveReportWithUserOld(Kernel::HLERequestContext& ctx) {
|
||||
// TODO(ogniK): Do we want to add play report?
|
||||
LOG_WARNING(Service_PREPO, "(STUBBED) called");
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto user_id = rp.PopRaw<u128>();
|
||||
const auto process_id = rp.PopRaw<u64>();
|
||||
|
||||
const auto data1 = ctx.ReadBuffer(0);
|
||||
const auto data2 = ctx.ReadBuffer(1);
|
||||
|
||||
LOG_DEBUG(
|
||||
Service_PREPO,
|
||||
"called, user_id={:016X}{:016X}, unk1={:016X}, data1_size={:016X}, data2_size={:016X}",
|
||||
user_id[1], user_id[0], process_id, data1.size(), data2.size());
|
||||
|
||||
const auto& reporter{Core::System::GetInstance().GetReporter()};
|
||||
reporter.SavePlayReport(Core::CurrentProcess()->GetTitleID(), process_id, {data1, data2},
|
||||
user_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
|
|
@ -68,6 +68,7 @@
|
|||
#include "core/hle/service/usb/usb.h"
|
||||
#include "core/hle/service/vi/vi.h"
|
||||
#include "core/hle/service/wlan/wlan.h"
|
||||
#include "core/reporter.h"
|
||||
|
||||
namespace Service {
|
||||
|
||||
|
@ -148,6 +149,8 @@ void ServiceFrameworkBase::ReportUnimplementedFunction(Kernel::HLERequestContext
|
|||
}
|
||||
buf.push_back('}');
|
||||
|
||||
Core::System::GetInstance().GetReporter().SaveUnimplementedFunctionReport(
|
||||
ctx, ctx.GetCommand(), function_name, service_name);
|
||||
UNIMPLEMENTED_MSG("Unknown / unimplemented {}", fmt::to_string(buf));
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue