C++程序  |  246行  |  5.13 KB

/*
 * Copyright 2011, The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef ELF_HEADER_H
#define ELF_HEADER_H

#include "ELFTypes.h"
#include "ELF.h"

#include <memory>
#include <string.h>

class ELFHeaderHelperMixin {
protected:
  static char const *getClassStr(int clazz);
  static char const *getEndiannessStr(int endianness);
  static char const *getOSABIStr(int abi);
  static char const *getObjectTypeStr(uint16_t type);
  static char const *getMachineStr(uint16_t machine);
  static char const *getVersionStr(uint32_t version);
};

template <unsigned Bitwidth>
class ELFHeader : private ELFHeaderHelperMixin {
public:
  ELF_TYPE_INTRO_TO_TEMPLATE_SCOPE(Bitwidth);

protected:
  byte_t   e_ident[EI_NIDENT];
  half_t   e_type;
  half_t   e_machine;
  word_t   e_version;
  addr_t   e_entry;
  offset_t e_phoff;
  offset_t e_shoff;
  word_t   e_flags;
  half_t   e_ehsize;
  half_t   e_phentsize;
  half_t   e_phnum;
  half_t   e_shentsize;
  half_t   e_shnum;
  half_t   e_shstrndx;

protected:
  ELFHeader() { }

public:
  byte_t getClass() const {
    return e_ident[EI_CLASS];
  }

  byte_t getEndianness() const {
    return e_ident[EI_DATA];
  }

  byte_t getVersionFromIdent() const {
    return e_ident[EI_VERSION];
  }

  byte_t getOSABI() const {
    return e_ident[EI_OSABI];
  }

  byte_t getABIVersion() const {
    return e_ident[EI_ABIVERSION];
  }

  bool is32bit() const {
    return e_ident[EI_CLASS] == ELFCLASS32;
  }

  bool is64bit() const {
    return e_ident[EI_CLASS] == ELFCLASS64;
  }

  bool isBigEndian() const {
    return e_ident[EI_DATA] == ELFDATA2MSB;
  }

  bool isLittleEndian() const {
    return e_ident[EI_DATA] == ELFDATA2LSB;
  }

  half_t getObjectType() const {
    return e_type;
  }

  half_t getMachine() const {
    return e_machine;
  }

  word_t getVersion() const {
    return e_version;
  }

  addr_t getEntryAddress() const {
    return e_entry;
  }

  offset_t getProgramHeaderTableOffset() const {
    return e_phoff;
  }

  offset_t getSectionHeaderTableOffset() const {
    return e_shoff;
  }

  word_t getFlags() const {
    return e_flags;
  }

  half_t getELFHeaderSize() const {
    return e_ehsize;
  }

  half_t getProgramHeaderEntrySize() const {
    return e_phentsize;
  }

  half_t getProgramHeaderNum() const {
    return e_phnum;
  }

  half_t getSectionHeaderEntrySize() const {
    return e_shentsize;
  }

  half_t getSectionHeaderNum() const {
    return e_shnum;
  }

  half_t getStringSectionIndex() const {
    return e_shstrndx;
  }

  template <typename Archiver>
  static ELFHeader *read(Archiver &AR) {
    if (!AR) {
      // Archiver is in bad state before calling read function.
      // Return NULL and do nothing.
      return 0;
    }

    std::unique_ptr<ELFHeader> header(new ELFHeader());
    if (!header->serialize(AR)) {
      // Unable to read the structure.  Return NULL.
      return 0;
    }

    if (!header->isValid()) {
      // Header read from archiver is not valid.  Return NULL.
      return 0;
    }

    return header.release();
  }

  void print();

  bool isValid() const {
    return (isValidELFIdent() && isCompatibleHeaderSize());
  }

private:
  template <typename Archiver>
  bool serialize(Archiver &AR) {
    AR.prologue(TypeTraits<ELFHeaderTy>::size);

    AR & e_ident;
    AR & e_type;
    AR & e_machine;
    AR & e_version;
    AR & e_entry;
    AR & e_phoff;
    AR & e_shoff;
    AR & e_flags;
    AR & e_ehsize;
    AR & e_phentsize;
    AR & e_phnum;
    AR & e_shentsize;
    AR & e_shnum;
    AR & e_shstrndx;

    AR.epilogue(TypeTraits<ELFHeaderTy>::size);
    return AR;
  }

  bool isValidMagicWord() const {
    return (memcmp(e_ident, "\x7f" "ELF", 4) == 0);
  }

  bool isValidClass() const {
    return ((Bitwidth == 32 && is32bit()) ||
            (Bitwidth == 64 && is64bit()));
  }

  bool isValidEndianness() const {
    return (isBigEndian() || isLittleEndian());
  }

  bool isValidHeaderVersion() const {
    return (getVersion() == EV_CURRENT);
  }

  bool isUnusedZeroedPadding() const {
    for (size_t i = EI_PAD; i < EI_NIDENT; ++i) {
      if (e_ident[i] != 0) {
        return false;
      }
    }
    return true;
  }

  bool isValidELFIdent() const {
    return (isValidMagicWord() &&
            isValidClass() &&
            isValidEndianness() &&
            isValidHeaderVersion() &&
            isUnusedZeroedPadding());
  }

  bool isCompatibleHeaderSize() const {
    return (
      (e_ehsize == TypeTraits<ELFHeaderTy>::size) &&
      (e_phnum == 0 || e_phentsize == TypeTraits<ELFProgramHeaderTy>::size) &&
      (e_shnum == 0 || e_shentsize == TypeTraits<ELFSectionHeaderTy>::size));
  }
};

#include "impl/ELFHeader.hxx"

#endif // ELF_HEADER_H