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