1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129

base / debug / test_elf_image_builder.h [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 <optional>
#include <string>
#include <string_view>
#include <vector>

#include "base/containers/span.h"
#include "base/memory/raw_ptr.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,
                                      std::string_view 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(std::string_view 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_;
  std::optional<std::string> soname_;
};

}  // namespace base

#endif  // BASE_DEBUG_TEST_ELF_IMAGE_BUILDER_H_