From ef9a7fa1f5e593bf6cd49aab2ee371b7ca84512e Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Sat, 29 Jun 2019 17:18:07 -0400 Subject: [PATCH] lm: Implement manager class to output to reporter --- src/core/hle/service/lm/manager.cpp | 129 ++++++++++++++++++++++++++++ src/core/hle/service/lm/manager.h | 104 ++++++++++++++++++++++ 2 files changed, 233 insertions(+) create mode 100644 src/core/hle/service/lm/manager.cpp create mode 100644 src/core/hle/service/lm/manager.h diff --git a/src/core/hle/service/lm/manager.cpp b/src/core/hle/service/lm/manager.cpp new file mode 100644 index 0000000000..fd8edaf46e --- /dev/null +++ b/src/core/hle/service/lm/manager.cpp @@ -0,0 +1,129 @@ +// Copyright 2019 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/assert.h" +#include "common/logging/log.h" +#include "common/string_util.h" +#include "core/hle/service/lm/manager.h" +#include "core/reporter.h" + +namespace Service::LM { + +std::ostream& operator<<(std::ostream& os, DestinationFlag dest) { + std::vector array; + const auto check_single_flag = [dest, &array](DestinationFlag check, std::string name) { + if ((static_cast(check) & static_cast(dest)) > 0) { + array.emplace_back(std::move(name)); + } + }; + + check_single_flag(DestinationFlag::Default, "Default"); + check_single_flag(DestinationFlag::UART, "UART"); + check_single_flag(DestinationFlag::UARTSleeping, "UART (Sleeping)"); + + os << "["; + for (const auto& entry : array) { + os << entry << ", "; + } + return os << "]"; +} + +std::ostream& operator<<(std::ostream& os, MessageHeader::Severity severity) { + switch (severity) { + case MessageHeader::Severity::Trace: + return os << "Trace"; + case MessageHeader::Severity::Info: + return os << "Info"; + case MessageHeader::Severity::Warning: + return os << "Warning"; + case MessageHeader::Severity::Error: + return os << "Error"; + case MessageHeader::Severity::Critical: + return os << "Critical"; + default: + return os << fmt::format("{:08X}", static_cast(severity)); + } +} + +std::ostream& operator<<(std::ostream& os, Field field) { + switch (field) { + case Field::Skip: + return os << "Skip"; + case Field::Message: + return os << "Message"; + case Field::Line: + return os << "Line"; + case Field::Filename: + return os << "Filename"; + case Field::Function: + return os << "Function"; + case Field::Module: + return os << "Module"; + case Field::Thread: + return os << "Thread"; + default: + return os << fmt::format("{:08X}", static_cast(field)); + } +} + +std::string FormatField(Field type, const std::vector& data) { + switch (type) { + case Field::Skip: + return ""; + case Field::Line: + if (data.size() >= sizeof(u32)) { + u32 line; + std::memcpy(&line, data.data(), sizeof(u32)); + return fmt::format("{:08X}", line); + } + return "[ERROR DECODING LINE NUMBER]"; + case Field::Message: + case Field::Filename: + case Field::Function: + case Field::Module: + case Field::Thread: + return Common::StringFromFixedZeroTerminatedBuffer( + reinterpret_cast(data.data()), data.size()); + default: + UNIMPLEMENTED(); + } +} + +Manager::Manager(Core::Reporter& reporter) : reporter(reporter) {} + +Manager::~Manager() = default; + +void Manager::SetEnabled(bool enabled) { + this->enabled = enabled; +} + +void Manager::SetDestination(DestinationFlag destination) { + this->destination = destination; +} + +void Manager::Log(LogMessage message) { + if (message.header.IsHeadLog()) { + InitializeLog(); + } + + current_log.emplace_back(std::move(message)); + + if (current_log.back().header.IsTailLog()) { + FinalizeLog(); + } +} + +void Manager::InitializeLog() { + current_log.clear(); + + LOG_INFO(Service_LM, "Initialized new log session!"); +} + +void Manager::FinalizeLog() { + reporter.SaveLogReport(static_cast(destination), std::move(current_log)); + + LOG_INFO(Service_LM, "Finalized current log session!"); +} + +} // 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 0000000000..af0a27257b --- /dev/null +++ b/src/core/hle/service/lm/manager.h @@ -0,0 +1,104 @@ +// Copyright 2019 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include +#include "common/bit_field.h" +#include "common/common_types.h" +#include "common/swap.h" + +namespace Core { +class Reporter; +} + +namespace Service::LM { + +enum class DestinationFlag : u32 { + Default = 1, + UART = 2, + UARTSleeping = 4, + + All = 0xFFFF, +}; + +struct MessageHeader { + enum Flags : u32_le { + IsHead = 1, + IsTail = 2, + }; + enum Severity : u32_le { + Trace, + Info, + Warning, + Error, + Critical, + }; + + u64_le pid; + u64_le thread_context; + union { + BitField<0, 16, Flags> flags; + BitField<16, 8, Severity> severity; + BitField<24, 8, u32> verbosity; + }; + u32_le payload_size; + + bool IsHeadLog() const { + return flags & IsHead; + } + bool IsTailLog() const { + return flags & IsTail; + } +}; +static_assert(sizeof(MessageHeader) == 0x18, "MessageHeader is incorrect size"); + +enum class Field : u8 { + Skip = 1, + Message = 2, + Line = 3, + Filename = 4, + Function = 5, + Module = 6, + Thread = 7, +}; + +std::ostream& operator<<(std::ostream& os, DestinationFlag dest); +std::ostream& operator<<(std::ostream& os, MessageHeader::Severity severity); +std::ostream& operator<<(std::ostream& os, Field field); + +using FieldMap = std::map>; + +struct LogMessage { + MessageHeader header; + FieldMap fields; +}; + +std::string FormatField(Field type, const std::vector& data); + +class Manager { +public: + Manager(Core::Reporter& reporter); + ~Manager(); + + void SetEnabled(bool enabled); + void SetDestination(DestinationFlag destination); + + void Log(LogMessage message); + +private: + void InitializeLog(); + void FinalizeLog(); + + bool enabled = true; + DestinationFlag destination = DestinationFlag::All; + + std::vector current_log; + + Core::Reporter& reporter; +}; + +} // namespace Service::LM