xmas_elf/
symbol_table.rs

1use ElfFile;
2use sections;
3
4use zero::Pod;
5
6use core::fmt;
7
8#[derive(Debug)]
9#[repr(C)]
10struct Entry32_ {
11    name: u32,
12    value: u32,
13    size: u32,
14    info: u8,
15    other: Visibility_,
16    shndx: u16,
17}
18
19#[derive(Debug)]
20#[repr(C)]
21struct Entry64_ {
22    name: u32,
23    info: u8,
24    other: Visibility_,
25    shndx: u16,
26    value: u64,
27    size: u64,
28}
29
30unsafe impl Pod for Entry32_ {}
31unsafe impl Pod for Entry64_ {}
32
33#[derive(Debug)]
34#[repr(C)]
35pub struct Entry32(Entry32_);
36
37#[derive(Debug)]
38#[repr(C)]
39pub struct Entry64(Entry64_);
40
41unsafe impl Pod for Entry32 {}
42unsafe impl Pod for Entry64 {}
43
44#[derive(Debug)]
45#[repr(C)]
46pub struct DynEntry32(Entry32_);
47
48#[derive(Debug)]
49#[repr(C)]
50pub struct DynEntry64(Entry64_);
51
52unsafe impl Pod for DynEntry32 {}
53unsafe impl Pod for DynEntry64 {}
54
55pub trait Entry {
56    fn name(&self) -> u32;
57    fn info(&self) -> u8;
58    fn other(&self) -> Visibility_;
59    fn shndx(&self) -> u16;
60    fn value(&self) -> u64;
61    fn size(&self) -> u64;
62
63    fn get_name<'a>(&'a self, elf_file: &ElfFile<'a>) -> Result<&'a str, &'static str>;
64
65    fn get_other(&self) -> Visibility {
66        self.other().as_visibility()
67    }
68
69    fn get_binding(&self) -> Result<Binding, &'static str> {
70        Binding_(self.info() >> 4).as_binding()
71    }
72
73    fn get_type(&self) -> Result<Type, &'static str> {
74        Type_(self.info() & 0xf).as_type()
75    }
76
77    fn get_section_header<'a>(&'a self,
78                              elf_file: &ElfFile<'a>,
79                              self_index: usize)
80                              -> Result<sections::SectionHeader<'a>, &'static str> {
81        match self.shndx() {
82            sections::SHN_XINDEX => {
83                // TODO factor out distinguished section names into sections consts
84                let header = elf_file.find_section_by_name(".symtab_shndx");
85                if let Some(header) = header {
86                    assert_eq!(header.get_type()?, sections::ShType::SymTabShIndex);
87                    if let sections::SectionData::SymTabShIndex(data) =
88                        header.get_data(elf_file)? {
89                        // TODO cope with u32 section indices (count is in sh_size of header 0, etc.)
90                        // Note that it is completely bogus to crop to u16 here.
91                        let index = data[self_index] as u16;
92                        assert_ne!(index, sections::SHN_UNDEF);
93                        elf_file.section_header(index)
94                    } else {
95                        Err("Expected SymTabShIndex")
96                    }
97                } else {
98                    Err("no .symtab_shndx section")
99                }
100            }
101            sections::SHN_UNDEF |
102            sections::SHN_ABS |
103            sections::SHN_COMMON => Err("Reserved section header index"),
104            i => elf_file.section_header(i),
105        }
106    }
107}
108
109impl fmt::Display for dyn Entry {
110    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
111        writeln!(f, "Symbol table entry:")?;
112        writeln!(f, "    name:             {:?}", self.name())?;
113        writeln!(f, "    binding:          {:?}", self.get_binding())?;
114        writeln!(f, "    type:             {:?}", self.get_type())?;
115        writeln!(f, "    other:            {:?}", self.get_other())?;
116        writeln!(f, "    shndx:            {:?}", self.shndx())?;
117        writeln!(f, "    value:            {:?}", self.value())?;
118        writeln!(f, "    size:             {:?}", self.size())?;
119        Ok(())
120    }
121}
122
123macro_rules! impl_entry {
124    ($name: ident with ElfFile::$strfunc: ident) => {
125        impl Entry for $name {
126            fn get_name<'a>(&'a self, elf_file: &ElfFile<'a>) -> Result<&'a str, &'static str> {
127                elf_file.$strfunc(self.name())
128            }
129
130            fn name(&self) -> u32 { self.0.name }
131            fn info(&self) -> u8 { self.0.info }
132            fn other(&self) -> Visibility_ { self.0.other }
133            fn shndx(&self) -> u16 { self.0.shndx }
134            fn value(&self) -> u64 { self.0.value as u64 }
135            fn size(&self) -> u64 { self.0.size as u64 }
136        }
137    }
138}
139impl_entry!(Entry32 with ElfFile::get_string);
140impl_entry!(Entry64 with ElfFile::get_string);
141impl_entry!(DynEntry32 with ElfFile::get_dyn_string);
142impl_entry!(DynEntry64 with ElfFile::get_dyn_string);
143
144#[derive(Copy, Clone, Debug)]
145pub struct Visibility_(u8);
146
147#[derive(Copy, Clone, Debug)]
148#[repr(u8)]
149pub enum Visibility {
150    Default = 0,
151    Internal = 1,
152    Hidden = 2,
153    Protected = 3,
154}
155
156impl Visibility_ {
157    pub fn as_visibility(self) -> Visibility {
158        match self.0 & 0x3 {
159            x if x == Visibility::Default as _ => Visibility::Default,
160            x if x == Visibility::Internal as _ => Visibility::Internal,
161            x if x == Visibility::Hidden as _ => Visibility::Hidden,
162            x if x == Visibility::Protected as _ => Visibility::Protected,
163            _ => unreachable!(),
164        }
165    }
166}
167
168#[derive(Copy, Clone, Debug)]
169pub struct Binding_(u8);
170
171#[derive(Copy, Clone, Debug, PartialEq, Eq)]
172pub enum Binding {
173    Local,
174    Global,
175    Weak,
176    OsSpecific(u8),
177    ProcessorSpecific(u8),
178}
179
180impl Binding_ {
181    pub fn as_binding(self) -> Result<Binding, &'static str> {
182        match self.0 {
183            0 => Ok(Binding::Local),
184            1 => Ok(Binding::Global),
185            2 => Ok(Binding::Weak),
186            b if (10..=12).contains(&b) => Ok(Binding::OsSpecific(b)),
187            b if (13..=15).contains(&b) => Ok(Binding::ProcessorSpecific(b)),
188            _ => Err("Invalid value for binding"),
189        }
190    }
191}
192
193// TODO should use a procedural macro for generating these things
194#[derive(Copy, Clone, Debug)]
195pub struct Type_(u8);
196
197#[derive(Copy, Clone, Debug, PartialEq, Eq)]
198pub enum Type {
199    NoType,
200    Object,
201    Func,
202    Section,
203    File,
204    Common,
205    Tls,
206    OsSpecific(u8),
207    ProcessorSpecific(u8),
208}
209
210impl Type_ {
211    pub fn as_type(self) -> Result<Type, &'static str> {
212        match self.0 {
213            0 => Ok(Type::NoType),
214            1 => Ok(Type::Object),
215            2 => Ok(Type::Func),
216            3 => Ok(Type::Section),
217            4 => Ok(Type::File),
218            5 => Ok(Type::Common),
219            6 => Ok(Type::Tls),
220            b if (10..=12).contains(&b) => Ok(Type::OsSpecific(b)),
221            b if (13..=15).contains(&b) => Ok(Type::ProcessorSpecific(b)),
222            _ => Err("Invalid value for type"),
223        }
224    }
225}