summaryrefslogtreecommitdiff
path: root/src/core/hle/service
diff options
context:
space:
mode:
authorGravatar bunnei2019-10-08 20:23:13 -0400
committerGravatar GitHub2019-10-08 20:23:13 -0400
commitb9c831de623df5a58cc5aa47392d6841bfef8d8b (patch)
tree2242bd5c0931997af15beccde978434b79a8d1d9 /src/core/hle/service
parentMerge pull request #2961 from DarkLordZach/azure-tag-names (diff)
parentlm: Flush manager output on core shutdown (diff)
downloadyuzu-b9c831de623df5a58cc5aa47392d6841bfef8d8b.tar.gz
yuzu-b9c831de623df5a58cc5aa47392d6841bfef8d8b.tar.xz
yuzu-b9c831de623df5a58cc5aa47392d6841bfef8d8b.zip
Merge pull request #2654 from DarkLordZach/lm-log-rewrite
lm: Rewrite logger to use core reporting services
Diffstat (limited to 'src/core/hle/service')
-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
5 files changed, 278 insertions, 156 deletions
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);