Skip to content
Open
6 changes: 3 additions & 3 deletions src/native/clr/include/host/host-environment.hh
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ namespace xamarin::android {
static void set_system_property (const char *name, const char *value) noexcept
{
// TODO: should we **actually** try to set the system property here? Would that even work? Needs testing
log_debug (LOG_DEFAULT, " System property {} = '{}'", optional_string (name), optional_string (value));
log_debugf (LOG_DEFAULT, " System property %s = '%s'", optional_string (name), optional_string (value));
}

[[gnu::flatten, gnu::always_inline]]
Expand Down Expand Up @@ -94,10 +94,10 @@ namespace xamarin::android {
static_local_string<SENSIBLE_PATH_MAX> dir (home_len + relative_path.length ());
Util::path_combine (dir, home.get_string_view (), relative_path);

log_debug (LOG_DEFAULT, "Creating XDG directory: {}"sv, optional_string (dir.get ()));
log_debugf (LOG_DEFAULT, "Creating XDG directory: %s", optional_string (dir.get ()));
int rv = Util::create_directory (dir.get (), Constants::DEFAULT_DIRECTORY_MODE);
if (rv < 0 && errno != EEXIST) {
log_warn (LOG_DEFAULT, "Failed to create XDG directory {}. {}"sv, optional_string (dir.get ()), strerror (errno));
log_warnf (LOG_DEFAULT, "Failed to create XDG directory %s. %s", optional_string (dir.get ()), strerror (errno));
}

if (!environment_variable_name.empty ()) {
Expand Down
7 changes: 7 additions & 0 deletions src/native/clr/include/shared/log_types.hh
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once

#include <cstdarg>
#include <cstdint>
#include <format>
#include <string>
Expand Down Expand Up @@ -47,6 +48,12 @@ namespace xamarin::android {
// A slightly faster alternative to other log functions as it doesn't parse the message
// for format placeholders nor it uses variable arguments
void log_write (LogCategories category, LogLevel level, const char *message) noexcept;
void log_writev (LogCategories category, LogLevel level, const char *format, va_list args) noexcept;
void log_writef (LogCategories category, LogLevel level, const char *format, ...) noexcept __attribute__ ((format (printf, 3, 4)));
void log_debugf (LogCategories category, const char *format, ...) noexcept __attribute__ ((format (printf, 2, 3)));
void log_infof (LogCategories category, const char *format, ...) noexcept __attribute__ ((format (printf, 2, 3)));
void log_warnf (LogCategories category, const char *format, ...) noexcept __attribute__ ((format (printf, 2, 3)));
void log_errorf (LogCategories category, const char *format, ...) noexcept __attribute__ ((format (printf, 2, 3)));

[[gnu::always_inline]]
static inline void log_write (LogCategories category, LogLevel level, std::string_view const& message) noexcept
Expand Down
21 changes: 18 additions & 3 deletions src/native/clr/shared/helpers.cc
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include <cstdarg>
#include <cstdio>
#include <cstring>
#include <android/set_abort_message.h>

Expand All @@ -7,11 +8,24 @@

using namespace xamarin::android;

[[noreturn]] void
Helpers::abort_applicationf (LogCategories category, std::source_location sloc, const char *format, ...) noexcept
{
char *message = nullptr;
const char *safe_format = format == nullptr ? "<null>" : format;
va_list args;
va_start (args, format);
int ret = vasprintf (&message, safe_format, args);
va_end (args);

abort_application (category, ret < 0 ? safe_format : message, true, sloc);
}

[[noreturn]] void
Helpers::abort_application (LogCategories category, const char *message, bool log_location, std::source_location sloc) noexcept
{
// Log it, but also...
log_fatal (category, "{}", message);
log_write (category, LogLevel::Fatal, message);

// ...let android include it in the tombstone, debuggerd output, stack trace etc
android_set_abort_message (message);
Expand All @@ -33,9 +47,10 @@ Helpers::abort_application (LogCategories category, const char *message, bool lo
}
}

log_fatal (
log_writef (
category,
"Abort at {}:{}:{} ('{}')",
LogLevel::Fatal,
"Abort at %s:%u:%u ('%s')",
file_name,
sloc.line (),
sloc.column (),
Expand Down
77 changes: 70 additions & 7 deletions src/native/clr/shared/log_functions.cc
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,17 @@ namespace {
};

constexpr size_t loglevel_map_max_index = (sizeof(loglevel_map) / sizeof(android_LogPriority)) - 1;

[[gnu::always_inline]]
auto priority_for_level (LogLevel level) noexcept -> android_LogPriority
{
size_t map_index = static_cast<size_t>(level);
if (map_index > loglevel_map_max_index) {
return DEFAULT_PRIORITY;
}

return loglevel_map[map_index];
}
}

unsigned int log_categories = LOG_NONE;
Expand Down Expand Up @@ -117,15 +128,67 @@ namespace xamarin::android {
void
log_write (LogCategories category, LogLevel level, const char *message) noexcept
{
size_t map_index = static_cast<size_t>(level);
android_LogPriority priority;
__android_log_write (priority_for_level (level), category_name (category), message);
}

if (map_index > loglevel_map_max_index) {
priority = DEFAULT_PRIORITY;
} else {
priority = loglevel_map[map_index];
void
log_writev (LogCategories category, LogLevel level, const char *format, va_list args) noexcept
{
const char *safe_format = format == nullptr ? "<null>" : format;
__android_log_vprint (priority_for_level (level), category_name (category), safe_format, args);
}

void
log_writef (LogCategories category, LogLevel level, const char *format, ...) noexcept
{
va_list args;
va_start (args, format);
log_writev (category, level, format, args);
va_end (args);
}

void
log_debugf (LogCategories category, const char *format, ...) noexcept
{
if ((log_categories & category) == 0) {
return;
}

va_list args;
va_start (args, format);
log_writev (category, LogLevel::Debug, format, args);
va_end (args);
}

void
log_infof (LogCategories category, const char *format, ...) noexcept
{
if ((log_categories & category) == 0) {
return;
}

__android_log_write (priority, category_name (category), message);
va_list args;
va_start (args, format);
log_writev (category, LogLevel::Info, format, args);
va_end (args);
}

void
log_warnf (LogCategories category, const char *format, ...) noexcept
{
va_list args;
va_start (args, format);
log_writev (category, LogLevel::Warn, format, args);
va_end (args);
}

void
log_errorf (LogCategories category, const char *format, ...) noexcept
{
va_list args;
va_start (args, format);
log_writev (category, LogLevel::Error, format, args);
va_end (args);
}

}
17 changes: 13 additions & 4 deletions src/native/common/include/runtime-base/strings.hh
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
#include <unistd.h>

#include <shared/helpers.hh>
namespace xamarin::android {
void log_errorf (LogCategories category, const char *format, ...) noexcept __attribute__ ((format (printf, 2, 3)));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 💡 Native C++ — This forward declaration of log_errorf duplicates the canonical one in shared/log_types.hh. Deliberately avoiding that heavyweight include is reasonable, but if the signature ever changes the two can silently diverge (the mismatch only surfaces in translation units that include both headers). Consider adding a short comment pointing at the canonical declaration, e.g. // Forward-declared to avoid including shared/log_types.hh; keep in sync with it.

(Rule: Native C++ — reduce duplication drift)

}

#if defined(XA_HOST_MONOVM)
#include <runtime-base/shared-constants.hh>
Expand Down Expand Up @@ -205,7 +208,7 @@ namespace xamarin::android {
}

if (!can_access (start_index)) {
log_error (LOG_DEFAULT, "Cannot convert string to integer, index {} is out of range", start_index);
log_errorf (LOG_DEFAULT, "Cannot convert string to integer, index %zu is out of range", start_index);
return false;
}

Expand All @@ -229,17 +232,23 @@ namespace xamarin::android {
}

if (out_of_range || errno == ERANGE) {
log_error (LOG_DEFAULT, "Value {} is out of range of this type ({}..{})", reinterpret_cast<char*>(s), static_cast<int64_t>(min), static_cast<uint64_t>(max));
log_errorf (
LOG_DEFAULT,
"Value %s is out of range of this type (%lld..%llu)",
reinterpret_cast<char*>(s),
static_cast<long long>(static_cast<int64_t>(min)),
static_cast<unsigned long long>(static_cast<uint64_t>(max))
);
return false;
}

if (endp == s) {
log_error (LOG_DEFAULT, "Value {} does not represent a base {} integer", reinterpret_cast<char*>(s), base);
log_errorf (LOG_DEFAULT, "Value %s does not represent a base %d integer", reinterpret_cast<char*>(s), base);
return false;
}

if (*endp != '\0') {
log_error (LOG_DEFAULT, "Value {} has non-numeric characters at the end", reinterpret_cast<char*>(s));
log_errorf (LOG_DEFAULT, "Value %s has non-numeric characters at the end", reinterpret_cast<char*>(s));
return false;
}

Expand Down
3 changes: 3 additions & 0 deletions src/native/common/include/shared/helpers.hh
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ namespace xamarin::android
[[noreturn]]
static void abort_application (LogCategories category, const char *message, bool log_location = true, std::source_location sloc = std::source_location::current ()) noexcept;

[[noreturn]]
static void abort_applicationf (LogCategories category, std::source_location sloc, const char *format, ...) noexcept __attribute__ ((format (printf, 3, 4)));

[[noreturn]]
static void abort_application (LogCategories category, std::string const& message, bool log_location = true, std::source_location sloc = std::source_location::current ()) noexcept
{
Expand Down
77 changes: 70 additions & 7 deletions src/native/mono/shared/log_functions.cc
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include <array>
#include <cstdarg>
#include <strings.h>

#include <android/log.h>
Expand Down Expand Up @@ -102,19 +103,81 @@ static constexpr android_LogPriority loglevel_map[] = {

static constexpr size_t loglevel_map_max_index = (sizeof(loglevel_map) / sizeof(android_LogPriority)) - 1;

static auto
priority_for_level (xamarin::android::LogLevel level) noexcept -> android_LogPriority
{
size_t map_index = static_cast<size_t>(level);
if (map_index > loglevel_map_max_index) {
return DEFAULT_PRIORITY;
}

return loglevel_map[map_index];
}

namespace xamarin::android {
void
log_write (LogCategories category, LogLevel level, const char *message) noexcept
{
size_t map_index = static_cast<size_t>(level);
android_LogPriority priority;
__android_log_write (priority_for_level (level), CATEGORY_NAME (category), message);
}

void
log_writev (LogCategories category, LogLevel level, const char *format, va_list args) noexcept
{
const char *safe_format = format == nullptr ? "<null>" : format;
__android_log_vprint (priority_for_level (level), CATEGORY_NAME (category), safe_format, args);
}

void
log_writef (LogCategories category, LogLevel level, const char *format, ...) noexcept
{
va_list args;
va_start (args, format);
log_writev (category, level, format, args);
va_end (args);
}

void
log_debugf (LogCategories category, const char *format, ...) noexcept
{
if ((log_categories & category) == 0) {
return;
}

va_list args;
va_start (args, format);
log_writev (category, LogLevel::Debug, format, args);
va_end (args);
}

if (map_index > loglevel_map_max_index) {
priority = DEFAULT_PRIORITY;
} else {
priority = loglevel_map[map_index];
void
log_infof (LogCategories category, const char *format, ...) noexcept
{
if ((log_categories & category) == 0) {
return;
}

__android_log_write (priority, CATEGORY_NAME (category), message);
va_list args;
va_start (args, format);
log_writev (category, LogLevel::Info, format, args);
va_end (args);
}

void
log_warnf (LogCategories category, const char *format, ...) noexcept
{
va_list args;
va_start (args, format);
log_writev (category, LogLevel::Warn, format, args);
va_end (args);
}

void
log_errorf (LogCategories category, const char *format, ...) noexcept
{
va_list args;
va_start (args, format);
log_writev (category, LogLevel::Error, format, args);
va_end (args);
}
}
7 changes: 7 additions & 0 deletions src/native/mono/shared/log_types.hh
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once

#include <cstdarg>
#include <cstdint>
#include <format>
#include <string>
Expand Down Expand Up @@ -47,6 +48,12 @@ namespace xamarin::android {
// A slightly faster alternative to other log functions as it doesn't parse the message
// for format placeholders nor it uses variable arguments
void log_write (LogCategories category, LogLevel level, const char *message) noexcept;
void log_writev (LogCategories category, LogLevel level, const char *format, va_list args) noexcept;
void log_writef (LogCategories category, LogLevel level, const char *format, ...) noexcept __attribute__ ((format (printf, 3, 4)));
void log_debugf (LogCategories category, const char *format, ...) noexcept __attribute__ ((format (printf, 2, 3)));
void log_infof (LogCategories category, const char *format, ...) noexcept __attribute__ ((format (printf, 2, 3)));
void log_warnf (LogCategories category, const char *format, ...) noexcept __attribute__ ((format (printf, 2, 3)));
void log_errorf (LogCategories category, const char *format, ...) noexcept __attribute__ ((format (printf, 2, 3)));

[[gnu::always_inline]]
static inline void log_write (LogCategories category, LogLevel level, std::string_view const& message) noexcept
Expand Down
16 changes: 5 additions & 11 deletions src/native/nativeaot/host/bridge-processing.cc
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
#include <format>

#include <host/bridge-processing.hh>
#include <runtime-base/logger.hh>
#include <shared/helpers.hh>
Expand All @@ -21,16 +19,12 @@ void BridgeProcessing::naot_initialize_on_runtime_init (JNIEnv *env) noexcept
GCUserPeerable_jiClearManagedReferences = env->GetMethodID (GCUserPeerable_class, "jiClearManagedReferences", "()V");

if (GCUserPeerable_jiAddManagedReference == nullptr || GCUserPeerable_jiClearManagedReferences == nullptr) [[unlikely]] {
constexpr auto ABSENT = "absent"sv;
constexpr auto PRESENT = "present"sv;

Helpers::abort_application (
Helpers::abort_applicationf (
LOG_DEFAULT,
std::format (
"Failed to find GCUserPeerable method(s): jiAddManagedReference ({}); jiClearManagedReferences ({})"sv,
GCUserPeerable_jiAddManagedReference == nullptr ? ABSENT : PRESENT,
GCUserPeerable_jiClearManagedReferences == nullptr ? ABSENT : PRESENT
)
std::source_location::current (),
"Failed to find GCUserPeerable method(s): jiAddManagedReference (%s); jiClearManagedReferences (%s)",
GCUserPeerable_jiAddManagedReference == nullptr ? "absent" : "present",
GCUserPeerable_jiClearManagedReferences == nullptr ? "absent" : "present"
);
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/native/nativeaot/host/host.cc
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ auto HostCommon::Java_JNI_OnLoad (JavaVM *vm, void *reserved) noexcept -> jint

if (__jni_on_load_handler_count > 0) {
for (uint32_t i = 0; i < __jni_on_load_handler_count; i++) {
log_debug (
log_debugf (
LOG_ASSEMBLY,
"Calling JNI on-load init func '{}' ({:p})",
"Calling JNI on-load init func '%s' (%p)",
optional_string (__jni_on_load_handler_names[i]),
reinterpret_cast<void*>(__jni_on_load_handlers[i])
);
Expand Down
Loading