@@ -8631,45 +8631,93 @@ def test(infile, source_map_added_dir=''):
8631
8631
test ('inner/a.cpp' , 'inner' )
8632
8632
8633
8633
def test_emsymbolizer (self ):
8634
- def check_loc_info (address , source , funcs , locs ):
8634
+ def check_dwarf_loc_info (address , funcs , locs ):
8635
8635
out = self .run_process (
8636
- [emsymbolizer , '-tcode' , '-s' , source , 'test_dwarf.wasm' , address ],
8636
+ [emsymbolizer , '-tcode' , '-s' , 'dwarf' , 'test_dwarf.wasm' , address ],
8637
8637
stdout = PIPE ).stdout
8638
8638
for func in funcs :
8639
8639
self .assertIn (func , out )
8640
8640
for loc in locs :
8641
8641
self .assertIn (loc , out )
8642
8642
8643
- # Use hard-coded addresses. This is potentially brittle, but LLVM's
8644
- # O1 output is pretty minimal so hopefully it won't break too much?
8645
- # Another option would be to disassemble the binary to look for certain
8646
- # instructions or code sequences.
8643
+ def check_source_map_loc_info (address , loc ):
8644
+ out = self .run_process (
8645
+ [emsymbolizer , '-tcode' , '-s' , 'sourcemap' , 'test_dwarf.wasm' ,
8646
+ address ],
8647
+ stdout = PIPE ).stdout
8648
+ self .assertIn (loc , out )
8649
+
8650
+ # Runs llvm-objdump to get the address of the first occurrence of the
8651
+ # specified line within the given function. llvm-objdump's output format
8652
+ # example is as follows:
8653
+ # ...
8654
+ # 00000004 <foo>:
8655
+ # ...
8656
+ # 6: 41 00 i32.const 0
8657
+ # ...
8658
+ # The addresses here are the offsets to start of the code section. Returns
8659
+ # the address string in hexadecimal.
8660
+ def get_addr (text ):
8661
+ out = self .run_process ([common .LLVM_OBJDUMP , '-d' , 'test_dwarf.wasm' ],
8662
+ stdout = PIPE ).stdout .strip ()
8663
+ out_lines = out .splitlines ()
8664
+ found = False
8665
+ for line in out_lines :
8666
+ if text in line :
8667
+ offset = line .strip ().split (':' )[0 ]
8668
+ found = True
8669
+ break
8670
+ assert found
8671
+ return '0x' + offset
8672
+
8673
+ # We test two locations within test_dwarf.c:
8674
+ # out_to_js(0); // line 6
8675
+ # __builtin_trap(); // line 13
8647
8676
8648
8677
# 1. Test DWARF + source map together
8649
8678
self .run_process ([EMCC , test_file ('core/test_dwarf.c' ),
8650
8679
'-g' , '-gsource-map' , '-O1' , '-o' , 'test_dwarf.js' ])
8651
- # 0x8 corresponds to out_to_js(0) within foo(), uninlined
8652
- # DWARF info provides function names, but source maps don't
8653
- check_loc_info ('0x8' , 'dwarf' , ['foo' ], ['test_dwarf.c:6:3' ])
8654
- check_loc_info ('0x8' , 'sourcemap' , [], ['test_dwarf.c:6:3' ])
8655
- # 0x1f corresponds to __builtin_trap() within bar(), inlined into main()
8656
- # DWARF info provides inlined info, but source maps don't
8657
- check_loc_info ('0x1f' , 'dwarf' , ['bar' , 'main' ],
8658
- ['test_dwarf.c:13:3' , 'test_dwarf.c:18:3' ])
8659
- check_loc_info ('0x1f' , 'sourcemap' , [], ['test_dwarf.c:13:3' ])
8680
+ # Address of out_to_js(0) within foo(), uninlined
8681
+ out_to_js_call_addr = get_addr ('call\t 0' )
8682
+ # Address of __builtin_trap() within bar(), inlined into main()
8683
+ unreachable_addr = get_addr ('unreachable' )
8684
+
8685
+ # Function name of out_to_js(0) within foo(), uninlined
8686
+ out_to_js_call_func = ['foo' ]
8687
+ # Function names of __builtin_trap() within bar(), inlined into main(). The
8688
+ # first one corresponds to the innermost inlined function.
8689
+ unreachable_func = ['bar' , 'main' ]
8690
+
8691
+ # Source location of out_to_js(0) within foo(), uninlined
8692
+ out_to_js_call_loc = ['test_dwarf.c:6:3' ]
8693
+ # Source locations of __builtin_trap() within bar(), inlined into main().
8694
+ # The first one corresponds to the innermost inlined location.
8695
+ unreachable_loc = ['test_dwarf.c:13:3' , 'test_dwarf.c:18:3' ]
8696
+
8697
+ # For DWARF, we check for the full inlined info for both function names and
8698
+ # source locations. Source maps provide neither function names nor inlined
8699
+ # info. So we only check for the source location of the outermost function.
8700
+ check_dwarf_loc_info (out_to_js_call_addr , out_to_js_call_func ,
8701
+ out_to_js_call_loc )
8702
+ check_source_map_loc_info (out_to_js_call_addr , out_to_js_call_loc [0 ])
8703
+ check_dwarf_loc_info (unreachable_addr , unreachable_func , unreachable_loc )
8704
+ check_source_map_loc_info (unreachable_addr , unreachable_loc [0 ])
8660
8705
8661
8706
# 2. Test source map only
8707
+ # The addresses, function names, and source locations are the same across
8708
+ # the builds because they are relative offsets from the code section, so we
8709
+ # don't need to recompute them
8662
8710
self .run_process ([EMCC , test_file ('core/test_dwarf.c' ),
8663
8711
'-gsource-map' , '-O1' , '-o' , 'test_dwarf.js' ])
8664
- check_loc_info ( '0x8' , 'sourcemap' , [], [ 'test_dwarf.c:6:3' ])
8665
- check_loc_info ( '0x1f' , 'sourcemap' , [], [ 'test_dwarf.c:13:3' ])
8712
+ check_source_map_loc_info ( out_to_js_call_addr , out_to_js_call_loc [ 0 ])
8713
+ check_source_map_loc_info ( unreachable_addr , unreachable_loc [ 0 ])
8666
8714
8667
8715
# 3. Test DWARF only
8668
8716
self .run_process ([EMCC , test_file ('core/test_dwarf.c' ),
8669
8717
'-g' , '-O1' , '-o' , 'test_dwarf.js' ])
8670
- check_loc_info ( '0x8' , 'dwarf' , [ 'foo' ], [ 'test_dwarf.c:6:3' ])
8671
- check_loc_info ( '0x1f' , 'dwarf' , [ 'bar' , 'main' ],
8672
- [ 'test_dwarf.c:13:3' , 'test_dwarf.c:18:3' ] )
8718
+ check_dwarf_loc_info ( out_to_js_call_addr , out_to_js_call_func ,
8719
+ out_to_js_call_loc )
8720
+ check_dwarf_loc_info ( unreachable_addr , unreachable_func , unreachable_loc )
8673
8721
8674
8722
def test_separate_dwarf (self ):
8675
8723
self .run_process ([EMCC , test_file ('hello_world.c' ), '-g' ])
0 commit comments