Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions src/settings_internal.js
Original file line number Diff line number Diff line change
Expand Up @@ -189,10 +189,14 @@ var EXPECT_MAIN = true;
// If true, building against Emscripten's wasm heap memory profiler.
var MEMORYPROFILER = false;

// Set automatically to :
// - 1 when using `-gsource-map`
// - 2 when using `gsource-map=inline` (embed sources content in source map)
var GENERATE_SOURCE_MAP = 0;
// Source map related options. You can specify both like
// -gsource-map=inline,names
// -gsource-map
var SOURCE_MAP_GENERATE = 0;
// -gsource-map=inline
var SOURCE_MAP_EMBED_SOURCE = 0;
// -gsource-map=names
var SOURCE_MAP_GENERATE_NAMES = 0;

var GENERATE_DWARF = false;

Expand Down
16 changes: 12 additions & 4 deletions test/test_other.py
Original file line number Diff line number Diff line change
Expand Up @@ -9626,16 +9626,17 @@ def check_source_map_loc_info(address, func, loc):
out = self.run_process(
[emsymbolizer, '-s', 'sourcemap', 'test_dwarf.wasm', address],
stdout=PIPE).stdout
self.assertIn(func, out)
if func:
self.assertIn(func, out)
self.assertIn(loc, out)

