// Copyright 2016 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef SRC_LIB_DEBUGGER_UTILS_ELF_READER_H_
#define SRC_LIB_DEBUGGER_UTILS_ELF_READER_H_

#include <climits>
#include <cstddef>
#include <cstdint>
#ifdef __APPLE__
// TODO(dje): Private copy until available on osx.
#include <src/lib/debugger_utils/third_party/musl/include/elf.h>
#else
#include <elf.h>
#endif
#include <memory>
#include <string>

#include "byte_block.h"

namespace debugger_utils {

// 32+64 support, bi-endian, mmap support can come later when needed

#if UINT_MAX == ULONG_MAX

using ElfHeader = Elf32_Ehdr;
using ElfSegmentHeader = Elf32_Phdr;
using ElfSectionHeader = Elf32_Shdr;
using ElfRawSymbol = Elf32_Sym;

#else

using ElfHeader = Elf64_Ehdr;
using ElfSegmentHeader = Elf64_Phdr;
using ElfSectionHeader = Elf64_Shdr;
using ElfRawSymbol = Elf64_Sym;

#endif

enum class ElfError {
  OK = 0,
  IO,
  BADELF,
  NOMEM,
};

const char* ElfErrorName(ElfError er);

class ElfReader;

class ElfSectionContents {
 public:
  ~ElfSectionContents();

  // Return the size in bytes of the section.
  // TODO(dje): 32x64
  size_t GetSize() const { return header_.sh_size; }

  // Return the number of entries in the section, assuming the section is
  // one that has "entries". E.g., symbol sections have entries, text sections
  // do not. For sections that don't have "entries" zero is returned.
  size_t GetNumEntries() const;

  // Fetch symbol |entry_number|.
  // The section must have type SHT_SYMTAB or SHT_DYNSYM.
  // WARNING: Space for the result may be reused for each call.
  // [We don't byteswap today, but when we do that is how this will work.
  // Symbols are generally used to create internal symbol tables and thus
  // are generally discarded immediately after use.]
  const ElfRawSymbol& GetSymbolEntry(size_t entry_number);

  const ElfSectionHeader& header() const { return header_; }

  const void* contents() const { return contents_; }

 private:
  friend class ElfReader;

  // Takes ownership of |contents|.
  // TODO(dje): separate method for mmap
  ElfSectionContents(const ElfSectionHeader& header, void* contents);

  // A copy is made of the header to separate the lifetime of the section's
  // contents from Reader. We could just save the pieces we use/need but
  // this is simple enough and saves us from having to continually add more.
  // Note that while we don't byteswap today, ElfSectionHeader contains the
  // ready-to-use version.
  const ElfSectionHeader header_;
  void* contents_;
};

class ElfReader {
 public:
  static ElfError Create(const std::string& file_name, std::shared_ptr<ByteBlock> byte_block,
                         uint32_t options, uint64_t base, std::unique_ptr<ElfReader>* out);
  ~ElfReader();

  const std::string& file_name() const { return file_name_; }

  // Read the ELF header at offset |base| in |m|.
  // The header is written in to |hdr|.
  static bool ReadHeader(const ByteBlock& m, uint64_t base, ElfHeader* hdr);

  // Return true if |hdr| is a valid ELF header.
  static bool VerifyHeader(const ElfHeader* hdr);

  const ElfHeader& header() { return header_; }

  // Return the number of program segments.
  size_t GetNumSegments() const { return header_.e_phnum; }

  // Read the program segment headers in.
  // This is a no-op if they are already read in.
  // This must be called before any call to GetSegment().
  ElfError ReadSegmentHeaders();

  // Free space allocated by ReadSegmentHeaders();
  void FreeSegmentHeaders();

  // Return the program segment header of |segment_number|.
  // |segment_number| must be valid, and ReadSegmentHeaders() must have
  // already been called.
  const ElfSegmentHeader& GetSegmentHeader(size_t segment_number);

  // Return the number of sections.
  size_t GetNumSections() const { return header_.e_shnum; }

  // Read the section headers in.
  // This is a no-op if they are already read in.
  // This must be called before any call to GetSection().
  ElfError ReadSectionHeaders();

  // Free space allocated by ReadSectionHeaders();
  void FreeSectionHeaders();

  // Return the section header of |section_number|.
  // |section_number| must be valid, and ReadSectionHeaders() must have
  // already been called.
  const ElfSectionHeader& GetSectionHeader(size_t section_number);

  // Return the section header with type |type|, an SHT_* value.
  // Returns nullptr if not found.
  const ElfSectionHeader* GetSectionHeaderByType(unsigned type);

  // Fetch the contents of |sh|.
  // This version malloc's space for the section, reads the contents into
  // the buffer, and assigns it to SectionContents.
  ElfError GetSectionContents(const ElfSectionHeader& sh,
                              std::unique_ptr<ElfSectionContents>* out_contents);

  // Maximum length in bytes of a build id.
  static constexpr size_t kMaxBuildIdSize = 64;

  // Store the build id, if present, in |buf|.
  // |buf_size| must be at least kMaxBuildIdSize * 2 + 1.
  // If a build id is not found |buf| is "" and OK is returned.
  // TODO(dje): As with other changes deferred for later,
  // one might consider using std::string here. Later.
  ElfError ReadBuildId(char* buf, size_t buf_size);

  // Read |length| bytes at |address| in the ELF object an store in |buffer|.
  // |address| is the offset from the beginning of the ELF object.
  bool Read(uint64_t address, void* buffer, size_t length) const;

 private:
  ElfReader(const std::string& file_name, std::shared_ptr<ByteBlock> byte_block, uint64_t base);

  // For debugging/informational purposes only.
  const std::string file_name_;

  // This is the API to read/write from wherever the ELF object lives.
  // It could be in process memory, or in a file, or wherever.
  const std::shared_ptr<ByteBlock> byte_block_;

  // The offset in |byte_block_| of the start of the ELF object.
  const uint64_t base_;

  ElfHeader header_;

  const ElfSegmentHeader* segment_headers_ = nullptr;
  const ElfSectionHeader* section_headers_ = nullptr;
};

}  // namespace debugger_utils

#endif  // SRC_LIB_DEBUGGER_UTILS_ELF_READER_H_
