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