mirror of
				https://github.com/Atmosphere-NX/Atmosphere-libs.git
				synced 2025-10-31 19:45:51 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			152 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			152 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
|  * Copyright (c) Atmosphère-NX
 | |
|  *
 | |
|  * This program is free software; you can redistribute it and/or modify it
 | |
|  * under the terms and conditions of the GNU General Public License,
 | |
|  * version 2, as published by the Free Software Foundation.
 | |
|  *
 | |
|  * This program is distributed in the hope it will be useful, but WITHOUT
 | |
|  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 | |
|  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 | |
|  * more details.
 | |
|  *
 | |
|  * You should have received a copy of the GNU General Public License
 | |
|  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | |
|  */
 | |
| #include <stratosphere.hpp>
 | |
| #include "lm_logger_impl.hpp"
 | |
| #include "lm_event_log_transmitter.hpp"
 | |
| #include "lm_log_buffer.hpp"
 | |
| #include "lm_log_packet_parser.hpp"
 | |
| #include "lm_log_getter_impl.hpp"
 | |
| #include "../impl/lm_log_packet_header.hpp"
 | |
| 
 | |
| namespace ams::lm::srv {
 | |
| 
 | |
|     bool IsFlushAvailable();
 | |
| 
 | |
|     bool g_is_logging_to_custom_sink = false;
 | |
| 
 | |
|     namespace {
 | |
| 
 | |
|         constinit u32 g_log_destination = lm::LogDestination_TargetManager;
 | |
| 
 | |
|         bool SetProcessId(const sf::InAutoSelectBuffer &message, u64 process_id) {
 | |
|             /* Check the message. */
 | |
|             AMS_ASSERT(util::IsAligned(reinterpret_cast<uintptr_t>(message.GetPointer()), alignof(impl::LogPacketHeader)));
 | |
| 
 | |
|             /* Get a modifiable copy of the header. */
 | |
|             auto *header = const_cast<impl::LogPacketHeader *>(reinterpret_cast<const impl::LogPacketHeader *>(message.GetPointer()));
 | |
| 
 | |
|             /* Check that the message size is correct. */
 | |
|             if (impl::LogPacketHeaderSize + header->GetPayloadSize() != message.GetSize()) {
 | |
|                 return false;
 | |
|             }
 | |
| 
 | |
|             /* Set the header's process id. */
 | |
|             header->SetProcessId(process_id);
 | |
| 
 | |
|             return true;
 | |
|         }
 | |
| 
 | |
|         void PutLogToTargetManager(const sf::InAutoSelectBuffer &message) {
 | |
|             /* Try to push the message. */
 | |
|             bool success;
 | |
|             if (IsFlushAvailable()) {
 | |
|                 success = LogBuffer::GetDefaultInstance().Push(message.GetPointer(), message.GetSize());
 | |
|             } else {
 | |
|                 success = LogBuffer::GetDefaultInstance().TryPush(message.GetPointer(), message.GetSize());
 | |
|             }
 | |
| 
 | |
|             /* If we fail, increment dropped packet count. */
 | |
|             if (!success) {
 | |
|                 EventLogTransmitter::GetDefaultInstance().IncreaseLogPacketDropCount();
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         void PutLogToUart(const sf::InAutoSelectBuffer &message) {
 | |
|             #if defined(AMS_BUILD_FOR_DEBUGGING) || defined(AMS_BUILD_FOR_AUDITING)
 | |
|             {
 | |
|                 /* Get header. */
 | |
|                 auto *data     = message.GetPointer();
 | |
|                 auto data_size = message.GetSize();
 | |
|                 const auto *header = reinterpret_cast<const impl::LogPacketHeader *>(data);
 | |
| 
 | |
|                 /* Get the module name. */
 | |
|                 char module_name[0x10] = {};
 | |
|                 LogPacketParser::ParseModuleName(module_name, sizeof(module_name), data, data_size);
 | |
| 
 | |
|                 /* Create log metadata. */
 | |
|                 const diag::LogMetaData log_meta = {
 | |
|                     .module_name = module_name,
 | |
|                     .severity    = static_cast<diag::LogSeverity>(header->GetSeverity()),
 | |
|                     .verbosity   = header->GetVerbosity(),
 | |
|                 };
 | |
| 
 | |
|                 LogPacketParser::ParseTextLogWithContext(message.GetPointer(), message.GetSize(), [](const char *txt, size_t size, void *arg) {
 | |
|                     /* Get metadata. */
 | |
|                     const auto &meta = *static_cast<const diag::LogMetaData *>(arg);
 | |
| 
 | |
|                     /* Put the message to uart. */
 | |
|                     diag::impl::PutImpl(meta, txt, size);
 | |
|                 }, const_cast<diag::LogMetaData *>(std::addressof(log_meta)));
 | |
|             }
 | |
|             #else
 | |
|             {
 | |
|                 AMS_UNUSED(message);
 | |
|             }
 | |
|             #endif
 | |
|         }
 | |
| 
 | |
|         void PutLogToCustomSink(const sf::InAutoSelectBuffer &message) {
 | |
|             LogPacketParser::ParseTextLogWithContext(message.GetPointer(), message.GetSize(), [](const char *txt, size_t size, void *) {
 | |
|                 /* Try to push the message. */
 | |
|                 if (!LogGetterImpl::GetBuffer().TryPush(txt, size)) {
 | |
|                     LogGetterImpl::IncreaseLogPacketDropCount();
 | |
|                 }
 | |
|             }, nullptr);
 | |
|         }
 | |
| 
 | |
|     }
 | |
| 
 | |
|     LoggerImpl::LoggerImpl(LogServiceImpl *parent, os::ProcessId process_id) : m_parent(parent), m_process_id(process_id.value) {
 | |
|         /* Log start of session for process. */
 | |
|         EventLogTransmitter::GetDefaultInstance().PushLogSessionBegin(m_process_id);
 | |
|     }
 | |
| 
 | |
|     LoggerImpl::~LoggerImpl() {
 | |
|         /* Log end of session for process. */
 | |
|         EventLogTransmitter::GetDefaultInstance().PushLogSessionEnd(m_process_id);
 | |
|     }
 | |
| 
 | |
|     Result LoggerImpl::Log(const sf::InAutoSelectBuffer &message) {
 | |
|         /* Try to set the log process id. */
 | |
|         /* NOTE: Nintendo succeeds here, for whatever purpose, so we will as well. */
 | |
|         R_UNLESS(SetProcessId(message, m_process_id), ResultSuccess());
 | |
| 
 | |
|         /* If we should, log to target manager. */
 | |
|         if (g_log_destination & lm::LogDestination_TargetManager) {
 | |
|             PutLogToTargetManager(message);
 | |
|         }
 | |
| 
 | |
|         /* If we should, log to uart. */
 | |
|         if ((g_log_destination & lm::LogDestination_Uart) || (IsFlushAvailable() && (g_log_destination & lm::LogDestination_UartIfSleep))) {
 | |
|             PutLogToUart(message);
 | |
|         }
 | |
| 
 | |
|         /* If we should, log to custom sink. */
 | |
|         if (g_is_logging_to_custom_sink) {
 | |
|             PutLogToCustomSink(message);
 | |
|         }
 | |
| 
 | |
|         R_SUCCEED();
 | |
|     }
 | |
| 
 | |
|     Result LoggerImpl::SetDestination(u32 destination) {
 | |
|         /* Set the log destination. */
 | |
|         g_log_destination = destination;
 | |
|         R_SUCCEED();
 | |
|     }
 | |
| 
 | |
| }
 |