From 7d442487557de82925f33546ce2ad2b89365c6b5 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Thu, 29 Aug 2024 12:55:22 -0700 Subject: [PATCH] Add emscripten_console_trace and emscripten_dbg_backtrace. NFC These are very useful for debugging. The former simply maps directly to `console.trace`. The latter use `dbg()` so it writes directly to stderr under node (better for multi-threaded apps). --- ChangeLog.md | 4 ++++ src/library.js | 11 +++++++++++ system/include/emscripten/console.h | 4 ++++ system/lib/libc/emscripten_console.c | 14 ++++++++++++++ test/common.py | 4 ++-- test/other/test_console_out.c | 2 ++ test/other/test_console_out.out | 4 ++++ test/test_other.py | 2 +- 8 files changed, 42 insertions(+), 3 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 1b47dfbe91d09..edbba54e2e2e8 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -22,6 +22,10 @@ See docs/process.md for more on how version tagging works. ----------------------- - Added support for WebGL extensions EXT_clip_control, EXT_depth_clamp, EXT_polygon_offset_clamp and WEBGL_polygon_mode (#20841) +- New `emscripten_console_trace` and `emscripten_dbg_backtrace` APIs we were + added to `console.h`. The former simply maps directly to `console.trace`. + The latter use `dbg()` so it writes directly to stderr under node (better for + multi-threaded apps). 3.1.65 - 08/22/24 ----------------- diff --git a/src/library.js b/src/library.js index ebe7a0a67533f..dbea5166843e2 100644 --- a/src/library.js +++ b/src/library.js @@ -2062,6 +2062,10 @@ addToLibrary({ emscripten_dbgn: (str, len) => dbg(UTF8ToString(str, len)), #endif + emscripten_dbg_backtrace: (str) => { + dbg(UTF8ToString(str) + '\n' + new Error().stack); + }, + // Use program_invocation_short_name and program_invocation_name in compiled // programs. This function is for implementing them. _emscripten_get_progname__deps: ['$getExecutableName', '$stringToUTF8'], @@ -2090,6 +2094,13 @@ addToLibrary({ console.error(UTF8ToString(str)); }, + emscripten_console_trace: (str) => { +#if ASSERTIONS + assert(typeof str == 'number'); +#endif + console.trace(UTF8ToString(str)); + }, + emscripten_throw_number: (number) => { throw number; }, diff --git a/system/include/emscripten/console.h b/system/include/emscripten/console.h index c1fb40a640285..ec46b19f773f9 100644 --- a/system/include/emscripten/console.h +++ b/system/include/emscripten/console.h @@ -16,6 +16,7 @@ extern "C" { void emscripten_console_log(const char *utf8String __attribute__((nonnull))); void emscripten_console_warn(const char *utf8String __attribute__((nonnull))); void emscripten_console_error(const char *utf8String __attribute__((nonnull))); +void emscripten_console_trace(const char *utf8String __attribute__((nonnull))); // Write to the out(), err() and dbg() JS functions directly. // These are defined an defined in shell.js and have different behavior compared @@ -27,6 +28,7 @@ void emscripten_console_error(const char *utf8String __attribute__((nonnull))); void emscripten_out(const char *utf8String __attribute__((nonnull))); void emscripten_err(const char *utf8String __attribute__((nonnull))); void emscripten_dbg(const char *utf8String __attribute__((nonnull))); +void emscripten_dbg_backtrace(const char *utf8String __attribute__((nonnull))); // Same as above but only with the length of string specified by the second // argument. This allows for non-NULL-terminated strings to be passed. @@ -43,9 +45,11 @@ void emscripten_dbgn(const char *utf8String __attribute__((nonnull)), size_t len void emscripten_console_logf(const char *format __attribute__((nonnull)), ...) __attribute__((__format__(printf, 1, 2))); void emscripten_console_warnf(const char *format __attribute__((nonnull)), ...) __attribute__((__format__(printf, 1, 2))); void emscripten_console_errorf(const char *format __attribute__((nonnull)), ...)__attribute__((__format__(printf, 1, 2))); +void emscripten_console_tracef(const char *format __attribute__((nonnull)), ...)__attribute__((__format__(printf, 1, 2))); void emscripten_outf(const char *format __attribute__((nonnull)), ...) __attribute__((__format__(printf, 1, 2))); void emscripten_errf(const char *format __attribute__((nonnull)), ...) __attribute__((__format__(printf, 1, 2))); void emscripten_dbgf(const char *format __attribute__((nonnull)), ...) __attribute__((__format__(printf, 1, 2))); +void emscripten_dbg_backtracef(const char *format __attribute__((nonnull)), ...) __attribute__((__format__(printf, 1, 2))); // Legacy/internal names for the above #define _emscripten_outf(format, ...) emscripten_outf(format, ##__VA_ARGS__) diff --git a/system/lib/libc/emscripten_console.c b/system/lib/libc/emscripten_console.c index 618297a112274..1797da36ecaea 100644 --- a/system/lib/libc/emscripten_console.c +++ b/system/lib/libc/emscripten_console.c @@ -41,6 +41,13 @@ void emscripten_console_warnf(const char* fmt, ...) { va_end(ap); } +void emscripten_console_tracef(const char* fmt, ...) { + va_list ap; + va_start(ap, fmt); + vlogf(fmt, ap, &emscripten_console_trace); + va_end(ap); +} + void emscripten_outf(const char* fmt, ...) { va_list ap; va_start(ap, fmt); @@ -62,4 +69,11 @@ void emscripten_dbgf(const char* fmt, ...) { vlogf(fmt, ap, &emscripten_dbg); va_end(ap); } + +void emscripten_dbg_backtracef(const char* fmt, ...) { + va_list ap; + va_start(ap, fmt); + vlogf(fmt, ap, &emscripten_dbg_backtrace); + va_end(ap); +} #endif diff --git a/test/common.py b/test/common.py index ca49b3c45091d..455e8e9798a4d 100644 --- a/test/common.py +++ b/test/common.py @@ -1480,9 +1480,9 @@ def assertContained(self, values, string, additional_info='', regex=False): if regex: if type(values) is str: - self.assertTrue(re.search(values, string), 'Expected regex "%s" to match on:\n%s' % (values, string)) + self.assertTrue(re.search(values, string, re.DOTALL), 'Expected regex "%s" to match on:\n%s' % (values, string)) else: - match_any = any(re.search(o, string) for o in values) + match_any = any(re.search(o, string, re.DOTALL) for o in values) self.assertTrue(match_any, 'Expected at least one of "%s" to match on:\n%s' % (values, string)) return diff --git a/test/other/test_console_out.c b/test/other/test_console_out.c index 4b0ee0f1b7633..aebd138d03072 100644 --- a/test/other/test_console_out.c +++ b/test/other/test_console_out.c @@ -5,11 +5,13 @@ int main(int argc, char** argv) { emscripten_err("this is err"); emscripten_out("this is out"); emscripten_dbg("this is dbg"); + emscripten_dbg_backtrace("this is dbg_backtrace"); // Formatting variants emscripten_errf("this is err: %d", argc); emscripten_outf("this is out: %d", argc + 1); emscripten_dbgf("this is dbg: %d", argc + 2); + emscripten_dbg_backtracef("this is dbg_backtrace: %d", argc + 3); // Length-taking variants emscripten_errn("hello err", 3); diff --git a/test/other/test_console_out.out b/test/other/test_console_out.out index 4da9ce11e41a6..04615b51f01e5 100644 --- a/test/other/test_console_out.out +++ b/test/other/test_console_out.out @@ -1,9 +1,13 @@ this is err this is out this is dbg +this is dbg_backtrace +.* this is err: 1 this is out: 2 this is dbg: 3 +this is dbg_backtrace: 4 +.* hel hell hello diff --git a/test/test_other.py b/test/test_other.py index a525f06806ed2..d3db50a9ef719 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -14701,7 +14701,7 @@ def test_proxy_to_worker(self): @also_with_standalone_wasm() def test_console_out(self): - self.do_other_test('test_console_out.c') + self.do_other_test('test_console_out.c', regex=True) @requires_wasm64 def test_explicit_target(self):