| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191 |
- // Copyright 2018 yuzu emulator team
- // Licensed under GPLv2 or any later version
- // Refer to the license.txt file included.
- #include <sstream>
- #include <string>
- #include "common/logging/log.h"
- #include "core/hle/ipc_helpers.h"
- #include "core/hle/kernel/client_session.h"
- #include "core/hle/service/lm/lm.h"
- namespace Service::LM {
- class Logger final : public ServiceFramework<Logger> {
- public:
- Logger() : ServiceFramework("Logger") {
- static const FunctionInfo functions[] = {
- {0x00000000, &Logger::Log, "Log"},
- };
- RegisterHandlers(functions);
- }
- ~Logger() = default;
- 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_le> 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,
- };
- /**
- * LM::Log service function
- * Inputs:
- * 0: 0x00000000
- * Outputs:
- * 0: ResultCode
- */
- void Log(Kernel::HLERequestContext& ctx) {
- // This function only succeeds - Get that out of the way
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(RESULT_SUCCESS);
- // Read MessageHeader, despite not doing anything with it right now
- MessageHeader header{};
- VAddr addr{ctx.BufferDescriptorX()[0].Address()};
- const VAddr end_addr{addr + ctx.BufferDescriptorX()[0].size};
- 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 message, filename, function;
- while (addr < end_addr) {
- const Field field{static_cast<Field>(Memory::Read8(addr++))};
- const size_t length{Memory::Read8(addr++)};
- if (static_cast<Field>(Memory::Read8(addr)) == Field::Skip) {
- ++addr;
- }
- switch (field) {
- 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;
- }
- addr += length;
- }
- // Empty log - nothing to do here
- if (log_stream.str().empty() && message.empty()) {
- return;
- }
- // Format a nicely printable string out of the log metadata
- if (!filename.empty()) {
- log_stream << filename << ':';
- }
- if (!function.empty()) {
- log_stream << function << ':';
- }
- if (line) {
- log_stream << std::to_string(line) << ':';
- }
- 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:
- NGLOG_TRACE(Debug_Emulated, "{}", log_stream.str());
- break;
- case MessageHeader::Severity::Info:
- NGLOG_INFO(Debug_Emulated, "{}", log_stream.str());
- break;
- case MessageHeader::Severity::Warning:
- NGLOG_WARNING(Debug_Emulated, "{}", log_stream.str());
- break;
- case MessageHeader::Severity::Error:
- NGLOG_ERROR(Debug_Emulated, "{}", log_stream.str());
- break;
- case MessageHeader::Severity::Critical:
- NGLOG_CRITICAL(Debug_Emulated, "{}", log_stream.str());
- break;
- }
- }
- }
- std::ostringstream log_stream;
- };
- void InstallInterfaces(SM::ServiceManager& service_manager) {
- std::make_shared<LM>()->InstallAsService(service_manager);
- }
- /**
- * LM::Initialize service function
- * Inputs:
- * 0: 0x00000000
- * Outputs:
- * 0: ResultCode
- */
- void LM::Initialize(Kernel::HLERequestContext& ctx) {
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<Logger>();
- NGLOG_DEBUG(Service_LM, "called");
- }
- LM::LM() : ServiceFramework("lm") {
- static const FunctionInfo functions[] = {
- {0x00000000, &LM::Initialize, "Initialize"},
- };
- RegisterHandlers(functions);
- }
- } // namespace Service::LM
|