ds_decomp/config/
section.rs

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    /// Iterates over every 32-bit word in the specified `range`, which defaults to the entire section if it is `None`. Note
222    /// that `code` must be the full raw content of this section.
223    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(&section.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}