source: soft/giet_vm/memo/src/libelfpp/elfpp_object.cc @ 249

Last change on this file since 249 was 238, checked in by alain, 12 years ago

Major evolution to support physical addresses larger than 32 bits.
The map.xml format has been modified: the vsegs associated to schedulers
are now explicitely defined and mapped in the page tables.

File size: 8.6 KB
Line 
1/*
2    This file is part of Libelfpp.
3
4    Libelfpp is free software: you can redistribute it and/or modify
5    it under the terms of the GNU Lesser General Public License as
6    published by the Free Software Foundation, either version 3 of the
7    License, or (at your option) any later version.
8
9    Libelfpp is distributed in the hope that it will be useful, but
10    WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    General Public License for more details.
13
14    You should have received a copy of the GNU Lesser General Public
15    License along with Libelfpp.  If not, see
16    <http://www.gnu.org/licenses/>.
17
18   Copyright (c) Alexandre Becoulet <alexandre.becoulet@free.fr>
19*/
20
21
22#include <stdexcept>
23#include <cstring>
24
25#include <dpp/foreach>
26#include <dpp/interval_set>
27
28#include <elfpp/object>
29#include <elfpp/access>
30#include <elfpp/section>
31#include <elfpp/segment>
32#include <elfpp/symbol>
33#include <elfpp/reloc>
34
35namespace elfpp
36{
37
38  ei_class_e object::get_word_width(e_machine_e machine)
39  {
40    switch (machine)
41      {
42      case EM_386:
43        return ELFCLASS32;
44
45      case EM_X86_64:
46        return ELFCLASS64;
47
48      default:
49        throw std::runtime_error("unable to guess machine word width");
50      }
51  }
52
53  ei_data_e object::get_byte_order(e_machine_e machine)
54  {
55    switch (machine)
56      {
57      case EM_SPARC:
58        return ELFDATA2MSB;
59
60      case EM_X86_64:
61      case EM_386:
62        return ELFDATA2LSB;
63
64      default:
65        throw std::runtime_error("unable to guess machine byte order");
66      }
67  }
68
69  object::object(e_machine_e machine,
70                 ei_class_e word_width,
71                 ei_data_e byte_order)
72    : section_tab_(),
73      os_abi_(ELFOSABI_SYSV),
74      type_(ET_REL),
75      machine_(machine),
76      generate_symtab_(true),
77      entry_(0),
78      flags_(0)
79  {
80    switch (machine)
81      {
82      case EM_X86_64:
83      case EM_386:
84        rel_with_addend_ = false;
85        break;
86
87      default:
88        rel_with_addend_ = true;
89        break;
90      }
91
92    if (byte_order == ELFDATANONE)
93      byte_order = get_byte_order(machine);
94
95    if (word_width == ELFCLASSNONE)
96      word_width = get_word_width(machine);
97
98    switch (word_width)
99    {
100        case ELFCLASS32: {
101          static elf32_access a;
102          access_ = static_cast<elf_access*>(&a);
103          break;
104        }
105
106        case ELFCLASS64: {
107          static elf64_access a;
108          access_ = static_cast<elf_access*>(&a);
109          break;
110        }
111
112        default:
113          throw std::runtime_error("bad elf class");
114        }
115
116
117  }
118
119  object::object()
120    : section_tab_(),
121      os_abi_(ELFOSABI_SYSV),
122      type_(ET_REL),
123      machine_(EM_NONE),
124      generate_symtab_(true),
125      entry_(0),
126      flags_(0)
127  {}
128
129   
130
131  void object::copy_info(object& obj, size_t word_width)
132  {
133
134        if(word_width == 32)
135                this->word_width_  = ELFCLASS32;
136        else if(word_width == 64)
137            this->word_width_  =  ELFCLASS64;
138        else
139            this->word_width_  = obj.word_width_ ;
140
141    this->byteorder_  = obj.byteorder_ ;
142    this->machine_  = obj.machine_ ;
143    this->os_abi_   = obj.os_abi_ ;
144    this->abi_ver_  = obj.abi_ver_ ;
145    this->type_     = obj.type_ ;
146    this->flags_    = obj.flags_ ;
147
148    switch (this->word_width_)
149    {
150        case ELFCLASS32: {
151          static elf32_access a;
152          access_ = static_cast<elf_access*>(&a);
153          break;
154        }
155
156        case ELFCLASS64: {
157          static elf64_access a;
158          access_ = static_cast<elf_access*>(&a);
159          break;
160        }
161
162        default:
163          throw std::runtime_error("bad elf class");
164        }
165
166  }
167
168  object::object(const std::string &filename)
169    : generate_symtab_(false)
170  {
171    FILE *file = fopen(filename.c_str(), "rb");
172
173    if (!file)
174      throw std::runtime_error("unable to open file");
175
176    unsigned char       e_ident[EI_NIDENT];     /* Magic number and other info */
177
178    if (fread(e_ident, EI_NIDENT, 1, file) != 1)
179      throw std::runtime_error("unable to read file");
180
181    try {
182
183      if (std::memcmp(e_ident, ELFMAG, 4))
184        throw std::runtime_error("bad elf file header");
185
186      switch (e_ident[EI_CLASS])
187        {
188        case ELFCLASS32: {
189          static elf32_access a;
190          access_ = static_cast<elf_access*>(&a);
191          break;
192        }
193
194        case ELFCLASS64: {
195          static elf64_access a;
196          access_ = static_cast<elf_access*>(&a);
197          break;
198        }
199
200        default:
201          throw std::runtime_error("bad elf class");
202        }
203
204      access_->read(*this, file);
205
206    } catch (...) {
207      fclose(file);
208      throw;
209    }
210
211    fclose(file);
212  }
213
214  object::~object()
215  {
216    FOREACH2(s, section_tab_)
217      delete &*s;
218
219    FOREACH(s, sym_tab_)
220      delete s->second;
221  }
222
223    e_machine_e object::get_machine()
224    {
225        return machine_;
226    }
227    ei_class_e object::get_word_width()
228    {
229        return  word_width_;
230    }
231    ei_data_e object::get_byteorder()
232    {
233        return byteorder_;
234    }
235
236  section & object::get_section(const std::string &name)
237  {
238    FOREACH(s, section_tab_)
239      if (s->get_name() == name)
240        return *s;
241
242    throw std::runtime_error("no such section");
243  }
244
245  void object::parse_symbol_table()
246  {
247    access_->load_symtab(*this);
248    access_->load_reltab(*this);
249  }
250
251  void object::set_relative_relocs(symbol *sym)
252  {
253    // find mangled symbol for each relocation and set offset relative
254    // to symbol value.
255    FOREACH2(k, sym->get_reloc_table())
256      {
257        if (k->get_mangled_symbol())
258          continue;
259
260        if (sym->get_type() == STT_SECTION)
261          {
262            section *sS = sym->get_section();
263            int64_t addend = k->get_addend();
264            try {
265              symbol &ss = sS->get_symbol(addend);
266              k->set_symbol(&ss);
267              k->set_addend(addend - ss.get_value());
268            } catch (std::runtime_error &e) {
269#if 0
270              std::cerr << e.what() << " at " << sS->get_name() << ":" << std::hex << addend
271                        << " while resolving section symbol addend at "
272                        << k->get_section()->get_name() << ":" << k->get_offset() << " type " << k->get_type() << std::endl;
273#endif
274            }
275          }
276
277        try {
278          symbol &msym = k->get_section()->get_symbol(k->get_offset());
279          // std::cerr << *i->second << " " << msym << std::endl;
280          k->set_mangled_symbol(&msym);
281          k->set_offset(k->get_offset() - msym.get_value());
282
283        } catch (std::runtime_error &e) {
284#if 0
285          if (strncmp(k->get_section()->get_name().c_str(), ".debug", 6))
286            std::cerr << e.what() << " at " << k->get_section()->get_name() << ":" << std::hex << k->get_offset() << std::endl;
287#endif
288        }
289
290      }
291  }
292
293  void object::create_orphan_symbols()
294  {
295    FOREACH(s, get_section_table())
296      {
297        if (!(s->get_flags() & SHF_ALLOC))
298          continue;
299
300        typedef dpp::interval_set<uint32_t> is_t;
301        is_t is;
302
303        is |= is_t::interval_type(s->get_size(), (uint32_t)-1);
304
305        FOREACH(i, s->get_symbol_table())
306          {
307            uint32_t val = i->second->get_value();
308            size_t size = i->second->get_size();
309
310            if (size)
311              is |= is_t::interval_type(val, val + size);
312          }
313
314        is = ~is;
315
316        // create symbols for all orphan section areas in this object
317        FOREACH(i, is)
318          {
319            static int nosym_id = 0;
320            char name[32];
321            sprintf(name, "nosym_%i", nosym_id++);
322            symbol *sym = new symbol(name);
323
324            sym->set_value(i->low_bound());
325            sym->set_size(i->high_bound() - i->low_bound());
326            sym->set_section(*s);
327            s->add_symbol(*sym);
328          }
329      }
330  }
331
332  void object::load_symbol_data()
333  {
334    FOREACH(s, get_section_table())
335      {
336        if (s->get_type() == SHT_NOBITS)
337          continue;
338
339        FOREACH(i, s->get_symbol_table())
340          {
341            symbol *j = i->second;
342
343            // copy section data in each symbol content buffer
344            size_t size = j->get_size();
345
346            if (size != 0 && j->get_value() + size <= s->get_size())
347              j->set_content(s->get_content() + j->get_value());
348          }
349      }
350  }
351
352  void object::set_relative_relocs()
353  {
354    FOREACH(s, get_section_table())
355      {
356        FOREACH(i, s->get_symbol_table())
357          set_relative_relocs(i->second);
358      }
359
360    FOREACH(i, get_symbol_table())
361      set_relative_relocs(i->second);
362  }
363
364  void object::write(const std::string &filename)
365  {
366    FILE *file = fopen(filename.c_str(), "wb");
367
368    if (!file)
369      throw std::runtime_error("unable to open file");
370
371    try {
372      access_->write(*this, file);
373    } catch (...) {
374      fclose(file);
375      throw;
376    }
377
378    fclose(file);
379  }
380
381  void object::add_section(section &sec)
382  {
383    section_tab_.push_back(sec);
384  }
385
386  void object::add_segment(segment &seg)
387  {
388    segment_tab_.push_back(seg);
389  }
390
391  void object::remove_section(section &sec)
392  {
393    sec.remove();
394  }
395
396  void object::add_symbol(symbol &sym)
397  {
398#if 0
399    if (sym.get_section())
400      sym.get_section()->add_symbol(sym);
401    else
402#endif
403      sym_tab_.insert(sym_tab_map_t::value_type(sym.get_name(), &sym));
404  }
405
406  void object::remove_symbol(symbol &sym)
407  {
408    sym_tab_.erase(sym.get_name());
409  }
410
411}
412
Note: See TracBrowser for help on using the repository browser.