elfkit/
symbol.rs

1use std::io::{Read, Write};
2use {types, Error, Header, SectionContent};
3use utils::hextab;
4use num_traits::{FromPrimitive, ToPrimitive};
5use strtab::Strtab;
6use section::{Section, SectionHeader};
7use std::fmt;
8
9#[derive(Debug, Clone, Eq, PartialEq)]
10pub enum SymbolSectionIndex {
11    Section(u16), // 1-6551
12    Undefined,    // 0
13    Absolute,     // 65521,
14    Common,       // 6552,
15}
16impl Default for SymbolSectionIndex {
17    fn default() -> SymbolSectionIndex {
18        SymbolSectionIndex::Undefined
19    }
20}
21
22#[derive(Default, Clone)]
23pub struct Symbol {
24    pub shndx:  SymbolSectionIndex,
25    pub value:  u64,
26    pub size:   u64,
27
28    pub name:   Vec<u8>,
29    pub stype:  types::SymbolType,
30    pub bind:   types::SymbolBind,
31    pub vis:    types::SymbolVis,
32
33    pub _name:  u32,
34}
35
36impl fmt::Debug for Symbol {
37    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
38        write!(f,
39               "  {} {:>5.5} {:<7.7} {:<6.6} {:<8.8} {:<3.3} {} ",
40               hextab(16, self.value),
41               self.size,
42               format!("{:?}", self.stype),
43               format!("{:?}", self.bind),
44               format!("{:?}", self.vis),
45               match self.shndx {
46                   SymbolSectionIndex::Undefined => String::from("UND"),
47                   SymbolSectionIndex::Absolute => String::from("ABS"),
48                   SymbolSectionIndex::Common => String::from("COM"),
49                   SymbolSectionIndex::Section(i) => format!("{}", i),
50               },
51               String::from_utf8_lossy(&self.name)
52              )
53    }
54}
55
56impl Symbol {
57    fn from_val(
58        tab:    Option<&Strtab>,
59        _name:  u32,
60        info:   u8,
61        other:  u8,
62        shndx:  u16,
63        value:  u64,
64        size:   u64,
65    ) -> Result<Symbol, Error> {
66        let name = match tab {
67            Some(tab) => tab.get(_name as usize),
68            None => Vec::default(),
69        };
70
71        let shndx = match shndx {
72            0 => SymbolSectionIndex::Undefined,
73            65521 => SymbolSectionIndex::Absolute,
74            65522 => SymbolSectionIndex::Common,
75            _ if shndx > 0 && shndx < 6552 => SymbolSectionIndex::Section(shndx),
76            _ => return Err(Error::InvalidSymbolShndx(String::from_utf8_lossy(&name).into_owned(), shndx)),
77        };
78
79        let reb = info & 0xf;
80        let stype = match types::SymbolType::from_u8(reb) {
81            Some(v) => v,
82            None => return Err(Error::InvalidSymbolType(reb)),
83        };
84
85        let reb = info >> 4;
86        let bind = match types::SymbolBind::from_u8(reb) {
87            Some(v) => v,
88            None => return Err(Error::InvalidSymbolBind(reb)),
89        };
90
91        let reb = other & 0x3;
92        let vis = match types::SymbolVis::from_u8(reb) {
93            Some(v) => v,
94            None => return Err(Error::InvalidSymbolVis(reb)),
95        };
96
97        Ok(Symbol {
98            shndx: shndx,
99            value: value,
100            size: size,
101
102            name: name,
103            stype: stype,
104            bind: bind,
105            vis: vis,
106
107            _name: _name,
108        })
109    }
110
111    pub fn entsize(eh: &Header) -> usize {
112        match eh.ident_class {
113            types::Class::Class64 => 24,
114            types::Class::Class32 => 16,
115        }
116    }
117
118    pub fn from_reader<R>(
119        mut io: R,
120        linked: Option<&SectionContent>,
121        eh: &Header,
122    ) -> Result<SectionContent, Error>
123    where
124        R: Read,
125    {
126        let tab = match linked {
127            None => None,
128            Some(&SectionContent::Strtab(ref s)) => Some(s),
129            any => return Err(Error::LinkedSectionIsNotStrtab{
130                during: "reading symbols",
131                link: any.map(|v|v.clone()),
132            }),
133        };
134
135        let mut r = Vec::new();
136        let mut b = vec![0; Self::entsize(eh)];
137        while io.read(&mut b)? > 0 {
138            let mut br = &b[..];
139            elf_dispatch_endianness!(eh => {
140                let _name = read_u32(&mut br)?;
141                r.push(match eh.ident_class {
142                    types::Class::Class64 => {
143                        let info = b[4];
144                        let other = b[5];
145                        br = &b[6..];
146                        let shndx = read_u16(&mut br)?;
147                        let value = read_u64(&mut br)?;
148                        let size  = read_u64(&mut br)?;
149
150                        Symbol::from_val(tab, _name, info, other, shndx, value, size)?
151                    }
152                    types::Class::Class32 => {
153                        let value = read_u32(&mut br)?;
154                        let size  = read_u32(&mut br)?;
155                        let info  = b[12];
156                        let other = b[13];
157                        br = &b[14..];
158                        let shndx = read_u16(&mut br)?;
159
160                        Symbol::from_val(tab, _name, info, other, shndx, value as u64, size as u64)?
161                    }
162                })
163            })
164        }
165
166        Ok(SectionContent::Symbols(r))
167    }
168
169    pub fn to_writer<W>(
170        &self,
171        mut io: W,
172        eh: &Header,
173    ) -> Result<(usize), Error>
174    where
175        W: Write,
176    {
177        let info = (self.bind.to_u8().unwrap() << 4) + (self.stype.to_u8().unwrap() & 0xf);
178        let other = self.vis.to_u8().unwrap();
179
180        let shndx = match self.shndx {
181            SymbolSectionIndex::Section(i) => i,
182            SymbolSectionIndex::Undefined => 0,
183            SymbolSectionIndex::Absolute => 65521,
184            SymbolSectionIndex::Common => 65522,
185        };
186
187        elf_write_u32!(eh, io, self._name)?;
188
189        Ok(match eh.ident_class {
190            types::Class::Class64 => {
191                io.write(&[info, other])?;
192                elf_write_u16!(eh, io, shndx)?;
193                elf_write_u64!(eh, io, self.value)?;
194                elf_write_u64!(eh, io, self.size)?;
195
196                2+2+8+8
197            }
198            types::Class::Class32 => {
199                elf_write_u32!(eh, io, self.value as u32)?;
200                elf_write_u32!(eh, io, self.size as u32)?;
201                io.write(&[info, other])?;
202                elf_write_u16!(eh, io, shndx)?;
203
204                4+4+2+2
205            }
206        })
207    }
208
209    pub fn sync(&mut self, linked: Option<&mut SectionContent>, _: &Header) -> Result<(), Error> {
210        match linked {
211            Some(&mut SectionContent::Strtab(ref mut strtab)) => {
212                self._name = strtab.insert(&self.name) as u32;
213            }
214            any => return Err(Error::LinkedSectionIsNotStrtab{
215                during: "syncing symbols",
216                link: any.map(|v|v.clone()),
217            }),
218        }
219        Ok(())
220    }
221}
222
223pub fn sysv_hash(s: &String) -> u64 {
224    let mut h: u64 = 0;
225    let mut g: u64;
226
227    for byte in s.bytes() {
228        h = (h << 4) + byte as u64;
229        g = h & 0xf0000000;
230        if g > 0 {
231            h ^= g >> 24;
232        }
233        h &= !g;
234    }
235    return h;
236}
237
238
239pub fn symhash(eh: &Header, symbols: &Vec<Symbol>, link: u32) -> Result<Section, Error> {
240    assert!(symbols.len() > 0);
241    //TODO i'm too lazy to do this correctly now, so we'll just emit a hashtable with nbuckets  == 1
242    let mut b = Vec::new();
243    {
244        let io = &mut b;
245        elf_write_uclass!(eh, io, 1)?; //nbuckets
246        elf_write_uclass!(eh, io, symbols.len() as u64)?; //nchains
247
248        elf_write_uclass!(eh, io, 1)?; //the bucket. pointing at symbol 1
249
250        elf_write_uclass!(eh, io, 0)?; //symbol 0
251
252        //the chains. every symbol just points at the next, because nbuckets == 1
253        for i in 1..symbols.len() - 1 {
254            elf_write_uclass!(eh, io, i as u64 + 1)?;
255        }
256
257        //except the last one
258        elf_write_uclass!(eh, io, 0)?;
259    }
260
261    Ok(Section {
262        name: b".hash".to_vec(),
263        header: SectionHeader {
264            name: 0,
265            shtype: types::SectionType::HASH,
266            flags: types::SectionFlags::ALLOC,
267            addr: 0,
268            offset: 0,
269            size: b.len() as u64,
270            link: link,
271            info: 0,
272            addralign: 0,
273            entsize: 8, // or 4 for CLass32
274        },
275        content: SectionContent::Raw(b),
276        addrlock: false,
277    })
278}