|  | // Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file | 
|  | // for details. All rights reserved. Use of this source code is governed by a | 
|  | // BSD-style license that can be found in the LICENSE file. | 
|  |  | 
|  | #ifndef RUNTIME_VM_ELF_H_ | 
|  | #define RUNTIME_VM_ELF_H_ | 
|  |  | 
|  | #include "vm/allocation.h" | 
|  | #include "vm/compiler/runtime_api.h" | 
|  | #include "vm/datastream.h" | 
|  | #include "vm/growable_array.h" | 
|  | #include "vm/zone.h" | 
|  |  | 
|  | namespace dart { | 
|  |  | 
|  | class Dwarf; | 
|  | class ElfWriteStream; | 
|  | class Section; | 
|  | class Segment; | 
|  | class StringTable; | 
|  | class SymbolTable; | 
|  |  | 
|  | class Elf : public ZoneAllocated { | 
|  | public: | 
|  | enum class Type { | 
|  | // A snapshot that should include segment contents. | 
|  | Snapshot, | 
|  | // Separately compiled debugging information that should not include | 
|  | // most segment contents. | 
|  | DebugInfo, | 
|  | }; | 
|  |  | 
|  | Elf(Zone* zone, BaseWriteStream* stream, Type type, Dwarf* dwarf = nullptr); | 
|  |  | 
|  | static constexpr intptr_t kPageSize = 16 * KB; | 
|  | static constexpr uword kNoSectionStart = 0; | 
|  |  | 
|  | bool IsStripped() const { return dwarf_ == nullptr; } | 
|  |  | 
|  | Zone* zone() { return zone_; } | 
|  | const Dwarf* dwarf() const { return dwarf_; } | 
|  | Dwarf* dwarf() { return dwarf_; } | 
|  |  | 
|  | // Returns the relocated address for the symbol with the given name or | 
|  | // kNoSectionStart if the symbol was not found. | 
|  | uword SymbolAddress(const char* name) const; | 
|  |  | 
|  | // What the next memory offset for an appropriately aligned section would be. | 
|  | // | 
|  | // Only used by AssemblyImageWriter and BlobImageWriter methods. | 
|  | intptr_t NextMemoryOffset(intptr_t alignment) const; | 
|  | intptr_t AddText(const char* name, const uint8_t* bytes, intptr_t size); | 
|  | intptr_t AddROData(const char* name, const uint8_t* bytes, intptr_t size); | 
|  | void AddDebug(const char* name, const uint8_t* bytes, intptr_t size); | 
|  |  | 
|  | // Adds a local symbol for the given offset and size in the "current" section, | 
|  | // that is, the section index for the symbol is for the next added section. | 
|  | void AddLocalSymbol(const char* name, | 
|  | intptr_t type, | 
|  | intptr_t offset, | 
|  | intptr_t size); | 
|  |  | 
|  | void Finalize(); | 
|  |  | 
|  | private: | 
|  | static constexpr const char* kBuildIdNoteName = ".note.gnu.build-id"; | 
|  |  | 
|  | static Section* CreateBSS(Zone* zone, Type type, intptr_t size); | 
|  |  | 
|  | // Adds the section and also creates a PT_LOAD segment for the section if it | 
|  | // is an allocated section. | 
|  | // | 
|  | // For allocated sections, if symbol_name is provided, a symbol for the | 
|  | // section will be added to the dynamic table (if allocated) and static | 
|  | // table (if not stripped) during finalization. | 
|  | // | 
|  | // Returns the memory offset if the section is allocated. | 
|  | intptr_t AddSection(Section* section, | 
|  | const char* name, | 
|  | const char* symbol_name = nullptr); | 
|  | // Replaces [old_section] with [new_section] in all appropriate places. If the | 
|  | // section is allocated, the memory size of the section must be the same as | 
|  | // the original to ensure any already-calculated memory offsets are unchanged. | 
|  | void ReplaceSection(Section* old_section, Section* new_section); | 
|  |  | 
|  | void AddStaticSymbol(const char* name, | 
|  | intptr_t binding, | 
|  | intptr_t type, | 
|  | intptr_t section_index, | 
|  | intptr_t address, | 
|  | intptr_t size); | 
|  | void AddDynamicSymbol(const char* name, | 
|  | intptr_t binding, | 
|  | intptr_t type, | 
|  | intptr_t section_index, | 
|  | intptr_t address, | 
|  | intptr_t size); | 
|  |  | 
|  | Segment* LastLoadSegment() const; | 
|  | const Section* FindSectionForAddress(intptr_t address) const; | 
|  | Section* CreateBuildIdNote(const void* description_bytes, | 
|  | intptr_t description_length); | 
|  | Section* GenerateFinalBuildId(); | 
|  |  | 
|  | void AddSectionSymbols(); | 
|  | void FinalizeDwarfSections(); | 
|  | void FinalizeProgramTable(); | 
|  | void ComputeFileOffsets(); | 
|  |  | 
|  | void WriteHeader(ElfWriteStream* stream); | 
|  | void WriteSectionTable(ElfWriteStream* stream); | 
|  | void WriteProgramTable(ElfWriteStream* stream); | 
|  | void WriteSections(ElfWriteStream* stream); | 
|  |  | 
|  | Zone* const zone_; | 
|  | BaseWriteStream* const unwrapped_stream_; | 
|  | const Type type_; | 
|  |  | 
|  | // If nullptr, then the ELF file should be stripped of static information like | 
|  | // the static symbol table (and its corresponding string table). | 
|  | Dwarf* const dwarf_; | 
|  |  | 
|  | // We always create a BSS section for all Elf files, though it may be NOBITS | 
|  | // if this is separate debugging information. | 
|  | Section* const bss_; | 
|  |  | 
|  | // All our strings would fit in a single page. However, we use separate | 
|  | // .shstrtab and .dynstr to work around a bug in Android's strip utility. | 
|  | StringTable* const shstrtab_; | 
|  | StringTable* const dynstrtab_; | 
|  | SymbolTable* const dynsym_; | 
|  |  | 
|  | // The static tables are lazily created when static symbols are added. | 
|  | StringTable* strtab_ = nullptr; | 
|  | SymbolTable* symtab_ = nullptr; | 
|  |  | 
|  | // We always create a GNU build ID for all Elf files. In order to create | 
|  | // the appropriate offset to it in an InstructionsSection object, we create an | 
|  | // initial build ID section as a placeholder and then replace that section | 
|  | // during finalization once we have the information to calculate the real one. | 
|  | Section* build_id_; | 
|  |  | 
|  | GrowableArray<Section*> sections_; | 
|  | GrowableArray<Segment*> segments_; | 
|  | intptr_t memory_offset_; | 
|  | intptr_t section_table_file_offset_ = -1; | 
|  | intptr_t section_table_file_size_ = -1; | 
|  | intptr_t program_table_file_offset_ = -1; | 
|  | intptr_t program_table_file_size_ = -1; | 
|  | }; | 
|  |  | 
|  | }  // namespace dart | 
|  |  | 
|  | #endif  // RUNTIME_VM_ELF_H_ |