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(§ion.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(§ion_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(¬e_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*>(¬e_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