From 081aad75d34a82b77ac894eca3d9836314576fa1 Mon Sep 17 00:00:00 2001 From: Derek Schuff Date: Mon, 8 Sep 2025 22:27:06 +0000 Subject: [PATCH 01/10] update tests --- test/test_other.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/test/test_other.py b/test/test_other.py index ac5bfb01aafa8..98d0477297e0a 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -3143,9 +3143,8 @@ def test_dwarf_sourcemap_names(self): (['-O1', '-g'], True, False, True), (['-O3', '-g'], True, False, True), (['-gsplit-dwarf'], True, False, True), - # TODO: It seems odd that -gsource-map leaves behind a name section. Should it? - (['-gsource-map'], False, True, True), - (['-g1', '-Oz', '-gsource-map'], False, True, True), + (['-gsource-map'], False, True, False), + (['-g1', '-Oz', '-gsource-map'], False, True, False), (['-gsource-map', '-g0'], False, False, False), # --emit-symbol-map should not affect the results (['--emit-symbol-map', '-gsource-map'], False, True, True), @@ -3157,7 +3156,6 @@ def test_dwarf_sourcemap_names(self): (['-g2', '-gsource-map'], False, True, True), (['-gsplit-dwarf', '-gsource-map'], True, True, True), (['-gsource-map', '-sERROR_ON_WASM_CHANGES_AFTER_LINK'], False, True, True), - (['-Oz', '-gsource-map'], False, True, True), ]: print(flags, expect_dwarf, expect_sourcemap, expect_names) self.emcc(test_file(source_file), flags, js_file) @@ -9254,7 +9252,7 @@ def test_binaryen_debug(self): (['-O0', '-gline-tables-only'], False, True, False), (['-O1'], False, True, False), (['-O3'], True, False, False), - (['-Oz', '-gsource-map'], False, True, False), # TODO: fix this (#20462) + (['-Oz', '-gsource-map'], False, False, False), (['-O2'], True, False, False), (['-O2', '-gz'], True, False, False), # -gz means debug compression, it should not enable debugging (['-O2', '-g1'], False, True, False), From d45dbdf03faa6248cb69dc17e491a6b5aaa4142c Mon Sep 17 00:00:00 2001 From: Derek Schuff Date: Tue, 9 Sep 2025 20:35:46 +0000 Subject: [PATCH 02/10] fix namesec --- test/test_other.py | 10 ++++++---- tools/cmdline.py | 7 ++----- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/test/test_other.py b/test/test_other.py index 98d0477297e0a..0423a41151152 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -3144,18 +3144,20 @@ def test_dwarf_sourcemap_names(self): (['-O3', '-g'], True, False, True), (['-gsplit-dwarf'], True, False, True), (['-gsource-map'], False, True, False), + (['-g2', '-gsource-map'], False, True, True), (['-g1', '-Oz', '-gsource-map'], False, True, False), (['-gsource-map', '-g0'], False, False, False), # --emit-symbol-map should not affect the results - (['--emit-symbol-map', '-gsource-map'], False, True, True), + (['--emit-symbol-map', '-gsource-map'], False, True, False), (['--emit-symbol-map'], False, False, False), (['--emit-symbol-map', '-Oz'], False, False, False), (['-sASYNCIFY=1', '-g0'], False, False, False), - (['-sASYNCIFY=1', '-gsource-map'], False, True, True), + (['-sASYNCIFY=1', '-gsource-map'], False, True, False), + (['-sASYNCIFY=1', '-gsource-map', '-g2'], False, True, True), (['-g', '-gsource-map'], True, True, True), (['-g2', '-gsource-map'], False, True, True), (['-gsplit-dwarf', '-gsource-map'], True, True, True), - (['-gsource-map', '-sERROR_ON_WASM_CHANGES_AFTER_LINK'], False, True, True), + (['-gsource-map', '-sERROR_ON_WASM_CHANGES_AFTER_LINK'], False, True, False), ]: print(flags, expect_dwarf, expect_sourcemap, expect_names) self.emcc(test_file(source_file), flags, js_file) @@ -9246,7 +9248,7 @@ def test_binaryen_debug(self): for args, expect_clean_js, expect_whitespace_js, expect_closured in [ (['-O0'], False, True, False), (['-O0', '-g1'], False, True, False), - (['-O0', '-g2'], False, True, False), # in -g2+, we emit -g to asm2wasm so function names are saved + (['-O0', '-g2'], False, True, False), (['-O0', '-g'], False, True, False), (['-O0', '--profiling-funcs'], False, True, False), (['-O0', '-gline-tables-only'], False, True, False), diff --git a/tools/cmdline.py b/tools/cmdline.py index 28621175d8d36..a7b42ce87c311 100644 --- a/tools/cmdline.py +++ b/tools/cmdline.py @@ -394,9 +394,9 @@ def consume_arg_file(): else: settings.SEPARATE_DWARF = True settings.GENERATE_DWARF = 1 + settings.DEBUG_LEVEL = 3 elif requested_level in ['source-map', 'source-map=inline']: settings.GENERATE_SOURCE_MAP = 1 if requested_level == 'source-map' else 2 - settings.EMIT_NAME_SECTION = 1 newargs[i] = '-g' elif requested_level == 'z': # Ignore `-gz`. We don't support debug info compression. @@ -407,10 +407,7 @@ def consume_arg_file(): # clang and make the emscripten code treat it like any other DWARF. settings.GENERATE_DWARF = 1 settings.EMIT_NAME_SECTION = 1 - # In all cases set the emscripten debug level to 3 so that we do not - # strip during link (during compile, this does not make a difference). - # TODO: possibly decouple some of these flags from the final debug level (#20462) - settings.DEBUG_LEVEL = 3 + settings.DEBUG_LEVEL = 3 elif check_flag('-profiling') or check_flag('--profiling'): settings.DEBUG_LEVEL = max(settings.DEBUG_LEVEL, 2) settings.EMIT_NAME_SECTION = 1 From 031edff20f62d2d2f067c5b1889d5e10b2f38ca4 Mon Sep 17 00:00:00 2001 From: Derek Schuff Date: Tue, 9 Sep 2025 22:41:25 +0000 Subject: [PATCH 03/10] fix test --- test/test_other.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_other.py b/test/test_other.py index 0423a41151152..5dae969813be9 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -9254,7 +9254,7 @@ def test_binaryen_debug(self): (['-O0', '-gline-tables-only'], False, True, False), (['-O1'], False, True, False), (['-O3'], True, False, False), - (['-Oz', '-gsource-map'], False, False, False), + (['-Oz', '-gsource-map'], True, False, False), (['-O2'], True, False, False), (['-O2', '-gz'], True, False, False), # -gz means debug compression, it should not enable debugging (['-O2', '-g1'], False, True, False), From 5640b596309146c71742ea66a20c1aa13abc34cb Mon Sep 17 00:00:00 2001 From: Derek Schuff Date: Tue, 9 Sep 2025 22:51:39 +0000 Subject: [PATCH 04/10] add changelog --- ChangeLog.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ChangeLog.md b/ChangeLog.md index 61e4f0f8291e3..a0ed5a5dfed6d 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -20,6 +20,13 @@ See docs/process.md for more on how version tagging works. 4.0.15 (in development) ----------------------- +- The `-gsource-map` flag has been updated to be independent of other types of + debugging effects (in particular it no longer causes the wasm binary to have + a name section, and it no longer suppresses minification of the JS output). + To get the previous behavior, add `-g2` along with `-gsource-map`. + See also the newly updated + [documentation](https://emscripten.org/docs/porting/Debugging.html) which + covers debugging flags and use cases. 4.0.14 - 09/02/25 ----------------- From 3d5720e480d52068f55a51393345cde65573b873 Mon Sep 17 00:00:00 2001 From: Derek Schuff Date: Tue, 9 Sep 2025 22:53:23 +0000 Subject: [PATCH 05/10] add PR link --- ChangeLog.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog.md b/ChangeLog.md index a0ed5a5dfed6d..e4198a8a6dc8a 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -26,7 +26,7 @@ See docs/process.md for more on how version tagging works. To get the previous behavior, add `-g2` along with `-gsource-map`. See also the newly updated [documentation](https://emscripten.org/docs/porting/Debugging.html) which - covers debugging flags and use cases. + covers debugging flags and use cases (#25238). 4.0.14 - 09/02/25 ----------------- From 749191572b215f88efe8f8ec49a85277dba52be5 Mon Sep 17 00:00:00 2001 From: Derek Schuff Date: Wed, 10 Sep 2025 18:58:35 +0000 Subject: [PATCH 06/10] Fix -g2 overriding gource-map when combining link+compile add case to ubsan_full_stack_trace tests --- test/test_core.py | 14 +++++++++----- tools/cmdline.py | 3 ++- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/test/test_core.py b/test/test_core.py index 6e58886318908..c9b544aebf8c0 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -9004,11 +9004,15 @@ def test_sanitize_vptr(self): ]) @parameterized({ - 'g': ('-g', [ + 'g': (['-g'], [ ".cpp:3:12: runtime error: reference binding to null pointer of type 'int'", 'in main', ]), - 'g4': ('-gsource-map', [ + 'g2': (['-g2'], [ + ".cpp:3:12: runtime error: reference binding to null pointer of type 'int'", + 'in main', + ]), + 'g4': (['-gsource-map', '-g2'], [ ".cpp:3:12: runtime error: reference binding to null pointer of type 'int'", 'in main ', '.cpp:3:8', @@ -9016,15 +9020,15 @@ def test_sanitize_vptr(self): }) @no_wasm2js('TODO: sanitizers in wasm2js') @no_esm_integration('sanitizers do not support WASM_ESM_INTEGRATION') - def test_ubsan_full_stack_trace(self, g_flag, expected_output): - if g_flag == '-gsource-map': + def test_ubsan_full_stack_trace(self, g_flags, expected_output): + if '-gsource-map' in g_flags: if self.is_wasm2js(): self.skipTest('wasm2js has no source map support') elif self.get_setting('EVAL_CTORS'): self.skipTest('EVAL_CTORS does not support source maps') create_file('pre.js', 'Module.UBSAN_OPTIONS = "print_stacktrace=1";') - self.cflags += ['-fsanitize=null', g_flag, '--pre-js=pre.js'] + self.cflags += ['-fsanitize=null', '--pre-js=pre.js'] + g_flags self.set_setting('ALLOW_MEMORY_GROWTH') self.do_runf('core/test_ubsan_full_null_ref.cpp', assert_all=True, expected_output=expected_output) diff --git a/tools/cmdline.py b/tools/cmdline.py index a7b42ce87c311..a8e1df4ec8171 100644 --- a/tools/cmdline.py +++ b/tools/cmdline.py @@ -368,7 +368,8 @@ def consume_arg_file(): settings.EMIT_NAME_SECTION = 1 # if we don't need to preserve LLVM debug info, do not keep this flag # for clang - if settings.DEBUG_LEVEL < 3: + if (settings.DEBUG_LEVEL < 3 and not + (settings.GENERATE_SOURCE_MAP or settings.SEPARATE_DWARF)): newargs[i] = '-g0' else: # for 3+, report -g3 to clang as -g4 etc. are not accepted From 04db06b9d80b37089b0d4898778dbe99f578acc4 Mon Sep 17 00:00:00 2001 From: Derek Schuff Date: Wed, 10 Sep 2025 21:42:31 +0000 Subject: [PATCH 07/10] fix more tests using source maps + names --- test/test_browser.py | 2 +- test/test_other.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test_browser.py b/test/test_browser.py index 7b04b20df7bab..65b98d5daa6b4 100644 --- a/test/test_browser.py +++ b/test/test_browser.py @@ -280,7 +280,7 @@ def test_sdl1_es6(self): self.reftest('hello_world_sdl.c', 'htmltest.png', cflags=['-sUSE_SDL', '-lGL', '-sEXPORT_ES6']) def test_emscripten_log(self): - self.btest_exit('test_emscripten_log.cpp', cflags=['-Wno-deprecated-pragma', '-gsource-map']) + self.btest_exit('test_emscripten_log.cpp', cflags=['-Wno-deprecated-pragma', '-gsource-map', '-g2']) @also_with_wasmfs def test_preload_file(self): diff --git a/test/test_other.py b/test/test_other.py index aa1c06b3ee2a5..5dd678b5b3e9d 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -12381,7 +12381,7 @@ def test_lsan_leaks(self, ext, args): def test_lsan_stack_trace(self, ext, regexes): self.do_runf( 'other/test_lsan_leaks.' + ext, - cflags=['-fsanitize=leak', '-gsource-map'], + cflags=['-fsanitize=leak', '-gsource-map', '-g2'], regex=True, assert_all=True, assert_returncode=NON_ZERO, From 488a12e7e3614c429f0f60d481b66538575f3fe0 Mon Sep 17 00:00:00 2001 From: Derek Schuff Date: Thu, 11 Sep 2025 18:41:16 +0000 Subject: [PATCH 08/10] add wasm-metadce to list of tools that support source map updates --- tools/building.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/building.py b/tools/building.py index 3bb40caaa7570..8fee774c0ec93 100644 --- a/tools/building.py +++ b/tools/building.py @@ -1232,7 +1232,7 @@ def run_binaryen_command(tool, infile, outfile=None, args=None, debug=False, std # we must tell binaryen to update it # TODO: all tools should support source maps; wasm-ctor-eval does not atm, # for example - if settings.GENERATE_SOURCE_MAP and outfile and tool in ['wasm-opt', 'wasm-emscripten-finalize']: + if settings.GENERATE_SOURCE_MAP and outfile and tool in ['wasm-opt', 'wasm-emscripten-finalize', 'wasm-metadce']: cmd += [f'--input-source-map={infile}.map'] cmd += [f'--output-source-map={outfile}.map'] shared.print_compiler_stage(cmd) From 963e3ddd51044a68b28dc0a70852722d761b4237 Mon Sep 17 00:00:00 2001 From: Derek Schuff Date: Thu, 11 Sep 2025 20:58:45 +0000 Subject: [PATCH 09/10] move tests from documentation PR --- test/test_other.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/test_other.py b/test/test_other.py index 7c8ed18584c7f..82ff8310fcb9a 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -3159,7 +3159,9 @@ def test_dwarf_sourcemap_names(self): (['-g', '-gsource-map'], True, True, True), (['-g2', '-gsource-map'], False, True, True), (['-gsplit-dwarf', '-gsource-map'], True, True, True), + (['-Oz', '-gsource-map'], False, True, False), (['-gsource-map', '-sERROR_ON_WASM_CHANGES_AFTER_LINK'], False, True, False), + (['-gsource-map', '-Og', '-sERROR_ON_WASM_CHANGES_AFTER_LINK'], False, True, False), ]: print(flags, expect_dwarf, expect_sourcemap, expect_names) self.emcc(test_file(source_file), flags, js_file) @@ -9263,6 +9265,9 @@ def test_binaryen_debug(self): (['-O2', '-g'], False, True, False), (['-O2', '--closure=1'], True, False, True), (['-O2', '--closure=1', '-g1'], True, True, True), + (['-O2', '--minify=0'], False, True, False), + (['-O2', '--profiling-funcs'], True, False, False), + (['-O2', '--profiling'], False, True, False), ]: print(args, expect_clean_js, expect_whitespace_js, expect_closured) delete_file('a.out.wat') From ac9ee93bd44db8cc85e61b67b17fbf6e04761125 Mon Sep 17 00:00:00 2001 From: Derek Schuff Date: Thu, 11 Sep 2025 23:05:59 +0000 Subject: [PATCH 10/10] add extra sanitizer runtime test --- test/test_core.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/test_core.py b/test/test_core.py index e5111a2a1be53..75da87605b46a 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -8978,6 +8978,8 @@ def test_sanitize_vptr(self): "which does not point to an object of type 'R'", ]) + # The sanitizer runtime can symbolize based on dwarf, a name section, a sourcemap, + # or a combination. @parameterized({ 'g': (['-g'], [ ".cpp:3:12: runtime error: reference binding to null pointer of type 'int'", @@ -8987,6 +8989,10 @@ def test_sanitize_vptr(self): ".cpp:3:12: runtime error: reference binding to null pointer of type 'int'", 'in main', ]), + 'gsource_map': (['-gsource-map'], [ + ".cpp:3:12: runtime error: reference binding to null pointer of type 'int'", + '.cpp:3:8', + ]), 'g4': (['-gsource-map', '-g2'], [ ".cpp:3:12: runtime error: reference binding to null pointer of type 'int'", 'in main ',