michael@0: #include "common/linux/synth_elf.h" michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: #include "common/using_std_string.h" michael@0: michael@0: namespace google_breakpad { michael@0: namespace synth_elf { michael@0: michael@0: #ifndef NT_GNU_BUILD_ID michael@0: #define NT_GNU_BUILD_ID 3 michael@0: #endif michael@0: michael@0: ELF::ELF(uint16_t machine, michael@0: uint8_t file_class, michael@0: Endianness endianness) michael@0: : Section(endianness), michael@0: addr_size_(file_class == ELFCLASS64 ? 8 : 4), michael@0: program_count_(0), michael@0: program_header_table_(endianness), michael@0: section_count_(0), michael@0: section_header_table_(endianness), michael@0: section_header_strings_(endianness) { michael@0: // Could add support for more machine types here if needed. michael@0: assert(machine == EM_386 || michael@0: machine == EM_X86_64 || michael@0: machine == EM_ARM); michael@0: assert(file_class == ELFCLASS32 || file_class == ELFCLASS64); michael@0: michael@0: start() = 0; michael@0: // Add ELF header michael@0: // e_ident michael@0: // EI_MAG0...EI_MAG3 michael@0: D8(ELFMAG0); michael@0: D8(ELFMAG1); michael@0: D8(ELFMAG2); michael@0: D8(ELFMAG3); michael@0: // EI_CLASS michael@0: D8(file_class); michael@0: // EI_DATA michael@0: D8(endianness == kLittleEndian ? ELFDATA2LSB : ELFDATA2MSB); michael@0: // EI_VERSION michael@0: D8(EV_CURRENT); michael@0: // EI_OSABI michael@0: D8(ELFOSABI_SYSV); michael@0: // EI_ABIVERSION michael@0: D8(0); michael@0: // EI_PAD michael@0: Append(7, 0); michael@0: assert(Size() == EI_NIDENT); michael@0: michael@0: // e_type michael@0: D16(ET_EXEC); //TODO: allow passing ET_DYN? michael@0: // e_machine michael@0: D16(machine); michael@0: // e_version michael@0: D32(EV_CURRENT); michael@0: // e_entry michael@0: Append(endianness, addr_size_, 0); michael@0: // e_phoff michael@0: Append(endianness, addr_size_, program_header_label_); michael@0: // e_shoff michael@0: Append(endianness, addr_size_, section_header_label_); michael@0: // e_flags michael@0: D32(0); michael@0: // e_ehsize michael@0: D16(addr_size_ == 8 ? sizeof(Elf64_Ehdr) : sizeof(Elf32_Ehdr)); michael@0: // e_phentsize michael@0: D16(addr_size_ == 8 ? sizeof(Elf64_Phdr) : sizeof(Elf32_Phdr)); michael@0: // e_phnum michael@0: D16(program_count_label_); michael@0: // e_shentsize michael@0: D16(addr_size_ == 8 ? sizeof(Elf64_Shdr) : sizeof(Elf32_Shdr)); michael@0: // e_shnum michael@0: D16(section_count_label_); michael@0: // e_shstrndx michael@0: D16(section_header_string_index_); michael@0: michael@0: // Add an empty section for SHN_UNDEF. michael@0: Section shn_undef; michael@0: AddSection("", shn_undef, SHT_NULL); michael@0: } michael@0: michael@0: int ELF::AddSection(const string& name, const Section& section, michael@0: uint32_t type, uint32_t flags, uint64_t addr, michael@0: uint32_t link, uint64_t entsize, uint64_t offset) { michael@0: Label offset_label; michael@0: Label string_label(section_header_strings_.Add(name)); michael@0: size_t size = section.Size(); michael@0: michael@0: int index = section_count_; michael@0: ++section_count_; michael@0: michael@0: section_header_table_ michael@0: // sh_name michael@0: .D32(string_label) michael@0: // sh_type michael@0: .D32(type) michael@0: // sh_flags michael@0: .Append(endianness(), addr_size_, flags) michael@0: // sh_addr michael@0: .Append(endianness(), addr_size_, addr) michael@0: // sh_offset michael@0: .Append(endianness(), addr_size_, offset_label) michael@0: // sh_size michael@0: .Append(endianness(), addr_size_, size) michael@0: // sh_link michael@0: .D32(link) michael@0: // sh_info michael@0: .D32(0) michael@0: // sh_addralign michael@0: .Append(endianness(), addr_size_, 0) michael@0: // sh_entsize michael@0: .Append(endianness(), addr_size_, entsize); michael@0: michael@0: sections_.push_back(ElfSection(section, type, addr, offset, offset_label, michael@0: size)); michael@0: return index; michael@0: } michael@0: michael@0: void ELF::AppendSection(ElfSection §ion) { michael@0: // NULL and NOBITS sections have no content, so they michael@0: // don't need to be written to the file. michael@0: if (section.type_ == SHT_NULL) { michael@0: section.offset_label_ = 0; michael@0: } else if (section.type_ == SHT_NOBITS) { michael@0: section.offset_label_ = section.offset_; michael@0: } else { michael@0: Mark(§ion.offset_label_); michael@0: Append(section); michael@0: Align(4); michael@0: } michael@0: } michael@0: michael@0: void ELF::AddSegment(int start, int end, uint32_t type, uint32_t flags) { michael@0: assert(start > 0); michael@0: assert(size_t(start) < sections_.size()); michael@0: assert(end > 0); michael@0: assert(size_t(end) < sections_.size()); michael@0: ++program_count_; michael@0: michael@0: // p_type michael@0: program_header_table_.D32(type); michael@0: michael@0: if (addr_size_ == 8) { michael@0: // p_flags michael@0: program_header_table_.D32(flags); michael@0: } michael@0: michael@0: size_t filesz = 0; michael@0: size_t memsz = 0; michael@0: bool prev_was_nobits = false; michael@0: for (int i = start; i <= end; ++i) { michael@0: size_t size = sections_[i].size_; michael@0: if (sections_[i].type_ != SHT_NOBITS) { michael@0: assert(!prev_was_nobits); michael@0: // non SHT_NOBITS sections are 4-byte aligned (see AddSection) michael@0: size = (size + 3) & ~3; michael@0: filesz += size; michael@0: } else { michael@0: prev_was_nobits = true; michael@0: } michael@0: memsz += size; michael@0: } michael@0: michael@0: program_header_table_ michael@0: // p_offset michael@0: .Append(endianness(), addr_size_, sections_[start].offset_label_) michael@0: // p_vaddr michael@0: .Append(endianness(), addr_size_, sections_[start].addr_) michael@0: // p_paddr michael@0: .Append(endianness(), addr_size_, sections_[start].addr_) michael@0: // p_filesz michael@0: .Append(endianness(), addr_size_, filesz) michael@0: // p_memsz michael@0: .Append(endianness(), addr_size_, memsz); michael@0: michael@0: if (addr_size_ == 4) { michael@0: // p_flags michael@0: program_header_table_.D32(flags); michael@0: } michael@0: michael@0: // p_align michael@0: program_header_table_.Append(endianness(), addr_size_, 0); michael@0: } michael@0: michael@0: void ELF::Finish() { michael@0: // Add the section header string table at the end. michael@0: section_header_string_index_ = section_count_; michael@0: //printf(".shstrtab size: %ld\n", section_header_strings_.Size()); michael@0: AddSection(".shstrtab", section_header_strings_, SHT_STRTAB); michael@0: //printf("section_count_: %ld, sections_.size(): %ld\n", michael@0: // section_count_, sections_.size()); michael@0: if (program_count_) { michael@0: Mark(&program_header_label_); michael@0: Append(program_header_table_); michael@0: } else { michael@0: program_header_label_ = 0; michael@0: } michael@0: michael@0: for (vector::iterator it = sections_.begin(); michael@0: it < sections_.end(); ++it) { michael@0: AppendSection(*it); michael@0: } michael@0: section_count_label_ = section_count_; michael@0: program_count_label_ = program_count_; michael@0: michael@0: // Section header table starts here. michael@0: Mark(§ion_header_label_); michael@0: Append(section_header_table_); michael@0: } michael@0: michael@0: SymbolTable::SymbolTable(Endianness endianness, michael@0: size_t addr_size, michael@0: StringTable& table) : Section(endianness), michael@0: addr_size_(addr_size), michael@0: table_(table) { michael@0: assert(addr_size_ == 4 || addr_size_ == 8); michael@0: } michael@0: michael@0: void SymbolTable::AddSymbol(const string& name, uint32_t value, michael@0: uint32_t size, unsigned info, uint16_t shndx) { michael@0: assert(addr_size_ == 4); michael@0: D32(table_.Add(name)); michael@0: D32(value); michael@0: D32(size); michael@0: D8(info); michael@0: D8(0); // other michael@0: D16(shndx); michael@0: } michael@0: michael@0: void SymbolTable::AddSymbol(const string& name, uint64_t value, michael@0: uint64_t size, unsigned info, uint16_t shndx) { michael@0: assert(addr_size_ == 8); michael@0: D32(table_.Add(name)); michael@0: D8(info); michael@0: D8(0); // other michael@0: D16(shndx); michael@0: D64(value); michael@0: D64(size); michael@0: } michael@0: michael@0: void Notes::AddNote(int type, const string &name, const uint8_t* desc_bytes, michael@0: size_t desc_size) { michael@0: // Elf32_Nhdr and Elf64_Nhdr are exactly the same. michael@0: Elf32_Nhdr note_header; michael@0: memset(¬e_header, 0, sizeof(note_header)); michael@0: note_header.n_namesz = name.length() + 1; michael@0: note_header.n_descsz = desc_size; michael@0: note_header.n_type = type; michael@0: michael@0: Append(reinterpret_cast(¬e_header), michael@0: sizeof(note_header)); michael@0: AppendCString(name); michael@0: Align(4); michael@0: Append(desc_bytes, desc_size); michael@0: Align(4); michael@0: } michael@0: michael@0: } // namespace synth_elf michael@0: } // namespace google_breakpad