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