current commit
260929.11 · deps: update lief to 1.0.0
/* Copyright 2017 - 2026 R. Thomas
 * Copyright 2017 - 2026 Quarkslab
 *
 * 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.
 */
#include "logging.hpp"
#include "LIEF/OAT/Header.hpp"
#include "LIEF/OAT/EnumToString.hpp"
#include "LIEF/OAT/hash.hpp"

#include <map>
#include <iomanip>
#include <sstream>


namespace LIEF::OAT {

Header::Header(const Header&) = default;
Header& Header::operator=(const Header&) = default;

Header::Header() :
  magic_{{'o', 'a', 't', '\n'}} {}


std::string Header::key_to_string(HEADER_KEYS key) {
  const static std::map<HEADER_KEYS, const char*> keys2str = {
      {HEADER_KEYS::KEY_IMAGE_LOCATION, "image-location"},
      {HEADER_KEYS::KEY_DEX2OAT_CMD_LINE, "dex2oat-cmdline"},
      {HEADER_KEYS::KEY_DEX2OAT_HOST, "dex2oat-host"},
      {HEADER_KEYS::KEY_PIC, "pic"},
      {HEADER_KEYS::KEY_HAS_PATCH_INFO, "has-patch-info"},
      {HEADER_KEYS::KEY_DEBUGGABLE, "debuggable"},
      {HEADER_KEYS::KEY_NATIVE_DEBUGGABLE, "native-debuggable"},
      {HEADER_KEYS::KEY_COMPILER_FILTER, "compiler-filter"},
      {HEADER_KEYS::KEY_CLASS_PATH, "classpath"},
      {HEADER_KEYS::KEY_BOOT_CLASS_PATH, "bootclasspath"},
      {HEADER_KEYS::KEY_CONCURRENT_COPYING, "concurrent-copying"},
      {HEADER_KEYS::KE_COMPILATION_REASON, "compilation-reason"},
  };

  auto it = keys2str.find(key);
  return it == keys2str.end() ? "UNKNOWN" : it->second;
}


Header::magic_t Header::magic() const {
  return magic_;
}

oat_version_t Header::version() const {
  return version_;
}


INSTRUCTION_SETS Header::instruction_set() const {
  return instruction_set_;
}


uint32_t Header::checksum() const {
  return checksum_;
}

uint32_t Header::nb_dex_files() const {
  return dex_file_count_;
}


uint32_t Header::executable_offset() const {
  return executable_offset_;
}

uint32_t Header::i2i_bridge_offset() const {
  return i2i_bridge_offset_;
}

uint32_t Header::i2c_code_bridge_offset() const {
  return i2c_code_bridge_offset_;
}

uint32_t Header::jni_dlsym_lookup_offset() const {
  return jni_dlsym_lookup_offset_;
}

uint32_t Header::quick_generic_jni_trampoline_offset() const {
  return quick_generic_jni_trampoline_offset_;
}

uint32_t Header::quick_imt_conflict_trampoline_offset() const {
  return quick_generic_jni_trampoline_offset_;
}

uint32_t Header::quick_resolution_trampoline_offset() const {
  return quick_imt_conflict_trampoline_offset_;
}

uint32_t Header::quick_to_interpreter_bridge_offset() const {
  return quick_to_interpreter_bridge_offset_;
}

int32_t Header::image_patch_delta() const {
  return image_patch_delta_;
}

uint32_t Header::image_file_location_oat_checksum() const {
  return image_file_location_oat_checksum_;
}
uint32_t Header::image_file_location_oat_data_begin() const {
  return image_file_location_oat_data_begin_;
}

uint32_t Header::key_value_size() const {
  return key_value_store_size_;
}

uint32_t Header::oat_dex_files_offset() const {
  return oat_dex_files_offset_;
}

Header::it_key_values_t Header::key_values() {
  it_key_values_t::container_type key_values_list;
  key_values_list.reserve(dex2oat_context_.size());

  for (auto& [k, v] : dex2oat_context_) {
    HEADER_KEYS key = k;
    std::string& value = v;
    key_values_list.emplace_back(key, value);
  }

  return key_values_list;
}

Header::it_const_key_values_t Header::key_values() const {
  std::remove_const<it_const_key_values_t::container_type>::type key_values_list;
  key_values_list.reserve(dex2oat_context_.size());

  for (const auto& [k, v] : dex2oat_context_) {
    HEADER_KEYS key = k;
    const std::string& value = v;
    key_values_list.emplace_back(key, value);
  }

  return key_values_list;
}


Header::keys_t Header::keys() const {
  Header::keys_t keys_list;
  keys_list.reserve(dex2oat_context_.size());
  for (const auto& p : dex2oat_context_) {
    keys_list.push_back(p.first);
  }
  return keys_list;
}

Header::values_t Header::values() const {
  Header::values_t values_list;
  values_list.reserve(dex2oat_context_.size());
  for (const auto& p : dex2oat_context_) {
    values_list.push_back(p.second);
  }
  return values_list;
}

const std::string* Header::get(HEADER_KEYS key) const {
  const auto it = dex2oat_context_.find(key);
  if (it == dex2oat_context_.end()) {
    return nullptr;
  }
  return &it->second;
}

std::string* Header::get(HEADER_KEYS key) {
  return const_cast<std::string*>(static_cast<const Header*>(this)->get(key));
}


Header& Header::set(HEADER_KEYS key, const std::string& value) {
  const auto it = dex2oat_context_.find(key);
  if (it == dex2oat_context_.end()) {
    LIEF_WARN("Key {} not found", to_string(key));
    return *this;
  }

  it->second = value;
  return *this;
}

const std::string* Header::operator[](HEADER_KEYS key) const {
  return get(key);
}

std::string* Header::operator[](HEADER_KEYS key) {
  return get(key);
}

void Header::accept(Visitor& visitor) const {
  visitor.visit(*this);
}


std::ostream& operator<<(std::ostream& os, const Header& hdr) {
  static constexpr size_t WIDTH = 45;
  os << std::hex << std::left << std::showbase;
  // os << std::setw(33) << std::setfill(' ') << "Version:"   << ident_magic <<
  // '\n'; os << std::setw(33) << std::setfill(' ') << "Location:"  << ident_magic
  // << '\n';
  os << std::setw(WIDTH) << std::setfill(' ') << "Checksum:" << std::hex
     << hdr.checksum() << '\n';
  os << std::setw(WIDTH) << std::setfill(' ')
     << "Instruction set:" << to_string(hdr.instruction_set()) << '\n';
  // os << std::setw(33) << std::setfill(' ') << "Instruction set features:"  <<
  // ident_magic << '\n';
  os << std::setw(WIDTH) << std::setfill(' ') << "Dex file count:" << std::dec
     << hdr.nb_dex_files() << '\n';
  os << std::setw(WIDTH) << std::setfill(' ') << "Executable offset:" << std::hex
     << hdr.executable_offset() << '\n';

  os << '\n';

  os << std::setw(WIDTH) << std::setfill(' ')
     << "Interpreter to Interpreter Bridge Offset:" << std::hex
     << hdr.i2i_bridge_offset() << '\n';
  os << std::setw(WIDTH) << std::setfill(' ')
     << "Interpreter to Compiled Code Bridge Offset:" << std::hex
     << hdr.i2c_code_bridge_offset() << '\n';

  os << '\n';

  os << std::setw(WIDTH) << std::setfill(' ')
     << "JNI dlsym lookup offset:" << std::hex << hdr.jni_dlsym_lookup_offset()
     << '\n';

  os << '\n';

  os << std::setw(WIDTH) << std::setfill(' ')
     << "Quick Generic JNI Trampoline Offset:" << std::hex
     << hdr.quick_generic_jni_trampoline_offset() << '\n';
  os << std::setw(WIDTH) << std::setfill(' ')
     << "Quick IMT Conflict Trampoline Offset:" << std::hex
     << hdr.quick_imt_conflict_trampoline_offset() << '\n';
  os << std::setw(WIDTH) << std::setfill(' ')
     << "Quick Resolution Trampoline Offset:" << std::hex
     << hdr.quick_resolution_trampoline_offset() << '\n';
  os << std::setw(WIDTH) << std::setfill(' ')
     << "Quick to Interpreter Bridge Offset:" << std::hex
     << hdr.quick_to_interpreter_bridge_offset() << '\n';

  os << '\n';

  os << std::setw(WIDTH) << std::setfill(' ') << "Image Patch Delta:" << std::dec
     << hdr.image_patch_delta() << '\n';

  os << '\n';

  os << std::setw(WIDTH) << std::setfill(' ')
     << "Image File Location OAT Checksum:" << std::hex
     << hdr.image_file_location_oat_checksum() << '\n';
  os << std::setw(WIDTH) << std::setfill(' ')
     << "Image File Location OAT Begin:" << std::hex
     << hdr.image_file_location_oat_data_begin() << '\n';

  os << '\n';

  for (const auto& p : hdr.key_values()) {
    os << std::setw(WIDTH) << std::setfill(' ')
       << Header::key_to_string(p.key) + ":" << *p.value << '\n';
  }

  return os;
}


}