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