def do_tests(src):
# 1. Test DWARF + source map together
# For DWARF, we check for the full inlined info for both function names and
# source locations. Source maps does not provide inlined info. So we only
# check for the info of the outermost function.
self.run_process([EMCC, test_file(src), '-g', '-gsource-map', '-O1', '-o',
'test_dwarf.js'])
self.run_process([EMCC, test_file(src), '-g', '-gsource-map=names', '-O1',
'-o', 'test_dwarf.js'])
check_dwarf_loc_info(out_to_js_call_addr, out_to_js_call_func,
out_to_js_call_loc)
check_source_map_loc_info(out_to_js_call_addr, out_to_js_call_func[0],
Expand All @@ -9650,13 +9651,20 @@ def do_tests(src):
# The addresses, function names, and source locations are the same across
# the builds because they are relative offsets from the code section, so we
# don't need to recompute them
self.run_process([EMCC, test_file(src), '-gsource-map', '-O1', '-o',
self.run_process([EMCC, test_file(src), '-gsource-map=names', '-O1', '-o',
'test_dwarf.js'])
check_source_map_loc_info(out_to_js_call_addr, out_to_js_call_func[0],
out_to_js_call_loc[0])
check_source_map_loc_info(unreachable_addr, unreachable_func[0],
unreachable_loc[0])

# 2-1. Test source map only with names section turned off
self.run_process([EMCC, test_file(src), '-gsource-map', '-O1', '-o',
'test_dwarf.js'])
check_source_map_loc_info(out_to_js_call_addr, None,
out_to_js_call_loc[0])
check_source_map_loc_info(unreachable_addr, None, unreachable_loc[0])

# 3. Test DWARF only
self.run_process([EMCC, test_file(src), '-g', '-O1', '-o',
'test_dwarf.js'])
Expand Down
8 changes: 5 additions & 3 deletions tools/building.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ def lld_flags_for_executable(external_symbols):
# those things.
if (not settings.GENERATE_DWARF and
not settings.EMIT_SYMBOL_MAP and
not settings.GENERATE_SOURCE_MAP and
not settings.SOURCE_MAP_GENERATE and
not settings.EMIT_NAME_SECTION and
not settings.ASYNCIFY):
cmd.append('--strip-debug')
Expand Down Expand Up @@ -1172,8 +1172,10 @@ def emit_wasm_source_map(wasm_file, map_file, final_wasm):
if settings.SOURCE_MAP_PREFIXES:
sourcemap_cmd += ['--prefix', *settings.SOURCE_MAP_PREFIXES]

if settings.GENERATE_SOURCE_MAP == 2:
if settings.SOURCE_MAP_EMBED_SOURCE:
sourcemap_cmd += ['--sources']
if settings.SOURCE_MAP_GENERATE_NAMES:
sourcemap_cmd += ['--names']

# TODO(sbc): Convert to using library internal API instead of running `main` here
rtn = wasm_sourcemap.main(sourcemap_cmd)
Expand Down Expand Up @@ -1257,7 +1259,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', 'wasm-metadce']:
if settings.SOURCE_MAP_GENERATE 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']
if shared.SKIP_SUBPROCS:
Expand Down
16 changes: 11 additions & 5 deletions tools/cmdline.py
Original file line number Diff line number Diff line change
Expand Up @@ -365,13 +365,13 @@ def consume_arg_file():
if debug_level == 0:
# Set these explicitly so -g0 overrides previous -g on the cmdline
settings.GENERATE_DWARF = 0
settings.GENERATE_SOURCE_MAP = 0
settings.SOURCE_MAP_GENERATE = 0
settings.EMIT_NAME_SECTION = 0
elif debug_level > 1:
settings.EMIT_NAME_SECTION = 1
# if we don't need to preserve LLVM debug info, do not keep this flag
# for clang
if debug_level < 3 and not (settings.GENERATE_SOURCE_MAP or settings.SEPARATE_DWARF):
if debug_level < 3 and not (settings.SOURCE_MAP_GENERATE or settings.SEPARATE_DWARF):
newargs[i] = '-g0'
else:
if debug_level == 3:
Expand All @@ -381,7 +381,7 @@ def consume_arg_file():
# Lower this to -g3, and report a warning.
newargs[i] = '-g3'
diagnostics.warning('deprecated', 'please replace -g4 with -gsource-map')
settings.GENERATE_SOURCE_MAP = 1
settings.SOURCE_MAP_GENERATE = 1
elif debug_level > 4:
exit_with_error("unknown argument: '%s'", arg)
else:
Expand All @@ -401,9 +401,15 @@ def consume_arg_file():
settings.SEPARATE_DWARF = True
settings.GENERATE_DWARF = 1
settings.DEBUG_LEVEL = 3
elif debug_level in ['source-map', 'source-map=inline']:
settings.GENERATE_SOURCE_MAP = 1 if debug_level == 'source-map' else 2
elif debug_level.startswith('source-map'):
settings.SOURCE_MAP_GENERATE = 1
newargs[i] = '-g'
if '=' in debug_level:
source_map_options = debug_level.split('=')[1].split(',')
if 'inline' in source_map_options:
settings.SOURCE_MAP_EMBED_SOURCE = 1
if 'names' in source_map_options:
settings.SOURCE_MAP_GENERATE_NAMES = 1
elif debug_level == 'z':
# Ignore `-gz`. We don't support debug info compression.
pass
Expand Down
4 changes: 2 additions & 2 deletions tools/emscripten.py
Original file line number Diff line number Diff line change
Expand Up @@ -565,7 +565,7 @@ def finalize_wasm(infile, outfile, js_syms):
if infile != outfile:
shutil.copy(infile, outfile)

if settings.GENERATE_SOURCE_MAP:
if settings.SOURCE_MAP_GENERATE:
building.emit_wasm_source_map(infile, outfile + '.map', outfile)
building.save_intermediate(outfile + '.map', 'base_wasm.map')
base_url = settings.SOURCE_MAP_BASE + os.path.basename(outfile) + '.map'
Expand Down Expand Up @@ -601,7 +601,7 @@ def finalize_wasm(infile, outfile, js_syms):

metadata = get_metadata(outfile, outfile, modify_wasm, args)

if settings.GENERATE_SOURCE_MAP:
if settings.SOURCE_MAP_GENERATE:
building.save_intermediate(outfile + '.map', 'post_finalize.map')

expected_exports = set(settings.EXPORTED_FUNCTIONS)
Expand Down
12 changes: 6 additions & 6 deletions tools/link.py
Original file line number Diff line number Diff line change
Expand Up @@ -764,7 +764,7 @@ def setup_sanitizers(options):
if settings.MEMORY64:
exit_with_error('MEMORY64 does not yet work with ASAN')

if settings.GENERATE_SOURCE_MAP:
if settings.SOURCE_MAP_GENERATE:
settings.LOAD_SOURCE_MAP = 1


Expand Down Expand Up @@ -875,9 +875,9 @@ def phase_linker_setup(options, linker_args): # noqa: C901, PLR0912, PLR0915
settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE += ['$addOnInit', '$addOnExit']

# TODO: support source maps with js_transform
if options.js_transform and settings.GENERATE_SOURCE_MAP:
if options.js_transform and settings.SOURCE_MAP_GENERATE:
logger.warning('disabling source maps because a js transform is being done')
settings.GENERATE_SOURCE_MAP = 0
settings.SOURCE_MAP_GENERATE = 0

# options.output_file is the user-specified one, target is what we will generate
if options.output_file:
Expand Down Expand Up @@ -1633,9 +1633,9 @@ def limit_incoming_module_api():
if settings.WASM_BIGINT:
settings.LEGALIZE_JS_FFI = 0

if settings.SINGLE_FILE and settings.GENERATE_SOURCE_MAP:
if settings.SINGLE_FILE and settings.SOURCE_MAP_GENERATE:
diagnostics.warning('emcc', 'SINGLE_FILE disables source map support (which requires a .map file)')
settings.GENERATE_SOURCE_MAP = 0
settings.SOURCE_MAP_GENERATE = 0

if options.use_closure_compiler == 2 and not settings.WASM2JS:
exit_with_error('closure compiler mode 2 assumes the code is asm.js, so not meaningful for wasm')
Expand Down Expand Up @@ -1760,7 +1760,7 @@ def get_full_import_name(name):
diagnostics.warning('experimental', '-sJSPI (ASYNCIFY=2) is still experimental')

if settings.WASM2JS:
if settings.GENERATE_SOURCE_MAP:
if settings.SOURCE_MAP_GENERATE:
exit_with_error('wasm2js does not support source maps yet (debug in wasm for now)')
if settings.MEMORY64:
exit_with_error('wasm2js does not support MEMORY64')
Expand Down
23 changes: 16 additions & 7 deletions tools/wasm-sourcemap.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ def parse_args(args):
parser.add_argument('--dwarfdump', help="path to llvm-dwarfdump executable")
parser.add_argument('--dwarfdump-output', nargs='?', help=argparse.SUPPRESS)
parser.add_argument('--basepath', help='base path for source files, which will be relative to this')
parser.add_argument('--names', action='store_true', help='generate function names in the names field')
return parser.parse_args(args)


Expand Down Expand Up @@ -399,12 +400,17 @@ def read_dwarf_info(wasm, options):
logger.debug('Reading DWARF information from %s' % wasm)
if not os.path.exists(options.dwarfdump):
utils.exit_with_error('llvm-dwarfdump not found: ' + options.dwarfdump)
# We need only three tags in the debug info: DW_TAG_compile_unit for
# source location, and DW_TAG_subprogram and DW_TAG_inlined_subroutine
# for the function ranges.
dwarfdump_cmd = [options.dwarfdump, '-debug-info', '-debug-line', wasm,
'-t', 'DW_TAG_compile_unit', '-t', 'DW_TAG_subprogram',
'-t', 'DW_TAG_inlined_subroutine']
dwarfdump_cmd = [options.dwarfdump, '-debug-info', '-debug-line', wasm]
if options.names:
# We need only three tags in the debug info: DW_TAG_compile_unit for
# source location, and DW_TAG_subprogram and DW_TAG_inlined_subroutine
# for the function ranges.
dwarfdump_cmd += ['-t', 'DW_TAG_compile_unit', '-t', 'DW_TAG_subprogram',
'-t', 'DW_TAG_inlined_subroutine']
else:
# We only need the top-level DW_TAG_compile_unit tags when not generating
# the names field
dwarfdump_cmd += ['--recurse-depth=0']
proc = shared.check_call(dwarfdump_cmd, stdout=shared.PIPE)
output = proc.stdout
else:
Expand Down Expand Up @@ -480,7 +486,10 @@ def read_dwarf_info(wasm, options):
# return entries sorted by the address field
entries = sorted(entries, key=lambda entry: entry['address'])

func_ranges = extract_func_ranges(debug_info)
if options.names:
func_ranges = extract_func_ranges(debug_info)
else:
func_ranges = []
return entries, func_ranges


Expand Down