Home | History | Annotate | Download | only in linux
      1 #include "common/linux/synth_elf.h"
      2 
      3 #include <assert.h>
      4 #include <elf.h>
      5 #include <stdio.h>
      6 #include <string.h>
      7 
      8 #include "common/linux/elf_gnu_compat.h"
      9 #include "common/using_std_string.h"
     10 
     11 namespace google_breakpad {
     12 namespace synth_elf {
     13 
     14 ELF::ELF(uint16_t machine,
     15          uint8_t file_class,
     16          Endianness endianness)
     17   : Section(endianness),
     18     addr_size_(file_class == ELFCLASS64 ? 8 : 4),
     19     program_count_(0),
     20     program_header_table_(endianness),
     21     section_count_(0),
     22     section_header_table_(endianness),
     23     section_header_strings_(endianness) {
     24   // Could add support for more machine types here if needed.
     25   assert(machine == EM_386 ||
     26          machine == EM_X86_64 ||
     27          machine == EM_ARM);
     28   assert(file_class == ELFCLASS32 || file_class == ELFCLASS64);
     29 
     30   start() = 0;
     31   // Add ELF header
     32   // e_ident
     33   // EI_MAG0...EI_MAG3
     34   D8(ELFMAG0);
     35   D8(ELFMAG1);
     36   D8(ELFMAG2);
     37   D8(ELFMAG3);
     38   // EI_CLASS
     39   D8(file_class);
     40   // EI_DATA
     41   D8(endianness == kLittleEndian ? ELFDATA2LSB : ELFDATA2MSB);
     42   // EI_VERSION
     43   D8(EV_CURRENT);
     44   // EI_OSABI
     45   D8(ELFOSABI_SYSV);
     46   // EI_ABIVERSION
     47   D8(0);
     48   // EI_PAD
     49   Append(7, 0);
     50   assert(Size() == EI_NIDENT);
     51 
     52   // e_type
     53   D16(ET_EXEC);  //TODO: allow passing ET_DYN?
     54   // e_machine
     55   D16(machine);
     56   // e_version
     57   D32(EV_CURRENT);
     58   // e_entry
     59   Append(endianness, addr_size_, 0);
     60   // e_phoff
     61   Append(endianness, addr_size_, program_header_label_);
     62   // e_shoff
     63   Append(endianness, addr_size_, section_header_label_);
     64   // e_flags
     65   D32(0);
     66   // e_ehsize
     67   D16(addr_size_ == 8 ? sizeof(Elf64_Ehdr) : sizeof(Elf32_Ehdr));
     68   // e_phentsize
     69   D16(addr_size_ == 8 ? sizeof(Elf64_Phdr) : sizeof(Elf32_Phdr));
     70   // e_phnum
     71   D16(program_count_label_);
     72   // e_shentsize
     73   D16(addr_size_ == 8 ? sizeof(Elf64_Shdr) : sizeof(Elf32_Shdr));
     74   // e_shnum
     75   D16(section_count_label_);
     76   // e_shstrndx
     77   D16(section_header_string_index_);
     78 
     79   // Add an empty section for SHN_UNDEF.
     80   Section shn_undef;
     81   AddSection("", shn_undef, SHT_NULL);
     82 }
     83 
     84 int ELF::AddSection(const string& name, const Section& section,
     85                     uint32_t type, uint32_t flags, uint64_t addr,
     86                     uint32_t link, uint64_t entsize, uint64_t offset) {
     87   Label offset_label;
     88   Label string_label(section_header_strings_.Add(name));
     89   size_t size = section.Size();
     90 
     91   int index = section_count_;
     92   ++section_count_;
     93 
     94   section_header_table_
     95     // sh_name
     96     .D32(string_label)
     97     // sh_type
     98     .D32(type)
     99     // sh_flags
    100     .Append(endianness(), addr_size_, flags)
    101     // sh_addr
    102     .Append(endianness(), addr_size_, addr)
    103     // sh_offset
    104     .Append(endianness(), addr_size_, offset_label)
    105     // sh_size
    106     .Append(endianness(), addr_size_, size)
    107     // sh_link
    108     .D32(link)
    109     // sh_info
    110     .D32(0)
    111     // sh_addralign
    112     .Append(endianness(), addr_size_, 0)
    113     // sh_entsize
    114     .Append(endianness(), addr_size_, entsize);
    115 
    116   sections_.push_back(ElfSection(section, type, addr, offset, offset_label,
    117                                  size));
    118   return index;
    119 }
    120 
    121 void ELF::AppendSection(ElfSection &section) {
    122   // NULL and NOBITS sections have no content, so they
    123   // don't need to be written to the file.
    124   if (section.type_ == SHT_NULL) {
    125     section.offset_label_ = 0;
    126   } else if (section.type_ == SHT_NOBITS) {
    127     section.offset_label_ = section.offset_;
    128   } else {
    129     Mark(&section.offset_label_);
    130     Append(section);
    131     Align(4);
    132   }
    133 }
    134 
    135 void ELF::AddSegment(int start, int end, uint32_t type, uint32_t flags) {
    136   assert(start > 0);
    137   assert(size_t(start) < sections_.size());
    138   assert(end > 0);
    139   assert(size_t(end) < sections_.size());
    140   ++program_count_;
    141 
    142   // p_type
    143   program_header_table_.D32(type);
    144 
    145   if (addr_size_ == 8) {
    146     // p_flags
    147     program_header_table_.D32(flags);
    148   }
    149 
    150   size_t filesz = 0;
    151   size_t memsz = 0;
    152   bool prev_was_nobits = false;
    153   for (int i = start; i <= end; ++i) {
    154     size_t size = sections_[i].size_;
    155     if (sections_[i].type_ != SHT_NOBITS) {
    156       assert(!prev_was_nobits);
    157       // non SHT_NOBITS sections are 4-byte aligned (see AddSection)
    158       size = (size + 3) & ~3;
    159       filesz += size;
    160     } else {
    161       prev_was_nobits = true;
    162     }
    163     memsz += size;
    164   }
    165 
    166   program_header_table_
    167     // p_offset
    168     .Append(endianness(), addr_size_, sections_[start].offset_label_)
    169     // p_vaddr
    170     .Append(endianness(), addr_size_, sections_[start].addr_)
    171     // p_paddr
    172     .Append(endianness(), addr_size_, sections_[start].addr_)
    173     // p_filesz
    174     .Append(endianness(), addr_size_, filesz)
    175     // p_memsz
    176     .Append(endianness(), addr_size_, memsz);
    177 
    178   if (addr_size_ == 4) {
    179     // p_flags
    180     program_header_table_.D32(flags);
    181   }
    182 
    183   // p_align
    184   program_header_table_.Append(endianness(), addr_size_, 0);
    185 }
    186 
    187 void ELF::Finish() {
    188   // Add the section header string table at the end.
    189   section_header_string_index_ = section_count_;
    190   //printf(".shstrtab size: %ld\n", section_header_strings_.Size());
    191   AddSection(".shstrtab", section_header_strings_, SHT_STRTAB);
    192   //printf("section_count_: %ld, sections_.size(): %ld\n",
    193   //     section_count_, sections_.size());
    194   if (program_count_) {
    195     Mark(&program_header_label_);
    196     Append(program_header_table_);
    197   } else {
    198     program_header_label_ = 0;
    199   }
    200 
    201   for (vector<ElfSection>::iterator it = sections_.begin();
    202        it < sections_.end(); ++it) {
    203     AppendSection(*it);
    204   }
    205   section_count_label_ = section_count_;
    206   program_count_label_ = program_count_;
    207 
    208   // Section header table starts here.
    209   Mark(&section_header_label_);
    210   Append(section_header_table_);
    211 }
    212 
    213 SymbolTable::SymbolTable(Endianness endianness,
    214                          size_t addr_size,
    215                          StringTable& table) : Section(endianness),
    216                                                addr_size_(addr_size),
    217                                                table_(table) {
    218   assert(addr_size_ == 4 || addr_size_ == 8);
    219 }
    220 
    221 void SymbolTable::AddSymbol(const string& name, uint32_t value,
    222                             uint32_t size, unsigned info, uint16_t shndx) {
    223   assert(addr_size_ == 4);
    224   D32(table_.Add(name));
    225   D32(value);
    226   D32(size);
    227   D8(info);
    228   D8(0); // other
    229   D16(shndx);
    230 }
    231 
    232 void SymbolTable::AddSymbol(const string& name, uint64_t value,
    233                             uint64_t size, unsigned info, uint16_t shndx) {
    234   assert(addr_size_ == 8);
    235   D32(table_.Add(name));
    236   D8(info);
    237   D8(0); // other
    238   D16(shndx);
    239   D64(value);
    240   D64(size);
    241 }
    242 
    243 void Notes::AddNote(int type, const string &name, const uint8_t* desc_bytes,
    244                     size_t desc_size) {
    245   // Elf32_Nhdr and Elf64_Nhdr are exactly the same.
    246   Elf32_Nhdr note_header;
    247   memset(&note_header, 0, sizeof(note_header));
    248   note_header.n_namesz = name.length() + 1;
    249   note_header.n_descsz = desc_size;
    250   note_header.n_type = type;
    251 
    252   Append(reinterpret_cast<const uint8_t*>(&note_header),
    253          sizeof(note_header));
    254   AppendCString(name);
    255   Align(4);
    256   Append(desc_bytes, desc_size);
    257   Align(4);
    258 }
    259 
    260 }  // namespace synth_elf
    261 }  // namespace google_breakpad
    262