From 9159153caff99062e2a3cd150dc67ddae7cb6b76 Mon Sep 17 00:00:00 2001 From: Rolel Date: Tue, 31 Dec 2024 12:18:41 +0100 Subject: [PATCH] Segfault are often repeated massively. This adds a repeat_printf function that will not reprint the line but count them if repeated. --- src/lindbergh/hook.c | 104 ++++++++++++++++++++++++++++++++++++++++++- src/lindbergh/hook.h | 1 + 2 files changed, 104 insertions(+), 1 deletion(-) diff --git a/src/lindbergh/hook.c b/src/lindbergh/hook.c index 84e1d9b..492020f 100644 --- a/src/lindbergh/hook.c +++ b/src/lindbergh/hook.c @@ -154,7 +154,7 @@ static void handleSegfault(int signal, siginfo_t *info, void *ptr) break; default: - printf("Warning: Skipping SEGFAULT %X\n", *code); + repeat_printf("Warning: Skipping SEGFAULT %X\n", *code); ctx->uc_mcontext.gregs[REG_EIP]++; // abort(); } @@ -1027,3 +1027,105 @@ char *__strdup(const char *string) } return ___strdup(string); } + + +/** + * @brief Prints formatted text in a way that avoids spamming identical lines. + * + * This function behaves similarly to printf, but tracks the last printed message. + * If the newly formatted string is identical to the last one, the previous console + * line is overwritten and a repetition counter "(xN)" is appended instead of + * printing a new line. + * + * @details + * Usage: + * 1. Call `repeat_printf("Some message");` as you would call printf(...). + * 2. If the next call uses the exact same message, the console line updates + * to "... (x2)", then "... (x3)", etc. + * 3. If the next call uses a different message, the old message is finalized + * (a newline is printed) and the new message is printed on a fresh line. + * 4. Calling `live_printf("")` or `repeat_printf(NULL)` finalizes the current + * message (if any) and resets the internal state. + * + * If the message ends with a newline ('\n'), the cursor is moved up one line + * after printing. This allows consecutive identical lines that end with '\n' + * to be updated in place, though note it may be visually confusing if your + * terminal is at the top line. + * + * @param format A printf-style format string, or NULL. If NULL or an empty + * string results from formatting, the current tracked message + * is finalized (a newline is printed, and the internal state + * is reset). + * @param ... Variadic arguments for the format string. + * + * @return (void) No return value. + */ +void repeat_printf(const char *format, ...) +{ + static char last_msg[256] = {0}; + static u_int repeat_count = 0; + + // If format is NULL, treat it as an empty string to trigger finalization. + if (format == NULL) { + format = ""; + } + + // Construct the new message using vsnprintf (like printf). + char msg[256]; + va_list args; + va_start(args, format); + vsnprintf(msg, sizeof(msg), format, args); + va_end(args); + + // If the constructed message is empty, finalize and reset. + if (msg[0] == '\0') { + if (repeat_count > 0) { + // Finalize the previous message with a newline. + printf("\n"); + fflush(stdout); + } + // Reset tracking variables. + last_msg[0] = '\0'; + repeat_count = 0; + return; + } + + // Check if the new message is the same as the last one. + if (strcmp(last_msg, msg) == 0) { + // Same message => increment counter, overwrite the line. + repeat_count++; + + // If the message ends with new line, we go up one line + size_t len = strlen(msg); + int ends_with_newline = 0; + if (len > 0 && msg[len - 1] == '\n') { + printf("\033[1A"); + ends_with_newline = 1; + msg[len - 1] = '\0'; // Remove the trailing '\n' + } + // Move cursor to the start of the line and clear it. + printf("\r\033[K"); + // Print the message with the updated repeat count if > 1 + if (repeat_count > 1) { + printf("%s (x%d)", msg, repeat_count); + } else { + // If repeat_count == 1, it means the first time for this message + // on this call. (Normally we shouldn't enter here with == 1 though.) + printf("%s", msg); + } + if (ends_with_newline) { + // Print a newline, then move cursor up one line + printf("\n"); + } + fflush(stdout); + } else { + // Track the new message. + strncpy(last_msg, msg, sizeof(last_msg) - 1); + last_msg[sizeof(last_msg) - 1] = '\0'; + repeat_count = 1; + + // Print the new message on a fresh line. + printf("%s", msg); + fflush(stdout); + } +} diff --git a/src/lindbergh/hook.h b/src/lindbergh/hook.h index 903c3dc..8880774 100644 --- a/src/lindbergh/hook.h +++ b/src/lindbergh/hook.h @@ -2,3 +2,4 @@ #include uint32_t get_crc32(const char *s, size_t n); +void repeat_printf(const char *format, ...);