summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/core/CMakeLists.txt2
-rw-r--r--src/core/core.cpp17
-rw-r--r--src/core/core.h8
-rw-r--r--src/core/hle/service/lm/lm.cpp187
-rw-r--r--src/core/hle/service/lm/lm.h6
-rw-r--r--src/core/hle/service/lm/manager.cpp133
-rw-r--r--src/core/hle/service/lm/manager.h106
-rw-r--r--src/core/hle/service/service.cpp2
-rw-r--r--src/core/reporter.cpp51
-rw-r--r--src/core/reporter.h14
10 files changed, 367 insertions, 159 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 3416854db..3b1d72cf9 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -335,6 +335,8 @@ add_library(core STATIC
335 hle/service/ldr/ldr.h 335 hle/service/ldr/ldr.h
336 hle/service/lm/lm.cpp 336 hle/service/lm/lm.cpp
337 hle/service/lm/lm.h 337 hle/service/lm/lm.h
338 hle/service/lm/manager.cpp
339 hle/service/lm/manager.h
338 hle/service/mig/mig.cpp 340 hle/service/mig/mig.cpp
339 hle/service/mig/mig.h 341 hle/service/mig/mig.h
340 hle/service/mii/mii.cpp 342 hle/service/mii/mii.cpp
diff --git a/src/core/core.cpp b/src/core/core.cpp
index a58ceb703..4d0ac72a5 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -35,6 +35,7 @@
35#include "core/hle/service/apm/controller.h" 35#include "core/hle/service/apm/controller.h"
36#include "core/hle/service/filesystem/filesystem.h" 36#include "core/hle/service/filesystem/filesystem.h"
37#include "core/hle/service/glue/manager.h" 37#include "core/hle/service/glue/manager.h"
38#include "core/hle/service/lm/manager.h"
38#include "core/hle/service/service.h" 39#include "core/hle/service/service.h"
39#include "core/hle/service/sm/sm.h" 40#include "core/hle/service/sm/sm.h"
40#include "core/loader/loader.h" 41#include "core/loader/loader.h"
@@ -250,6 +251,8 @@ struct System::Impl {
250 telemetry_session->AddField(Telemetry::FieldType::Performance, "Mean_Frametime_MS", 251 telemetry_session->AddField(Telemetry::FieldType::Performance, "Mean_Frametime_MS",
251 perf_stats->GetMeanFrametime()); 252 perf_stats->GetMeanFrametime());
252 253
254 lm_manager.Flush();
255
253 is_powered_on = false; 256 is_powered_on = false;
254 exit_lock = false; 257 exit_lock = false;
255 258
@@ -338,6 +341,7 @@ struct System::Impl {
338 bool is_powered_on = false; 341 bool is_powered_on = false;
339 bool exit_lock = false; 342 bool exit_lock = false;
340 343
344 Reporter reporter;
341 std::unique_ptr<Memory::CheatEngine> cheat_engine; 345 std::unique_ptr<Memory::CheatEngine> cheat_engine;
342 std::unique_ptr<Tools::Freezer> memory_freezer; 346 std::unique_ptr<Tools::Freezer> memory_freezer;
343 std::array<u8, 0x20> build_id{}; 347 std::array<u8, 0x20> build_id{};
@@ -348,8 +352,9 @@ struct System::Impl {
348 /// APM (Performance) services 352 /// APM (Performance) services
349 Service::APM::Controller apm_controller{core_timing}; 353 Service::APM::Controller apm_controller{core_timing};
350 354
351 /// Glue services 355 /// Service State
352 Service::Glue::ARPManager arp_manager; 356 Service::Glue::ARPManager arp_manager;
357 Service::LM::Manager lm_manager{reporter};
353 358
354 /// Service manager 359 /// Service manager
355 std::shared_ptr<Service::SM::ServiceManager> service_manager; 360 std::shared_ptr<Service::SM::ServiceManager> service_manager;
@@ -357,8 +362,6 @@ struct System::Impl {
357 /// Telemetry session for this emulation session 362 /// Telemetry session for this emulation session
358 std::unique_ptr<Core::TelemetrySession> telemetry_session; 363 std::unique_ptr<Core::TelemetrySession> telemetry_session;
359 364
360 Reporter reporter;
361
362 ResultStatus status = ResultStatus::Success; 365 ResultStatus status = ResultStatus::Success;
363 std::string status_details = ""; 366 std::string status_details = "";
364 367
@@ -634,6 +637,14 @@ const Service::APM::Controller& System::GetAPMController() const {
634 return impl->apm_controller; 637 return impl->apm_controller;
635} 638}
636 639
640Service::LM::Manager& System::GetLogManager() {
641 return impl->lm_manager;
642}
643
644const Service::LM::Manager& System::GetLogManager() const {
645 return impl->lm_manager;
646}
647
637void System::SetExitLock(bool locked) { 648void System::SetExitLock(bool locked) {
638 impl->exit_lock = locked; 649 impl->exit_lock = locked;
639} 650}
diff --git a/src/core/core.h b/src/core/core.h
index d13b6aa5e..90e7ac607 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -57,6 +57,10 @@ namespace Glue {
57class ARPManager; 57class ARPManager;
58} 58}
59 59
60namespace LM {
61class Manager;
62} // namespace LM
63
60namespace SM { 64namespace SM {
61class ServiceManager; 65class ServiceManager;
62} // namespace SM 66} // namespace SM
@@ -327,6 +331,10 @@ public:
327 331
328 const Service::APM::Controller& GetAPMController() const; 332 const Service::APM::Controller& GetAPMController() const;
329 333
334 Service::LM::Manager& GetLogManager();
335
336 const Service::LM::Manager& GetLogManager() const;
337
330 void SetExitLock(bool locked); 338 void SetExitLock(bool locked);
331 339
332 bool GetExitLock() const; 340 bool GetExitLock() const;
diff --git a/src/core/hle/service/lm/lm.cpp b/src/core/hle/service/lm/lm.cpp
index 2a61593e2..435f2d286 100644
--- a/src/core/hle/service/lm/lm.cpp
+++ b/src/core/hle/service/lm/lm.cpp
@@ -6,8 +6,10 @@
6#include <string> 6#include <string>
7 7
8#include "common/logging/log.h" 8#include "common/logging/log.h"
9#include "common/scope_exit.h"
9#include "core/hle/ipc_helpers.h" 10#include "core/hle/ipc_helpers.h"
10#include "core/hle/service/lm/lm.h" 11#include "core/hle/service/lm/lm.h"
12#include "core/hle/service/lm/manager.h"
11#include "core/hle/service/service.h" 13#include "core/hle/service/service.h"
12#include "core/memory.h" 14#include "core/memory.h"
13 15
@@ -15,65 +17,16 @@ namespace Service::LM {
15 17
16class ILogger final : public ServiceFramework<ILogger> { 18class ILogger final : public ServiceFramework<ILogger> {
17public: 19public:
18 ILogger() : ServiceFramework("ILogger") { 20 ILogger(Manager& manager) : ServiceFramework("ILogger"), manager(manager) {
19 static const FunctionInfo functions[] = { 21 static const FunctionInfo functions[] = {
20 {0x00000000, &ILogger::Initialize, "Initialize"}, 22 {0, &ILogger::Log, "Log"},
21 {0x00000001, &ILogger::SetDestination, "SetDestination"}, 23 {1, &ILogger::SetDestination, "SetDestination"},
22 }; 24 };
23 RegisterHandlers(functions); 25 RegisterHandlers(functions);
24 } 26 }
25 27
26private: 28private:
27 struct MessageHeader { 29 void Log(Kernel::HLERequestContext& ctx) {
28 enum Flags : u32_le {
29 IsHead = 1,
30 IsTail = 2,
31 };
32 enum Severity : u32_le {
33 Trace,
34 Info,
35 Warning,
36 Error,
37 Critical,
38 };
39
40 u64_le pid;
41 u64_le threadContext;
42 union {
43 BitField<0, 16, Flags> flags;
44 BitField<16, 8, Severity> severity;
45 BitField<24, 8, u32> verbosity;
46 };
47 u32_le payload_size;
48
49 bool IsHeadLog() const {
50 return flags & Flags::IsHead;
51 }
52 bool IsTailLog() const {
53 return flags & Flags::IsTail;
54 }
55 };
56 static_assert(sizeof(MessageHeader) == 0x18, "MessageHeader is incorrect size");
57
58 /// Log field type
59 enum class Field : u8 {
60 Skip = 1,
61 Message = 2,
62 Line = 3,
63 Filename = 4,
64 Function = 5,
65 Module = 6,
66 Thread = 7,
67 };
68
69 /**
70 * ILogger::Initialize service function
71 * Inputs:
72 * 0: 0x00000000
73 * Outputs:
74 * 0: ResultCode
75 */
76 void Initialize(Kernel::HLERequestContext& ctx) {
77 // This function only succeeds - Get that out of the way 30 // This function only succeeds - Get that out of the way
78 IPC::ResponseBuilder rb{ctx, 2}; 31 IPC::ResponseBuilder rb{ctx, 2};
79 rb.Push(RESULT_SUCCESS); 32 rb.Push(RESULT_SUCCESS);
@@ -85,140 +38,70 @@ private:
85 Memory::ReadBlock(addr, &header, sizeof(MessageHeader)); 38 Memory::ReadBlock(addr, &header, sizeof(MessageHeader));
86 addr += sizeof(MessageHeader); 39 addr += sizeof(MessageHeader);
87 40
88 if (header.IsHeadLog()) { 41 FieldMap fields;
89 log_stream.str("");
90 log_stream.clear();
91 }
92
93 // Parse out log metadata
94 u32 line{};
95 std::string module;
96 std::string message;
97 std::string filename;
98 std::string function;
99 std::string thread;
100 while (addr < end_addr) { 42 while (addr < end_addr) {
101 const Field field{static_cast<Field>(Memory::Read8(addr++))}; 43 const auto field = static_cast<Field>(Memory::Read8(addr++));
102 const std::size_t length{Memory::Read8(addr++)}; 44 const auto length = Memory::Read8(addr++);
103 45
104 if (static_cast<Field>(Memory::Read8(addr)) == Field::Skip) { 46 if (static_cast<Field>(Memory::Read8(addr)) == Field::Skip) {
105 ++addr; 47 ++addr;
106 } 48 }
107 49
108 switch (field) { 50 SCOPE_EXIT({ addr += length; });
109 case Field::Skip:
110 break;
111 case Field::Message:
112 message = Memory::ReadCString(addr, length);
113 break;
114 case Field::Line:
115 line = Memory::Read32(addr);
116 break;
117 case Field::Filename:
118 filename = Memory::ReadCString(addr, length);
119 break;
120 case Field::Function:
121 function = Memory::ReadCString(addr, length);
122 break;
123 case Field::Module:
124 module = Memory::ReadCString(addr, length);
125 break;
126 case Field::Thread:
127 thread = Memory::ReadCString(addr, length);
128 break;
129 }
130 51
131 addr += length; 52 if (field == Field::Skip) {
132 } 53 continue;
54 }
133 55
134 // Empty log - nothing to do here 56 std::vector<u8> data(length);
135 if (log_stream.str().empty() && message.empty()) { 57 Memory::ReadBlock(addr, data.data(), length);
136 return; 58 fields.emplace(field, std::move(data));
137 } 59 }
138 60
139 // Format a nicely printable string out of the log metadata 61 manager.Log({header, std::move(fields)});
140 if (!filename.empty()) {
141 log_stream << filename << ':';
142 }
143 if (!module.empty()) {
144 log_stream << module << ':';
145 }
146 if (!function.empty()) {
147 log_stream << function << ':';
148 }
149 if (line) {
150 log_stream << std::to_string(line) << ':';
151 }
152 if (!thread.empty()) {
153 log_stream << thread << ':';
154 }
155 if (log_stream.str().length() > 0 && log_stream.str().back() == ':') {
156 log_stream << ' ';
157 }
158 log_stream << message;
159
160 if (header.IsTailLog()) {
161 switch (header.severity) {
162 case MessageHeader::Severity::Trace:
163 LOG_DEBUG(Debug_Emulated, "{}", log_stream.str());
164 break;
165 case MessageHeader::Severity::Info:
166 LOG_INFO(Debug_Emulated, "{}", log_stream.str());
167 break;
168 case MessageHeader::Severity::Warning:
169 LOG_WARNING(Debug_Emulated, "{}", log_stream.str());
170 break;
171 case MessageHeader::Severity::Error:
172 LOG_ERROR(Debug_Emulated, "{}", log_stream.str());
173 break;
174 case MessageHeader::Severity::Critical:
175 LOG_CRITICAL(Debug_Emulated, "{}", log_stream.str());
176 break;
177 }
178 }
179 } 62 }
180 63
181 // This service function is intended to be used as a way to
182 // redirect logging output to different destinations, however,
183 // given we always want to see the logging output, it's sufficient
184 // to do nothing and return success here.
185 void SetDestination(Kernel::HLERequestContext& ctx) { 64 void SetDestination(Kernel::HLERequestContext& ctx) {
186 LOG_DEBUG(Service_LM, "called"); 65 IPC::RequestParser rp{ctx};
66 const auto destination = rp.PopEnum<DestinationFlag>();
67
68 LOG_DEBUG(Service_LM, "called, destination={:08X}", static_cast<u32>(destination));
69
70 manager.SetDestination(destination);
187 71
188 IPC::ResponseBuilder rb{ctx, 2}; 72 IPC::ResponseBuilder rb{ctx, 2};
189 rb.Push(RESULT_SUCCESS); 73 rb.Push(RESULT_SUCCESS);
190 } 74 }
191 75
192 std::ostringstream log_stream; 76 Manager& manager;
193}; 77};
194 78
195class LM final : public ServiceFramework<LM> { 79class LM final : public ServiceFramework<LM> {
196public: 80public:
197 explicit LM() : ServiceFramework{"lm"} { 81 explicit LM(Manager& manager) : ServiceFramework{"lm"}, manager(manager) {
82 // clang-format off
198 static const FunctionInfo functions[] = { 83 static const FunctionInfo functions[] = {
199 {0x00000000, &LM::OpenLogger, "OpenLogger"}, 84 {0, &LM::OpenLogger, "OpenLogger"},
200 }; 85 };
86 // clang-format on
87
201 RegisterHandlers(functions); 88 RegisterHandlers(functions);
202 } 89 }
203 90
204 /** 91private:
205 * LM::OpenLogger service function
206 * Inputs:
207 * 0: 0x00000000
208 * Outputs:
209 * 0: ResultCode
210 */
211 void OpenLogger(Kernel::HLERequestContext& ctx) { 92 void OpenLogger(Kernel::HLERequestContext& ctx) {
212 LOG_DEBUG(Service_LM, "called"); 93 LOG_DEBUG(Service_LM, "called");
213 94
214 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 95 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
215 rb.Push(RESULT_SUCCESS); 96 rb.Push(RESULT_SUCCESS);
216 rb.PushIpcInterface<ILogger>(); 97 rb.PushIpcInterface<ILogger>(manager);
217 } 98 }
99
100 Manager& manager;
218}; 101};
219 102
220void InstallInterfaces(SM::ServiceManager& service_manager) { 103void InstallInterfaces(Core::System& system) {
221 std::make_shared<LM>()->InstallAsService(service_manager); 104 std::make_shared<LM>(system.GetLogManager())->InstallAsService(system.ServiceManager());
222} 105}
223 106
224} // namespace Service::LM 107} // namespace Service::LM
diff --git a/src/core/hle/service/lm/lm.h b/src/core/hle/service/lm/lm.h
index 7806ae27b..d40410b5c 100644
--- a/src/core/hle/service/lm/lm.h
+++ b/src/core/hle/service/lm/lm.h
@@ -4,13 +4,13 @@
4 4
5#pragma once 5#pragma once
6 6
7namespace Service::SM { 7namespace Core {
8class ServiceManager; 8class System;
9} 9}
10 10
11namespace Service::LM { 11namespace Service::LM {
12 12
13/// Registers all LM services with the specified service manager. 13/// Registers all LM services with the specified service manager.
14void InstallInterfaces(SM::ServiceManager& service_manager); 14void InstallInterfaces(Core::System& system);
15 15
16} // namespace Service::LM 16} // namespace Service::LM
diff --git a/src/core/hle/service/lm/manager.cpp b/src/core/hle/service/lm/manager.cpp
new file mode 100644
index 000000000..b67081b86
--- /dev/null
+++ b/src/core/hle/service/lm/manager.cpp
@@ -0,0 +1,133 @@
1// Copyright 2019 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/assert.h"
6#include "common/logging/log.h"
7#include "common/string_util.h"
8#include "core/hle/service/lm/manager.h"
9#include "core/reporter.h"
10
11namespace Service::LM {
12
13std::ostream& operator<<(std::ostream& os, DestinationFlag dest) {
14 std::vector<std::string> array;
15 const auto check_single_flag = [dest, &array](DestinationFlag check, std::string name) {
16 if ((static_cast<u32>(check) & static_cast<u32>(dest)) != 0) {
17 array.emplace_back(std::move(name));
18 }
19 };
20
21 check_single_flag(DestinationFlag::Default, "Default");
22 check_single_flag(DestinationFlag::UART, "UART");
23 check_single_flag(DestinationFlag::UARTSleeping, "UART (Sleeping)");
24
25 os << "[";
26 for (const auto& entry : array) {
27 os << entry << ", ";
28 }
29 return os << "]";
30}
31
32std::ostream& operator<<(std::ostream& os, MessageHeader::Severity severity) {
33 switch (severity) {
34 case MessageHeader::Severity::Trace:
35 return os << "Trace";
36 case MessageHeader::Severity::Info:
37 return os << "Info";
38 case MessageHeader::Severity::Warning:
39 return os << "Warning";
40 case MessageHeader::Severity::Error:
41 return os << "Error";
42 case MessageHeader::Severity::Critical:
43 return os << "Critical";
44 default:
45 return os << fmt::format("{:08X}", static_cast<u32>(severity));
46 }
47}
48
49std::ostream& operator<<(std::ostream& os, Field field) {
50 switch (field) {
51 case Field::Skip:
52 return os << "Skip";
53 case Field::Message:
54 return os << "Message";
55 case Field::Line:
56 return os << "Line";
57 case Field::Filename:
58 return os << "Filename";
59 case Field::Function:
60 return os << "Function";
61 case Field::Module:
62 return os << "Module";
63 case Field::Thread:
64 return os << "Thread";
65 default:
66 return os << fmt::format("{:08X}", static_cast<u32>(field));
67 }
68}
69
70std::string FormatField(Field type, const std::vector<u8>& data) {
71 switch (type) {
72 case Field::Skip:
73 return "";
74 case Field::Line:
75 if (data.size() >= sizeof(u32)) {
76 u32 line;
77 std::memcpy(&line, data.data(), sizeof(u32));
78 return fmt::format("{}", line);
79 }
80 return "[ERROR DECODING LINE NUMBER]";
81 case Field::Message:
82 case Field::Filename:
83 case Field::Function:
84 case Field::Module:
85 case Field::Thread:
86 return Common::StringFromFixedZeroTerminatedBuffer(
87 reinterpret_cast<const char*>(data.data()), data.size());
88 default:
89 UNIMPLEMENTED();
90 }
91}
92
93Manager::Manager(Core::Reporter& reporter) : reporter(reporter) {}
94
95Manager::~Manager() = default;
96
97void Manager::SetEnabled(bool enabled) {
98 this->enabled = enabled;
99}
100
101void Manager::SetDestination(DestinationFlag destination) {
102 this->destination = destination;
103}
104
105void Manager::Log(LogMessage message) {
106 if (message.header.IsHeadLog()) {
107 InitializeLog();
108 }
109
110 current_log.emplace_back(std::move(message));
111
112 if (current_log.back().header.IsTailLog()) {
113 FinalizeLog();
114 }
115}
116
117void Manager::Flush() {
118 FinalizeLog();
119}
120
121void Manager::InitializeLog() {
122 current_log.clear();
123
124 LOG_INFO(Service_LM, "Initialized new log session");
125}
126
127void Manager::FinalizeLog() {
128 reporter.SaveLogReport(static_cast<u32>(destination), std::move(current_log));
129
130 LOG_INFO(Service_LM, "Finalized current log session");
131}
132
133} // namespace Service::LM
diff --git a/src/core/hle/service/lm/manager.h b/src/core/hle/service/lm/manager.h
new file mode 100644
index 000000000..544e636ba
--- /dev/null
+++ b/src/core/hle/service/lm/manager.h
@@ -0,0 +1,106 @@
1// Copyright 2019 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <map>
8#include <ostream>
9#include <vector>
10#include "common/bit_field.h"
11#include "common/common_types.h"
12#include "common/swap.h"
13
14namespace Core {
15class Reporter;
16}
17
18namespace Service::LM {
19
20enum class DestinationFlag : u32 {
21 Default = 1,
22 UART = 2,
23 UARTSleeping = 4,
24
25 All = 0xFFFF,
26};
27
28struct MessageHeader {
29 enum Flags : u32_le {
30 IsHead = 1,
31 IsTail = 2,
32 };
33 enum Severity : u32_le {
34 Trace,
35 Info,
36 Warning,
37 Error,
38 Critical,
39 };
40
41 u64_le pid;
42 u64_le thread_context;
43 union {
44 BitField<0, 16, Flags> flags;
45 BitField<16, 8, Severity> severity;
46 BitField<24, 8, u32> verbosity;
47 };
48 u32_le payload_size;
49
50 bool IsHeadLog() const {
51 return flags & IsHead;
52 }
53 bool IsTailLog() const {
54 return flags & IsTail;
55 }
56};
57static_assert(sizeof(MessageHeader) == 0x18, "MessageHeader is incorrect size");
58
59enum class Field : u8 {
60 Skip = 1,
61 Message = 2,
62 Line = 3,
63 Filename = 4,
64 Function = 5,
65 Module = 6,
66 Thread = 7,
67};
68
69std::ostream& operator<<(std::ostream& os, DestinationFlag dest);
70std::ostream& operator<<(std::ostream& os, MessageHeader::Severity severity);
71std::ostream& operator<<(std::ostream& os, Field field);
72
73using FieldMap = std::map<Field, std::vector<u8>>;
74
75struct LogMessage {
76 MessageHeader header;
77 FieldMap fields;
78};
79
80std::string FormatField(Field type, const std::vector<u8>& data);
81
82class Manager {
83public:
84 explicit Manager(Core::Reporter& reporter);
85 ~Manager();
86
87 void SetEnabled(bool enabled);
88 void SetDestination(DestinationFlag destination);
89
90 void Log(LogMessage message);
91
92 void Flush();
93
94private:
95 void InitializeLog();
96 void FinalizeLog();
97
98 bool enabled = true;
99 DestinationFlag destination = DestinationFlag::All;
100
101 std::vector<LogMessage> current_log;
102
103 Core::Reporter& reporter;
104};
105
106} // namespace Service::LM
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index f2c6fe9dc..7c5302017 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -226,7 +226,7 @@ void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system) {
226 LBL::InstallInterfaces(*sm); 226 LBL::InstallInterfaces(*sm);
227 LDN::InstallInterfaces(*sm); 227 LDN::InstallInterfaces(*sm);
228 LDR::InstallInterfaces(*sm, system); 228 LDR::InstallInterfaces(*sm, system);
229 LM::InstallInterfaces(*sm); 229 LM::InstallInterfaces(system);
230 Migration::InstallInterfaces(*sm); 230 Migration::InstallInterfaces(*sm);
231 Mii::InstallInterfaces(*sm); 231 Mii::InstallInterfaces(*sm);
232 MM::InstallInterfaces(*sm); 232 MM::InstallInterfaces(*sm);
diff --git a/src/core/reporter.cpp b/src/core/reporter.cpp
index 9c657929e..6f4af77fd 100644
--- a/src/core/reporter.cpp
+++ b/src/core/reporter.cpp
@@ -7,6 +7,7 @@
7 7
8#include <fmt/chrono.h> 8#include <fmt/chrono.h>
9#include <fmt/format.h> 9#include <fmt/format.h>
10#include <fmt/ostream.h>
10#include <json.hpp> 11#include <json.hpp>
11 12
12#include "common/file_util.h" 13#include "common/file_util.h"
@@ -17,6 +18,7 @@
17#include "core/hle/kernel/hle_ipc.h" 18#include "core/hle/kernel/hle_ipc.h"
18#include "core/hle/kernel/process.h" 19#include "core/hle/kernel/process.h"
19#include "core/hle/result.h" 20#include "core/hle/result.h"
21#include "core/hle/service/lm/manager.h"
20#include "core/reporter.h" 22#include "core/reporter.h"
21#include "core/settings.h" 23#include "core/settings.h"
22 24
@@ -354,6 +356,55 @@ void Reporter::SaveErrorReport(u64 title_id, ResultCode result,
354 SaveToFile(std::move(out), GetPath("error_report", title_id, timestamp)); 356 SaveToFile(std::move(out), GetPath("error_report", title_id, timestamp));
355} 357}
356 358
359void Reporter::SaveLogReport(u32 destination, std::vector<Service::LM::LogMessage> messages) const {
360 if (!IsReportingEnabled()) {
361 return;
362 }
363
364 const auto timestamp = GetTimestamp();
365 json out;
366
367 out["yuzu_version"] = GetYuzuVersionData();
368 out["report_common"] =
369 GetReportCommonData(system.CurrentProcess()->GetTitleID(), RESULT_SUCCESS, timestamp);
370
371 out["log_destination"] =
372 fmt::format("{}", static_cast<Service::LM::DestinationFlag>(destination));
373
374 auto json_messages = json::array();
375 std::transform(messages.begin(), messages.end(), std::back_inserter(json_messages),
376 [](const Service::LM::LogMessage& message) {
377 json out;
378 out["is_head"] = fmt::format("{}", message.header.IsHeadLog());
379 out["is_tail"] = fmt::format("{}", message.header.IsTailLog());
380 out["pid"] = fmt::format("{:016X}", message.header.pid);
381 out["thread_context"] =
382 fmt::format("{:016X}", message.header.thread_context);
383 out["payload_size"] = fmt::format("{:016X}", message.header.payload_size);
384 out["flags"] = fmt::format("{:04X}", message.header.flags.Value());
385 out["severity"] = fmt::format("{}", message.header.severity.Value());
386 out["verbosity"] = fmt::format("{:02X}", message.header.verbosity);
387
388 auto fields = json::array();
389 std::transform(message.fields.begin(), message.fields.end(),
390 std::back_inserter(fields), [](const auto& kv) {
391 json out;
392 out["type"] = fmt::format("{}", kv.first);
393 out["data"] =
394 Service::LM::FormatField(kv.first, kv.second);
395 return out;
396 });
397
398 out["fields"] = std::move(fields);
399 return out;
400 });
401
402 out["log_messages"] = std::move(json_messages);
403
404 SaveToFile(std::move(out),
405 GetPath("log_report", system.CurrentProcess()->GetTitleID(), timestamp));
406}
407
357void Reporter::SaveFilesystemAccessReport(Service::FileSystem::LogMode log_mode, 408void Reporter::SaveFilesystemAccessReport(Service::FileSystem::LogMode log_mode,
358 std::string log_message) const { 409 std::string log_message) const {
359 if (!IsReportingEnabled()) 410 if (!IsReportingEnabled())
diff --git a/src/core/reporter.h b/src/core/reporter.h
index f08aa11fb..380941b1b 100644
--- a/src/core/reporter.h
+++ b/src/core/reporter.h
@@ -20,6 +20,10 @@ namespace Service::FileSystem {
20enum class LogMode : u32; 20enum class LogMode : u32;
21} 21}
22 22
23namespace Service::LM {
24struct LogMessage;
25} // namespace Service::LM
26
23namespace Core { 27namespace Core {
24 28
25class System; 29class System;
@@ -29,18 +33,22 @@ public:
29 explicit Reporter(System& system); 33 explicit Reporter(System& system);
30 ~Reporter(); 34 ~Reporter();
31 35
36 // Used by fatal services
32 void SaveCrashReport(u64 title_id, ResultCode result, u64 set_flags, u64 entry_point, u64 sp, 37 void SaveCrashReport(u64 title_id, ResultCode result, u64 set_flags, u64 entry_point, u64 sp,
33 u64 pc, u64 pstate, u64 afsr0, u64 afsr1, u64 esr, u64 far, 38 u64 pc, u64 pstate, u64 afsr0, u64 afsr1, u64 esr, u64 far,
34 const std::array<u64, 31>& registers, const std::array<u64, 32>& backtrace, 39 const std::array<u64, 31>& registers, const std::array<u64, 32>& backtrace,
35 u32 backtrace_size, const std::string& arch, u32 unk10) const; 40 u32 backtrace_size, const std::string& arch, u32 unk10) const;
36 41
42 // Used by syscall svcBreak
37 void SaveSvcBreakReport(u32 type, bool signal_debugger, u64 info1, u64 info2, 43 void SaveSvcBreakReport(u32 type, bool signal_debugger, u64 info1, u64 info2,
38 std::optional<std::vector<u8>> resolved_buffer = {}) const; 44 std::optional<std::vector<u8>> resolved_buffer = {}) const;
39 45
46 // Used by HLE service handler
40 void SaveUnimplementedFunctionReport(Kernel::HLERequestContext& ctx, u32 command_id, 47 void SaveUnimplementedFunctionReport(Kernel::HLERequestContext& ctx, u32 command_id,
41 const std::string& name, 48 const std::string& name,
42 const std::string& service_name) const; 49 const std::string& service_name) const;
43 50
51 // Used by stub applet implementation
44 void SaveUnimplementedAppletReport(u32 applet_id, u32 common_args_version, u32 library_version, 52 void SaveUnimplementedAppletReport(u32 applet_id, u32 common_args_version, u32 library_version,
45 u32 theme_color, bool startup_sound, u64 system_tick, 53 u32 theme_color, bool startup_sound, u64 system_tick,
46 std::vector<std::vector<u8>> normal_channel, 54 std::vector<std::vector<u8>> normal_channel,
@@ -55,6 +63,7 @@ public:
55 void SavePlayReport(PlayReportType type, u64 title_id, std::vector<std::vector<u8>> data, 63 void SavePlayReport(PlayReportType type, u64 title_id, std::vector<std::vector<u8>> data,
56 std::optional<u64> process_id = {}, std::optional<u128> user_id = {}) const; 64 std::optional<u64> process_id = {}, std::optional<u128> user_id = {}) const;
57 65
66 // Used by error applet
58 void SaveErrorReport(u64 title_id, ResultCode result, 67 void SaveErrorReport(u64 title_id, ResultCode result,
59 std::optional<std::string> custom_text_main = {}, 68 std::optional<std::string> custom_text_main = {},
60 std::optional<std::string> custom_text_detail = {}) const; 69 std::optional<std::string> custom_text_detail = {}) const;
@@ -62,6 +71,11 @@ public:
62 void SaveFilesystemAccessReport(Service::FileSystem::LogMode log_mode, 71 void SaveFilesystemAccessReport(Service::FileSystem::LogMode log_mode,
63 std::string log_message) const; 72 std::string log_message) const;
64 73
74 // Used by lm services
75 void SaveLogReport(u32 destination, std::vector<Service::LM::LogMessage> messages) const;
76
77 // Can be used anywhere to generate a backtrace and general info report at any point during
78 // execution. Not intended to be used for anything other than debugging or testing.
65 void SaveUserReport() const; 79 void SaveUserReport() const;
66 80
67private: 81private: