Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/crates/cranelift/src/debug/write_debuginfo.rs
3057 views
1
use crate::debug::Compilation;
2
pub use crate::debug::transform::transform_dwarf;
3
use cranelift_codegen::ir::Endianness;
4
use cranelift_codegen::isa::{
5
TargetIsa,
6
unwind::{CfaUnwindInfo, UnwindInfo},
7
};
8
use gimli::write::{
9
Address, Dwarf, EndianVec, FrameTable, Result as WriteResult, Sections, Writer,
10
};
11
use gimli::{RunTimeEndian, SectionId};
12
use wasmtime_environ::error::Result as EnvResult;
13
14
pub struct DwarfSection {
15
pub name: &'static str,
16
pub body: Vec<u8>,
17
pub relocs: Vec<DwarfSectionReloc>,
18
}
19
20
#[derive(Clone)]
21
pub struct DwarfSectionReloc {
22
pub target: DwarfSectionRelocTarget,
23
pub offset: u32,
24
pub addend: i32,
25
pub size: u8,
26
}
27
28
#[derive(Clone)]
29
pub enum DwarfSectionRelocTarget {
30
Func(usize),
31
Section(&'static str),
32
}
33
34
fn emit_dwarf_sections(
35
isa: &dyn TargetIsa,
36
mut dwarf: Dwarf,
37
frames: Option<FrameTable>,
38
) -> EnvResult<Vec<DwarfSection>> {
39
let endian = match isa.endianness() {
40
Endianness::Little => RunTimeEndian::Little,
41
Endianness::Big => RunTimeEndian::Big,
42
};
43
let writer = WriterRelocate {
44
relocs: Vec::new(),
45
writer: EndianVec::new(endian),
46
};
47
let mut sections = Sections::new(writer);
48
dwarf.write(&mut sections)?;
49
if let Some(frames) = frames {
50
frames.write_debug_frame(&mut sections.debug_frame)?;
51
}
52
53
let mut result = Vec::new();
54
sections.for_each_mut(|id, s| -> EnvResult<()> {
55
let name = id.name();
56
let body = s.writer.take();
57
if body.is_empty() {
58
return Ok(());
59
}
60
let mut relocs = vec![];
61
::std::mem::swap(&mut relocs, &mut s.relocs);
62
result.push(DwarfSection { name, body, relocs });
63
Ok(())
64
})?;
65
66
Ok(result)
67
}
68
69
#[derive(Clone)]
70
pub struct WriterRelocate {
71
relocs: Vec<DwarfSectionReloc>,
72
writer: EndianVec<RunTimeEndian>,
73
}
74
75
impl Writer for WriterRelocate {
76
type Endian = RunTimeEndian;
77
78
fn endian(&self) -> Self::Endian {
79
self.writer.endian()
80
}
81
82
fn len(&self) -> usize {
83
self.writer.len()
84
}
85
86
fn write(&mut self, bytes: &[u8]) -> WriteResult<()> {
87
self.writer.write(bytes)
88
}
89
90
fn write_at(&mut self, offset: usize, bytes: &[u8]) -> WriteResult<()> {
91
self.writer.write_at(offset, bytes)
92
}
93
94
fn write_address(&mut self, address: Address, size: u8) -> WriteResult<()> {
95
match address {
96
Address::Constant(val) => self.write_udata(val, size),
97
Address::Symbol { symbol, addend } => {
98
let offset = self.len() as u32;
99
self.relocs.push(DwarfSectionReloc {
100
target: DwarfSectionRelocTarget::Func(symbol),
101
offset,
102
size,
103
addend: addend as i32,
104
});
105
self.write_udata(addend as u64, size)
106
}
107
}
108
}
109
110
fn write_offset(&mut self, val: usize, section: SectionId, size: u8) -> WriteResult<()> {
111
let offset = self.len() as u32;
112
let target = DwarfSectionRelocTarget::Section(section.name());
113
self.relocs.push(DwarfSectionReloc {
114
target,
115
offset,
116
size,
117
addend: val as i32,
118
});
119
self.write_udata(val as u64, size)
120
}
121
122
fn write_offset_at(
123
&mut self,
124
offset: usize,
125
val: usize,
126
section: SectionId,
127
size: u8,
128
) -> WriteResult<()> {
129
let target = DwarfSectionRelocTarget::Section(section.name());
130
self.relocs.push(DwarfSectionReloc {
131
target,
132
offset: offset as u32,
133
size,
134
addend: val as i32,
135
});
136
self.write_udata_at(offset, val as u64, size)
137
}
138
}
139
140
fn create_frame_table(
141
isa: &dyn TargetIsa,
142
compilation: &mut Compilation<'_>,
143
) -> Option<FrameTable> {
144
let mut table = FrameTable::default();
145
146
let cie_id = table.add_cie(isa.create_systemv_cie()?);
147
148
for (_, symbol, metadata) in compilation.functions() {
149
// The CFA-based unwind info will either be natively present, or we
150
// have generated it and placed into the "cfa_unwind_info" auxiliary
151
// field. We shouldn't emit both, though, it'd be wasteful.
152
let mut unwind_info: Option<&CfaUnwindInfo> = None;
153
if let Some(UnwindInfo::SystemV(info)) = &metadata.unwind_info {
154
debug_assert!(metadata.cfa_unwind_info.is_none());
155
unwind_info = Some(info);
156
} else if let Some(info) = &metadata.cfa_unwind_info {
157
unwind_info = Some(info);
158
}
159
160
if let Some(info) = unwind_info {
161
table.add_fde(cie_id, info.to_fde(Address::Symbol { symbol, addend: 0 }));
162
}
163
}
164
165
Some(table)
166
}
167
168
pub fn emit_dwarf(
169
isa: &dyn TargetIsa,
170
compilation: &mut Compilation<'_>,
171
) -> EnvResult<Vec<DwarfSection>> {
172
let dwarf = transform_dwarf(isa, compilation)?;
173
let frame_table = create_frame_table(isa, compilation);
174
let sections = emit_dwarf_sections(isa, dwarf, frame_table)?;
175
Ok(sections)
176
}
177
178