1#![allow(clippy::cast_ptr_alignment)]
20
21use crate::types::{ModuleAddressMap, ModuleVmctxInfo, ValueLabelsRanges};
22use anyhow::Error;
23use faerie::{Artifact, Decl};
24use more_asserts::assert_gt;
25use target_lexicon::{BinaryFormat, Triple};
26
27pub use crate::read_debuginfo::{read_debuginfo, DebugInfoData, WasmFileInfo};
28pub use crate::transform::transform_dwarf;
29pub use crate::write_debuginfo::{emit_dwarf, ResolvedSymbol, SymbolResolver};
30
31mod gc;
32mod read_debuginfo;
33mod transform;
34pub mod types;
35mod write_debuginfo;
36
37struct FunctionRelocResolver {}
38impl SymbolResolver for FunctionRelocResolver {
39 fn resolve_symbol(&self, symbol: usize, addend: i64) -> ResolvedSymbol {
40 let name = format!("_wasm_function_{}", symbol);
41 ResolvedSymbol::Reloc { name, addend }
42 }
43}
44
45pub fn emit_debugsections(
46 obj: &mut Artifact,
47 vmctx_info: &ModuleVmctxInfo,
48 pointer_width_bytes: u8,
49 debuginfo_data: &DebugInfoData,
50 at: &ModuleAddressMap,
51 ranges: &ValueLabelsRanges,
52) -> Result<(), Error> {
53 let resolver = FunctionRelocResolver {};
54 let dwarf = transform_dwarf(pointer_width_bytes, debuginfo_data, at, vmctx_info, ranges)?;
55 emit_dwarf(obj, dwarf, &resolver)?;
56 Ok(())
57}
58
59struct ImageRelocResolver<'a> {
60 func_offsets: &'a Vec<u64>,
61}
62
63impl<'a> SymbolResolver for ImageRelocResolver<'a> {
64 fn resolve_symbol(&self, symbol: usize, addend: i64) -> ResolvedSymbol {
65 let func_start = self.func_offsets[symbol];
66 ResolvedSymbol::PhysicalAddress(func_start + addend as u64)
67 }
68}
69
70pub fn emit_debugsections_image(
72 triple: Triple,
73 pointer_width_bytes: u8,
74 debuginfo_data: &DebugInfoData,
75 vmctx_info: &ModuleVmctxInfo,
76 at: &ModuleAddressMap,
77 ranges: &ValueLabelsRanges,
78 funcs: &[(*const u8, usize)],
79) -> Result<Vec<u8>, Error> {
80 let func_offsets = &funcs
81 .iter()
82 .map(|(ptr, _)| *ptr as u64)
83 .collect::<Vec<u64>>();
84 let mut obj = Artifact::new(triple, String::from("module"));
85 let resolver = ImageRelocResolver { func_offsets };
86 let dwarf = transform_dwarf(pointer_width_bytes, debuginfo_data, at, vmctx_info, ranges)?;
87
88 assert_gt!(funcs.len(), 0);
90 let mut segment_body: (usize, usize) = (!0, 0);
91 for (body_ptr, body_len) in funcs {
92 segment_body.0 = std::cmp::min(segment_body.0, *body_ptr as usize);
93 segment_body.1 = std::cmp::max(segment_body.1, *body_ptr as usize + body_len);
94 }
95 let segment_body = (segment_body.0 as *const u8, segment_body.1 - segment_body.0);
96
97 let body = unsafe { std::slice::from_raw_parts(segment_body.0, segment_body.1) };
98 obj.declare_with("all", Decl::function(), body.to_vec())?;
99
100 emit_dwarf(&mut obj, dwarf, &resolver)?;
101
102 let mut bytes = obj.emit_as(BinaryFormat::Elf)?;
104 convert_faerie_elf_to_loadable_file(&mut bytes, segment_body.0);
106
107 Ok(bytes)
111}
112
113fn convert_faerie_elf_to_loadable_file(bytes: &mut Vec<u8>, code_ptr: *const u8) {
114 use std::ffi::CStr;
115 use std::os::raw::c_char;
116
117 assert!(
118 bytes[0x4] == 2 && bytes[0x5] == 1,
119 "bits and endianess in .ELF"
120 );
121 let e_phoff = unsafe { *(bytes.as_ptr().offset(0x20) as *const u64) };
122 let e_phnum = unsafe { *(bytes.as_ptr().offset(0x38) as *const u16) };
123 assert!(
124 e_phoff == 0 && e_phnum == 0,
125 "program header table is empty"
126 );
127 let e_phentsize = unsafe { *(bytes.as_ptr().offset(0x36) as *const u16) };
128 assert_eq!(e_phentsize, 0x38, "size of ph");
129 let e_shentsize = unsafe { *(bytes.as_ptr().offset(0x3A) as *const u16) };
130 assert_eq!(e_shentsize, 0x40, "size of sh");
131
132 let e_shoff = unsafe { *(bytes.as_ptr().offset(0x28) as *const u64) };
133 let e_shnum = unsafe { *(bytes.as_ptr().offset(0x3C) as *const u16) };
134 let mut shstrtab_off = 0;
135 let mut segment = None;
136 for i in 0..e_shnum {
137 let off = e_shoff as isize + i as isize * e_shentsize as isize;
138 let sh_type = unsafe { *(bytes.as_ptr().offset(off + 0x4) as *const u32) };
139 if sh_type == 3 {
140 shstrtab_off = unsafe { *(bytes.as_ptr().offset(off + 0x18) as *const u64) };
141 }
142 if sh_type != 1 {
143 continue;
144 }
145 let sh_name = unsafe {
147 let sh_name_off = *(bytes.as_ptr().offset(off) as *const u32);
148 CStr::from_ptr(
149 bytes
150 .as_ptr()
151 .offset((shstrtab_off + sh_name_off as u64) as isize)
152 as *const c_char,
153 )
154 .to_str()
155 .expect("name")
156 };
157 if sh_name != ".text.all" {
158 continue;
159 }
160
161 assert!(segment.is_none());
162 unsafe {
165 *(bytes.as_ptr().offset(off + 0x10) as *mut u64) = code_ptr as u64;
166 };
167 let sh_offset = unsafe { *(bytes.as_ptr().offset(off + 0x18) as *const u64) };
168 let sh_size = unsafe { *(bytes.as_ptr().offset(off + 0x20) as *const u64) };
169 segment = Some((sh_offset, code_ptr, sh_size));
170 unsafe {
172 let sh_name_off = *(bytes.as_ptr().offset(off) as *const u32);
173 bytes[(shstrtab_off + sh_name_off as u64) as usize + ".text".len()] = 0;
174 }
175 }
176
177 let ph_off = bytes.len();
179 if let Some((sh_offset, v_offset, sh_size)) = segment {
180 let segment = vec![0; 0x38];
181 unsafe {
182 *(segment.as_ptr() as *mut u32) = 0x1;
183 *(segment.as_ptr().offset(0x8) as *mut u64) = sh_offset;
184 *(segment.as_ptr().offset(0x10) as *mut u64) = v_offset as u64;
185 *(segment.as_ptr().offset(0x18) as *mut u64) = v_offset as u64;
186 *(segment.as_ptr().offset(0x20) as *mut u64) = sh_size;
187 *(segment.as_ptr().offset(0x28) as *mut u64) = sh_size;
188 }
189 bytes.extend_from_slice(&segment);
190 } else {
191 unreachable!();
192 }
193
194 unsafe {
197 *(bytes.as_ptr().offset(0x10) as *mut u16) = 3;
198 *(bytes.as_ptr().offset(0x20) as *mut u64) = ph_off as u64;
199 *(bytes.as_ptr().offset(0x38) as *mut u16) = 1 as u16;
200 }
201}