1use crate::common::{DebugAddrBase, DebugAddrIndex, SectionId};
2use crate::read::{Reader, ReaderOffset, Result, Section};
3
4#[derive(Debug, Default, Clone, Copy)]
6pub struct DebugAddr<R> {
7    section: R,
8}
9
10impl<R: Reader> DebugAddr<R> {
11    pub fn get_address(
29        &self,
30        address_size: u8,
31        base: DebugAddrBase<R::Offset>,
32        index: DebugAddrIndex<R::Offset>,
33    ) -> Result<u64> {
34        let input = &mut self.section.clone();
35        input.skip(base.0)?;
36        input.skip(R::Offset::from_u64(
37            index.0.into_u64() * u64::from(address_size),
38        )?)?;
39        input.read_address(address_size)
40    }
41}
42
43impl<T> DebugAddr<T> {
44    pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugAddr<R>
50    where
51        F: FnMut(&'a T) -> R,
52    {
53        borrow(&self.section).into()
54    }
55}
56
57impl<R> Section<R> for DebugAddr<R> {
58    fn id() -> SectionId {
59        SectionId::DebugAddr
60    }
61
62    fn reader(&self) -> &R {
63        &self.section
64    }
65}
66
67impl<R> From<R> for DebugAddr<R> {
68    fn from(section: R) -> Self {
69        DebugAddr { section }
70    }
71}
72
73#[cfg(test)]
74mod tests {
75    use super::*;
76    use crate::read::EndianSlice;
77    use crate::test_util::GimliSectionMethods;
78    use crate::{Format, LittleEndian};
79    use test_assembler::{Endian, Label, LabelMaker, Section};
80
81    #[test]
82    fn test_get_address() {
83        for format in [Format::Dwarf32, Format::Dwarf64] {
84            for address_size in [4, 8] {
85                let zero = Label::new();
86                let length = Label::new();
87                let start = Label::new();
88                let first = Label::new();
89                let end = Label::new();
90                let mut section = Section::with_endian(Endian::Little)
91                    .mark(&zero)
92                    .initial_length(format, &length, &start)
93                    .D16(5)
94                    .D8(address_size)
95                    .D8(0)
96                    .mark(&first);
97                for i in 0..20 {
98                    section = section.word(address_size, 1000 + i);
99                }
100                section = section.mark(&end);
101                length.set_const((&end - &start) as u64);
102
103                let section = section.get_contents().unwrap();
104                let debug_addr = DebugAddr::from(EndianSlice::new(§ion, LittleEndian));
105                let base = DebugAddrBase((&first - &zero) as usize);
106
107                assert_eq!(
108                    debug_addr.get_address(address_size, base, DebugAddrIndex(0)),
109                    Ok(1000)
110                );
111                assert_eq!(
112                    debug_addr.get_address(address_size, base, DebugAddrIndex(19)),
113                    Ok(1019)
114                );
115            }
116        }
117    }
118}