diff options
| author | bunnei <bunneidev@gmail.com> | 2019-10-08 20:23:13 -0400 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2019-10-08 20:23:13 -0400 | 
| commit | b9c831de623df5a58cc5aa47392d6841bfef8d8b (patch) | |
| tree | 2242bd5c0931997af15beccde978434b79a8d1d9 /src/core/hle/service | |
| parent | 464353bc5751dfc62a64c5eb64a632a8df5fed63 (diff) | |
| parent | 6212df3beb38d0484b6ceedad18be99f107f7d96 (diff) | |
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.cpp | 187 | ||||
| -rw-r--r-- | src/core/hle/service/lm/lm.h | 6 | ||||
| -rw-r--r-- | src/core/hle/service/lm/manager.cpp | 133 | ||||
| -rw-r--r-- | src/core/hle/service/lm/manager.h | 106 | ||||
| -rw-r--r-- | src/core/hle/service/service.cpp | 2 | 
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 @@  #include <string>  #include "common/logging/log.h" +#include "common/scope_exit.h"  #include "core/hle/ipc_helpers.h"  #include "core/hle/service/lm/lm.h" +#include "core/hle/service/lm/manager.h"  #include "core/hle/service/service.h"  #include "core/memory.h" @@ -15,65 +17,16 @@ namespace Service::LM {  class ILogger final : public ServiceFramework<ILogger> {  public: -    ILogger() : ServiceFramework("ILogger") { +    ILogger(Manager& manager) : ServiceFramework("ILogger"), manager(manager) {          static const FunctionInfo functions[] = { -            {0x00000000, &ILogger::Initialize, "Initialize"}, -            {0x00000001, &ILogger::SetDestination, "SetDestination"}, +            {0, &ILogger::Log, "Log"}, +            {1, &ILogger::SetDestination, "SetDestination"},          };          RegisterHandlers(functions);      }  private: -    struct MessageHeader { -        enum Flags : u32_le { -            IsHead = 1, -            IsTail = 2, -        }; -        enum Severity : u32_le { -            Trace, -            Info, -            Warning, -            Error, -            Critical, -        }; - -        u64_le pid; -        u64_le threadContext; -        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 & Flags::IsHead; -        } -        bool IsTailLog() const { -            return flags & Flags::IsTail; -        } -    }; -    static_assert(sizeof(MessageHeader) == 0x18, "MessageHeader is incorrect size"); - -    /// Log field type -    enum class Field : u8 { -        Skip = 1, -        Message = 2, -        Line = 3, -        Filename = 4, -        Function = 5, -        Module = 6, -        Thread = 7, -    }; - -    /** -     * ILogger::Initialize service function -     *  Inputs: -     *      0: 0x00000000 -     *  Outputs: -     *      0: ResultCode -     */ -    void Initialize(Kernel::HLERequestContext& ctx) { +    void Log(Kernel::HLERequestContext& ctx) {          // This function only succeeds - Get that out of the way          IPC::ResponseBuilder rb{ctx, 2};          rb.Push(RESULT_SUCCESS); @@ -85,140 +38,70 @@ private:          Memory::ReadBlock(addr, &header, sizeof(MessageHeader));          addr += sizeof(MessageHeader); -        if (header.IsHeadLog()) { -            log_stream.str(""); -            log_stream.clear(); -        } - -        // Parse out log metadata -        u32 line{}; -        std::string module; -        std::string message; -        std::string filename; -        std::string function; -        std::string thread; +        FieldMap fields;          while (addr < end_addr) { -            const Field field{static_cast<Field>(Memory::Read8(addr++))}; -            const std::size_t length{Memory::Read8(addr++)}; +            const auto field = static_cast<Field>(Memory::Read8(addr++)); +            const auto length = Memory::Read8(addr++);              if (static_cast<Field>(Memory::Read8(addr)) == Field::Skip) {                  ++addr;              } -            switch (field) { -            case Field::Skip: -                break; -            case Field::Message: -                message = Memory::ReadCString(addr, length); -                break; -            case Field::Line: -                line = Memory::Read32(addr); -                break; -            case Field::Filename: -                filename = Memory::ReadCString(addr, length); -                break; -            case Field::Function: -                function = Memory::ReadCString(addr, length); -                break; -            case Field::Module: -                module = Memory::ReadCString(addr, length); -                break; -            case Field::Thread: -                thread = Memory::ReadCString(addr, length); -                break; -            } +            SCOPE_EXIT({ addr += length; }); -            addr += length; -        } +            if (field == Field::Skip) { +                continue; +            } -        // Empty log - nothing to do here -        if (log_stream.str().empty() && message.empty()) { -            return; +            std::vector<u8> data(length); +            Memory::ReadBlock(addr, data.data(), length); +            fields.emplace(field, std::move(data));          } -        // Format a nicely printable string out of the log metadata -        if (!filename.empty()) { -            log_stream << filename << ':'; -        } -        if (!module.empty()) { -            log_stream << module << ':'; -        } -        if (!function.empty()) { -            log_stream << function << ':'; -        } -        if (line) { -            log_stream << std::to_string(line) << ':'; -        } -        if (!thread.empty()) { -            log_stream << thread << ':'; -        } -        if (log_stream.str().length() > 0 && log_stream.str().back() == ':') { -            log_stream << ' '; -        } -        log_stream << message; - -        if (header.IsTailLog()) { -            switch (header.severity) { -            case MessageHeader::Severity::Trace: -                LOG_DEBUG(Debug_Emulated, "{}", log_stream.str()); -                break; -            case MessageHeader::Severity::Info: -                LOG_INFO(Debug_Emulated, "{}", log_stream.str()); -                break; -            case MessageHeader::Severity::Warning: -                LOG_WARNING(Debug_Emulated, "{}", log_stream.str()); -                break; -            case MessageHeader::Severity::Error: -                LOG_ERROR(Debug_Emulated, "{}", log_stream.str()); -                break; -            case MessageHeader::Severity::Critical: -                LOG_CRITICAL(Debug_Emulated, "{}", log_stream.str()); -                break; -            } -        } +        manager.Log({header, std::move(fields)});      } -    // This service function is intended to be used as a way to -    // redirect logging output to different destinations, however, -    // given we always want to see the logging output, it's sufficient -    // to do nothing and return success here.      void SetDestination(Kernel::HLERequestContext& ctx) { -        LOG_DEBUG(Service_LM, "called"); +        IPC::RequestParser rp{ctx}; +        const auto destination = rp.PopEnum<DestinationFlag>(); + +        LOG_DEBUG(Service_LM, "called, destination={:08X}", static_cast<u32>(destination)); + +        manager.SetDestination(destination);          IPC::ResponseBuilder rb{ctx, 2};          rb.Push(RESULT_SUCCESS);      } -    std::ostringstream log_stream; +    Manager& manager;  };  class LM final : public ServiceFramework<LM> {  public: -    explicit LM() : ServiceFramework{"lm"} { +    explicit LM(Manager& manager) : ServiceFramework{"lm"}, manager(manager) { +        // clang-format off          static const FunctionInfo functions[] = { -            {0x00000000, &LM::OpenLogger, "OpenLogger"}, +            {0, &LM::OpenLogger, "OpenLogger"},          }; +        // clang-format on +          RegisterHandlers(functions);      } -    /** -     * LM::OpenLogger service function -     *  Inputs: -     *      0: 0x00000000 -     *  Outputs: -     *      0: ResultCode -     */ +private:      void OpenLogger(Kernel::HLERequestContext& ctx) {          LOG_DEBUG(Service_LM, "called");          IPC::ResponseBuilder rb{ctx, 2, 0, 1};          rb.Push(RESULT_SUCCESS); -        rb.PushIpcInterface<ILogger>(); +        rb.PushIpcInterface<ILogger>(manager);      } + +    Manager& manager;  }; -void InstallInterfaces(SM::ServiceManager& service_manager) { -    std::make_shared<LM>()->InstallAsService(service_manager); +void InstallInterfaces(Core::System& system) { +    std::make_shared<LM>(system.GetLogManager())->InstallAsService(system.ServiceManager());  }  } // 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 @@  #pragma once -namespace Service::SM { -class ServiceManager; +namespace Core { +class System;  }  namespace Service::LM {  /// Registers all LM services with the specified service manager. -void InstallInterfaces(SM::ServiceManager& service_manager); +void InstallInterfaces(Core::System& system);  } // 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 @@ +// 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<std::string> array; +    const auto check_single_flag = [dest, &array](DestinationFlag check, std::string name) { +        if ((static_cast<u32>(check) & static_cast<u32>(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<u32>(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<u32>(field)); +    } +} + +std::string FormatField(Field type, const std::vector<u8>& 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("{}", 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<const char*>(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::Flush() { +    FinalizeLog(); +} + +void Manager::InitializeLog() { +    current_log.clear(); + +    LOG_INFO(Service_LM, "Initialized new log session"); +} + +void Manager::FinalizeLog() { +    reporter.SaveLogReport(static_cast<u32>(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 000000000..544e636ba --- /dev/null +++ b/src/core/hle/service/lm/manager.h @@ -0,0 +1,106 @@ +// Copyright 2019 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <map> +#include <ostream> +#include <vector> +#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<Field, std::vector<u8>>; + +struct LogMessage { +    MessageHeader header; +    FieldMap fields; +}; + +std::string FormatField(Field type, const std::vector<u8>& data); + +class Manager { +public: +    explicit Manager(Core::Reporter& reporter); +    ~Manager(); + +    void SetEnabled(bool enabled); +    void SetDestination(DestinationFlag destination); + +    void Log(LogMessage message); + +    void Flush(); + +private: +    void InitializeLog(); +    void FinalizeLog(); + +    bool enabled = true; +    DestinationFlag destination = DestinationFlag::All; + +    std::vector<LogMessage> current_log; + +    Core::Reporter& reporter; +}; + +} // 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) {      LBL::InstallInterfaces(*sm);      LDN::InstallInterfaces(*sm);      LDR::InstallInterfaces(*sm, system); -    LM::InstallInterfaces(*sm); +    LM::InstallInterfaces(system);      Migration::InstallInterfaces(*sm);      Mii::InstallInterfaces(*sm);      MM::InstallInterfaces(*sm); | 
