blob: 7dfee81fab428d7f419fc4a918bd3598aa4a0207 [file] [log] [blame]
Avi Drissmane4622aa2022-09-08 20:36:061// Copyright 2020 The Chromium Authors
Mike Wittmanf1ff2df2020-07-28 19:58:072// 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 Sonzognie5fff99c2024-02-21 15:58:2411#include <optional>
Mike Wittmanf1ff2df2020-07-28 19:58:0712#include <string>
Helmut Januschkae1fe1aa2024-03-13 02:21:2813#include <string_view>
Mike Wittmanf1ff2df2020-07-28 19:58:0714#include <vector>
15
16#include "base/containers/span.h"
Keishi Hattori0e45c022021-11-27 09:25:5217#include "base/memory/raw_ptr.h"
Mike Wittmanf1ff2df2020-07-28 19:58:0718
19#if __SIZEOF_POINTER__ == 4
Mike Wittman6a7b517e2020-08-04 18:35:4420using Addr = Elf32_Addr;
Mike Wittmanf1ff2df2020-07-28 19:58:0721using Ehdr = Elf32_Ehdr;
22using Half = Elf32_Half;
23using Off = Elf32_Off;
24using Phdr = Elf32_Phdr;
25using Word = Elf32_Word;
26#else
Mike Wittman6a7b517e2020-08-04 18:35:4427using Addr = Elf64_Addr;
Mike Wittmanf1ff2df2020-07-28 19:58:0728using Ehdr = Elf64_Ehdr;
29using Half = Elf64_Half;
30using Off = Elf64_Off;
31using Phdr = Elf64_Phdr;
32using Word = Elf64_Word;
33#endif
34
35namespace base {
36
37// In-memory ELF image constructed by TestElfImageBuilder.
38class 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 Hattori0e45c022021-11-27 09:25:5253 raw_ptr<const void> elf_start_;
Mike Wittmanf1ff2df2020-07-28 19:58:0754};
55
56// Builds an in-memory image of an ELF file for testing.
57class TestElfImageBuilder {
58 public:
Mike Wittman6a7b517e2020-08-04 18:35:4459 // The type of mapping to use for virtual addresses in the ELF file.
60 enum MappingType {
Mike Wittman87363cc12020-08-04 19:10:1561 RELOCATABLE, // Virtual address == file offset.
62 RELOCATABLE_WITH_BIAS, // Virtual address == file offset + load bias.
63 NON_RELOCATABLE, // Virtual address == mapped address.
Mike Wittman6a7b517e2020-08-04 18:35:4464 };
65
Mike Wittmand22625d2020-08-04 20:26:0966 // 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 Wittman6a7b517e2020-08-04 18:35:4470 explicit TestElfImageBuilder(MappingType mapping_type);
Mike Wittmanf1ff2df2020-07-28 19:58:0771 ~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 Januschkae1fe1aa2024-03-13 02:21:2882 std::string_view name,
Mike Wittmanf1ff2df2020-07-28 19:58:0783 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 Januschkae1fe1aa2024-03-13 02:21:2887 TestElfImageBuilder& AddSoName(std::string_view soname);
Mike Wittmanf1ff2df2020-07-28 19:58:0788
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 Wittman6a7b517e2020-08-04 18:35:4498 // 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 Wittman87363cc12020-08-04 19:10:15103 Addr GetVirtualAddressForOffset(Off offset, const uint8_t* elf_start) const;
Mike Wittman6a7b517e2020-08-04 18:35:44104
Mike Wittmanf1ff2df2020-07-28 19:58:07105 // 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 Wittman87363cc12020-08-04 19:10:15114 Phdr CreatePhdr(Word type,
115 Word flags,
116 size_t align,
117 Off offset,
118 Addr vaddr,
119 size_t size);
Mike Wittmanf1ff2df2020-07-28 19:58:07120
Mike Wittman6a7b517e2020-08-04 18:35:44121 const MappingType mapping_type_;
Mike Wittmanf1ff2df2020-07-28 19:58:07122 std::vector<std::vector<uint8_t>> note_contents_;
123 std::vector<LoadSegment> load_segments_;
Arthur Sonzognie5fff99c2024-02-21 15:58:24124 std::optional<std::string> soname_;
Mike Wittmanf1ff2df2020-07-28 19:58:07125};
126
127} // namespace base
128
129#endif // BASE_DEBUG_TEST_ELF_IMAGE_BUILDER_H_