190ac295eSAlex Crichton use super::AddressTransform;
287c33c29SAlex Crichton use super::expression::{CompiledExpression, FunctionFrameInfo};
3af476a51SSingleAccretion use super::utils::append_vmctx_info;
4af476a51SSingleAccretion use crate::debug::Compilation;
5a96845c3SAlex Crichton use crate::translate::get_vmctx_value_label;
687c33c29SAlex Crichton use cranelift_codegen::isa::TargetIsa;
79ce3ffe1SAlex Crichton use gimli::LineEncoding;
890ac295eSAlex Crichton use gimli::write;
987c33c29SAlex Crichton use std::collections::{HashMap, HashSet};
1087c33c29SAlex Crichton use std::path::PathBuf;
1187c33c29SAlex Crichton use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
12c7cab275SNick Fitzgerald use wasmtime_environ::error::{Context, Error};
1387c33c29SAlex Crichton use wasmtime_environ::{
14dd8c48b3SAlex Crichton     DebugInfoData, EntityRef, FunctionMetadata, PrimaryMap, StaticModuleIndex, WasmFileInfo,
15496237c2SNick Fitzgerald     WasmValType,
1687c33c29SAlex Crichton };
1787c33c29SAlex Crichton 
1887c33c29SAlex Crichton const PRODUCER_NAME: &str = "wasmtime";
1987c33c29SAlex Crichton 
2087c33c29SAlex Crichton macro_rules! assert_dwarf_str {
2187c33c29SAlex Crichton     ($s:expr) => {{
2287c33c29SAlex Crichton         let s = $s;
2387c33c29SAlex Crichton         if cfg!(debug_assertions) {
2487c33c29SAlex Crichton             // Perform check the same way as gimli does it.
2587c33c29SAlex Crichton             let bytes: Vec<u8> = s.clone().into();
2687c33c29SAlex Crichton             debug_assert!(!bytes.contains(&0), "DWARF string shall not have NULL byte");
2787c33c29SAlex Crichton         }
2887c33c29SAlex Crichton         s
2987c33c29SAlex Crichton     }};
3087c33c29SAlex Crichton }
3187c33c29SAlex Crichton 
generate_line_info( addr_tr: &PrimaryMap<StaticModuleIndex, AddressTransform>, translated: &HashSet<usize>, out_encoding: gimli::Encoding, w: &WasmFileInfo, comp_dir_id: write::StringId, name_id: write::StringId, name: &str, ) -> Result<(write::LineProgram, write::FileId), Error>3287c33c29SAlex Crichton fn generate_line_info(
33dd8c48b3SAlex Crichton     addr_tr: &PrimaryMap<StaticModuleIndex, AddressTransform>,
34dd8c48b3SAlex Crichton     translated: &HashSet<usize>,
3587c33c29SAlex Crichton     out_encoding: gimli::Encoding,
3687c33c29SAlex Crichton     w: &WasmFileInfo,
3787c33c29SAlex Crichton     comp_dir_id: write::StringId,
3887c33c29SAlex Crichton     name_id: write::StringId,
3987c33c29SAlex Crichton     name: &str,
407cd4f630SPhilip Craig ) -> Result<(write::LineProgram, write::FileId), Error> {
4187c33c29SAlex Crichton     let out_comp_dir = write::LineString::StringRef(comp_dir_id);
4287c33c29SAlex Crichton     let out_comp_name = write::LineString::StringRef(name_id);
4387c33c29SAlex Crichton 
4487c33c29SAlex Crichton     let line_encoding = LineEncoding::default();
4587c33c29SAlex Crichton 
4687c33c29SAlex Crichton     let mut out_program = write::LineProgram::new(
4787c33c29SAlex Crichton         out_encoding,
4887c33c29SAlex Crichton         line_encoding,
4987c33c29SAlex Crichton         out_comp_dir,
5078d5940fSAlex Crichton         None,
5187c33c29SAlex Crichton         out_comp_name,
5287c33c29SAlex Crichton         None,
5387c33c29SAlex Crichton     );
5487c33c29SAlex Crichton 
5587c33c29SAlex Crichton     let file_index = out_program.add_file(
5687c33c29SAlex Crichton         write::LineString::String(name.as_bytes().to_vec()),
5787c33c29SAlex Crichton         out_program.default_directory(),
5887c33c29SAlex Crichton         None,
5987c33c29SAlex Crichton     );
6087c33c29SAlex Crichton 
61dd8c48b3SAlex Crichton     let maps = addr_tr.iter().flat_map(|(_, transform)| {
62dd8c48b3SAlex Crichton         transform.map().iter().filter_map(|(_, map)| {
63dd8c48b3SAlex Crichton             if translated.contains(&map.symbol) {
64dd8c48b3SAlex Crichton                 None
65dd8c48b3SAlex Crichton             } else {
66dd8c48b3SAlex Crichton                 Some((map.symbol, map))
6787c33c29SAlex Crichton             }
68dd8c48b3SAlex Crichton         })
69dd8c48b3SAlex Crichton     });
7087c33c29SAlex Crichton 
71dd8c48b3SAlex Crichton     for (symbol, map) in maps {
7287c33c29SAlex Crichton         let base_addr = map.offset;
7343db4612SSingleAccretion         out_program.begin_sequence(Some(write::Address::Symbol {
7443db4612SSingleAccretion             symbol,
7543db4612SSingleAccretion             addend: base_addr as i64,
7643db4612SSingleAccretion         }));
7743db4612SSingleAccretion 
7843db4612SSingleAccretion         // Always emit a row for offset zero - debuggers expect this.
7943db4612SSingleAccretion         out_program.row().address_offset = 0;
8043db4612SSingleAccretion         out_program.row().file = file_index;
8143db4612SSingleAccretion         out_program.row().line = 0; // Special line number for non-user code.
8243db4612SSingleAccretion         out_program.row().discriminator = 1;
8343db4612SSingleAccretion         out_program.row().is_statement = true;
8443db4612SSingleAccretion         out_program.generate_row();
8543db4612SSingleAccretion 
8643db4612SSingleAccretion         let mut is_prologue_end = true;
8787c33c29SAlex Crichton         for addr_map in map.addresses.iter() {
8887c33c29SAlex Crichton             let address_offset = (addr_map.generated - base_addr) as u64;
8987c33c29SAlex Crichton             out_program.row().address_offset = address_offset;
905856590fSAlex Crichton             let wasm_offset = w.code_section_offset + addr_map.wasm;
9187c33c29SAlex Crichton             out_program.row().line = wasm_offset;
9287c33c29SAlex Crichton             out_program.row().discriminator = 1;
9343db4612SSingleAccretion             out_program.row().prologue_end = is_prologue_end;
9487c33c29SAlex Crichton             out_program.generate_row();
9543db4612SSingleAccretion 
9643db4612SSingleAccretion             is_prologue_end = false;
9787c33c29SAlex Crichton         }
9843db4612SSingleAccretion         let end_addr = (base_addr + map.len - 1) as u64;
9987c33c29SAlex Crichton         out_program.end_sequence(end_addr);
10087c33c29SAlex Crichton     }
10187c33c29SAlex Crichton 
1027cd4f630SPhilip Craig     Ok((out_program, file_index))
10387c33c29SAlex Crichton }
10487c33c29SAlex Crichton 
check_invalid_chars_in_name(s: &str) -> Option<&str>10587c33c29SAlex Crichton fn check_invalid_chars_in_name(s: &str) -> Option<&str> {
10690ac295eSAlex Crichton     if s.contains('\x00') { None } else { Some(s) }
10787c33c29SAlex Crichton }
10887c33c29SAlex Crichton 
autogenerate_dwarf_wasm_path(di: &DebugInfoData) -> PathBuf10987c33c29SAlex Crichton fn autogenerate_dwarf_wasm_path(di: &DebugInfoData) -> PathBuf {
11087c33c29SAlex Crichton     static NEXT_ID: AtomicUsize = AtomicUsize::new(0);
11187c33c29SAlex Crichton     let module_name = di
11287c33c29SAlex Crichton         .name_section
11387c33c29SAlex Crichton         .module_name
11487c33c29SAlex Crichton         .and_then(check_invalid_chars_in_name)
11587c33c29SAlex Crichton         .map(|s| s.to_string())
1167cd4f630SPhilip Craig         .unwrap_or_else(|| format!("<gen-{}>.wasm", NEXT_ID.fetch_add(1, SeqCst)));
1177cd4f630SPhilip Craig     let path = format!("/<wasm-module>/{module_name}");
11887c33c29SAlex Crichton     PathBuf::from(path)
11987c33c29SAlex Crichton }
12087c33c29SAlex Crichton 
12187c33c29SAlex Crichton struct WasmTypesDieRefs {
12287c33c29SAlex Crichton     i32: write::UnitEntryId,
12387c33c29SAlex Crichton     i64: write::UnitEntryId,
12487c33c29SAlex Crichton     f32: write::UnitEntryId,
12587c33c29SAlex Crichton     f64: write::UnitEntryId,
12687c33c29SAlex Crichton }
12787c33c29SAlex Crichton 
add_wasm_types( unit: &mut write::Unit, root_id: write::UnitEntryId, out_strings: &mut write::StringTable, ) -> WasmTypesDieRefs12887c33c29SAlex Crichton fn add_wasm_types(
12987c33c29SAlex Crichton     unit: &mut write::Unit,
13087c33c29SAlex Crichton     root_id: write::UnitEntryId,
13187c33c29SAlex Crichton     out_strings: &mut write::StringTable,
13287c33c29SAlex Crichton ) -> WasmTypesDieRefs {
13387c33c29SAlex Crichton     macro_rules! def_type {
13487c33c29SAlex Crichton         ($id:literal, $size:literal, $enc:path) => {{
13587c33c29SAlex Crichton             let die_id = unit.add(root_id, gimli::DW_TAG_base_type);
13687c33c29SAlex Crichton             let die = unit.get_mut(die_id);
13787c33c29SAlex Crichton             die.set(
13887c33c29SAlex Crichton                 gimli::DW_AT_name,
13987c33c29SAlex Crichton                 write::AttributeValue::StringRef(out_strings.add($id)),
14087c33c29SAlex Crichton             );
14187c33c29SAlex Crichton             die.set(gimli::DW_AT_byte_size, write::AttributeValue::Data1($size));
14287c33c29SAlex Crichton             die.set(gimli::DW_AT_encoding, write::AttributeValue::Encoding($enc));
14387c33c29SAlex Crichton             die_id
14487c33c29SAlex Crichton         }};
14587c33c29SAlex Crichton     }
14687c33c29SAlex Crichton 
14787c33c29SAlex Crichton     let i32_die_id = def_type!("i32", 4, gimli::DW_ATE_signed);
14887c33c29SAlex Crichton     let i64_die_id = def_type!("i64", 8, gimli::DW_ATE_signed);
14987c33c29SAlex Crichton     let f32_die_id = def_type!("f32", 4, gimli::DW_ATE_float);
15087c33c29SAlex Crichton     let f64_die_id = def_type!("f64", 8, gimli::DW_ATE_float);
15187c33c29SAlex Crichton 
15287c33c29SAlex Crichton     WasmTypesDieRefs {
15387c33c29SAlex Crichton         i32: i32_die_id,
15487c33c29SAlex Crichton         i64: i64_die_id,
15587c33c29SAlex Crichton         f32: f32_die_id,
15687c33c29SAlex Crichton         f64: f64_die_id,
15787c33c29SAlex Crichton     }
15887c33c29SAlex Crichton }
15987c33c29SAlex Crichton 
resolve_var_type( index: usize, wasm_types: &WasmTypesDieRefs, func_meta: &FunctionMetadata, ) -> Option<(write::UnitEntryId, bool)>16087c33c29SAlex Crichton fn resolve_var_type(
16187c33c29SAlex Crichton     index: usize,
16287c33c29SAlex Crichton     wasm_types: &WasmTypesDieRefs,
16387c33c29SAlex Crichton     func_meta: &FunctionMetadata,
16487c33c29SAlex Crichton ) -> Option<(write::UnitEntryId, bool)> {
16587c33c29SAlex Crichton     let (ty, is_param) = if index < func_meta.params.len() {
16687c33c29SAlex Crichton         (func_meta.params[index], true)
16787c33c29SAlex Crichton     } else {
16887c33c29SAlex Crichton         let mut i = (index - func_meta.params.len()) as u32;
16987c33c29SAlex Crichton         let mut j = 0;
17087c33c29SAlex Crichton         while j < func_meta.locals.len() && i >= func_meta.locals[j].0 {
17187c33c29SAlex Crichton             i -= func_meta.locals[j].0;
17287c33c29SAlex Crichton             j += 1;
17387c33c29SAlex Crichton         }
17487c33c29SAlex Crichton         if j >= func_meta.locals.len() {
17587c33c29SAlex Crichton             // Ignore the var index out of bound.
17687c33c29SAlex Crichton             return None;
17787c33c29SAlex Crichton         }
17887c33c29SAlex Crichton         (func_meta.locals[j].1, false)
17987c33c29SAlex Crichton     };
18087c33c29SAlex Crichton     let type_die_id = match ty {
181496237c2SNick Fitzgerald         WasmValType::I32 => wasm_types.i32,
182496237c2SNick Fitzgerald         WasmValType::I64 => wasm_types.i64,
183496237c2SNick Fitzgerald         WasmValType::F32 => wasm_types.f32,
184496237c2SNick Fitzgerald         WasmValType::F64 => wasm_types.f64,
18587c33c29SAlex Crichton         _ => {
18687c33c29SAlex Crichton             // Ignore unsupported types.
18787c33c29SAlex Crichton             return None;
18887c33c29SAlex Crichton         }
18987c33c29SAlex Crichton     };
19087c33c29SAlex Crichton     Some((type_die_id, is_param))
19187c33c29SAlex Crichton }
19287c33c29SAlex Crichton 
generate_vars( unit: &mut write::Unit, die_id: write::UnitEntryId, addr_tr: &AddressTransform, frame_info: &FunctionFrameInfo, scope_ranges: &[(u64, u64)], vmctx_ptr_die_ref: write::DebugInfoRef, wasm_types: &WasmTypesDieRefs, func_meta: &FunctionMetadata, locals_names: Option<&HashMap<u32, &str>>, out_strings: &mut write::StringTable, isa: &dyn TargetIsa, ) -> Result<(), Error>19387c33c29SAlex Crichton fn generate_vars(
19487c33c29SAlex Crichton     unit: &mut write::Unit,
19587c33c29SAlex Crichton     die_id: write::UnitEntryId,
19687c33c29SAlex Crichton     addr_tr: &AddressTransform,
19787c33c29SAlex Crichton     frame_info: &FunctionFrameInfo,
19887c33c29SAlex Crichton     scope_ranges: &[(u64, u64)],
199*7ee620a5SPhilip Craig     vmctx_ptr_die_ref: write::DebugInfoRef,
20087c33c29SAlex Crichton     wasm_types: &WasmTypesDieRefs,
20187c33c29SAlex Crichton     func_meta: &FunctionMetadata,
20287c33c29SAlex Crichton     locals_names: Option<&HashMap<u32, &str>>,
20387c33c29SAlex Crichton     out_strings: &mut write::StringTable,
20487c33c29SAlex Crichton     isa: &dyn TargetIsa,
20587c33c29SAlex Crichton ) -> Result<(), Error> {
20687c33c29SAlex Crichton     let vmctx_label = get_vmctx_value_label();
20787c33c29SAlex Crichton 
2080e9121daSFrankReh     // Normalize order of ValueLabelsRanges keys to have reproducible results.
20987c33c29SAlex Crichton     let mut vars = frame_info.value_ranges.keys().collect::<Vec<_>>();
21087c33c29SAlex Crichton     vars.sort_by(|a, b| a.index().cmp(&b.index()));
21187c33c29SAlex Crichton 
21287c33c29SAlex Crichton     for label in vars {
21387c33c29SAlex Crichton         if label.index() == vmctx_label.index() {
21487c33c29SAlex Crichton             append_vmctx_info(
21587c33c29SAlex Crichton                 unit,
21687c33c29SAlex Crichton                 die_id,
217af476a51SSingleAccretion                 vmctx_ptr_die_ref,
21887c33c29SAlex Crichton                 addr_tr,
21987c33c29SAlex Crichton                 Some(frame_info),
22087c33c29SAlex Crichton                 scope_ranges,
22187c33c29SAlex Crichton                 out_strings,
22287c33c29SAlex Crichton                 isa,
22387c33c29SAlex Crichton             )?;
22487c33c29SAlex Crichton         } else {
22587c33c29SAlex Crichton             let var_index = label.index();
22687c33c29SAlex Crichton             let (type_die_id, is_param) =
22787c33c29SAlex Crichton                 if let Some(result) = resolve_var_type(var_index, wasm_types, func_meta) {
22887c33c29SAlex Crichton                     result
22987c33c29SAlex Crichton                 } else {
23087c33c29SAlex Crichton                     // Skipping if type of local cannot be detected.
23187c33c29SAlex Crichton                     continue;
23287c33c29SAlex Crichton                 };
23387c33c29SAlex Crichton 
23487c33c29SAlex Crichton             let loc_list_id = {
23587c33c29SAlex Crichton                 let locs = CompiledExpression::from_label(*label)
23687c33c29SAlex Crichton                     .build_with_locals(scope_ranges, addr_tr, Some(frame_info), isa)
237d2c9d2a2SSingleAccretion                     .expressions
23887c33c29SAlex Crichton                     .map(|i| {
23987c33c29SAlex Crichton                         i.map(|(begin, length, data)| write::Location::StartLength {
24087c33c29SAlex Crichton                             begin,
24187c33c29SAlex Crichton                             length,
24287c33c29SAlex Crichton                             data,
24387c33c29SAlex Crichton                         })
24487c33c29SAlex Crichton                     })
24587c33c29SAlex Crichton                     .collect::<Result<Vec<_>, _>>()?;
24687c33c29SAlex Crichton                 unit.locations.add(write::LocationList(locs))
24787c33c29SAlex Crichton             };
24887c33c29SAlex Crichton 
24987c33c29SAlex Crichton             let var_id = unit.add(
25087c33c29SAlex Crichton                 die_id,
25187c33c29SAlex Crichton                 if is_param {
25287c33c29SAlex Crichton                     gimli::DW_TAG_formal_parameter
25387c33c29SAlex Crichton                 } else {
25487c33c29SAlex Crichton                     gimli::DW_TAG_variable
25587c33c29SAlex Crichton                 },
25687c33c29SAlex Crichton             );
25787c33c29SAlex Crichton             let var = unit.get_mut(var_id);
25887c33c29SAlex Crichton 
25987c33c29SAlex Crichton             let name_id = match locals_names
26087c33c29SAlex Crichton                 .and_then(|m| m.get(&(var_index as u32)))
26187c33c29SAlex Crichton                 .and_then(|s| check_invalid_chars_in_name(s))
26287c33c29SAlex Crichton             {
26387c33c29SAlex Crichton                 Some(n) => out_strings.add(assert_dwarf_str!(n)),
264a0442ea0SHamir Mahal                 None => out_strings.add(format!("var{var_index}")),
26587c33c29SAlex Crichton             };
26687c33c29SAlex Crichton 
26787c33c29SAlex Crichton             var.set(gimli::DW_AT_name, write::AttributeValue::StringRef(name_id));
26887c33c29SAlex Crichton             var.set(
26987c33c29SAlex Crichton                 gimli::DW_AT_type,
27087c33c29SAlex Crichton                 write::AttributeValue::UnitRef(type_die_id),
27187c33c29SAlex Crichton             );
27287c33c29SAlex Crichton             var.set(
27387c33c29SAlex Crichton                 gimli::DW_AT_location,
27487c33c29SAlex Crichton                 write::AttributeValue::LocationListRef(loc_list_id),
27587c33c29SAlex Crichton             );
27687c33c29SAlex Crichton         }
27787c33c29SAlex Crichton     }
27887c33c29SAlex Crichton     Ok(())
27987c33c29SAlex Crichton }
28087c33c29SAlex Crichton 
check_invalid_chars_in_path(path: PathBuf) -> Option<PathBuf>28187c33c29SAlex Crichton fn check_invalid_chars_in_path(path: PathBuf) -> Option<PathBuf> {
28287c33c29SAlex Crichton     path.clone()
28387c33c29SAlex Crichton         .to_str()
28487c33c29SAlex Crichton         .and_then(move |s| if s.contains('\x00') { None } else { Some(path) })
28587c33c29SAlex Crichton }
28687c33c29SAlex Crichton 
287af476a51SSingleAccretion /// Generate "simulated" native DWARF for functions lacking WASM-level DWARF.
generate_simulated_dwarf( compilation: &mut Compilation<'_>, addr_tr: &PrimaryMap<StaticModuleIndex, AddressTransform>, translated: &HashSet<usize>, out_encoding: gimli::Encoding, vmctx_ptr_die_refs: &PrimaryMap<StaticModuleIndex, write::DebugInfoRef>, out_units: &mut write::UnitTable, out_strings: &mut write::StringTable, isa: &dyn TargetIsa, ) -> Result<(), Error>28887c33c29SAlex Crichton pub fn generate_simulated_dwarf(
289dd8c48b3SAlex Crichton     compilation: &mut Compilation<'_>,
290dd8c48b3SAlex Crichton     addr_tr: &PrimaryMap<StaticModuleIndex, AddressTransform>,
291dd8c48b3SAlex Crichton     translated: &HashSet<usize>,
29287c33c29SAlex Crichton     out_encoding: gimli::Encoding,
293*7ee620a5SPhilip Craig     vmctx_ptr_die_refs: &PrimaryMap<StaticModuleIndex, write::DebugInfoRef>,
29487c33c29SAlex Crichton     out_units: &mut write::UnitTable,
29587c33c29SAlex Crichton     out_strings: &mut write::StringTable,
29687c33c29SAlex Crichton     isa: &dyn TargetIsa,
29787c33c29SAlex Crichton ) -> Result<(), Error> {
298dd8c48b3SAlex Crichton     let (wasm_file, path) = {
299dd8c48b3SAlex Crichton         let di = &compilation.translations.iter().next().unwrap().1.debuginfo;
30087c33c29SAlex Crichton         let path = di
30187c33c29SAlex Crichton             .wasm_file
30287c33c29SAlex Crichton             .path
30387c33c29SAlex Crichton             .to_owned()
30487c33c29SAlex Crichton             .and_then(check_invalid_chars_in_path)
30587c33c29SAlex Crichton             .unwrap_or_else(|| autogenerate_dwarf_wasm_path(di));
306dd8c48b3SAlex Crichton         (&di.wasm_file, path)
307dd8c48b3SAlex Crichton     };
30887c33c29SAlex Crichton 
3097cd4f630SPhilip Craig     let (unit, root_id, file_id) = {
31090ac295eSAlex Crichton         let comp_dir_id = out_strings.add(assert_dwarf_str!(
31190ac295eSAlex Crichton             path.parent()
31287c33c29SAlex Crichton                 .context("path dir")?
31387c33c29SAlex Crichton                 .to_str()
31490ac295eSAlex Crichton                 .context("path dir encoding")?
31590ac295eSAlex Crichton         ));
31687c33c29SAlex Crichton         let name = path
31787c33c29SAlex Crichton             .file_name()
31887c33c29SAlex Crichton             .context("path name")?
31987c33c29SAlex Crichton             .to_str()
32087c33c29SAlex Crichton             .context("path name encoding")?;
32187c33c29SAlex Crichton         let name_id = out_strings.add(assert_dwarf_str!(name));
32287c33c29SAlex Crichton 
3237cd4f630SPhilip Craig         let (out_program, file_id) = generate_line_info(
32487c33c29SAlex Crichton             addr_tr,
32587c33c29SAlex Crichton             translated,
32687c33c29SAlex Crichton             out_encoding,
327dd8c48b3SAlex Crichton             wasm_file,
32887c33c29SAlex Crichton             comp_dir_id,
32987c33c29SAlex Crichton             name_id,
33087c33c29SAlex Crichton             name,
33187c33c29SAlex Crichton         )?;
33287c33c29SAlex Crichton 
33387c33c29SAlex Crichton         let unit_id = out_units.add(write::Unit::new(out_encoding, out_program));
33487c33c29SAlex Crichton         let unit = out_units.get_mut(unit_id);
33587c33c29SAlex Crichton 
33687c33c29SAlex Crichton         let root_id = unit.root();
33787c33c29SAlex Crichton         let root = unit.get_mut(root_id);
33887c33c29SAlex Crichton 
33987c33c29SAlex Crichton         let id = out_strings.add(PRODUCER_NAME);
34087c33c29SAlex Crichton         root.set(gimli::DW_AT_producer, write::AttributeValue::StringRef(id));
341329ae912SPhilip Craig         root.set(
342329ae912SPhilip Craig             gimli::DW_AT_language,
343329ae912SPhilip Craig             write::AttributeValue::Language(gimli::DW_LANG_C11),
344329ae912SPhilip Craig         );
34587c33c29SAlex Crichton         root.set(gimli::DW_AT_name, write::AttributeValue::StringRef(name_id));
34687c33c29SAlex Crichton         root.set(
34787c33c29SAlex Crichton             gimli::DW_AT_stmt_list,
34887c33c29SAlex Crichton             write::AttributeValue::LineProgramRef,
34987c33c29SAlex Crichton         );
35087c33c29SAlex Crichton         root.set(
35187c33c29SAlex Crichton             gimli::DW_AT_comp_dir,
35287c33c29SAlex Crichton             write::AttributeValue::StringRef(comp_dir_id),
35387c33c29SAlex Crichton         );
3547cd4f630SPhilip Craig         (unit, root_id, file_id)
35587c33c29SAlex Crichton     };
35687c33c29SAlex Crichton 
357af476a51SSingleAccretion     let wasm_types = add_wasm_types(unit, root_id, out_strings);
35843db4612SSingleAccretion     let mut unit_ranges = vec![];
359dd8c48b3SAlex Crichton     for (module, index) in compilation.indexes().collect::<Vec<_>>() {
360dd8c48b3SAlex Crichton         let (symbol, _) = compilation.function(module, index);
361dd8c48b3SAlex Crichton         if translated.contains(&symbol) {
36287c33c29SAlex Crichton             continue;
36387c33c29SAlex Crichton         }
36487c33c29SAlex Crichton 
365dd8c48b3SAlex Crichton         let addr_tr = &addr_tr[module];
366dd8c48b3SAlex Crichton         let map = &addr_tr.map()[index];
36787c33c29SAlex Crichton         let die_id = unit.add(root_id, gimli::DW_TAG_subprogram);
36887c33c29SAlex Crichton         let die = unit.get_mut(die_id);
36943db4612SSingleAccretion         let low_pc = write::Address::Symbol {
370dd8c48b3SAlex Crichton             symbol,
37143db4612SSingleAccretion             addend: map.offset as i64,
37243db4612SSingleAccretion         };
37343db4612SSingleAccretion         let code_length = map.len as u64;
37443db4612SSingleAccretion         die.set(gimli::DW_AT_low_pc, write::AttributeValue::Address(low_pc));
37587c33c29SAlex Crichton         die.set(
37687c33c29SAlex Crichton             gimli::DW_AT_high_pc,
37743db4612SSingleAccretion             write::AttributeValue::Udata(code_length),
37887c33c29SAlex Crichton         );
37943db4612SSingleAccretion         unit_ranges.push(write::Range::StartLength {
38043db4612SSingleAccretion             begin: low_pc,
38143db4612SSingleAccretion             length: code_length,
38243db4612SSingleAccretion         });
38387c33c29SAlex Crichton 
384dd8c48b3SAlex Crichton         let translation = &compilation.translations[module];
385dd8c48b3SAlex Crichton         let func_index = translation.module.func_index(index);
386dd8c48b3SAlex Crichton         let di = &translation.debuginfo;
387dd8c48b3SAlex Crichton         let id = match di
388dd8c48b3SAlex Crichton             .name_section
389dd8c48b3SAlex Crichton             .func_names
390dd8c48b3SAlex Crichton             .get(&func_index)
39187c33c29SAlex Crichton             .and_then(|s| check_invalid_chars_in_name(s))
39287c33c29SAlex Crichton         {
39387c33c29SAlex Crichton             Some(n) => out_strings.add(assert_dwarf_str!(n)),
394dd8c48b3SAlex Crichton             None => out_strings.add(format!("wasm-function[{}]", func_index.as_u32())),
39587c33c29SAlex Crichton         };
39687c33c29SAlex Crichton 
39787c33c29SAlex Crichton         die.set(gimli::DW_AT_name, write::AttributeValue::StringRef(id));
39887c33c29SAlex Crichton 
39987c33c29SAlex Crichton         die.set(
40087c33c29SAlex Crichton             gimli::DW_AT_decl_file,
4017cd4f630SPhilip Craig             write::AttributeValue::FileIndex(Some(file_id)),
40287c33c29SAlex Crichton         );
40387c33c29SAlex Crichton 
40487c33c29SAlex Crichton         let f_start = map.addresses[0].wasm;
4055856590fSAlex Crichton         let wasm_offset = di.wasm_file.code_section_offset + f_start;
40687c33c29SAlex Crichton         die.set(
4077cd4f630SPhilip Craig             gimli::DW_AT_decl_line,
40887c33c29SAlex Crichton             write::AttributeValue::Udata(wasm_offset),
40987c33c29SAlex Crichton         );
41087c33c29SAlex Crichton 
411dd8c48b3SAlex Crichton         let frame_info = compilation.function_frame_info(module, index);
412dd8c48b3SAlex Crichton         let source_range = addr_tr.func_source_range(index);
41387c33c29SAlex Crichton         generate_vars(
41487c33c29SAlex Crichton             unit,
41587c33c29SAlex Crichton             die_id,
41687c33c29SAlex Crichton             addr_tr,
41787c33c29SAlex Crichton             &frame_info,
41887c33c29SAlex Crichton             &[(source_range.0, source_range.1)],
419af476a51SSingleAccretion             vmctx_ptr_die_refs[module],
420af476a51SSingleAccretion             &wasm_types,
421dd8c48b3SAlex Crichton             &di.wasm_file.funcs[index.as_u32() as usize],
422dd8c48b3SAlex Crichton             di.name_section.locals_names.get(&func_index),
42387c33c29SAlex Crichton             out_strings,
42487c33c29SAlex Crichton             isa,
42587c33c29SAlex Crichton         )?;
42687c33c29SAlex Crichton     }
42743db4612SSingleAccretion     let unit_ranges_id = unit.ranges.add(write::RangeList(unit_ranges));
42843db4612SSingleAccretion     unit.get_mut(root_id).set(
42943db4612SSingleAccretion         gimli::DW_AT_ranges,
43043db4612SSingleAccretion         write::AttributeValue::RangeListRef(unit_ranges_id),
43143db4612SSingleAccretion     );
43287c33c29SAlex Crichton 
43387c33c29SAlex Crichton     Ok(())
43487c33c29SAlex Crichton }
435