-
Notifications
You must be signed in to change notification settings - Fork 3.5k
Add name section and object symbol table support to emsymbolizer #21367
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
7fd1614
95c8b8f
53571cb
3158e60
420f5a4
3293dc5
2d3a457
1912780
3469517
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,8 +8,10 @@ | |
| # line/column number, potentially including inlining. | ||
| # If the wasm has separate DWARF info, do the above with the side file | ||
| # If there is a source map, we can parse it to get file and line number. | ||
| # If there is an emscripten symbol map, we can parse that to get the symbol name | ||
| # If there is a name section or symbol table, llvm-nm can show the symbol name. | ||
| # If there is an emscripten symbol map, we can use that to get the symbol name | ||
| # If there is a name section or symbol table, llvm-symbolizer can show the | ||
| # symbol name. | ||
| # Separate DWARF and emscripten symbol maps are not supported yet. | ||
|
|
||
| import argparse | ||
| import json | ||
|
|
@@ -50,21 +52,27 @@ def get_codesec_offset(module): | |
|
|
||
|
|
||
| def has_debug_line_section(module): | ||
| for sec in module.sections(): | ||
| if sec.name == ".debug_line": | ||
| return True | ||
| return False | ||
| return module.get_custom_section('.debug_line') is not None | ||
|
|
||
|
|
||
| def has_name_section(module): | ||
| return module.get_custom_section('name') is not None | ||
|
|
||
|
|
||
| def has_linking_section(module): | ||
| return module.get_custom_section('linking') is not None | ||
|
|
||
| def symbolize_address_dwarf(module, address): | ||
| vma_adjust = get_codesec_offset(module) | ||
|
|
||
| def symbolize_address_symbolizer(module, address, is_dwarf=False): | ||
| vma_adjust = get_codesec_offset(module) if is_dwarf else 0 | ||
|
||
| cmd = [LLVM_SYMBOLIZER, '-e', module.filename, f'--adjust-vma={vma_adjust}', | ||
| str(address)] | ||
| out = shared.run_process(cmd, stdout=subprocess.PIPE).stdout.strip() | ||
| out_lines = out.splitlines() | ||
|
|
||
| # Source location regex, e.g., /abc/def.c:3:5 | ||
| SOURCE_LOC_RE = re.compile(r'(.+):(\d+):(\d+)$') | ||
| # llvm-dwarfdump prints two lines per location. The first line contains a | ||
| # llvm-symbolizer prints two lines per location. The first line contains a | ||
| # function name, and the second contains a source location like | ||
| # '/abc/def.c:3:5'. If the function or source info is not available, it will | ||
| # be printed as '??', in which case we store None. If the line and column info | ||
|
|
@@ -210,30 +218,32 @@ def main(args): | |
| with webassembly.Module(args.wasm_file) as module: | ||
| base = 16 if args.address.lower().startswith('0x') else 10 | ||
| address = int(args.address, base) | ||
| symbolized = 0 | ||
|
|
||
| if args.addrtype == 'code': | ||
| address += get_codesec_offset(module) | ||
|
|
||
| if ((has_debug_line_section(module) and not args.source) or | ||
| 'dwarf' in args.source): | ||
| symbolize_address_dwarf(module, address) | ||
| symbolized += 1 | ||
|
|
||
| if ((get_sourceMappingURL_section(module) and not args.source) or | ||
| 'sourcemap' in args.source): | ||
| 'dwarf' in args.source): | ||
| symbolize_address_symbolizer(module, address, is_dwarf=True) | ||
| elif ((get_sourceMappingURL_section(module) and not args.source) or | ||
| 'sourcemap' in args.source): | ||
| symbolize_address_sourcemap(module, address, args.file) | ||
| symbolized += 1 | ||
|
|
||
| if not symbolized: | ||
| elif ((has_name_section(module) and not args.source) or | ||
| 'names' in args.source): | ||
| symbolize_address_symbolizer(module, address, is_dwarf=False) | ||
| elif ((has_linking_section(module) and not args.source) or | ||
| 'symtab' in args.source): | ||
| symbolize_address_symbolizer(module, address, is_dwarf=False) | ||
| else: | ||
| raise Error('No .debug_line or sourceMappingURL section found in ' | ||
| f'{module.filename}.' | ||
| " I don't know how to symbolize this file yet") | ||
|
|
||
|
|
||
| def get_args(): | ||
| parser = argparse.ArgumentParser() | ||
| parser.add_argument('-s', '--source', choices=['dwarf', 'sourcemap'], | ||
| parser.add_argument('-s', '--source', choices=['dwarf', 'sourcemap', | ||
| 'names', 'symtab'], | ||
| help='Force debug info source type', default=()) | ||
| parser.add_argument('-f', '--file', action='store', | ||
| help='Force debug info source file') | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -9753,6 +9753,12 @@ def check_source_map_loc_info(address, loc): | |||||
| stdout=PIPE).stdout | ||||||
| self.assertIn(loc, out) | ||||||
|
|
||||||
| def check_func_info(address, func): | ||||||
|
||||||
| out = self.run_process( | ||||||
| [emsymbolizer, 'test_dwarf.wasm', address], stdout=PIPE).stdout | ||||||
| print(out) | ||||||
| self.assertIn(func, out) | ||||||
|
|
||||||
| # Runs llvm-objdump to get the address of the first occurrence of the | ||||||
| # specified line within the given function. llvm-objdump's output format | ||||||
| # example is as follows: | ||||||
|
|
@@ -9825,6 +9831,24 @@ def get_addr(text): | |||||
| out_to_js_call_loc) | ||||||
| check_dwarf_loc_info(unreachable_addr, unreachable_func, unreachable_loc) | ||||||
|
|
||||||
| # 4. Test name section only | ||||||
| self.run_process([emstrip, '--strip-debug', 'test_dwarf.wasm']) | ||||||
| with webassembly.Module('test_dwarf.wasm') as wasm: | ||||||
| self.assertTrue(wasm.has_name_section()) | ||||||
| self.assertIsNone(wasm.get_custom_section('.debug_info')) | ||||||
| check_func_info(out_to_js_call_addr, out_to_js_call_func[0]) | ||||||
| # The name section will not reflect bar being inlined into main | ||||||
|
||||||
| # The name section will not reflect bar being inlined into main | |
| # The name section will reflect bar being inlined into main |
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess this was intended to mean that DWARF has the inlining info, and shows bar, but name section doesn't I made it more claer.
Uh oh!
There was an error while loading. Please reload this page.