diff options
| author | 2021-01-20 18:25:15 +1100 | |
|---|---|---|
| committer | 2021-01-20 18:25:15 +1100 | |
| commit | 83f8c1a25ef9a65eac0d000e41373bc212c5ba1c (patch) | |
| tree | 8dc5bd39652d0a3ada62e67fcae90f67564fd656 /src/core/hle/service/lm | |
| parent | Merge pull request #5755 from FearlessTobi/port-5344 (diff) | |
| download | yuzu-83f8c1a25ef9a65eac0d000e41373bc212c5ba1c.tar.gz yuzu-83f8c1a25ef9a65eac0d000e41373bc212c5ba1c.tar.xz yuzu-83f8c1a25ef9a65eac0d000e41373bc212c5ba1c.zip | |
lm: Recode LM service
Rework the service to spit out to logs instead of a seperate file as well as fix any crashes caused by lm.
Diffstat (limited to 'src/core/hle/service/lm')
| -rw-r--r-- | src/core/hle/service/lm/lm.cpp | 317 | ||||
| -rw-r--r-- | src/core/hle/service/lm/manager.cpp | 134 | ||||
| -rw-r--r-- | src/core/hle/service/lm/manager.h | 106 |
3 files changed, 286 insertions, 271 deletions
diff --git a/src/core/hle/service/lm/lm.cpp b/src/core/hle/service/lm/lm.cpp index 8e49b068c..f4f6533ad 100644 --- a/src/core/hle/service/lm/lm.cpp +++ b/src/core/hle/service/lm/lm.cpp | |||
| @@ -5,22 +5,71 @@ | |||
| 5 | #include <sstream> | 5 | #include <sstream> |
| 6 | #include <string> | 6 | #include <string> |
| 7 | 7 | ||
| 8 | #include <optional> | ||
| 9 | #include <unordered_map> | ||
| 10 | #include <boost/container_hash/hash.hpp> | ||
| 8 | #include "common/logging/log.h" | 11 | #include "common/logging/log.h" |
| 9 | #include "common/scope_exit.h" | 12 | #include "common/scope_exit.h" |
| 10 | #include "core/core.h" | 13 | #include "core/core.h" |
| 11 | #include "core/hle/ipc_helpers.h" | 14 | #include "core/hle/ipc_helpers.h" |
| 12 | #include "core/hle/service/lm/lm.h" | 15 | #include "core/hle/service/lm/lm.h" |
| 13 | #include "core/hle/service/lm/manager.h" | ||
| 14 | #include "core/hle/service/service.h" | 16 | #include "core/hle/service/service.h" |
| 15 | #include "core/memory.h" | 17 | #include "core/memory.h" |
| 16 | 18 | ||
| 17 | namespace Service::LM { | 19 | namespace Service::LM { |
| 20 | enum class LogSeverity : u8 { | ||
| 21 | Trace = 0, | ||
| 22 | Info = 1, | ||
| 23 | Warning = 2, | ||
| 24 | Error = 3, | ||
| 25 | Fatal = 4, | ||
| 26 | }; | ||
| 27 | |||
| 28 | // To keep flags out of hashing as well as the payload size | ||
| 29 | struct LogPacketHeaderEntry { | ||
| 30 | u64_le pid{}; | ||
| 31 | u64_le tid{}; | ||
| 32 | LogSeverity severity{}; | ||
| 33 | u8 verbosity{}; | ||
| 34 | |||
| 35 | auto operator<=>(const LogPacketHeaderEntry&) const = default; | ||
| 36 | }; | ||
| 37 | } // namespace Service::LM | ||
| 38 | |||
| 39 | namespace std { | ||
| 40 | template <> | ||
| 41 | struct hash<Service::LM::LogPacketHeaderEntry> { | ||
| 42 | std::size_t operator()(const Service::LM::LogPacketHeaderEntry& k) const { | ||
| 43 | std::size_t seed{}; | ||
| 44 | boost::hash_combine(seed, k.pid); | ||
| 45 | boost::hash_combine(seed, k.tid); | ||
| 46 | boost::hash_combine(seed, k.severity); | ||
| 47 | boost::hash_combine(seed, k.verbosity); | ||
| 48 | return seed; | ||
| 49 | }; | ||
| 50 | }; | ||
| 51 | } // namespace std | ||
| 52 | |||
| 53 | namespace Service::LM { | ||
| 54 | |||
| 55 | enum class LogDestination : u32 { | ||
| 56 | TargetManager = 1 << 0, | ||
| 57 | Uart = 1 << 1, | ||
| 58 | UartSleep = 1 << 2, | ||
| 59 | All = 0xffff, | ||
| 60 | }; | ||
| 61 | DECLARE_ENUM_FLAG_OPERATORS(LogDestination); | ||
| 62 | |||
| 63 | enum class LogPacketFlags : u8 { | ||
| 64 | Head = 1 << 0, | ||
| 65 | Tail = 1 << 1, | ||
| 66 | LittleEndian = 1 << 2, | ||
| 67 | }; | ||
| 68 | DECLARE_ENUM_FLAG_OPERATORS(LogPacketFlags); | ||
| 18 | 69 | ||
| 19 | class ILogger final : public ServiceFramework<ILogger> { | 70 | class ILogger final : public ServiceFramework<ILogger> { |
| 20 | public: | 71 | public: |
| 21 | explicit ILogger(Core::System& system_) | 72 | explicit ILogger(Core::System& system_) : ServiceFramework{system_, "ILogger"} { |
| 22 | : ServiceFramework{system_, "ILogger"}, manager{system_.GetLogManager()}, | ||
| 23 | memory{system_.Memory()} { | ||
| 24 | static const FunctionInfo functions[] = { | 73 | static const FunctionInfo functions[] = { |
| 25 | {0, &ILogger::Log, "Log"}, | 74 | {0, &ILogger::Log, "Log"}, |
| 26 | {1, &ILogger::SetDestination, "SetDestination"}, | 75 | {1, &ILogger::SetDestination, "SetDestination"}, |
| @@ -30,54 +79,260 @@ public: | |||
| 30 | 79 | ||
| 31 | private: | 80 | private: |
| 32 | void Log(Kernel::HLERequestContext& ctx) { | 81 | void Log(Kernel::HLERequestContext& ctx) { |
| 82 | std::size_t offset{}; | ||
| 83 | const auto data = ctx.ReadBuffer(); | ||
| 84 | |||
| 33 | // This function only succeeds - Get that out of the way | 85 | // This function only succeeds - Get that out of the way |
| 34 | IPC::ResponseBuilder rb{ctx, 2}; | 86 | IPC::ResponseBuilder rb{ctx, 2}; |
| 35 | rb.Push(RESULT_SUCCESS); | 87 | rb.Push(RESULT_SUCCESS); |
| 36 | 88 | ||
| 37 | // Read MessageHeader, despite not doing anything with it right now | 89 | if (data.size() < sizeof(LogPacketHeader)) { |
| 38 | MessageHeader header{}; | 90 | LOG_ERROR(Service_LM, "Data size is too small for header! size={}", data.size()); |
| 39 | VAddr addr{ctx.BufferDescriptorX()[0].Address()}; | 91 | return; |
| 40 | const VAddr end_addr{addr + ctx.BufferDescriptorX()[0].size}; | 92 | } |
| 41 | memory.ReadBlock(addr, &header, sizeof(MessageHeader)); | ||
| 42 | addr += sizeof(MessageHeader); | ||
| 43 | |||
| 44 | FieldMap fields; | ||
| 45 | while (addr < end_addr) { | ||
| 46 | const auto field = static_cast<Field>(memory.Read8(addr++)); | ||
| 47 | const auto length = memory.Read8(addr++); | ||
| 48 | 93 | ||
| 49 | if (static_cast<Field>(memory.Read8(addr)) == Field::Skip) { | 94 | LogPacketHeader header{}; |
| 50 | ++addr; | 95 | std::memcpy(&header, data.data(), sizeof(LogPacketHeader)); |
| 51 | } | 96 | offset += sizeof(LogPacketHeader); |
| 52 | 97 | ||
| 53 | SCOPE_EXIT({ addr += length; }); | 98 | LogPacketHeaderEntry entry{ |
| 99 | .pid = header.pid, | ||
| 100 | .tid = header.tid, | ||
| 101 | .severity = header.severity, | ||
| 102 | .verbosity = header.verbosity, | ||
| 103 | }; | ||
| 54 | 104 | ||
| 55 | if (field == Field::Skip) { | 105 | if (True(header.flags & LogPacketFlags::Head)) { |
| 56 | continue; | 106 | std::vector<u8> tmp(data.size() - sizeof(LogPacketHeader)); |
| 107 | std::memcpy(tmp.data(), data.data() + offset, tmp.size()); | ||
| 108 | entries[entry] = std::move(tmp); | ||
| 109 | } else { | ||
| 110 | // Append to existing entry | ||
| 111 | if (!entries.contains(entry)) { | ||
| 112 | LOG_ERROR(Service_LM, "Log entry does not exist!"); | ||
| 113 | return; | ||
| 57 | } | 114 | } |
| 115 | std::vector<u8> tmp(data.size() - sizeof(LogPacketHeader)); | ||
| 58 | 116 | ||
| 59 | std::vector<u8> data(length); | 117 | auto& existing_entry = entries[entry]; |
| 60 | memory.ReadBlock(addr, data.data(), length); | 118 | const auto base = existing_entry.size(); |
| 61 | fields.emplace(field, std::move(data)); | 119 | existing_entry.resize(base + (data.size() - sizeof(LogPacketHeader))); |
| 120 | std::memcpy(existing_entry.data() + base, data.data() + offset, | ||
| 121 | (data.size() - sizeof(LogPacketHeader))); | ||
| 62 | } | 122 | } |
| 63 | 123 | ||
| 64 | manager.Log({header, std::move(fields)}); | 124 | if (True(header.flags & LogPacketFlags::Tail)) { |
| 125 | auto it = entries.find(entry); | ||
| 126 | if (it == entries.end()) { | ||
| 127 | LOG_ERROR(Service_LM, "Log entry does not exist!"); | ||
| 128 | return; | ||
| 129 | } | ||
| 130 | ParseLog(it->first, it->second); | ||
| 131 | entries.erase(it); | ||
| 132 | } | ||
| 65 | } | 133 | } |
| 66 | 134 | ||
| 67 | void SetDestination(Kernel::HLERequestContext& ctx) { | 135 | void SetDestination(Kernel::HLERequestContext& ctx) { |
| 68 | IPC::RequestParser rp{ctx}; | 136 | IPC::RequestParser rp{ctx}; |
| 69 | const auto destination = rp.PopEnum<DestinationFlag>(); | 137 | const auto log_destination = rp.PopEnum<LogDestination>(); |
| 70 | |||
| 71 | LOG_DEBUG(Service_LM, "called, destination={:08X}", destination); | ||
| 72 | 138 | ||
| 73 | manager.SetDestination(destination); | 139 | LOG_DEBUG(Service_LM, "called, destination={}", DestinationToString(log_destination)); |
| 140 | destination = log_destination; | ||
| 74 | 141 | ||
| 75 | IPC::ResponseBuilder rb{ctx, 2}; | 142 | IPC::ResponseBuilder rb{ctx, 2}; |
| 76 | rb.Push(RESULT_SUCCESS); | 143 | rb.Push(RESULT_SUCCESS); |
| 77 | } | 144 | } |
| 78 | 145 | ||
| 79 | Manager& manager; | 146 | u32 ReadLeb128(const std::vector<u8>& data, std::size_t& offset) { |
| 80 | Core::Memory::Memory& memory; | 147 | u32 result{}; |
| 148 | u32 shift{}; | ||
| 149 | do { | ||
| 150 | result |= (data[offset] & 0x7f) << shift; | ||
| 151 | shift += 7; | ||
| 152 | offset++; | ||
| 153 | if (offset >= data.size()) { | ||
| 154 | break; | ||
| 155 | } | ||
| 156 | } while ((data[offset] & 0x80) != 0); | ||
| 157 | return result; | ||
| 158 | } | ||
| 159 | |||
| 160 | std::optional<std::string> ReadString(const std::vector<u8>& data, std::size_t& offset, | ||
| 161 | std::size_t length) { | ||
| 162 | if (length == 0) { | ||
| 163 | return std::nullopt; | ||
| 164 | } | ||
| 165 | std::string output(length, '\0'); | ||
| 166 | std::memcpy(output.data(), data.data() + offset, length); | ||
| 167 | offset += length; | ||
| 168 | return output; | ||
| 169 | } | ||
| 170 | |||
| 171 | u32_le ReadAsU32(const std::vector<u8>& data, std::size_t& offset, std::size_t length) { | ||
| 172 | ASSERT(length == sizeof(u32)); | ||
| 173 | u32_le output{}; | ||
| 174 | std::memcpy(&output, data.data() + offset, sizeof(u32)); | ||
| 175 | offset += length; | ||
| 176 | return output; | ||
| 177 | } | ||
| 178 | |||
| 179 | u64_le ReadAsU64(const std::vector<u8>& data, std::size_t& offset, std::size_t length) { | ||
| 180 | ASSERT(length == sizeof(u64)); | ||
| 181 | u64_le output{}; | ||
| 182 | std::memcpy(&output, data.data() + offset, sizeof(u64)); | ||
| 183 | offset += length; | ||
| 184 | return output; | ||
| 185 | } | ||
| 186 | |||
| 187 | void ParseLog(const LogPacketHeaderEntry entry, const std::vector<u8>& log_data) { | ||
| 188 | // Possible entries | ||
| 189 | std::optional<std::string> text_log; | ||
| 190 | std::optional<u32> line_number; | ||
| 191 | std::optional<std::string> file_name; | ||
| 192 | std::optional<std::string> function_name; | ||
| 193 | std::optional<std::string> module_name; | ||
| 194 | std::optional<std::string> thread_name; | ||
| 195 | std::optional<u64> log_pack_drop_count; | ||
| 196 | std::optional<s64> user_system_clock; | ||
| 197 | std::optional<std::string> process_name; | ||
| 198 | |||
| 199 | std::size_t offset{}; | ||
| 200 | while (offset < log_data.size()) { | ||
| 201 | const auto key = static_cast<LogDataChunkKey>(ReadLeb128(log_data, offset)); | ||
| 202 | const auto chunk_size = ReadLeb128(log_data, offset); | ||
| 203 | |||
| 204 | switch (key) { | ||
| 205 | case LogDataChunkKey::LogSessionBegin: | ||
| 206 | case LogDataChunkKey::LogSessionEnd: | ||
| 207 | break; | ||
| 208 | case LogDataChunkKey::TextLog: | ||
| 209 | text_log = ReadString(log_data, offset, chunk_size); | ||
| 210 | break; | ||
| 211 | case LogDataChunkKey::LineNumber: | ||
| 212 | line_number = ReadAsU32(log_data, offset, chunk_size); | ||
| 213 | break; | ||
| 214 | case LogDataChunkKey::FileName: | ||
| 215 | file_name = ReadString(log_data, offset, chunk_size); | ||
| 216 | break; | ||
| 217 | case LogDataChunkKey::FunctionName: | ||
| 218 | function_name = ReadString(log_data, offset, chunk_size); | ||
| 219 | break; | ||
| 220 | case LogDataChunkKey::ModuleName: | ||
| 221 | module_name = ReadString(log_data, offset, chunk_size); | ||
| 222 | break; | ||
| 223 | case LogDataChunkKey::ThreadName: | ||
| 224 | thread_name = ReadString(log_data, offset, chunk_size); | ||
| 225 | break; | ||
| 226 | case LogDataChunkKey::LogPacketDropCount: | ||
| 227 | log_pack_drop_count = ReadAsU64(log_data, offset, chunk_size); | ||
| 228 | break; | ||
| 229 | case LogDataChunkKey::UserSystemClock: | ||
| 230 | user_system_clock = ReadAsU64(log_data, offset, chunk_size); | ||
| 231 | break; | ||
| 232 | case LogDataChunkKey::ProcessName: | ||
| 233 | process_name = ReadString(log_data, offset, chunk_size); | ||
| 234 | break; | ||
| 235 | } | ||
| 236 | } | ||
| 237 | |||
| 238 | std::string output_log{}; | ||
| 239 | if (process_name) { | ||
| 240 | output_log += fmt::format("Process: {}\n", *process_name); | ||
| 241 | } | ||
| 242 | if (module_name) { | ||
| 243 | output_log += fmt::format("Module: {}\n", *module_name); | ||
| 244 | } | ||
| 245 | if (file_name) { | ||
| 246 | output_log += fmt::format("File: {}\n", *file_name); | ||
| 247 | } | ||
| 248 | if (function_name) { | ||
| 249 | output_log += fmt::format("Function: {}\n", *function_name); | ||
| 250 | } | ||
| 251 | if (line_number && *line_number != 0) { | ||
| 252 | output_log += fmt::format("Line: {}\n", *line_number); | ||
| 253 | } | ||
| 254 | output_log += fmt::format("ProcessID: {}\n", entry.pid); | ||
| 255 | output_log += fmt::format("ThreadID: {}\n", entry.tid); | ||
| 256 | |||
| 257 | if (text_log) { | ||
| 258 | output_log += fmt::format("Log Text: {}\n", *text_log); | ||
| 259 | } | ||
| 260 | |||
| 261 | switch (entry.severity) { | ||
| 262 | case LogSeverity::Trace: | ||
| 263 | LOG_DEBUG(Service_LM, "LogManager DEBUG ({}):\n{}", DestinationToString(destination), | ||
| 264 | output_log); | ||
| 265 | break; | ||
| 266 | case LogSeverity::Info: | ||
| 267 | LOG_INFO(Service_LM, "LogManager INFO ({}):\n{}", DestinationToString(destination), | ||
| 268 | output_log); | ||
| 269 | break; | ||
| 270 | case LogSeverity::Warning: | ||
| 271 | LOG_WARNING(Service_LM, "LogManager WARNING ({}):\n{}", | ||
| 272 | DestinationToString(destination), output_log); | ||
| 273 | break; | ||
| 274 | case LogSeverity::Error: | ||
| 275 | LOG_ERROR(Service_LM, "LogManager ERROR ({}):\n{}", DestinationToString(destination), | ||
| 276 | output_log); | ||
| 277 | break; | ||
| 278 | case LogSeverity::Fatal: | ||
| 279 | LOG_CRITICAL(Service_LM, "LogManager FATAL ({}):\n{}", DestinationToString(destination), | ||
| 280 | output_log); | ||
| 281 | break; | ||
| 282 | default: | ||
| 283 | LOG_CRITICAL(Service_LM, "LogManager UNKNOWN ({}):\n{}", | ||
| 284 | DestinationToString(destination), output_log); | ||
| 285 | break; | ||
| 286 | } | ||
| 287 | } | ||
| 288 | |||
| 289 | std::string DestinationToString(LogDestination destination) { | ||
| 290 | if (True(destination & LogDestination::All)) { | ||
| 291 | return "TargetManager | Uart | UartSleep"; | ||
| 292 | } | ||
| 293 | std::string output{}; | ||
| 294 | if (True(destination & LogDestination::TargetManager)) { | ||
| 295 | output += "| TargetManager"; | ||
| 296 | } | ||
| 297 | if (True(destination & LogDestination::Uart)) { | ||
| 298 | output += "| Uart"; | ||
| 299 | } | ||
| 300 | if (True(destination & LogDestination::UartSleep)) { | ||
| 301 | output += "| UartSleep"; | ||
| 302 | } | ||
| 303 | if (output.length() > 0) { | ||
| 304 | return output.substr(2); | ||
| 305 | } | ||
| 306 | return "No Destination"; | ||
| 307 | } | ||
| 308 | |||
| 309 | enum class LogDataChunkKey : u32 { | ||
| 310 | LogSessionBegin = 0, | ||
| 311 | LogSessionEnd = 1, | ||
| 312 | TextLog = 2, | ||
| 313 | LineNumber = 3, | ||
| 314 | FileName = 4, | ||
| 315 | FunctionName = 5, | ||
| 316 | ModuleName = 6, | ||
| 317 | ThreadName = 7, | ||
| 318 | LogPacketDropCount = 8, | ||
| 319 | UserSystemClock = 9, | ||
| 320 | ProcessName = 10, | ||
| 321 | }; | ||
| 322 | |||
| 323 | struct LogPacketHeader { | ||
| 324 | u64_le pid{}; | ||
| 325 | u64_le tid{}; | ||
| 326 | LogPacketFlags flags{}; | ||
| 327 | INSERT_PADDING_BYTES(1); | ||
| 328 | LogSeverity severity{}; | ||
| 329 | u8 verbosity{}; | ||
| 330 | u32_le payload_size{}; | ||
| 331 | }; | ||
| 332 | static_assert(sizeof(LogPacketHeader) == 0x18, "LogPacketHeader is an invalid size"); | ||
| 333 | |||
| 334 | std::unordered_map<LogPacketHeaderEntry, std::vector<u8>> entries{}; | ||
| 335 | LogDestination destination{LogDestination::All}; | ||
| 81 | }; | 336 | }; |
| 82 | 337 | ||
| 83 | class LM final : public ServiceFramework<LM> { | 338 | class LM final : public ServiceFramework<LM> { |
diff --git a/src/core/hle/service/lm/manager.cpp b/src/core/hle/service/lm/manager.cpp deleted file mode 100644 index 3ee2374e7..000000000 --- a/src/core/hle/service/lm/manager.cpp +++ /dev/null | |||
| @@ -1,134 +0,0 @@ | |||
| 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 | |||
| 11 | namespace Service::LM { | ||
| 12 | |||
| 13 | std::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 | |||
| 32 | std::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 | |||
| 49 | std::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 | |||
| 70 | std::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_MSG("Unimplemented field type={}", type); | ||
| 90 | return ""; | ||
| 91 | } | ||
| 92 | } | ||
| 93 | |||
| 94 | Manager::Manager(Core::Reporter& reporter) : reporter(reporter) {} | ||
| 95 | |||
| 96 | Manager::~Manager() = default; | ||
| 97 | |||
| 98 | void Manager::SetEnabled(bool enabled) { | ||
| 99 | this->enabled = enabled; | ||
| 100 | } | ||
| 101 | |||
| 102 | void Manager::SetDestination(DestinationFlag destination) { | ||
| 103 | this->destination = destination; | ||
| 104 | } | ||
| 105 | |||
| 106 | void Manager::Log(LogMessage message) { | ||
| 107 | if (message.header.IsHeadLog()) { | ||
| 108 | InitializeLog(); | ||
| 109 | } | ||
| 110 | |||
| 111 | current_log.emplace_back(std::move(message)); | ||
| 112 | |||
| 113 | if (current_log.back().header.IsTailLog()) { | ||
| 114 | FinalizeLog(); | ||
| 115 | } | ||
| 116 | } | ||
| 117 | |||
| 118 | void Manager::Flush() { | ||
| 119 | FinalizeLog(); | ||
| 120 | } | ||
| 121 | |||
| 122 | void Manager::InitializeLog() { | ||
| 123 | current_log.clear(); | ||
| 124 | |||
| 125 | LOG_INFO(Service_LM, "Initialized new log session"); | ||
| 126 | } | ||
| 127 | |||
| 128 | void Manager::FinalizeLog() { | ||
| 129 | reporter.SaveLogReport(static_cast<u32>(destination), std::move(current_log)); | ||
| 130 | |||
| 131 | LOG_INFO(Service_LM, "Finalized current log session"); | ||
| 132 | } | ||
| 133 | |||
| 134 | } // namespace Service::LM | ||
diff --git a/src/core/hle/service/lm/manager.h b/src/core/hle/service/lm/manager.h deleted file mode 100644 index 544e636ba..000000000 --- a/src/core/hle/service/lm/manager.h +++ /dev/null | |||
| @@ -1,106 +0,0 @@ | |||
| 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 | |||
| 14 | namespace Core { | ||
| 15 | class Reporter; | ||
| 16 | } | ||
| 17 | |||
| 18 | namespace Service::LM { | ||
| 19 | |||
| 20 | enum class DestinationFlag : u32 { | ||
| 21 | Default = 1, | ||
| 22 | UART = 2, | ||
| 23 | UARTSleeping = 4, | ||
| 24 | |||
| 25 | All = 0xFFFF, | ||
| 26 | }; | ||
| 27 | |||
| 28 | struct 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 | }; | ||
| 57 | static_assert(sizeof(MessageHeader) == 0x18, "MessageHeader is incorrect size"); | ||
| 58 | |||
| 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 | std::ostream& operator<<(std::ostream& os, DestinationFlag dest); | ||
| 70 | std::ostream& operator<<(std::ostream& os, MessageHeader::Severity severity); | ||
| 71 | std::ostream& operator<<(std::ostream& os, Field field); | ||
| 72 | |||
| 73 | using FieldMap = std::map<Field, std::vector<u8>>; | ||
| 74 | |||
| 75 | struct LogMessage { | ||
| 76 | MessageHeader header; | ||
| 77 | FieldMap fields; | ||
| 78 | }; | ||
| 79 | |||
| 80 | std::string FormatField(Field type, const std::vector<u8>& data); | ||
| 81 | |||
| 82 | class Manager { | ||
| 83 | public: | ||
| 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 | |||
| 94 | private: | ||
| 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 | ||