1use std::{
2 backtrace::Backtrace,
3 collections::{BTreeMap, HashMap},
4 fmt::Display,
5 num::ParseIntError,
6 ops::Range,
7};
8
9use serde::Serialize;
10use snafu::Snafu;
11
12use crate::{
13 analysis::functions::Function,
14 util::{bytes::FromSlice, parse::parse_u32},
15};
16
17use super::{iter_attributes, module::Module, ParseContext};
18
19#[derive(Clone, Copy)]
20pub struct SectionIndex(pub usize);
21
22#[derive(Clone)]
23pub struct Section {
24 name: String,
25 kind: SectionKind,
26 start_address: u32,
27 end_address: u32,
28 alignment: u32,
29 functions: BTreeMap<u32, Function>,
30}
31
32#[derive(Debug, Snafu)]
33pub enum SectionError {
34 #[snafu(display(
35 "Section {name} must not end ({end_address:#010x}) before it starts ({start_address:#010x}):\n{backtrace}"
36 ))]
37 EndBeforeStart { name: String, start_address: u32, end_address: u32, backtrace: Backtrace },
38 #[snafu(display("Section {name} aligment ({alignment}) must be a power of two:\n{backtrace}"))]
39 AlignmentPowerOfTwo { name: String, alignment: u32, backtrace: Backtrace },
40 #[snafu(display("Section {name} starts at a misaligned address {start_address:#010x}; the provided alignment was {alignment}:\n{backtrace}"))]
41 MisalignedStart { name: String, start_address: u32, alignment: u32, backtrace: Backtrace },
42}
43
44#[derive(Debug, Snafu)]
45pub enum SectionParseError {
46 #[snafu(transparent)]
47 SectionKind { source: SectionKindError },
48 #[snafu(display("{context}: failed to parse start address '{value}': {error}\n{backtrace}"))]
49 ParseStartAddress { context: ParseContext, value: String, error: ParseIntError, backtrace: Backtrace },
50 #[snafu(display("{context}: failed to parse end address '{value}': {error}\n{backtrace}"))]
51 ParseEndAddress { context: ParseContext, value: String, error: ParseIntError, backtrace: Backtrace },
52 #[snafu(display("{context}: failed to parse alignment '{value}': {error}\n{backtrace}"))]
53 ParseAlignment { context: ParseContext, value: String, error: ParseIntError, backtrace: Backtrace },
54 #[snafu(display(
55 "{context}: expected section attribute 'kind', 'start', 'end' or 'align' but got '{key}':\n{backtrace}"
56 ))]
57 UnknownAttribute { context: ParseContext, key: String, backtrace: Backtrace },
58 #[snafu(display("{context}: missing '{attribute}' attribute:\n{backtrace}"))]
59 MissingAttribute { context: ParseContext, attribute: String, backtrace: Backtrace },
60 #[snafu(display("{context}: {error}"))]
61 Section { context: ParseContext, error: SectionError },
62}
63
64#[derive(Debug, Snafu)]
65pub enum SectionInheritParseError {
66 #[snafu(display("{context}: section {name} does not exist in this file's header:\n{backtrace}"))]
67 NotInHeader { context: ParseContext, name: String, backtrace: Backtrace },
68 #[snafu(display("{context}: attribute '{attribute}' should be omitted as it is inherited from this file's header"))]
69 InheritedAttribute { context: ParseContext, attribute: String, backtrace: Backtrace },
70 #[snafu(transparent)]
71 SectionParse { source: SectionParseError },
72}
73
74#[derive(Debug, Snafu)]
75pub enum SectionCodeError {
76 #[snafu(display("section starts before base address:\n{backtrace}"))]
77 StartsBeforeBaseAddress { backtrace: Backtrace },
78 #[snafu(display("section ends after code ends:\n{backtrace}"))]
79 EndsOutsideModule { backtrace: Backtrace },
80}
81
82pub struct SectionOptions {
83 pub name: String,
84 pub kind: SectionKind,
85 pub start_address: u32,
86 pub end_address: u32,
87 pub alignment: u32,
88 pub functions: Option<BTreeMap<u32, Function>>,
89}
90
91impl Section {
92 pub fn new(options: SectionOptions) -> Result<Self, SectionError> {
93 let SectionOptions { name, kind, start_address, end_address, alignment, functions } = options;
94
95 if end_address < start_address {
96 return EndBeforeStartSnafu { name, start_address, end_address }.fail();
97 }
98 if !alignment.is_power_of_two() {
99 return AlignmentPowerOfTwoSnafu { name, alignment }.fail();
100 }
101 let misalign_mask = alignment - 1;
102 if (start_address & misalign_mask) != 0 {
103 return MisalignedStartSnafu { name, start_address, alignment }.fail();
104 }
105
106 let functions = functions.unwrap_or_else(BTreeMap::new);
107
108 Ok(Self { name, kind, start_address, end_address, alignment, functions })
109 }
110
111 pub fn inherit(other: &Section, start_address: u32, end_address: u32) -> Result<Self, SectionError> {
112 if end_address < start_address {
113 return EndBeforeStartSnafu { name: other.name.clone(), start_address, end_address }.fail();
114 }
115 Ok(Self {
116 name: other.name.clone(),
117 kind: other.kind,
118 start_address,
119 end_address,
120 alignment: other.alignment,
121 functions: BTreeMap::new(),
122 })
123 }
124
125 pub(crate) fn parse(line: &str, context: &ParseContext) -> Result<Option<Self>, SectionParseError> {
126 let mut words = line.split_whitespace();
127 let Some(name) = words.next() else { return Ok(None) };
128
129 let mut kind = None;
130 let mut start = None;
131 let mut end = None;
132 let mut align = None;
133 for (key, value) in iter_attributes(words) {
134 match key {
135 "kind" => kind = Some(SectionKind::parse(value, context)?),
136 "start" => {
137 start = Some(parse_u32(value).map_err(|error| ParseStartAddressSnafu { context, value, error }.build())?)
138 }
139 "end" => end = Some(parse_u32(value).map_err(|error| ParseEndAddressSnafu { context, value, error }.build())?),
140 "align" => {
141 align = Some(parse_u32(value).map_err(|error| ParseAlignmentSnafu { context, value, error }.build())?)
142 }
143 _ => return UnknownAttributeSnafu { context: context.clone(), key }.fail(),
144 }
145 }
146
147 let kind = kind.ok_or_else(|| MissingAttributeSnafu { context, attribute: "kind" }.build())?;
148 let start_address = start.ok_or_else(|| MissingAttributeSnafu { context, attribute: "start" }.build())?;
149 let end_address = end.ok_or_else(|| MissingAttributeSnafu { context, attribute: "end" }.build())?;
150 let alignment = align.ok_or_else(|| MissingAttributeSnafu { context, attribute: "align" }.build())?;
151
152 Ok(Some(
153 Section::new(SectionOptions {
154 name: name.to_string(),
155 kind,
156 start_address,
157 end_address,
158 alignment,
159 functions: None,
160 })
161 .map_err(|error| SectionSnafu { context, error }.build())?,
162 ))
163 }
164
165 pub(crate) fn parse_inherit(
166 line: &str,
167 context: &ParseContext,
168 sections: &Sections,
169 ) -> Result<Option<Self>, SectionInheritParseError> {
170 let mut words = line.split_whitespace();
171 let Some(name) = words.next() else { return Ok(None) };
172
173 let (_, inherit_section) = sections.by_name(name).ok_or_else(|| NotInHeaderSnafu { context, name }.build())?;
174
175 let mut start = None;
176 let mut end = None;
177 for (key, value) in iter_attributes(words) {
178 match key {
179 "kind" => return InheritedAttributeSnafu { context, attribute: "kind" }.fail(),
180 "start" => {
181 start = Some(parse_u32(value).map_err(|error| ParseStartAddressSnafu { context, value, error }.build())?)
182 }
183 "end" => end = Some(parse_u32(value).map_err(|error| ParseEndAddressSnafu { context, value, error }.build())?),
184 "align" => return InheritedAttributeSnafu { context, attribute: "align" }.fail(),
185 _ => return UnknownAttributeSnafu { context, key }.fail()?,
186 }
187 }
188
189 Ok(Some(
190 Section::inherit(
191 inherit_section,
192 start.ok_or_else(|| MissingAttributeSnafu { context, attribute: "start" }.build())?,
193 end.ok_or_else(|| MissingAttributeSnafu { context, attribute: "end" }.build())?,
194 )
195 .map_err(|error| SectionSnafu { context, error }.build())?,
196 ))
197 }
198
199 pub fn code_from_module<'a>(&'a self, module: &'a Module) -> Result<Option<&'a [u8]>, SectionCodeError> {
200 self.code(module.code(), module.base_address())
201 }
202
203 pub fn code<'a>(&'a self, code: &'a [u8], base_address: u32) -> Result<Option<&'a [u8]>, SectionCodeError> {
204 if self.kind() == SectionKind::Bss {
205 return Ok(None);
206 }
207 if self.start_address() < base_address {
208 return StartsBeforeBaseAddressSnafu.fail();
209 }
210 let start = self.start_address() - base_address;
211 let end = self.end_address() - base_address;
212 if end > code.len() as u32 {
213 return EndsOutsideModuleSnafu.fail();
214 }
215 Ok(Some(&code[start as usize..end as usize]))
216 }
217
218 pub fn size(&self) -> u32 {
219 self.end_address - self.start_address
220 }
221
222 pub fn iter_words<'a>(&'a self, code: &'a [u8], range: Option<Range<u32>>) -> impl Iterator<Item = Word> + 'a {
225 let range = range.unwrap_or(self.address_range());
226 let start = range.start.next_multiple_of(4);
227 let end = range.end & !3;
228
229 (start..end).step_by(4).map(move |address| {
230 let offset = address - self.start_address();
231 let bytes = &code[offset as usize..];
232 Word { address, value: u32::from_le_slice(bytes) }
233 })
234 }
235
236 pub fn name(&self) -> &str {
237 &self.name
238 }
239
240 pub fn kind(&self) -> SectionKind {
241 self.kind
242 }
243
244 pub fn start_address(&self) -> u32 {
245 self.start_address
246 }
247
248 pub fn end_address(&self) -> u32 {
249 self.end_address
250 }
251
252 pub fn address_range(&self) -> Range<u32> {
253 self.start_address..self.end_address
254 }
255
256 pub fn alignment(&self) -> u32 {
257 self.alignment
258 }
259
260 pub fn overlaps_with(&self, other: &Section) -> bool {
261 self.start_address < other.end_address && other.start_address < self.end_address
262 }
263
264 pub fn functions(&self) -> &BTreeMap<u32, Function> {
265 &self.functions
266 }
267
268 pub fn functions_mut(&mut self) -> &mut BTreeMap<u32, Function> {
269 &mut self.functions
270 }
271
272 pub fn add_function(&mut self, function: Function) {
273 self.functions.insert(function.start_address(), function);
274 }
275}
276
277impl Display for Section {
278 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
279 write!(
280 f,
281 "{:11} start:{:#010x} end:{:#010x} kind:{} align:{}",
282 self.name, self.start_address, self.end_address, self.kind, self.alignment
283 )?;
284
285 Ok(())
286 }
287}
288
289#[derive(PartialEq, Eq, Clone, Copy, Serialize)]
290pub enum SectionKind {
291 Code,
292 Data,
293 Rodata,
294 Bss,
295}
296
297#[derive(Debug, Snafu)]
298pub enum SectionKindError {
299 #[snafu(display("{context}: unknown section kind '{value}', must be one of: code, data, bss"))]
300 UnknownKind { context: ParseContext, value: String, backtrace: Backtrace },
301}
302
303impl SectionKind {
304 pub fn parse(value: &str, context: &ParseContext) -> Result<Self, SectionKindError> {
305 match value {
306 "code" => Ok(Self::Code),
307 "data" => Ok(Self::Data),
308 "rodata" => Ok(Self::Rodata),
309 "bss" => Ok(Self::Bss),
310 _ => UnknownKindSnafu { context, value }.fail(),
311 }
312 }
313
314 pub fn is_initialized(self) -> bool {
315 match self {
316 SectionKind::Code => true,
317 SectionKind::Data => true,
318 SectionKind::Rodata => true,
319 SectionKind::Bss => false,
320 }
321 }
322
323 pub fn is_writeable(self) -> bool {
324 match self {
325 SectionKind::Code => false,
326 SectionKind::Data => true,
327 SectionKind::Rodata => false,
328 SectionKind::Bss => true,
329 }
330 }
331
332 pub fn is_executable(self) -> bool {
333 match self {
334 SectionKind::Code => true,
335 SectionKind::Data => false,
336 SectionKind::Rodata => false,
337 SectionKind::Bss => false,
338 }
339 }
340}
341
342impl Display for SectionKind {
343 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
344 match self {
345 Self::Code => write!(f, "code"),
346 Self::Data => write!(f, "data"),
347 Self::Rodata => write!(f, "rodata"),
348 Self::Bss => write!(f, "bss"),
349 }
350 }
351}
352
353pub struct Sections {
354 sections: Vec<Section>,
355 sections_by_name: HashMap<String, SectionIndex>,
356}
357
358#[derive(Debug, Snafu)]
359pub enum SectionsError {
360 #[snafu(display("Section '{name}' already exists:\n{backtrace}"))]
361 DuplicateName { name: String, backtrace: Backtrace },
362 #[snafu(display("Section '{name}' overlaps with '{other_name}':\n{backtrace}"))]
363 Overlapping { name: String, other_name: String, backtrace: Backtrace },
364}
365
366impl Sections {
367 pub fn new() -> Self {
368 Self { sections: vec![], sections_by_name: HashMap::new() }
369 }
370
371 pub fn add(&mut self, section: Section) -> Result<SectionIndex, SectionsError> {
372 if self.sections_by_name.contains_key(§ion.name) {
373 return DuplicateNameSnafu { name: section.name }.fail();
374 }
375 for other in &self.sections {
376 if section.overlaps_with(other) {
377 return OverlappingSnafu { name: section.name, other_name: other.name.to_string() }.fail();
378 }
379 }
380
381 let index = SectionIndex(self.sections.len());
382 self.sections_by_name.insert(section.name.clone(), index);
383 self.sections.push(section);
384 Ok(index)
385 }
386
387 pub fn get(&self, index: SectionIndex) -> &Section {
388 &self.sections[index.0]
389 }
390
391 pub fn get_mut(&mut self, index: SectionIndex) -> &mut Section {
392 &mut self.sections[index.0]
393 }
394
395 pub fn by_name(&self, name: &str) -> Option<(SectionIndex, &Section)> {
396 let &index = self.sections_by_name.get(name)?;
397 Some((index, &self.sections[index.0]))
398 }
399
400 pub fn iter(&self) -> impl Iterator<Item = &Section> {
401 self.sections.iter()
402 }
403
404 pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut Section> {
405 self.sections.iter_mut()
406 }
407
408 pub fn len(&self) -> usize {
409 self.sections.len()
410 }
411
412 pub fn get_by_contained_address(&self, address: u32) -> Option<(SectionIndex, &Section)> {
413 self.sections
414 .iter()
415 .enumerate()
416 .find(|(_, s)| address >= s.start_address && address < s.end_address)
417 .map(|(i, s)| (SectionIndex(i), s))
418 }
419
420 pub fn get_by_contained_address_mut(&mut self, address: u32) -> Option<(SectionIndex, &mut Section)> {
421 self.sections
422 .iter_mut()
423 .enumerate()
424 .find(|(_, s)| address >= s.start_address && address < s.end_address)
425 .map(|(i, s)| (SectionIndex(i), s))
426 }
427
428 pub fn add_function(&mut self, function: Function) {
429 let address = function.first_instruction_address();
430 self.sections
431 .iter_mut()
432 .find(|s| address >= s.start_address && address < s.end_address)
433 .unwrap()
434 .functions
435 .insert(address, function);
436 }
437
438 pub fn sorted_by_address(&self) -> Vec<&Section> {
439 let mut sections = self.sections.iter().collect::<Vec<_>>();
440 sections.sort_unstable_by(|a, b| a.start_address.cmp(&b.start_address).then(a.end_address.cmp(&b.end_address)));
441 sections
442 }
443
444 pub fn functions(&self) -> impl Iterator<Item = &Function> {
445 self.sections.iter().flat_map(|s| s.functions.values())
446 }
447
448 pub fn functions_mut(&mut self) -> impl Iterator<Item = &mut Function> {
449 self.sections.iter_mut().flat_map(|s| s.functions.values_mut())
450 }
451
452 pub fn base_address(&self) -> Option<u32> {
453 self.sections.iter().map(|s| s.start_address).min()
454 }
455
456 pub fn end_address(&self) -> Option<u32> {
457 self.sections.iter().map(|s| s.end_address).max()
458 }
459
460 pub fn bss_size(&self) -> u32 {
461 self.sections.iter().filter(|s| s.kind == SectionKind::Bss).map(|s| s.size()).sum()
462 }
463
464 pub fn bss_range(&self) -> Option<Range<u32>> {
465 self.sections
466 .iter()
467 .filter(|s| s.kind == SectionKind::Bss)
468 .map(|s| s.address_range())
469 .reduce(|a, b| a.start.min(b.start)..a.end.max(b.end))
470 }
471
472 pub fn get_section_after(&self, text_end: u32) -> Option<&Section> {
473 self.sorted_by_address().iter().copied().find(|s| s.start_address >= text_end)
474 }
475}
476
477impl IntoIterator for Sections {
478 type Item = Section;
479
480 type IntoIter = <Vec<Self::Item> as IntoIterator>::IntoIter;
481
482 fn into_iter(self) -> Self::IntoIter {
483 self.sections.into_iter()
484 }
485}
486
487pub struct Word {
488 pub address: u32,
489 pub value: u32,
490}