| Avi Drissman | e4622aa | 2022-09-08 20:36:06 | [diff] [blame] | 1 | // Copyright 2020 The Chromium Authors |
| Mike Wittman | f1ff2df | 2020-07-28 19:58:07 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #ifndef BASE_DEBUG_TEST_ELF_IMAGE_BUILDER_H_ |
| 6 | #define BASE_DEBUG_TEST_ELF_IMAGE_BUILDER_H_ |
| 7 | |
| 8 | #include <elf.h> |
| 9 | |
| 10 | #include <cstdint> |
| Arthur Sonzogni | e5fff99c | 2024-02-21 15:58:24 | [diff] [blame] | 11 | #include <optional> |
| Mike Wittman | f1ff2df | 2020-07-28 19:58:07 | [diff] [blame] | 12 | #include <string> |
| Helmut Januschka | e1fe1aa | 2024-03-13 02:21:28 | [diff] [blame] | 13 | #include <string_view> |
| Mike Wittman | f1ff2df | 2020-07-28 19:58:07 | [diff] [blame] | 14 | #include <vector> |
| 15 | |
| 16 | #include "base/containers/span.h" |
| Keishi Hattori | 0e45c02 | 2021-11-27 09:25:52 | [diff] [blame] | 17 | #include "base/memory/raw_ptr.h" |
| Mike Wittman | f1ff2df | 2020-07-28 19:58:07 | [diff] [blame] | 18 | |
| 19 | #if __SIZEOF_POINTER__ == 4 |
| Mike Wittman | 6a7b517e | 2020-08-04 18:35:44 | [diff] [blame] | 20 | using Addr = Elf32_Addr; |
| Mike Wittman | f1ff2df | 2020-07-28 19:58:07 | [diff] [blame] | 21 | using Ehdr = Elf32_Ehdr; |
| 22 | using Half = Elf32_Half; |
| 23 | using Off = Elf32_Off; |
| 24 | using Phdr = Elf32_Phdr; |
| 25 | using Word = Elf32_Word; |
| 26 | #else |
| Mike Wittman | 6a7b517e | 2020-08-04 18:35:44 | [diff] [blame] | 27 | using Addr = Elf64_Addr; |
| Mike Wittman | f1ff2df | 2020-07-28 19:58:07 | [diff] [blame] | 28 | using Ehdr = Elf64_Ehdr; |
| 29 | using Half = Elf64_Half; |
| 30 | using Off = Elf64_Off; |
| 31 | using Phdr = Elf64_Phdr; |
| 32 | using Word = Elf64_Word; |
| 33 | #endif |
| 34 | |
| 35 | namespace base { |
| 36 | |
| 37 | // In-memory ELF image constructed by TestElfImageBuilder. |
| 38 | class TestElfImage { |
| 39 | public: |
| 40 | // |buffer| is a memory buffer containing the ELF image. |elf_start| is the |
| 41 | // start address of the ELF image within the buffer. |
| 42 | TestElfImage(std::vector<uint8_t> buffer, const void* elf_start); |
| 43 | ~TestElfImage(); |
| 44 | |
| 45 | TestElfImage(TestElfImage&&); |
| 46 | TestElfImage& operator=(TestElfImage&&); |
| 47 | |
| 48 | // The start address of the ELF image. |
| 49 | const void* elf_start() const { return elf_start_; } |
| 50 | |
| 51 | private: |
| 52 | std::vector<uint8_t> buffer_; |
| Keishi Hattori | 0e45c02 | 2021-11-27 09:25:52 | [diff] [blame] | 53 | raw_ptr<const void> elf_start_; |
| Mike Wittman | f1ff2df | 2020-07-28 19:58:07 | [diff] [blame] | 54 | }; |
| 55 | |
| 56 | // Builds an in-memory image of an ELF file for testing. |
| 57 | class TestElfImageBuilder { |
| 58 | public: |
| Mike Wittman | 6a7b517e | 2020-08-04 18:35:44 | [diff] [blame] | 59 | // The type of mapping to use for virtual addresses in the ELF file. |
| 60 | enum MappingType { |
| Mike Wittman | 87363cc1 | 2020-08-04 19:10:15 | [diff] [blame] | 61 | RELOCATABLE, // Virtual address == file offset. |
| 62 | RELOCATABLE_WITH_BIAS, // Virtual address == file offset + load bias. |
| 63 | NON_RELOCATABLE, // Virtual address == mapped address. |
| Mike Wittman | 6a7b517e | 2020-08-04 18:35:44 | [diff] [blame] | 64 | }; |
| 65 | |
| Mike Wittman | d22625d | 2020-08-04 20:26:09 | [diff] [blame] | 66 | // The load bias to use for RELOCATABLE_WITH_BIAS. 0xc000 is a commonly used |
| 67 | // load bias for Android system ELF images. |
| 68 | static constexpr size_t kLoadBias = 0xc000; |
| 69 | |
| Mike Wittman | 6a7b517e | 2020-08-04 18:35:44 | [diff] [blame] | 70 | explicit TestElfImageBuilder(MappingType mapping_type); |
| Mike Wittman | f1ff2df | 2020-07-28 19:58:07 | [diff] [blame] | 71 | ~TestElfImageBuilder(); |
| 72 | |
| 73 | TestElfImageBuilder(const TestElfImageBuilder&) = delete; |
| 74 | TestElfImageBuilder& operator=(const TestElfImageBuilder&) = delete; |
| 75 | |
| 76 | // Add a PT_LOAD segment with the specified rwx |flags|. The contents will be |
| 77 | // filled with |size| bytes of zeros. |
| 78 | TestElfImageBuilder& AddLoadSegment(Word flags, size_t size); |
| 79 | |
| 80 | // Add a PT_NOTE segment with the specified state. |
| 81 | TestElfImageBuilder& AddNoteSegment(Word type, |
| Helmut Januschka | e1fe1aa | 2024-03-13 02:21:28 | [diff] [blame] | 82 | std::string_view name, |
| Mike Wittman | f1ff2df | 2020-07-28 19:58:07 | [diff] [blame] | 83 | span<const uint8_t> desc); |
| 84 | |
| 85 | // Adds a DT_SONAME dynamic section and the necessary state to support it. May |
| 86 | // be invoked at most once. |
| Helmut Januschka | e1fe1aa | 2024-03-13 02:21:28 | [diff] [blame] | 87 | TestElfImageBuilder& AddSoName(std::string_view soname); |
| Mike Wittman | f1ff2df | 2020-07-28 19:58:07 | [diff] [blame] | 88 | |
| 89 | TestElfImage Build(); |
| 90 | |
| 91 | private: |
| 92 | // Properties of a load segment to create. |
| 93 | struct LoadSegment; |
| 94 | |
| 95 | // Computed sizing state for parts of the ELF image. |
| 96 | struct ImageMeasures; |
| 97 | |
| Mike Wittman | 6a7b517e | 2020-08-04 18:35:44 | [diff] [blame] | 98 | // Gets the 'virtual address' corresponding to |offset| to write into the |
| 99 | // image, according to |mapping_type_|. Relocatable ELF images have virtual |
| 100 | // addresses equal to the offset with a possible constant load bias. |
| 101 | // Non-relocatable ELF images have virtual addresses equal to the actual |
| 102 | // memory address. |
| Mike Wittman | 87363cc1 | 2020-08-04 19:10:15 | [diff] [blame] | 103 | Addr GetVirtualAddressForOffset(Off offset, const uint8_t* elf_start) const; |
| Mike Wittman | 6a7b517e | 2020-08-04 18:35:44 | [diff] [blame] | 104 | |
| Mike Wittman | f1ff2df | 2020-07-28 19:58:07 | [diff] [blame] | 105 | // Measures sizes/start offset of segments in the image. |
| 106 | ImageMeasures MeasureSizesAndOffsets() const; |
| 107 | |
| 108 | // Appends a header of type |T| at |loc|, a memory address within the ELF |
| 109 | // image being constructed, and returns the address past the header. |
| 110 | template <typename T> |
| 111 | static uint8_t* AppendHdr(const T& hdr, uint8_t* loc); |
| 112 | |
| 113 | Ehdr CreateEhdr(Half phnum); |
| Mike Wittman | 87363cc1 | 2020-08-04 19:10:15 | [diff] [blame] | 114 | Phdr CreatePhdr(Word type, |
| 115 | Word flags, |
| 116 | size_t align, |
| 117 | Off offset, |
| 118 | Addr vaddr, |
| 119 | size_t size); |
| Mike Wittman | f1ff2df | 2020-07-28 19:58:07 | [diff] [blame] | 120 | |
| Mike Wittman | 6a7b517e | 2020-08-04 18:35:44 | [diff] [blame] | 121 | const MappingType mapping_type_; |
| Mike Wittman | f1ff2df | 2020-07-28 19:58:07 | [diff] [blame] | 122 | std::vector<std::vector<uint8_t>> note_contents_; |
| 123 | std::vector<LoadSegment> load_segments_; |
| Arthur Sonzogni | e5fff99c | 2024-02-21 15:58:24 | [diff] [blame] | 124 | std::optional<std::string> soname_; |
| Mike Wittman | f1ff2df | 2020-07-28 19:58:07 | [diff] [blame] | 125 | }; |
| 126 | |
| 127 | } // namespace base |
| 128 | |
| 129 | #endif // BASE_DEBUG_TEST_ELF_IMAGE_BUILDER_H_ |