Compare commits

..

2 Commits

Author SHA1 Message Date
N00byKing
3147910cad main.cpp: Fix Grammar 2018-04-04 12:24:41 +02:00
N00byKing
a17925b5b5 core, main.h: Abort on 32Bit ROMs 2018-04-03 01:20:34 +02:00
24 changed files with 117 additions and 165 deletions

View File

@@ -17,7 +17,6 @@ endif()
# libfmt
add_subdirectory(fmt)
add_library(fmt::fmt ALIAS fmt)
# getopt
if (MSVC)

2
externals/fmt vendored

View File

@@ -89,7 +89,7 @@ endif()
create_target_directory_groups(common)
target_link_libraries(common PUBLIC Boost::boost fmt microprofile)
target_link_libraries(common PUBLIC Boost::boost microprofile)
if (ARCHITECTURE_x86_64)
target_link_libraries(common PRIVATE xbyak)
endif()

View File

@@ -11,7 +11,6 @@
#include "common/logging/filter.h"
#include "common/logging/log.h"
#include "common/logging/text_formatter.h"
#include "common/string_util.h"
namespace Log {
@@ -107,20 +106,25 @@ const char* GetLevelName(Level log_level) {
}
Entry CreateEntry(Class log_class, Level log_level, const char* filename, unsigned int line_nr,
const char* function, std::string message) {
const char* function, const char* format, va_list args) {
using std::chrono::duration_cast;
using std::chrono::steady_clock;
static steady_clock::time_point time_origin = steady_clock::now();
std::array<char, 4 * 1024> formatting_buffer;
Entry entry;
entry.timestamp = duration_cast<std::chrono::microseconds>(steady_clock::now() - time_origin);
entry.log_class = log_class;
entry.log_level = log_level;
entry.filename = Common::TrimSourcePath(filename);
entry.line_num = line_nr;
entry.function = function;
entry.message = std::move(message);
snprintf(formatting_buffer.data(), formatting_buffer.size(), "%s:%s:%u", filename, function,
line_nr);
entry.location = std::string(formatting_buffer.data());
vsnprintf(formatting_buffer.data(), formatting_buffer.size(), format, args);
entry.message = std::string(formatting_buffer.data());
return entry;
}
@@ -131,29 +135,16 @@ void SetFilter(Filter* new_filter) {
filter = new_filter;
}
void LogMessage(Class log_class, Level log_level, const char* filename, unsigned int line_num,
void LogMessage(Class log_class, Level log_level, const char* filename, unsigned int line_nr,
const char* function, const char* format, ...) {
if (filter && !filter->CheckMessage(log_class, log_level))
if (filter != nullptr && !filter->CheckMessage(log_class, log_level))
return;
std::array<char, 4 * 1024> formatting_buffer;
va_list args;
va_start(args, format);
vsnprintf(formatting_buffer.data(), formatting_buffer.size(), format, args);
Entry entry = CreateEntry(log_class, log_level, filename, line_nr, function, format, args);
va_end(args);
Entry entry = CreateEntry(log_class, log_level, filename, line_num, function,
std::string(formatting_buffer.data()));
PrintColoredMessage(entry);
}
void LogMessage(Class log_class, Level log_level, const char* filename, unsigned int line_num,
const char* function, const char* format, const fmt::format_args& args) {
if (filter && !filter->CheckMessage(log_class, log_level))
return;
Entry entry =
CreateEntry(log_class, log_level, filename, line_num, function, fmt::vformat(format, args));
PrintColoredMessage(entry);
}
} // namespace Log

View File

@@ -22,16 +22,13 @@ struct Entry {
std::chrono::microseconds timestamp;
Class log_class;
Level log_level;
std::string filename;
unsigned int line_num;
std::string function;
std::string location;
std::string message;
Entry() = default;
Entry(Entry&& o) = default;
Entry& operator=(Entry&& o) = default;
Entry& operator=(const Entry& o) = default;
};
/**
@@ -47,7 +44,7 @@ const char* GetLevelName(Level log_level);
/// Creates a log entry by formatting the given source location, and message.
Entry CreateEntry(Class log_class, Level log_level, const char* filename, unsigned int line_nr,
const char* function, std::string message);
const char* function, const char* format, va_list args);
void SetFilter(Filter* filter);
} // namespace Log

View File

@@ -65,14 +65,14 @@ bool Filter::ParseFilterRule(const std::string::const_iterator begin,
const std::string::const_iterator end) {
auto level_separator = std::find(begin, end, ':');
if (level_separator == end) {
NGLOG_ERROR(Log, "Invalid log filter. Must specify a log level after `:`: %s",
std::string(begin, end).c_str());
LOG_ERROR(Log, "Invalid log filter. Must specify a log level after `:`: %s",
std::string(begin, end).c_str());
return false;
}
const Level level = GetLevelByName(level_separator + 1, end);
if (level == Level::Count) {
NGLOG_ERROR(Log, "Unknown log level in filter: %s", std::string(begin, end).c_str());
LOG_ERROR(Log, "Unknown log level in filter: %s", std::string(begin, end).c_str());
return false;
}
@@ -83,7 +83,7 @@ bool Filter::ParseFilterRule(const std::string::const_iterator begin,
const Class log_class = GetClassByName(begin, level_separator);
if (log_class == Class::Count) {
NGLOG_ERROR(Log, "Unknown log class in filter: %s", std::string(begin, end).c_str());
LOG_ERROR(Log, "Unknown log class in filter: %s", std::string(begin, end).c_str());
return false;
}

View File

@@ -19,7 +19,7 @@ namespace Log {
class Filter {
public:
/// Initializes the filter with all classes having `default_level` as the minimum level.
Filter(Level default_level = Level::Info);
Filter(Level default_level);
/// Resets the filter so that all classes have `level` as the minimum displayed level.
void ResetAll(Level level);

View File

@@ -4,7 +4,6 @@
#pragma once
#include <fmt/format.h>
#include "common/common_types.h"
namespace Log {
@@ -92,7 +91,7 @@ enum class Class : ClassType {
};
/// Logs a message to the global logger.
void LogMessage(Class log_class, Level log_level, const char* filename, unsigned int line_num,
void LogMessage(Class log_class, Level log_level, const char* filename, unsigned int line_nr,
const char* function,
#ifdef _MSC_VER
_Printf_format_string_
@@ -104,16 +103,6 @@ void LogMessage(Class log_class, Level log_level, const char* filename, unsigned
#endif
;
/// Logs a message to the global logger, using fmt
void LogMessage(Class log_class, Level log_level, const char* filename, unsigned int line_num,
const char* function, const char* format, const fmt::format_args& args);
template <typename... Args>
void FmtLogMessage(Class log_class, Level log_level, const char* filename, unsigned int line_num,
const char* function, const char* format, const Args&... args) {
LogMessage(log_class, log_level, filename, line_num, function, format, fmt::make_args(args...));
}
} // namespace Log
#define LOG_GENERIC(log_class, log_level, ...) \
@@ -136,28 +125,3 @@ void FmtLogMessage(Class log_class, Level log_level, const char* filename, unsig
LOG_GENERIC(::Log::Class::log_class, ::Log::Level::Error, __VA_ARGS__)
#define LOG_CRITICAL(log_class, ...) \
LOG_GENERIC(::Log::Class::log_class, ::Log::Level::Critical, __VA_ARGS__)
// Define the fmt lib macros
#ifdef _DEBUG
#define NGLOG_TRACE(log_class, ...) \
::Log::FmtLogMessage(::Log::Class::log_class, ::Log::Level::Trace, __FILE__, __LINE__, \
__func__, __VA_ARGS__)
#else
#define NGLOG_TRACE(log_class, fmt, ...) (void(0))
#endif
#define NGLOG_DEBUG(log_class, ...) \
::Log::FmtLogMessage(::Log::Class::log_class, ::Log::Level::Debug, __FILE__, __LINE__, \
__func__, __VA_ARGS__)
#define NGLOG_INFO(log_class, ...) \
::Log::FmtLogMessage(::Log::Class::log_class, ::Log::Level::Info, __FILE__, __LINE__, \
__func__, __VA_ARGS__)
#define NGLOG_WARNING(log_class, ...) \
::Log::FmtLogMessage(::Log::Class::log_class, ::Log::Level::Warning, __FILE__, __LINE__, \
__func__, __VA_ARGS__)
#define NGLOG_ERROR(log_class, ...) \
::Log::FmtLogMessage(::Log::Class::log_class, ::Log::Level::Error, __FILE__, __LINE__, \
__func__, __VA_ARGS__)
#define NGLOG_CRITICAL(log_class, ...) \
::Log::FmtLogMessage(::Log::Class::log_class, ::Log::Level::Critical, __FILE__, __LINE__, \
__func__, __VA_ARGS__)

View File

@@ -18,29 +18,50 @@
namespace Log {
std::string FormatLogMessage(const Entry& entry) {
// TODO(bunnei): This should be moved to a generic path manipulation library
const char* TrimSourcePath(const char* path, const char* root) {
const char* p = path;
while (*p != '\0') {
const char* next_slash = p;
while (*next_slash != '\0' && *next_slash != '/' && *next_slash != '\\') {
++next_slash;
}
bool is_src = Common::ComparePartialString(p, next_slash, root);
p = next_slash;
if (*p != '\0') {
++p;
}
if (is_src) {
path = p;
}
}
return path;
}
void FormatLogMessage(const Entry& entry, char* out_text, size_t text_len) {
unsigned int time_seconds = static_cast<unsigned int>(entry.timestamp.count() / 1000000);
unsigned int time_fractional = static_cast<unsigned int>(entry.timestamp.count() % 1000000);
const char* class_name = GetLogClassName(entry.log_class);
const char* level_name = GetLevelName(entry.log_level);
return fmt::format("[{:4d}.{:06d}] {} <{}> {}:{}:{}: {}", time_seconds, time_fractional,
class_name, level_name, entry.filename, entry.function, entry.line_num,
entry.message);
snprintf(out_text, text_len, "[%4u.%06u] %s <%s> %s: %s", time_seconds, time_fractional,
class_name, level_name, TrimSourcePath(entry.location.c_str()), entry.message.c_str());
}
void PrintMessage(const Entry& entry) {
auto str = FormatLogMessage(entry) + '\n';
fputs(str.c_str(), stderr);
std::array<char, 4 * 1024> format_buffer;
FormatLogMessage(entry, format_buffer.data(), format_buffer.size());
fputs(format_buffer.data(), stderr);
fputc('\n', stderr);
}
void PrintColoredMessage(const Entry& entry) {
#ifdef _WIN32
HANDLE console_handle = GetStdHandle(STD_ERROR_HANDLE);
if (console_handle == INVALID_HANDLE_VALUE) {
return;
}
static HANDLE console_handle = GetStdHandle(STD_ERROR_HANDLE);
CONSOLE_SCREEN_BUFFER_INFO original_info = {0};
GetConsoleScreenBufferInfo(console_handle, &original_info);

View File

@@ -10,8 +10,20 @@ namespace Log {
struct Entry;
/**
* Attempts to trim an arbitrary prefix from `path`, leaving only the part starting at `root`. It's
* intended to be used to strip a system-specific build directory from the `__FILE__` macro,
* leaving only the path relative to the sources root.
*
* @param path The input file path as a null-terminated string
* @param root The name of the root source directory as a null-terminated string. Path up to and
* including the last occurrence of this name will be stripped
* @return A pointer to the same string passed as `path`, but starting at the trimmed portion
*/
const char* TrimSourcePath(const char* path, const char* root = "src");
/// Formats a log entry into the provided text buffer.
std::string FormatLogMessage(const Entry& entry);
void FormatLogMessage(const Entry& entry, char* out_text, size_t text_len);
/// Formats and prints a log entry to stderr.
void PrintMessage(const Entry& entry);
/// Prints the same message as `PrintMessage`, but colored acoording to the severity level.

View File

@@ -462,27 +462,4 @@ std::string StringFromFixedZeroTerminatedBuffer(const char* buffer, size_t max_l
return std::string(buffer, len);
}
const char* TrimSourcePath(const char* path, const char* root) {
const char* p = path;
while (*p != '\0') {
const char* next_slash = p;
while (*next_slash != '\0' && *next_slash != '/' && *next_slash != '\\') {
++next_slash;
}
bool is_src = Common::ComparePartialString(p, next_slash, root);
p = next_slash;
if (*p != '\0') {
++p;
}
if (is_src) {
path = p;
}
}
return path;
}
} // namespace Common

