summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/core/hle/service/lm/lm.cpp162
1 files changed, 22 insertions, 140 deletions
diff --git a/src/core/hle/service/lm/lm.cpp b/src/core/hle/service/lm/lm.cpp
index efba18fe7..435f2d286 100644
--- a/src/core/hle/service/lm/lm.cpp
+++ b/src/core/hle/service/lm/lm.cpp
@@ -17,65 +17,16 @@ namespace Service::LM {
17 17
18class ILogger final : public ServiceFramework<ILogger> { 18class ILogger final : public ServiceFramework<ILogger> {
19public: 19public:
20 ILogger() : ServiceFramework("ILogger") { 20 ILogger(Manager& manager) : ServiceFramework("ILogger"), manager(manager) {
21 static const FunctionInfo functions[] = { 21 static const FunctionInfo functions[] = {
22 {0x00000000, &ILogger::Initialize, "Initialize"}, 22 {0, &ILogger::Log, "Log"},
23 {0x00000001, &ILogger::SetDestination, "SetDestination"}, 23 {1, &ILogger::SetDestination, "SetDestination"},
24 }; 24 };
25 RegisterHandlers(functions); 25 RegisterHandlers(functions);
26 } 26 }
27 27
28private: 28private:
29 struct MessageHeader { 29 void Log(Kernel::HLERequestContext& ctx) {
30 enum Flags : u32_le {
31 IsHead = 1,
32 IsTail = 2,
33 };
34 enum Severity : u32_le {
35 Trace,
36 Info,
37 Warning,
38 Error,
39 Critical,
40 };
41
42 u64_le pid;
43 u64_le threadContext;
44 union {
45 BitField<0, 16, Flags> flags;
46 BitField<16, 8, Severity> severity;
47 BitField<24, 8, u32> verbosity;
48 };
49 u32_le payload_size;
50
51 bool IsHeadLog() const {
52 return flags & Flags::IsHead;
53 }
54 bool IsTailLog() const {
55 return flags & Flags::IsTail;
56 }
57 };
58 static_assert(sizeof(MessageHeader) == 0x18, "MessageHeader is incorrect size");
59
60 /// Log field type
61 enum class Field : u8 {
62 Skip = 1,
63 Message = 2,
64 Line = 3,
65 Filename = 4,
66 Function = 5,
67 Module = 6,
68 Thread = 7,
69 };
70
71 /**
72 * ILogger::Initialize service function
73 * Inputs:
74 * 0: 0x00000000
75 * Outputs:
76 * 0: ResultCode
77 */
78 void Initialize(Kernel::HLERequestContext& ctx) {
79 // This function only succeeds - Get that out of the way 30 // This function only succeeds - Get that out of the way
80 IPC::ResponseBuilder rb{ctx, 2}; 31 IPC::ResponseBuilder rb{ctx, 2};
81 rb.Push(RESULT_SUCCESS); 32 rb.Push(RESULT_SUCCESS);
@@ -87,111 +38,42 @@ private:
87 Memory::ReadBlock(addr, &header, sizeof(MessageHeader)); 38 Memory::ReadBlock(addr, &header, sizeof(MessageHeader));
88 addr += sizeof(MessageHeader); 39 addr += sizeof(MessageHeader);
89 40
90 if (header.IsHeadLog()) { 41 FieldMap fields;
91 log_stream.str("");
92 log_stream.clear();
93 }
94
95 // Parse out log metadata
96 u32 line{};
97 std::string module;
98 std::string message;
99 std::string filename;
100 std::string function;
101 std::string thread;
102 while (addr < end_addr) { 42 while (addr < end_addr) {
103 const Field field{static_cast<Field>(Memory::Read8(addr++))}; 43 const auto field = static_cast<Field>(Memory::Read8(addr++));
104 const std::size_t length{Memory::Read8(addr++)}; 44 const auto length = Memory::Read8(addr++);
105 45
106 if (static_cast<Field>(Memory::Read8(addr)) == Field::Skip) { 46 if (static_cast<Field>(Memory::Read8(addr)) == Field::Skip) {
107 ++addr; 47 ++addr;
108 } 48 }
109 49
110 switch (field) { 50 SCOPE_EXIT({ addr += length; });
111 case Field::Skip:
112 break;
113 case Field::Message:
114 message = Memory::ReadCString(addr, length);
115 break;
116 case Field::Line:
117 line = Memory::Read32(addr);
118 break;
119 case Field::Filename:
120 filename = Memory::ReadCString(addr, length);
121 break;
122 case Field::Function:
123 function = Memory::ReadCString(addr, length);
124 break;
125 case Field::Module:
126 module = Memory::ReadCString(addr, length);
127 break;
128 case Field::Thread:
129 thread = Memory::ReadCString(addr, length);
130 break;
131 }
132 51
133 addr += length; 52 if (field == Field::Skip) {
134 } 53 continue;
54 }
135 55
136 // Empty log - nothing to do here 56 std::vector<u8> data(length);
137 if (log_stream.str().empty() && message.empty()) { 57 Memory::ReadBlock(addr, data.data(), length);
138 return; 58 fields.emplace(field, std::move(data));
139 } 59 }
140 60
141 // Format a nicely printable string out of the log metadata 61 manager.Log({header, std::move(fields)});
142 if (!filename.empty()) {
143 log_stream << filename << ':';
144 }
145 if (!module.empty()) {
146 log_stream << module << ':';
147 }
148 if (!function.empty()) {
149 log_stream << function << ':';
150 }
151 if (line) {
152 log_stream << std::to_string(line) << ':';
153 }
154 if (!thread.empty()) {
155 log_stream << thread << ':';
156 }
157 if (log_stream.str().length() > 0 && log_stream.str().back() == ':') {
158 log_stream << ' ';
159 }
160 log_stream << message;
161
162 if (header.IsTailLog()) {
163 switch (header.severity) {
164 case MessageHeader::Severity::Trace:
165 LOG_DEBUG(Debug_Emulated, "{}", log_stream.str());
166 break;
167 case MessageHeader::Severity::Info:
168 LOG_INFO(Debug_Emulated, "{}", log_stream.str());
169 break;
170 case MessageHeader::Severity::Warning:
171 LOG_WARNING(Debug_Emulated, "{}", log_stream.str());
172 break;
173 case MessageHeader::Severity::Error:
174 LOG_ERROR(Debug_Emulated, "{}", log_stream.str());
175 break;
176 case MessageHeader::Severity::Critical:
177 LOG_CRITICAL(Debug_Emulated, "{}", log_stream.str());
178 break;
179 }
180 }
181 } 62 }
182 63
183 // This service function is intended to be used as a way to
184 // redirect logging output to different destinations, however,
185 // given we always want to see the logging output, it's sufficient
186 // to do nothing and return success here.
187 void SetDestination(Kernel::HLERequestContext& ctx) { 64 void SetDestination(Kernel::HLERequestContext& ctx) {
188 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);
189 71
190 IPC::ResponseBuilder rb{ctx, 2}; 72 IPC::ResponseBuilder rb{ctx, 2};
191 rb.Push(RESULT_SUCCESS); 73 rb.Push(RESULT_SUCCESS);
192 } 74 }
193 75
194 std::ostringstream log_stream; 76 Manager& manager;
195}; 77};
196 78
197class LM final : public ServiceFramework<LM> { 79class LM final : public ServiceFramework<LM> {