lm.cpp 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. // Copyright 2018 yuzu emulator team
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <sstream>
  5. #include <string>
  6. #include "common/logging/log.h"
  7. #include "core/hle/ipc_helpers.h"
  8. #include "core/hle/service/lm/lm.h"
  9. #include "core/hle/service/service.h"
  10. #include "core/memory.h"
  11. namespace Service::LM {
  12. class ILogger final : public ServiceFramework<ILogger> {
  13. public:
  14. ILogger() : ServiceFramework("ILogger") {
  15. static const FunctionInfo functions[] = {
  16. {0x00000000, &ILogger::Initialize, "Initialize"},
  17. {0x00000001, nullptr, "SetDestination"},
  18. };
  19. RegisterHandlers(functions);
  20. }
  21. private:
  22. struct MessageHeader {
  23. enum Flags : u32_le {
  24. IsHead = 1,
  25. IsTail = 2,
  26. };
  27. enum Severity : u32_le {
  28. Trace,
  29. Info,
  30. Warning,
  31. Error,
  32. Critical,
  33. };
  34. u64_le pid;
  35. u64_le threadContext;
  36. union {
  37. BitField<0, 16, Flags> flags;
  38. BitField<16, 8, Severity> severity;
  39. BitField<24, 8, u32_le> verbosity;
  40. };
  41. u32_le payload_size;
  42. bool IsHeadLog() const {
  43. return flags & Flags::IsHead;
  44. }
  45. bool IsTailLog() const {
  46. return flags & Flags::IsTail;
  47. }
  48. };
  49. static_assert(sizeof(MessageHeader) == 0x18, "MessageHeader is incorrect size");
  50. /// Log field type
  51. enum class Field : u8 {
  52. Skip = 1,
  53. Message = 2,
  54. Line = 3,
  55. Filename = 4,
  56. Function = 5,
  57. Module = 6,
  58. Thread = 7,
  59. };
  60. /**
  61. * ILogger::Initialize service function
  62. * Inputs:
  63. * 0: 0x00000000
  64. * Outputs:
  65. * 0: ResultCode
  66. */
  67. void Initialize(Kernel::HLERequestContext& ctx) {
  68. // This function only succeeds - Get that out of the way
  69. IPC::ResponseBuilder rb{ctx, 2};
  70. rb.Push(RESULT_SUCCESS);
  71. // Read MessageHeader, despite not doing anything with it right now
  72. MessageHeader header{};
  73. VAddr addr{ctx.BufferDescriptorX()[0].Address()};
  74. const VAddr end_addr{addr + ctx.BufferDescriptorX()[0].size};
  75. Memory::ReadBlock(addr, &header, sizeof(MessageHeader));
  76. addr += sizeof(MessageHeader);
  77. if (header.IsHeadLog()) {
  78. log_stream.str("");
  79. log_stream.clear();
  80. }
  81. // Parse out log metadata
  82. u32 line{};
  83. std::string message, filename, function;
  84. while (addr < end_addr) {
  85. const Field field{static_cast<Field>(Memory::Read8(addr++))};
  86. const size_t length{Memory::Read8(addr++)};
  87. if (static_cast<Field>(Memory::Read8(addr)) == Field::Skip) {
  88. ++addr;
  89. }
  90. switch (field) {
  91. case Field::Message:
  92. message = Memory::ReadCString(addr, length);
  93. break;
  94. case Field::Line:
  95. line = Memory::Read32(addr);
  96. break;
  97. case Field::Filename:
  98. filename = Memory::ReadCString(addr, length);
  99. break;
  100. case Field::Function:
  101. function = Memory::ReadCString(addr, length);
  102. break;
  103. }
  104. addr += length;
  105. }
  106. // Empty log - nothing to do here
  107. if (log_stream.str().empty() && message.empty()) {
  108. return;
  109. }
  110. // Format a nicely printable string out of the log metadata
  111. if (!filename.empty()) {
  112. log_stream << filename << ':';
  113. }
  114. if (!function.empty()) {
  115. log_stream << function << ':';
  116. }
  117. if (line) {
  118. log_stream << std::to_string(line) << ':';
  119. }
  120. if (log_stream.str().length() > 0 && log_stream.str().back() == ':') {
  121. log_stream << ' ';
  122. }
  123. log_stream << message;
  124. if (header.IsTailLog()) {
  125. switch (header.severity) {
  126. case MessageHeader::Severity::Trace:
  127. LOG_TRACE(Debug_Emulated, "{}", log_stream.str());
  128. break;
  129. case MessageHeader::Severity::Info:
  130. LOG_INFO(Debug_Emulated, "{}", log_stream.str());
  131. break;
  132. case MessageHeader::Severity::Warning:
  133. LOG_WARNING(Debug_Emulated, "{}", log_stream.str());
  134. break;
  135. case MessageHeader::Severity::Error:
  136. LOG_ERROR(Debug_Emulated, "{}", log_stream.str());
  137. break;
  138. case MessageHeader::Severity::Critical:
  139. LOG_CRITICAL(Debug_Emulated, "{}", log_stream.str());
  140. break;
  141. }
  142. }
  143. }
  144. std::ostringstream log_stream;
  145. };
  146. class LM final : public ServiceFramework<LM> {
  147. public:
  148. explicit LM() : ServiceFramework{"lm"} {
  149. static const FunctionInfo functions[] = {
  150. {0x00000000, &LM::OpenLogger, "OpenLogger"},
  151. };
  152. RegisterHandlers(functions);
  153. }
  154. /**
  155. * LM::OpenLogger service function
  156. * Inputs:
  157. * 0: 0x00000000
  158. * Outputs:
  159. * 0: ResultCode
  160. */
  161. void OpenLogger(Kernel::HLERequestContext& ctx) {
  162. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  163. rb.Push(RESULT_SUCCESS);
  164. rb.PushIpcInterface<ILogger>();
  165. LOG_DEBUG(Service_LM, "called");
  166. }
  167. };
  168. void InstallInterfaces(SM::ServiceManager& service_manager) {
  169. std::make_shared<LM>()->InstallAsService(service_manager);
  170. }
  171. } // namespace Service::LM