synth_elf.cc revision 8ade75f9558e31d25aec862a552fe78f9ba98c82
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 8namespace google_breakpad { 9namespace synth_elf { 10 11#ifndef NT_GNU_BUILD_ID 12#define NT_GNU_BUILD_ID 3 13#endif 14 15ELF::ELF(uint16_t machine, 16 uint8_t file_class, 17 Endianness endianness) 18 : Section(endianness), 19 addr_size_(file_class == ELFCLASS64 ? 8 : 4), 20 program_count_(0), 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 84int 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 // NULL and NOBITS sections have no content, so they 117 // don't need to be written to the file. 118 if (type == SHT_NULL) { 119 offset_label = 0; 120 } else if (type == SHT_NOBITS) { 121 offset_label = offset; 122 } else { 123 Mark(&offset_label); 124 Append(section); 125 Align(4); 126 } 127 return index; 128} 129 130void ELF::Finish() { 131 // Add the section header string table at the end. 132 section_header_string_index_ = section_count_; 133 //printf(".shstrtab size: %ld\n", section_header_strings_.Size()); 134 AddSection(".shstrtab", section_header_strings_, SHT_STRTAB); 135 //printf("section_count_: %ld, sections_.size(): %ld\n", 136 // section_count_, sections_.size()); 137 section_count_label_ = section_count_; 138 program_count_label_ = program_count_; 139 // TODO: allow adding entries to program header table 140 program_header_label_ = 0; 141 142 // Section header table starts here. 143 Mark(§ion_header_label_); 144 Append(section_header_table_); 145} 146 147SymbolTable::SymbolTable(Endianness endianness, 148 size_t addr_size, 149 StringTable& table) : Section(endianness), 150 addr_size_(addr_size), 151 table_(table) { 152 assert(addr_size_ == 4 || addr_size_ == 8); 153} 154 155void SymbolTable::AddSymbol(const string& name, uint32_t value, 156 uint32_t size, unsigned info, uint16_t shndx) { 157 assert(addr_size_ == 4); 158 D32(table_.Add(name)); 159 D32(value); 160 D32(size); 161 D8(info); 162 D8(0); // other 163 D16(shndx); 164} 165 166void SymbolTable::AddSymbol(const string& name, uint64_t value, 167 uint64_t size, unsigned info, uint16_t shndx) { 168 assert(addr_size_ == 8); 169 D32(table_.Add(name)); 170 D8(info); 171 D8(0); // other 172 D16(shndx); 173 D64(value); 174 D64(size); 175} 176 177BuildIDNote::BuildIDNote(const uint8_t* id_bytes, 178 size_t id_size, 179 Endianness endianness) : Section(endianness) { 180 const char kNoteName[] = "GNU"; 181 // Elf32_Nhdr and Elf64_Nhdr are exactly the same. 182 Elf32_Nhdr note_header; 183 memset(¬e_header, 0, sizeof(note_header)); 184 note_header.n_namesz = sizeof(kNoteName); 185 note_header.n_descsz = id_size; 186 note_header.n_type = NT_GNU_BUILD_ID; 187 188 Append(reinterpret_cast<const uint8_t*>(¬e_header), 189 sizeof(note_header)); 190 AppendCString(kNoteName); 191 Append(id_bytes, id_size); 192} 193 194// static 195void BuildIDNote::AppendSection(ELF& elf, 196 const uint8_t* id_bytes, 197 size_t id_size) { 198 const char kBuildIDSectionName[] = ".note.gnu.build-id"; 199 BuildIDNote note(id_bytes, id_size, elf.endianness()); 200 elf.AddSection(kBuildIDSectionName, note, SHT_NOTE); 201} 202 203} // namespace synth_elf 204} // namespace google_breakpad 205