blob: 095e19171ac53575d165e34947b1945a9d9b8ee6 [file] [log] [blame]
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_DEBUG_TEST_ELF_IMAGE_BUILDER_H_
#define BASE_DEBUG_TEST_ELF_IMAGE_BUILDER_H_
#include <elf.h>
#include <cstdint>
#include <string>
#include <vector>
#include "base/containers/span.h"
#include "base/memory/raw_ptr.h"
#include "base/strings/string_piece.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#if __SIZEOF_POINTER__ == 4
using Addr = Elf32_Addr;
using Ehdr = Elf32_Ehdr;
using Half = Elf32_Half;
using Off = Elf32_Off;
using Phdr = Elf32_Phdr;
using Word = Elf32_Word;
#else
using Addr = Elf64_Addr;
using Ehdr = Elf64_Ehdr;
using Half = Elf64_Half;
using Off = Elf64_Off;
using Phdr = Elf64_Phdr;
using Word = Elf64_Word;
#endif
namespace base {
// In-memory ELF image constructed by TestElfImageBuilder.
class TestElfImage {
public:
// |buffer| is a memory buffer containing the ELF image. |elf_start| is the
// start address of the ELF image within the buffer.
TestElfImage(std::vector<uint8_t> buffer, const void* elf_start);
~TestElfImage();
TestElfImage(TestElfImage&&);
TestElfImage& operator=(TestElfImage&&);
// The start address of the ELF image.
const void* elf_start() const { return elf_start_; }
private:
std::vector<uint8_t> buffer_;
raw_ptr<const void> elf_start_;
};
// Builds an in-memory image of an ELF file for testing.
class TestElfImageBuilder {
public:
// The type of mapping to use for virtual addresses in the ELF file.
enum MappingType {
RELOCATABLE, // Virtual address == file offset.
RELOCATABLE_WITH_BIAS, // Virtual address == file offset + load bias.
NON_RELOCATABLE, // Virtual address == mapped address.
};
// The load bias to use for RELOCATABLE_WITH_BIAS. 0xc000 is a commonly used
// load bias for Android system ELF images.
static constexpr size_t kLoadBias = 0xc000;
explicit TestElfImageBuilder(MappingType mapping_type);
~TestElfImageBuilder();
TestElfImageBuilder(const TestElfImageBuilder&) = delete;
TestElfImageBuilder& operator=(const TestElfImageBuilder&) = delete;
// Add a PT_LOAD segment with the specified rwx |flags|. The contents will be
// filled with |size| bytes of zeros.
TestElfImageBuilder& AddLoadSegment(Word flags, size_t size);
// Add a PT_NOTE segment with the specified state.
TestElfImageBuilder& AddNoteSegment(Word type,
StringPiece name,
span<const uint8_t> desc);
// Adds a DT_SONAME dynamic section and the necessary state to support it. May
// be invoked at most once.
TestElfImageBuilder& AddSoName(StringPiece soname);
TestElfImage Build();
private:
// Properties of a load segment to create.
struct LoadSegment;
// Computed sizing state for parts of the ELF image.
struct ImageMeasures;
// Gets the 'virtual address' corresponding to |offset| to write into the
// image, according to |mapping_type_|. Relocatable ELF images have virtual
// addresses equal to the offset with a possible constant load bias.
// Non-relocatable ELF images have virtual addresses equal to the actual
// memory address.
Addr GetVirtualAddressForOffset(Off offset, const uint8_t* elf_start) const;
// Measures sizes/start offset of segments in the image.
ImageMeasures MeasureSizesAndOffsets() const;
// Appends a header of type |T| at |loc|, a memory address within the ELF
// image being constructed, and returns the address past the header.
template <typename T>
static uint8_t* AppendHdr(const T& hdr, uint8_t* loc);
Ehdr CreateEhdr(Half phnum);
Phdr CreatePhdr(Word type,
Word flags,
size_t align,
Off offset,
Addr vaddr,
size_t size);
const MappingType mapping_type_;
std::vector<std::vector<uint8_t>> note_contents_;
std::vector<LoadSegment> load_segments_;
absl::optional<std::string> soname_;
};
} // namespace base
#endif // BASE_DEBUG_TEST_ELF_IMAGE_BUILDER_H_