View File

@@ -134,17 +134,4 @@ bool ComparePartialString(InIt begin, InIt end, const char* other) {
* NUL-terminated then the string ends at max_len characters.
*/
std::string StringFromFixedZeroTerminatedBuffer(const char* buffer, size_t max_len);
/**
* Attempts to trim an arbitrary prefix from `path`, leaving only the part starting at `root`. It's
* intended to be used to strip a system-specific build directory from the `__FILE__` macro,
* leaving only the path relative to the sources root.
*
* @param path The input file path as a null-terminated string
* @param root The name of the root source directory as a null-terminated string. Path up to and
* including the last occurrence of this name will be stripped
* @return A pointer to the same string passed as `path`, but starting at the trimmed portion
*/
const char* TrimSourcePath(const char* path, const char* root = "src");
} // namespace Common

View File

@@ -103,19 +103,7 @@ inline __attribute__((always_inline)) u64 swap64(u64 _data) {
return __builtin_bswap64(_data);
}
#elif defined(__Bitrig__) || defined(__OpenBSD__)
// redefine swap16, swap32, swap64 as inline functions
#undef swap16
#undef swap32
#undef swap64
inline u16 swap16(u16 _data) {
return __swap16(_data);
}
inline u32 swap32(u32 _data) {
return __swap32(_data);
}
inline u64 swap64(u64 _data) {
return __swap64(_data);
}
// swap16, swap32, swap64 are left as is
#elif defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__)
inline u16 swap16(u16 _data) {
return bswap16(_data);

View File

@@ -15,7 +15,7 @@ namespace Telemetry {
/// Field type, used for grouping fields together in the final submitted telemetry log
enum class FieldType : u8 {
None = 0, ///< No specified field group
App, ///< yuzu application fields (e.g. version, branch, etc.)
App, ///< Citra application fields (e.g. version, branch, etc.)
Session, ///< Emulated session fields (e.g. title ID, log, etc.)
Performance, ///< Emulated performance (e.g. fps, emulated CPU speed, etc.)
UserFeedback, ///< User submitted feedback (e.g. star rating, user notes, etc.)

View File

@@ -92,6 +92,8 @@ System::ResultStatus System::Load(EmuWindow* emu_window, const std::string& file
return ResultStatus::ErrorLoader_ErrorEncrypted;
case Loader::ResultStatus::ErrorInvalidFormat:
return ResultStatus::ErrorLoader_ErrorInvalidFormat;
case Loader::ResultStatus::ErrorUnsupportedArch:
return ResultStatus::ErrorUnsupportedArch;
default:
return ResultStatus::ErrorSystemMode;
}
@@ -115,6 +117,8 @@ System::ResultStatus System::Load(EmuWindow* emu_window, const std::string& file
return ResultStatus::ErrorLoader_ErrorEncrypted;
case Loader::ResultStatus::ErrorInvalidFormat:
return ResultStatus::ErrorLoader_ErrorInvalidFormat;
case Loader::ResultStatus::ErrorUnsupportedArch:
return ResultStatus::ErrorUnsupportedArch;
default:
return ResultStatus::ErrorLoader;
}

View File

@@ -44,6 +44,7 @@ public:
ErrorSystemFiles, ///< Error in finding system files
ErrorSharedFont, ///< Error in finding shared font
ErrorVideoCore, ///< Error in the video core
ErrorUnsupportedArch, ///< Unsupported Architecture (32-Bit ROMs)
ErrorUnknown ///< Any other error
};

View File

@@ -112,15 +112,15 @@ void ServiceFrameworkBase::ReportUnimplementedFunction(Kernel::HLERequestContext
auto cmd_buf = ctx.CommandBuffer();
std::string function_name = info == nullptr ? fmt::format("{}", ctx.GetCommand()) : info->name;
fmt::memory_buffer buf;
fmt::format_to(buf, "function '{}': port='{}' cmd_buf={{[0]={:#x}", function_name, service_name,
cmd_buf[0]);
fmt::MemoryWriter w;
w.write("function '{}': port='{}' cmd_buf={{[0]={:#x}", function_name, service_name,
cmd_buf[0]);
for (int i = 1; i <= 8; ++i) {
fmt::format_to(buf, ", [{}]={:#x}", i, cmd_buf[i]);
w.write(", [{}]={:#x}", i, cmd_buf[i]);
}
buf.push_back('}');
w << '}';
LOG_ERROR(Service, "unknown / unimplemented %s", fmt::to_string(buf).c_str());
LOG_ERROR(Service, "unknown / unimplemented %s", w.c_str());
UNIMPLEMENTED();
}

View File

@@ -119,6 +119,11 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load(
}
metadata.Print();
const FileSys::ProgramAddressSpaceType arch_bits{metadata.GetAddressSpaceType()};
if (arch_bits == FileSys::ProgramAddressSpaceType::Is32Bit) {
return ResultStatus::ErrorUnsupportedArch;
}
// Load NSO modules
VAddr next_load_addr{Memory::PROCESS_IMAGE_VADDR};
for (const auto& module : {"rtld", "main", "subsdk0", "subsdk1", "subsdk2", "subsdk3",

View File

@@ -72,6 +72,7 @@ enum class ResultStatus {
ErrorAlreadyLoaded,
ErrorMemoryAllocationFailed,
ErrorEncrypted,
ErrorUnsupportedArch,
};
/// Interface for loading an application

View File

@@ -87,8 +87,8 @@ TelemetrySession::TelemetrySession() {
#ifdef ENABLE_WEB_SERVICE
if (Settings::values.enable_telemetry) {
backend = std::make_unique<WebService::TelemetryJson>(
Settings::values.telemetry_endpoint_url, Settings::values.yuzu_username,
Settings::values.yuzu_token);
Settings::values.telemetry_endpoint_url, Settings::values.citra_username,
Settings::values.citra_token);
} else {
backend = std::make_unique<Telemetry::NullVisitor>();
}

View File

@@ -50,8 +50,8 @@ u64 RegenerateTelemetryId();
/**
* Verifies the username and token.
* @param username yuzu username to use for authentication.
* @param token yuzu token to use for authentication.
* @param username Citra username to use for authentication.
* @param token Citra token to use for authentication.
* @param func A function that gets exectued when the verification is finished
* @returns Future with bool indicating whether the verification succeeded
*/

View File

@@ -357,7 +357,12 @@ bool GMainWindow::LoadROM(const QString& filename) {
QMessageBox::critical(this, tr("Error while loading ROM!"),
tr("The ROM format is not supported."));
break;
case Core::System::ResultStatus::ErrorUnsupportedArch:
LOG_CRITICAL(Frontend, "Unsupported architecture detected!",
filename.toStdString().c_str());
QMessageBox::critical(this, tr("Error while loading ROM!"),
tr("The ROM uses currently unusable 32-bit architecture"));
break;
case Core::System::ResultStatus::ErrorSystemMode:
LOG_CRITICAL(Frontend, "Failed to load ROM!");
QMessageBox::critical(this, tr("Error while loading ROM!"),
@@ -371,9 +376,9 @@ bool GMainWindow::LoadROM(const QString& filename) {
"yuzu. A real Switch is required.<br/><br/>"
"For more information on dumping and decrypting games, please see the following "
"wiki pages: <ul>"
"<li><a href='https://yuzu-emu.org/wiki/dumping-game-cartridges/'>Dumping Game "
"<li><a href='https://citra-emu.org/wiki/dumping-game-cartridges/'>Dumping Game "
"Cartridges</a></li>"
"<li><a href='https://yuzu-emu.org/wiki/dumping-installed-titles/'>Dumping "
"<li><a href='https://citra-emu.org/wiki/dumping-installed-titles/'>Dumping "
"Installed Titles</a></li>"
"</ul>"));
break;
@@ -408,7 +413,7 @@ bool GMainWindow::LoadROM(const QString& filename) {
}
void GMainWindow::BootGame(const QString& filename) {
NGLOG_INFO(Frontend, "yuzu starting...");
LOG_INFO(Frontend, "yuzu starting...");
StoreRecentFile(filename); // Put the filename on top of the list
if (!LoadROM(filename))
@@ -695,18 +700,18 @@ void GMainWindow::UpdateStatusBar() {
void GMainWindow::OnCoreError(Core::System::ResultStatus result, std::string details) {
QMessageBox::StandardButton answer;
QString status_message;
const QString common_message = tr(
"The game you are trying to load requires additional files from your Switch to be dumped "
"before playing.<br/><br/>For more information on dumping these files, please see the "
"following wiki page: <a "
"href='https://yuzu-emu.org/wiki/"
"dumping-system-archives-and-the-shared-fonts-from-a-switch-console/'>Dumping System "
"Archives and the Shared Fonts from a Switch Console</a>.<br/><br/>Would you like to quit "
"back to the game list? Continuing emulation may result in crashes, corrupted save "
"data, or other bugs.");
const QString common_message =
tr("The game you are trying to load requires additional files from your 3DS to be dumped "
"before playing.<br/><br/>For more information on dumping these files, please see the "
"following wiki page: <a "
"href='https://citra-emu.org/wiki/"
"dumping-system-archives-and-the-shared-fonts-from-a-3ds-console/'>Dumping System "
"Archives and the Shared Fonts from a 3DS Console</a>.<br/><br/>Would you like to quit "
"back to the game list? Continuing emulation may result in crashes, corrupted save "
"data, or other bugs.");
switch (result) {
case Core::System::ResultStatus::ErrorSystemFiles: {
QString message = "yuzu was unable to locate a Switch system archive";
QString message = "Citra was unable to locate a 3DS system archive";
if (!details.empty()) {
message.append(tr(": %1. ").arg(details.c_str()));
} else {
@@ -721,7 +726,7 @@ void GMainWindow::OnCoreError(Core::System::ResultStatus result, std::string det
}
case Core::System::ResultStatus::ErrorSharedFont: {
QString message = tr("yuzu was unable to locate the Switch shared fonts. ");
QString message = tr("Citra was unable to locate the 3DS shared fonts. ");
message.append(common_message);
answer = QMessageBox::question(this, tr("Shared Fonts Not Found"), message,
QMessageBox::Yes | QMessageBox::No, QMessageBox::No);

View File

@@ -177,12 +177,12 @@ gdbstub_port=24689
# 0: No, 1 (default): Yes
enable_telemetry =
# Endpoint URL for submitting telemetry data
telemetry_endpoint_url =
telemetry_endpoint_url = https://services.citra-emu.org/api/telemetry
# Endpoint URL to verify the username and token
verify_endpoint_url =
# Username and token for yuzu Web Service
verify_endpoint_url = https://services.citra-emu.org/api/profile
# Username and token for Citra Web Service
# See https://services.citra-emu.org/ for more info
yuzu_username =
yuzu_token =
citra_username =
citra_token =
)";
}

View File

@@ -147,7 +147,7 @@ int main(int argc, char** argv) {
LOG_CRITICAL(Frontend, "The game that you are trying to load must be decrypted before "
"being used with yuzu. \n\n For more information on dumping and "
"decrypting games, please refer to: "
"https://yuzu-emu.org/wiki/dumping-game-cartridges/");
"https://citra-emu.org/wiki/dumping-game-cartridges/");
return -1;
case Core::System::ResultStatus::ErrorLoader_ErrorInvalidFormat:
LOG_CRITICAL(Frontend, "Error while loading ROM: The ROM format is not supported.");