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