From 95bcc4da5b3642ea7f7bbde9849d02a550924f2e Mon Sep 17 00:00:00 2001 From: Carter Li Date: Sat, 3 Oct 2026 14:27:24 +0800 Subject: [PATCH] Common: adds more FF_DEBUG --- src/common/android/binder.c | 29 +++++++++++++++++++++++++++-- src/common/android/dex.c | 29 +++++++++++++++++++++++++++-- src/common/apple/cf_helpers.c | 32 ++++++++++++++++++++++++++++++++ src/common/apple/smc_temps.c | 30 ++++++++++++++++++++++++++++-- src/common/impl/dbus.c | 3 +++ src/common/impl/io_unix.c | 19 +++++++++++++++++-- src/common/impl/jsonconfig.c | 13 +++++++++++++ src/common/impl/lua.c | 3 +++ src/common/impl/path.c | 4 ++++ src/common/impl/percent.c | 5 +++++ src/common/impl/sysctl.c | 7 +++++++ 11 files changed, 166 insertions(+), 8 deletions(-) diff --git a/src/common/android/binder.c b/src/common/android/binder.c index 41e163524..fd9ea332a 100644 --- a/src/common/android/binder.c +++ b/src/common/android/binder.c @@ -1,5 +1,7 @@ #include "common/android/binder.h" +#include "common/debug.h" +#include #include #include #include @@ -9,11 +11,16 @@ const char* ffBinderOpen(FFBinder* binder) { const int fd = open(FF_BINDER_DEVICE, O_RDWR | O_CLOEXEC); if (fd < 0) { + FF_DEBUG("open(" FF_BINDER_DEVICE ") failed: %s", strerror(errno)); return "Failed to open " FF_BINDER_DEVICE; } struct binder_version version = { .protocol_version = 0 }; - if (ioctl(fd, BINDER_VERSION, &version) != 0 || version.protocol_version != BINDER_CURRENT_PROTOCOL_VERSION) { + const int versionIoctl = ioctl(fd, BINDER_VERSION, &version); + if (versionIoctl != 0 || version.protocol_version != BINDER_CURRENT_PROTOCOL_VERSION) { + FF_DEBUG("BINDER_VERSION reported protocol %u, expected %u (%s)", + version.protocol_version, BINDER_CURRENT_PROTOCOL_VERSION, + versionIoctl != 0 ? strerror(errno) : "version mismatch"); close(fd); return "Unsupported binder protocol version"; } @@ -22,6 +29,7 @@ const char* ffBinderOpen(FFBinder* binder) { // addresses in BR_REPLY, so it has to stay mapped for as long as the handle is used. void* shared = mmap(nullptr, FF_BINDER_SHARED_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, fd, 0); if (shared == MAP_FAILED) { + FF_DEBUG("mmap(" FF_BINDER_DEVICE ") failed: %s", strerror(errno)); close(fd); return "Failed to mmap " FF_BINDER_DEVICE; } @@ -55,6 +63,8 @@ const char* ffBinderTransact(FFBinder* binder, uint32_t handle, uint32_t code, u reply->fdCount = 0; if (parcel->truncated) { + FF_DEBUG("The parcel was truncated at %zu bytes, the caller buffer holds %zu", + parcel->size, parcel->capacity); return "Binder parcel does not fit the caller buffer"; } @@ -86,6 +96,7 @@ const char* ffBinderTransact(FFBinder* binder, uint32_t handle, uint32_t code, u .read_buffer = (binder_uintptr_t) (uintptr_t) readBuffer, }; if (ioctl(binder->fd, BINDER_WRITE_READ, &exchange) != 0) { + FF_DEBUG("BINDER_WRITE_READ(handle=%u, code=%u) failed: %s", handle, code, strerror(errno)); return "BINDER_WRITE_READ failed"; } @@ -103,8 +114,10 @@ const char* ffBinderTransact(FFBinder* binder, uint32_t handle, uint32_t code, u break; case BR_FAILED_REPLY: + FF_DEBUG("BR_FAILED_REPLY for handle=%u, code=%u", handle, code); return "Binder transaction failed"; case BR_DEAD_REPLY: + FF_DEBUG("BR_DEAD_REPLY: handle=%u is dead", handle); return "Binder service is not running"; case BR_INCREFS: @@ -123,6 +136,8 @@ const char* ffBinderTransact(FFBinder* binder, uint32_t handle, uint32_t code, u case BR_REPLY: { if ((size_t) (end - cursor) < sizeof(struct binder_transaction_data)) { + FF_DEBUG("BR_REPLY is truncated: %zu of %zu bytes left", + (size_t) (end - cursor), sizeof(struct binder_transaction_data)); return "Truncated binder reply"; } struct binder_transaction_data data; @@ -140,6 +155,8 @@ const char* ffBinderTransact(FFBinder* binder, uint32_t handle, uint32_t code, u const char* error = nullptr; if (payloadSize > 0) { if (payloadSize > reply->capacity) { + FF_DEBUG("The reply carries %zu payload bytes, the caller buffer holds %zu", + payloadSize, reply->capacity); error = "Binder reply does not fit the caller buffer"; } else { memcpy(reply->data, payload, payloadSize); @@ -211,6 +228,7 @@ const char* ffBinderTransact(FFBinder* binder, uint32_t handle, uint32_t code, u // later transaction on them fails with BR_FAILED_REPLY, which says nothing about the // real cause. Reported, but only when nothing more specific is already at hand. if (ioctl(binder->fd, BINDER_WRITE_READ, &release) != 0 && error == nullptr) { + FF_DEBUG("BC_ACQUIRE/BC_FREE_BUFFER failed: %s", strerror(errno)); error = "Releasing the binder reply failed"; } @@ -218,10 +236,13 @@ const char* ffBinderTransact(FFBinder* binder, uint32_t handle, uint32_t code, u } default: + FF_DEBUG("Unexpected binder command 0x%08x for handle=%u, code=%u", command, handle, code); return "Unexpected binder command"; } } + FF_DEBUG("The binder reply for handle=%u, code=%u held no BR_REPLY (%zu bytes read)", + handle, code, (size_t) exchange.read_consumed); return "No reply from binder"; } @@ -238,12 +259,16 @@ const char* ffBinderLookupService(FFBinder* binder, const char* name, uint32_t t return error; } if (ffBinderReplyIsStatus(&reply)) { + FF_DEBUG("The service manager returned a status parcel for %s, code=%u", name, transactionCode); return "Service manager rejected the request"; } - if (ffBinderReadI32(reply.data, reply.size, 0) != 0) { + const int32_t exception = ffBinderReadI32(reply.data, reply.size, 0); + if (exception != 0) { + FF_DEBUG("The service manager raised exception %d for %s", exception, name); return "Service manager raised an exception"; } if (reply.handleCount == 0) { + FF_DEBUG("The service manager returned no handle for %s", name); return "Service is not registered"; } diff --git a/src/common/android/dex.c b/src/common/android/dex.c index c1de5b6fe..904477a38 100644 --- a/src/common/android/dex.c +++ b/src/common/android/dex.c @@ -2,8 +2,10 @@ #include "common/debug.h" #include "common/mallocHelper.h" +#include #include #include +#include #include #include #include @@ -460,6 +462,8 @@ static const char* findDexEntry(const uint8_t* jar, size_t jarSize, const char* } } if (eocd == SIZE_MAX) { + FF_DEBUG("No end-of-central-directory record in the last %zu bytes of a %zu byte jar", + newest - oldest + FF_ZIP_EOCD_SIZE, jarSize); return "The jar has no zip directory"; } @@ -479,6 +483,8 @@ static const char* findDexEntry(const uint8_t* jar, size_t jarSize, const char* const uint16_t commentLength = dexU16(jar + offset + FF_ZIP_OFF_CENTRAL_COMMENT_LENGTH); const size_t entrySize = FF_ZIP_CENTRAL_SIZE + (size_t) nameLength + (size_t) extraLength + (size_t) commentLength; if (entrySize > directoryEnd - offset) { + FF_DEBUG("A zip entry claims %zu bytes but only %zu remain in the directory", + entrySize, (size_t) (directoryEnd - offset)); return "A zip directory entry runs past the directory"; } @@ -487,6 +493,8 @@ static const char* findDexEntry(const uint8_t* jar, size_t jarSize, const char* const uint32_t uncompressed = dexU32(jar + offset + FF_ZIP_OFF_CENTRAL_UNCOMPRESSED_SIZE); const uint32_t localOffset = dexU32(jar + offset + FF_ZIP_OFF_CENTRAL_LOCAL_OFFSET); if (compressedSize == FF_ZIP_ZIP64_SENTINEL || uncompressed == FF_ZIP_ZIP64_SENTINEL || localOffset == FF_ZIP_ZIP64_SENTINEL) { + FF_DEBUG("The dex entry is zip64: compressed=%u, uncompressed=%u, localOffset=%u", + compressedSize, uncompressed, localOffset); return "A dex entry is stored as zip64, which is not supported"; } if (localOffset > jarSize || FF_ZIP_LOCAL_HEADER_SIZE > jarSize - localOffset) { @@ -509,6 +517,7 @@ static const char* findDexEntry(const uint8_t* jar, size_t jarSize, const char* offset += entrySize; } + FF_DEBUG("No entry in the %zu byte jar is named %s", jarSize, entry); return "The jar has no usable dex entry"; } @@ -545,6 +554,7 @@ static const char* inflateDex(const uint8_t* data, size_t dataSize, uint32_t unc // the pointer, which is also why no failure path has to free it by hand. FF_AUTO_FREE uint8_t* buffer = malloc(uncompressedSize); if (buffer == nullptr) { + FF_DEBUG("malloc(%u) for the inflated dex failed", uncompressedSize); return "malloc failed"; } @@ -557,12 +567,16 @@ static const char* inflateDex(const uint8_t* data, size_t dataSize, uint32_t unc stream.next_out = buffer; stream.avail_out = (uInt) uncompressedSize; - if (ffinflateInit2_(&stream, -MAX_WBITS, ZLIB_VERSION, (int) sizeof(z_stream)) != Z_OK) { + const int initStatus = ffinflateInit2_(&stream, -MAX_WBITS, ZLIB_VERSION, (int) sizeof(z_stream)); + if (initStatus != Z_OK) { + FF_DEBUG("inflateInit2() failed: zlib status %d", initStatus); return "inflateInit2 failed"; } const int status = ffinflate(&stream, Z_FINISH); ffinflateEnd(&stream); if (status != Z_STREAM_END || stream.total_out != (uLong) uncompressedSize) { + FF_DEBUG("inflate() returned %d, produced %lu of %u bytes", + status, stream.total_out, uncompressedSize); return "Inflating the dex failed"; } @@ -587,19 +601,25 @@ const char* ffDexStaticInts(const char* jarPath, const FFDexStaticIntRequest* re const int fd = open(jarPath, O_RDONLY | O_CLOEXEC); if (fd < 0) { + FF_DEBUG("open(%s) failed: %s", jarPath, strerror(errno)); return "open(jar) failed"; } struct stat st = {}; - if (fstat(fd, &st) != 0 || st.st_size <= 0) { + const int statStatus = fstat(fd, &st); + if (statStatus != 0 || st.st_size <= 0) { + FF_DEBUG("fstat(%s) reported %s (%lld bytes)", jarPath, + statStatus != 0 ? strerror(errno) : "an empty file", (long long) st.st_size); close(fd); return "fstat(jar) failed"; } mapping.mappedSize = (size_t) st.st_size; mapping.mapped = mmap(nullptr, mapping.mappedSize, PROT_READ, MAP_PRIVATE, fd, 0); // The mapping outlives the descriptor, so the descriptor can go either way from here. + const int mmapErrno = mapping.mapped == MAP_FAILED ? errno : 0; close(fd); if (mapping.mapped == MAP_FAILED) { + FF_DEBUG("mmap(%s, %zu bytes) failed: %s", jarPath, mapping.mappedSize, strerror(mmapErrno)); mapping.mapped = nullptr; return "mmap(jar) failed"; } @@ -610,6 +630,8 @@ const char* ffDexStaticInts(const char* jarPath, const FFDexStaticIntRequest* re FF_AUTO_FREE uint8_t* settled = calloc(count, 1); FF_AUTO_FREE uint32_t* typeIndexes = malloc((size_t) count * sizeof(uint32_t)); if (settled == nullptr || typeIndexes == nullptr) { + FF_DEBUG("Allocating %zu bytes for %u static int requests failed", + (size_t) count * (1 + sizeof(uint32_t)), count); return "malloc failed"; } @@ -650,6 +672,7 @@ const char* ffDexStaticInts(const char* jarPath, const FFDexStaticIntRequest* re } data = findDexMagic(mapping.mapped, mapping.mappedSize, &dataSize); if (data == nullptr) { + FF_DEBUG("Neither %s nor a dex magic signature is in the %zu byte jar", entry, mapping.mappedSize); return "No dex in the jar"; } } else if (method == FF_ZIP_METHOD_DEFLATED) { @@ -664,6 +687,8 @@ const char* ffDexStaticInts(const char* jarPath, const FFDexStaticIntRequest* re return "The jar deflates its dex entries and fastfetch was built without zlib"; #endif } else if (method != FF_ZIP_METHOD_STORED) { + FF_DEBUG("%s uses compression method %u, only %u (stored) and %u (deflated) are handled", + entry, method, FF_ZIP_METHOD_STORED, FF_ZIP_METHOD_DEFLATED); return "A dex entry uses an unsupported compression method"; } // A STORED entry needs no further work: `dataSize` already holds the `compressedSize` that diff --git a/src/common/apple/cf_helpers.c b/src/common/apple/cf_helpers.c index 87ea2bbb1..033c0bedb 100644 --- a/src/common/apple/cf_helpers.c +++ b/src/common/apple/cf_helpers.c @@ -1,36 +1,47 @@ #include "cf_helpers.h" +#include "common/debug.h" const char* ffCfNumGetInt64(CFTypeRef cf, int64_t* result) { if (CFGetTypeID(cf) == CFNumberGetTypeID()) { if (!CFNumberGetValue((CFNumberRef) cf, kCFNumberSInt64Type, result)) { + FF_DEBUG("CFNumberGetValue(kCFNumberSInt64Type) failed, the number is of type 0x%08lx", + (unsigned long) CFNumberGetType((CFNumberRef) cf)); return "Number type is not SInt64"; } return nullptr; } else if (CFGetTypeID(cf) == CFDataGetTypeID()) { if (CFDataGetLength((CFDataRef) cf) != sizeof(int64_t)) { + FF_DEBUG("CFData holds %ld bytes, int64_t needs %zu", + (long) CFDataGetLength((CFDataRef) cf), sizeof(int64_t)); return "Data length is not sizeof(int64_t)"; } CFDataGetBytes((CFDataRef) cf, CFRangeMake(0, sizeof(int64_t)), (uint8_t*) result); return nullptr; } + FF_DEBUG("Expected a CFNumber or CFData, got TypeID 0x%08lx", (unsigned long) CFGetTypeID(cf)); return "TypeID is neither 'CFNumber' nor 'CFData'"; } const char* ffCfNumGetInt(CFTypeRef cf, int32_t* result) { if (CFGetTypeID(cf) == CFNumberGetTypeID()) { if (!CFNumberGetValue((CFNumberRef) cf, kCFNumberSInt32Type, result)) { + FF_DEBUG("CFNumberGetValue(kCFNumberSInt32Type) failed, the number is of type 0x%08lx", + (unsigned long) CFNumberGetType((CFNumberRef) cf)); return "Number type is not SInt32"; } return nullptr; } else if (CFGetTypeID(cf) == CFDataGetTypeID()) { if (CFDataGetLength((CFDataRef) cf) != sizeof(*result)) { + FF_DEBUG("CFData holds %ld bytes, int32_t needs %zu", + (long) CFDataGetLength((CFDataRef) cf), sizeof(*result)); return "Data length is not sizeof(int32_t)"; } CFDataGetBytes((CFDataRef) cf, CFRangeMake(0, sizeof(*result)), (uint8_t*) result); return nullptr; } + FF_DEBUG("Expected a CFNumber or CFData, got TypeID 0x%08lx", (unsigned long) CFGetTypeID(cf)); return "TypeID is neither 'CFNumber' nor 'CFData'"; } @@ -38,16 +49,20 @@ const char* ffCfNumGetDouble(CFTypeRef cf, double* result) { if (CFGetTypeID(cf) == CFNumberGetTypeID()) { if (!CFNumberGetValue((CFNumberRef) cf, kCFNumberDoubleType, result) && !CFNumberGetValue((CFNumberRef) cf, kCFNumberFloatType, result)) { + FF_DEBUG("CFNumber is of type 0x%08lx, neither Double nor Float", + (unsigned long) CFNumberGetType((CFNumberRef) cf)); return "Number type is not Double or Float"; } return nullptr; } + FF_DEBUG("Expected a CFNumber, got TypeID 0x%08lx", (unsigned long) CFGetTypeID(cf)); return "TypeID is neither 'CFNumber'"; } const char* ffCfDateGetEpoch(CFTypeRef cf, uint64_t* result) { if (CFGetTypeID(cf) != CFDateGetTypeID()) { + FF_DEBUG("Expected a CFDate, got TypeID 0x%08lx", (unsigned long) CFGetTypeID(cf)); return "TypeID is not 'CFDate'"; } @@ -76,6 +91,7 @@ const char* ffCfStrGetString(CFTypeRef cf, FFstrbuf* result) { } ffStrbufEnsureFixedLengthFree(result, (uint32_t) CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8)); if (!CFStringGetCString(cfStr, result->chars, result->allocated, kCFStringEncodingUTF8)) { + FF_DEBUG("CFStringGetCString() failed for a %u character string", (unsigned) length); return "CFStringGetCString() failed"; } // CFStringGetCString ensures the buffer is NUL terminated @@ -93,6 +109,7 @@ const char* ffCfStrGetString(CFTypeRef cf, FFstrbuf* result) { result->length = (uint32_t) strnlen(result->chars, length); result->chars[result->length] = '\0'; } else { + FF_DEBUG("Expected a CFString or CFData, got TypeID 0x%08lx", (unsigned long) CFGetTypeID(cf)); return "TypeID is neither 'CFString' nor 'CFData'"; } @@ -116,6 +133,7 @@ const char* ffCfDataGetDataAsString(CFTypeRef cf, FFstrbuf* result) { result->length = length; result->chars[result->length] = '\0'; } else { + FF_DEBUG("Expected a CFData, got TypeID 0x%08lx", (unsigned long) CFGetTypeID(cf)); return "TypeID is not 'CFData'"; } @@ -125,6 +143,7 @@ const char* ffCfDataGetDataAsString(CFTypeRef cf, FFstrbuf* result) { const char* ffCfDictGetString(CFDictionaryRef dict, CFStringRef key, FFstrbuf* result) { CFTypeRef cf = (CFTypeRef) CFDictionaryGetValue(dict, key); if (cf == nullptr) { + FF_DEBUG("The dictionary has no value for the key"); return "CFDictionaryGetValue() failed"; } @@ -134,6 +153,7 @@ const char* ffCfDictGetString(CFDictionaryRef dict, CFStringRef key, FFstrbuf* r const char* ffCfDictGetDataAsString(CFDictionaryRef dict, CFStringRef key, FFstrbuf* result) { CFTypeRef cf = (CFTypeRef) CFDictionaryGetValue(dict, key); if (cf == nullptr) { + FF_DEBUG("The dictionary has no value for the key"); return "CFDictionaryGetValue() failed"; } @@ -143,10 +163,12 @@ const char* ffCfDictGetDataAsString(CFDictionaryRef dict, CFStringRef key, FFstr const char* ffCfDictGetBool(CFDictionaryRef dict, CFStringRef key, bool* result) { CFBooleanRef cf = (CFBooleanRef) CFDictionaryGetValue(dict, key); if (cf == nullptr) { + FF_DEBUG("The dictionary has no value for the key"); return "CFDictionaryGetValue() failed"; } if (CFGetTypeID(cf) != CFBooleanGetTypeID()) { + FF_DEBUG("Expected a CFBoolean, got TypeID 0x%08lx", (unsigned long) CFGetTypeID(cf)); return "TypeID is not 'CFBoolean'"; } @@ -157,6 +179,7 @@ const char* ffCfDictGetBool(CFDictionaryRef dict, CFStringRef key, bool* result) const char* ffCfDictGetInt(CFDictionaryRef dict, CFStringRef key, int* result) { CFTypeRef cf = (CFTypeRef) CFDictionaryGetValue(dict, key); if (cf == nullptr) { + FF_DEBUG("The dictionary has no value for the key"); return "CFDictionaryGetValue() failed"; } @@ -166,6 +189,7 @@ const char* ffCfDictGetInt(CFDictionaryRef dict, CFStringRef key, int* result) { const char* ffCfDictGetInt64(CFDictionaryRef dict, CFStringRef key, int64_t* result) { CFTypeRef cf = (CFTypeRef) CFDictionaryGetValue(dict, key); if (cf == nullptr) { + FF_DEBUG("The dictionary has no value for the key"); return "CFDictionaryGetValue() failed"; } @@ -175,6 +199,7 @@ const char* ffCfDictGetInt64(CFDictionaryRef dict, CFStringRef key, int64_t* res const char* ffCfDictGetDouble(CFDictionaryRef dict, CFStringRef key, double* result) { CFTypeRef cf = (CFTypeRef) CFDictionaryGetValue(dict, key); if (cf == nullptr) { + FF_DEBUG("The dictionary has no value for the key"); return "CFDictionaryGetValue() failed"; } @@ -184,16 +209,20 @@ const char* ffCfDictGetDouble(CFDictionaryRef dict, CFStringRef key, double* res const char* ffCfDictGetData(CFDictionaryRef dict, CFStringRef key, uint32_t offset, uint32_t size, uint8_t* result, uint32_t* length) { CFTypeRef cf = (CFTypeRef) CFDictionaryGetValue(dict, key); if (cf == nullptr) { + FF_DEBUG("The dictionary has no value for the key"); return "CFDictionaryGetValue() failed"; } if (CFGetTypeID(cf) != CFDataGetTypeID()) { + FF_DEBUG("Expected a CFData, got TypeID 0x%08lx", (unsigned long) CFGetTypeID(cf)); return "TypeID is not 'CFData'"; } CFIndex trueLength = CFDataGetLength((CFDataRef) cf); if (trueLength < offset + size) { + FF_DEBUG("The CFData holds %ld bytes, the caller asked for [%u, %u)", + (long) trueLength, offset, offset + size); return "Data length is less than offset + size"; } @@ -208,6 +237,8 @@ const char* ffCfDictGetData(CFDictionaryRef dict, CFStringRef key, uint32_t offs const char* ffCfDictGetDict(CFDictionaryRef dict, CFStringRef key, CFDictionaryRef* result) { CFDictionaryRef cf = (CFDictionaryRef) CFDictionaryGetValue(dict, key); if (cf == nullptr || CFGetTypeID(cf) != CFDictionaryGetTypeID()) { + FF_DEBUG("Expected a CFDictionary, got %s", + cf == nullptr ? "no value at all" : "a value of another type"); return "TypeID is not 'CFDictionary'"; } @@ -218,6 +249,7 @@ const char* ffCfDictGetDict(CFDictionaryRef dict, CFStringRef key, CFDictionaryR const char* ffCfDictGetDateAsEpoch(CFDictionaryRef dict, CFStringRef key, uint64_t* result) { CFTypeRef cf = (CFTypeRef) CFDictionaryGetValue(dict, key); if (cf == nullptr) { + FF_DEBUG("The dictionary has no value for the key"); return "CFDictionaryGetValue() failed"; } diff --git a/src/common/apple/smc_temps.c b/src/common/apple/smc_temps.c index 9fb18210f..48c99d561 100644 --- a/src/common/apple/smc_temps.c +++ b/src/common/apple/smc_temps.c @@ -1,5 +1,6 @@ #include "smc_temps.h" #include "common/apple/cf_helpers.h" +#include "common/debug.h" #include "common/strutil.h" #include @@ -83,7 +84,10 @@ static void smcUltostr(char* str, uint32_t val) { static const char* smcCall(io_connect_t conn, uint32_t selector, SmcKeyData_t* inputStructure, SmcKeyData_t* outputStructure) { size_t size = sizeof(SmcKeyData_t); - if (IOConnectCallStructMethod(conn, selector, inputStructure, size, outputStructure, &size) != kIOReturnSuccess) { + const IOReturn callStatus = IOConnectCallStructMethod(conn, selector, inputStructure, size, outputStructure, &size); + if (callStatus != kIOReturnSuccess) { + FF_DEBUG("IOConnectCallStructMethod(selector=%u, command=%u) failed: IOReturn 0x%08x", + selector, (uint32_t) (unsigned char) inputStructure->data8, (unsigned) callStatus); return "IOConnectCallStructMethod(conn) failed"; } return nullptr; @@ -136,10 +140,13 @@ static const char* smcReadSmcVal(io_connect_t conn, const UInt32Char_t key, SmcV static const char* smcOpen(io_connect_t* conn) { FF_IOOBJECT_AUTO_RELEASE io_object_t device = IOServiceGetMatchingService(MACH_PORT_NULL, IOServiceMatching("AppleSMC")); if (!device) { + FF_DEBUG("IOKit has no AppleSMC service"); return "No SMC device found"; } - if (IOServiceOpen(device, mach_task_self(), 0, conn) != kIOReturnSuccess) { + const IOReturn openStatus = IOServiceOpen(device, mach_task_self(), 0, conn); + if (openStatus != kIOReturnSuccess) { + FF_DEBUG("IOServiceOpen(AppleSMC) failed: IOReturn 0x%08x", (unsigned) openStatus); return "IOServiceOpen() failed"; } @@ -153,6 +160,7 @@ static const char* smcReadValue(io_connect_t conn, const UInt32Char_t key, doubl return error; } if (val.dataSize == 0) { + FF_DEBUG("The SMC key %s reported a data size of 0", key); return "Empty SMC result"; } @@ -173,9 +181,12 @@ static const char* smcReadValue(io_connect_t conn, const UInt32Char_t key, doubl *value = (double) ntohll(*(uint64_t*) (val.bytes)); break; default: + FF_DEBUG("SMC key %s: unsigned type %s has an unsupported size of %u bytes", + key, val.dataType, val.dataSize); return "Unsupported SMC unsigned integer data size"; } } else { + FF_DEBUG("SMC key %s: unsupported unsigned type %s", key, val.dataType); return "Unsupported SMC unsigned data type"; } break; @@ -204,9 +215,13 @@ static const char* smcReadValue(io_connect_t conn, const UInt32Char_t key, doubl } else if (ffStrEquals(val.dataType, "fpe2")) { *value = ntohs(*(uint16_t*) (val.bytes)) / 4.0; } else { + FF_DEBUG("SMC key %s: unsupported fixed point type %s of %u bytes", + key, val.dataType, val.dataSize); return "Unsupported SMC floating point data type"; } } else { + FF_DEBUG("SMC key %s: unsupported floating point type %s of %u bytes", + key, val.dataType, val.dataSize); return "Unsupported SMC floating point data type"; } break; @@ -227,6 +242,8 @@ static const char* smcReadValue(io_connect_t conn, const UInt32Char_t key, doubl *value = (double) ntohll(*(int64_t*) (val.bytes)); break; default: + FF_DEBUG("SMC key %s: signed type %s has an unsupported size of %u bytes", + key, val.dataType, val.dataSize); return "Unsupported SMC signed integer data size"; } } else if (val.dataType[1] == 'p' && val.dataSize == 2) // signed fixed point types @@ -252,9 +269,12 @@ static const char* smcReadValue(io_connect_t conn, const UInt32Char_t key, doubl } else if (ffStrEquals(val.dataType, "spf0")) { *value = (int16_t) ntohs(*(int16_t*) (val.bytes)) / 1.0; } else { + FF_DEBUG("SMC key %s: unsupported signed fixed point type %s of %u bytes", + key, val.dataType, val.dataSize); return "Unsupported SMC signed integer data type"; } } else { + FF_DEBUG("SMC key %s: unsupported signed type %s", key, val.dataType); return "Unsupported SMC signed data type"; } break; @@ -263,11 +283,15 @@ static const char* smcReadValue(io_connect_t conn, const UInt32Char_t key, doubl if (ffStrEquals(val.dataType, "{pwm") && val.dataSize == 2) { *value = (double) ntohs(*(uint16_t*) (val.bytes)) * 100 / 65536.0; } else { + FF_DEBUG("SMC key %s: unsupported special type %s of %u bytes", key, val.dataType, val.dataSize); return "Unsupported SMC special data type"; } break; default: + FF_DEBUG("SMC key %s: unknown data type '%c%c' (%s) of %u bytes", + key, val.dataType[0] ? val.dataType[0] : '?', val.dataType[1] ? val.dataType[1] : '?', + val.dataType, val.dataSize); return "Unsupported SMC data type"; } return nullptr; @@ -300,6 +324,7 @@ const char* ffDetectSmcSpecificTemp(const char* sensor, double* result) { } if (!detectTemp(conn, sensor, result)) { + FF_DEBUG("The SMC sensor %s could not be read, or read a value outside 10..120", sensor); return "Could not read SMC temperature"; } @@ -490,6 +515,7 @@ const char* ffDetectSmcTemps(enum FFTempType type, double* result) { break; } + FF_DEBUG("None of the SMC sensors for temp type %d reported a usable reading", (int) type); if (count == 0) { return "No temperatures detected"; } diff --git a/src/common/impl/dbus.c b/src/common/impl/dbus.c index ca20efb18..15041e079 100644 --- a/src/common/impl/dbus.c +++ b/src/common/impl/dbus.c @@ -2,6 +2,7 @@ #ifdef FF_HAVE_DBUS + #include "common/debug.h" #include "common/thread.h" #include "common/strutil.h" @@ -39,11 +40,13 @@ static const FFDBusLibrary* loadLib(void) { const char* ffDBusLoadData(DBusBusType busType, FFDBusData* data) { data->lib = loadLib(); if (data->lib == nullptr) { + FF_DEBUG("libdbus-1 could not be loaded"); return "Failed to load DBus library"; } data->connection = data->lib->ffdbus_bus_get(busType, nullptr); if (data->connection == nullptr) { + FF_DEBUG("dbus_bus_get(busType=%d) returned no connection", (int) busType); return "Failed to connect to DBus"; } diff --git a/src/common/impl/io_unix.c b/src/common/impl/io_unix.c index 56f9922ef..36cbe53f0 100644 --- a/src/common/impl/io_unix.c +++ b/src/common/impl/io_unix.c @@ -1,5 +1,6 @@ #include "common/io.h" #include "fastfetch.h" +#include "common/debug.h" #include "common/strutil.h" #include "common/time.h" @@ -41,9 +42,11 @@ bool ffWriteFileData(const char* fileName, size_t dataSize, const void* data) { createSubfolders(fileName); fd = open(fileName, openFlagsModes, openFlagsRights); if (fd == -1) { + FF_DEBUG("open(%s) failed after creating the parent folders: %s", fileName, strerror(errno)); return false; } } else { + FF_DEBUG("open(%s) failed: %s", fileName, strerror(errno)); return false; } } @@ -146,16 +149,19 @@ const char* ffGetTerminalResponse(const char* request, int nParams, const char* if (ftty < 0) { ftty = open("/dev/tty", O_RDWR | O_NOCTTY | O_CLOEXEC); if (ftty < 0) { + FF_DEBUG("open(/dev/tty) failed: %s", strerror(errno)); return "open(\"/dev/tty\", O_RDWR | O_NOCTTY | O_CLOEXEC) failed"; } if (tcgetattr(ftty, &oldTerm) == -1) { + FF_DEBUG("tcgetattr(/dev/tty) failed: %s", strerror(errno)); return "tcgetattr(STDIN_FILENO, &oldTerm) failed"; } struct termios newTerm = oldTerm; newTerm.c_lflag &= (tcflag_t) ~(ICANON | ECHO); if (tcsetattr(ftty, TCSAFLUSH, &newTerm) == -1) { + FF_DEBUG("tcsetattr(/dev/tty) failed: %s", strerror(errno)); return "tcsetattr(STDIN_FILENO, TCSAFLUSH, &newTerm)"; } atexit(restoreTerm); @@ -165,7 +171,10 @@ const char* ffGetTerminalResponse(const char* request, int nParams, const char* // Give the terminal some time to respond #ifndef __APPLE__ - if (poll(&(struct pollfd) { .fd = ftty, .events = POLLIN }, 1, FF_IO_TERM_RESP_WAIT_MS) <= 0) { + const int pollResult = poll(&(struct pollfd) { .fd = ftty, .events = POLLIN }, 1, FF_IO_TERM_RESP_WAIT_MS); + if (pollResult <= 0) { + FF_DEBUG("poll(/dev/tty) returned %d after %d ms: %s", + pollResult, FF_IO_TERM_RESP_WAIT_MS, pollResult == 0 ? "timed out" : strerror(errno)); return "poll(/dev/tty) timeout or failed"; } #else @@ -175,7 +184,10 @@ const char* ffGetTerminalResponse(const char* request, int nParams, const char* fd_set rd; FD_ZERO(&rd); FD_SET(ftty, &rd); - if (select(ftty + 1, &rd, nullptr, nullptr, &(struct timeval) { .tv_sec = FF_IO_TERM_RESP_WAIT_MS / 1000, .tv_usec = (FF_IO_TERM_RESP_WAIT_MS % 1000) * 1000 }) <= 0) { + const int selectResult = select(ftty + 1, &rd, nullptr, nullptr, &(struct timeval) { .tv_sec = FF_IO_TERM_RESP_WAIT_MS / 1000, .tv_usec = (FF_IO_TERM_RESP_WAIT_MS % 1000) * 1000 }); + if (selectResult <= 0) { + FF_DEBUG("select(/dev/tty) returned %d after %d ms: %s", + selectResult, FF_IO_TERM_RESP_WAIT_MS, selectResult == 0 ? "timed out" : strerror(errno)); return "select(/dev/tty) timeout or failed"; } } @@ -191,6 +203,8 @@ const char* ffGetTerminalResponse(const char* request, int nParams, const char* ssize_t nRead = read(ftty, buffer + bytesRead, sizeof(buffer) - bytesRead - 1); if (nRead <= 0) { + FF_DEBUG("read(/dev/tty) returned %zd after %zu bytes: %s", + nRead, bytesRead, nRead == 0 ? "the terminal closed the connection" : strerror(errno)); va_end(args); return "read(STDIN_FILENO, buffer, sizeof(buffer) - 1) failed"; } @@ -204,6 +218,7 @@ const char* ffGetTerminalResponse(const char* request, int nParams, const char* va_end(cargs); if (ret <= 0) { + FF_DEBUG("vsscanf(\"%s\") matched %d of %d parameters", buffer, ret, nParams); va_end(args); return "vsscanf(buffer, format, args) failed"; } diff --git a/src/common/impl/jsonconfig.c b/src/common/impl/jsonconfig.c index 336d27212..c0b14e260 100644 --- a/src/common/impl/jsonconfig.c +++ b/src/common/impl/jsonconfig.c @@ -1,5 +1,6 @@ #include "fastfetch.h" #include "common/color.h" +#include "common/debug.h" #include "common/jsonconfig.h" #include "common/printing.h" #include "common/io.h" @@ -87,6 +88,7 @@ const char* ffJsonConfigParseEnum(yyjson_val* val, int* result, FFKeyValuePair p } } + FF_DEBUG("The enum value %d is not one of the accepted integers", intVal); return "Invalid enum integer"; } else if (yyjson_is_str(val)) { const char* strVal = yyjson_get_str(val); @@ -97,8 +99,11 @@ const char* ffJsonConfigParseEnum(yyjson_val* val, int* result, FFKeyValuePair p } } + FF_DEBUG("The enum string \"%s\" is not one of the accepted names", strVal); return "Invalid enum string"; } else { + FF_DEBUG("The enum value is of JSON type %s, not a string or an integer", + yyjson_get_type_desc(val)); return "Invalid enum value type; must be a string or integer"; } } @@ -273,6 +278,7 @@ static const char* printJsonConfig(FFdata* data, bool prepare) { assert(root); if (!yyjson_is_obj(root)) { + FF_DEBUG("The config root is of JSON type %s", yyjson_get_type_desc(root)); return "Invalid JSON config format. Root value must be an object"; } @@ -281,6 +287,7 @@ static const char* printJsonConfig(FFdata* data, bool prepare) { return nullptr; } if (!yyjson_is_arr(modules)) { + FF_DEBUG("'modules' is of JSON type %s", yyjson_get_type_desc(modules)); return "Property 'modules' must be an array of strings or objects"; } @@ -303,6 +310,7 @@ static const char* printJsonConfig(FFdata* data, bool prepare) { yyjson_val* conditions = yyjson_obj_get(module, "condition"); if (conditions) { if (!yyjson_is_obj(conditions)) { + FF_DEBUG("'condition' is of JSON type %s", yyjson_get_type_desc(conditions)); return "Property 'condition' must be an object"; } @@ -329,6 +337,8 @@ static const char* printJsonConfig(FFdata* data, bool prepare) { yyjson_val* previousSucceeded = yyjson_obj_get(conditions, "succeeded"); if (previousSucceeded && !unsafe_yyjson_is_null(previousSucceeded)) { if (!unsafe_yyjson_is_bool(previousSucceeded)) { + FF_DEBUG("'condition.succeeded' is of JSON type %s", + yyjson_get_type_desc(previousSucceeded)); return "Property 'succeeded' in 'condition' must be a boolean"; } gatedOnSucceeded = true; @@ -355,6 +365,7 @@ static const char* printJsonConfig(FFdata* data, bool prepare) { if (gatedOnSucceeded && ffStrEqualsIgnCase(yyjson_get_str(yyjson_obj_get(module, "type")), ffCommandModuleInfo.name)) { yyjson_val* parallel = yyjson_obj_get(module, "parallel"); if (parallel == nullptr || yyjson_get_bool(parallel)) { + FF_DEBUG("The command module at index %zu is gated on 'condition.succeeded' and runs in parallel", idx); return "Module \"command\" cannot be combined with \"condition.succeeded\" while it runs in " "parallel: whether it is printed is only known in the print pass, so it cannot be " "prepared, and the prepared results are matched to modules by position. Set " @@ -371,12 +382,14 @@ static const char* printJsonConfig(FFdata* data, bool prepare) { type = yyjson_get_str(yyjson_obj_get(module, "type")); if (!type) { + FF_DEBUG("The module object at index %zu has no \"type\" key, or it is not a string", idx); return "module object must contain a \"type\" key ( case sensitive )"; } if (yyjson_obj_size(module) == 1) { // contains only Property type module = nullptr; } } else { + FF_DEBUG("The modules entry at index %zu is of JSON type %s", idx, yyjson_get_type_desc(module)); return "modules must be an array of strings or objects"; } diff --git a/src/common/impl/lua.c b/src/common/impl/lua.c index 871bf43b0..6b59ec5fc 100644 --- a/src/common/impl/lua.c +++ b/src/common/impl/lua.c @@ -1,6 +1,7 @@ #if FF_HAVE_LUA #include "common/lua.h" + #include "common/debug.h" #include "common/mallocHelper.h" struct FFLuaData luaData; @@ -141,6 +142,7 @@ static int yyjsonEncode(lua_State* L) { const char* ffLuaLoadState(void) { if (luaData.inited) { if (luaData.L == nullptr) { + FF_DEBUG("The Lua state was already initialised and is gone"); return "Lua library is not available"; } return nullptr; @@ -212,6 +214,7 @@ const char* ffLuaLoadState(void) { lua_State* L = ffluaL_newstate(); if (L == nullptr) { + FF_DEBUG("luaL_newstate() could not allocate an interpreter"); return "luaL_newstate() failed"; } #if LUA_VERSION_NUM >= 505 diff --git a/src/common/impl/path.c b/src/common/impl/path.c index 32e21ca8f..158610207 100644 --- a/src/common/impl/path.c +++ b/src/common/impl/path.c @@ -1,4 +1,5 @@ #include "common/path.h" +#include "common/debug.h" #include "common/io.h" #include "common/arrutil.h" @@ -6,6 +7,7 @@ const char* ffFindExecutableInPath(const char* name, FFstrbuf* result) { char* path = getenv("PATH"); if (!path) { + FF_DEBUG("The PATH environment variable is not set"); return "$PATH not set"; } @@ -50,6 +52,7 @@ const char* ffFindExecutableInPath(const char* name, FFstrbuf* result) { return nullptr; } ffStrbufClear(result); + FF_DEBUG("%s is not executable in any of the %s entries", name, "PATH"); return "Executable not found"; } #else @@ -62,6 +65,7 @@ const char* ffFindExecutableInPath(const char* name, FFstrbuf* result) { char buffer[MAX_PATH + 1]; DWORD length = SearchPathA(nullptr, name, ".exe", sizeof(buffer), buffer, nullptr); if (length == 0) { + FF_DEBUG("SearchPathA(%s) failed: %s", name, ffDebugWin32Error(GetLastError())); ffStrbufClear(result); return "Executable not found"; } diff --git a/src/common/impl/percent.c b/src/common/impl/percent.c index 3ffbf9331..0b8c8407e 100644 --- a/src/common/impl/percent.c +++ b/src/common/impl/percent.c @@ -1,4 +1,5 @@ #include "fastfetch.h" +#include "common/debug.h" #include "common/percent.h" #include "common/color.h" #include "common/option.h" @@ -27,6 +28,8 @@ const char* ffPercentParseTypeJsonConfig(yyjson_val* jsonVal, FFPercentageTypeFl yyjson_arr_foreach (jsonVal, idx, max, item) { const char* flag = yyjson_get_str(item); if (!flag) { + FF_DEBUG("A percent.type array entry is of JSON type %s, not a string", + yyjson_get_type_desc(item)); return "Error: percent.type: invalid flag string"; } if (ffStrEqualsIgnCase(flag, "num")) { @@ -40,6 +43,7 @@ const char* ffPercentParseTypeJsonConfig(yyjson_val* jsonVal, FFPercentageTypeFl } else if (ffStrEqualsIgnCase(flag, "bar-monochrome")) { flags |= FF_PERCENTAGE_TYPE_BAR_MONOCHROME_BIT; } else { + FF_DEBUG("Unknown percent.type flag \"%s\"", flag); return "Error: percent.type: unknown flag string"; } } @@ -48,6 +52,7 @@ const char* ffPercentParseTypeJsonConfig(yyjson_val* jsonVal, FFPercentageTypeFl return nullptr; } + FF_DEBUG("percent.type is of JSON type %s", yyjson_get_type_desc(jsonVal)); return "Error: usage: percent.type must be a number or an array of strings"; } diff --git a/src/common/impl/sysctl.c b/src/common/impl/sysctl.c index 29d4a3afc..1c1136372 100644 --- a/src/common/impl/sysctl.c +++ b/src/common/impl/sysctl.c @@ -1,17 +1,22 @@ #include "common/sysctl.h" +#include "common/debug.h" +#include #include +#include #ifdef __OpenBSD__ const char* ffSysctlGetString(int mib1, int mib2, FFstrbuf* result) { size_t neededLength; if (sysctl((int[]) { mib1, mib2 }, 2, nullptr, &neededLength, nullptr, 0) != 0 || neededLength == 1) { // neededLength is 1 for empty strings, because of the null terminator + FF_DEBUG("sysctl({%d, %d}) length query failed: %s", mib1, mib2, strerror(errno)); return "sysctl() length query failed"; } ffStrbufEnsureFree(result, (uint32_t) neededLength - 1); if (sysctl((int[]) { mib1, mib2 }, 2, result->chars + result->length, &neededLength, nullptr, 0) != 0) { + FF_DEBUG("sysctl({%d, %d}) failed to retrieve %zu bytes: %s", mib1, mib2, neededLength, strerror(errno)); return "sysctl() failed to retrieve string data"; } @@ -62,12 +67,14 @@ int64_t ffSysctlGetInt64(int mib1, int mib2, int64_t defaultValue) { const char* ffSysctlGetString(const char* propName, FFstrbuf* result) { size_t neededLength; if (sysctlbyname(propName, nullptr, &neededLength, nullptr, 0) != 0 || neededLength == 1) { // neededLength is 1 for empty strings, because of the null terminator + FF_DEBUG("sysctlbyname(%s) length query failed: %s", propName, strerror(errno)); return "sysctlbyname() failed"; } ffStrbufEnsureFree(result, (uint32_t) neededLength - 1); if (sysctlbyname(propName, result->chars + result->length, &neededLength, nullptr, 0) != 0) { + FF_DEBUG("sysctlbyname(%s) failed to retrieve %zu bytes: %s", propName, neededLength, strerror(errno)); return "sysctlbyname() failed to retrieve string data"; }