Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit df683b74 authored by Christopher Ferris's avatar Christopher Ferris
Browse files

Fix support finding global variables.

The code was not properly getting the variable addresses and using
the offset and address fields of the .data section.

Fix all of that, and update the tests.

Bug: 145162678

Test: Unit tests pass.
Test: ./art/test/run-test --dex2oat-jobs 4 --host --prebuild --compact-dex-level fast --jit --no-relocate --runtime-option -Xcheck:jni  137-cfi
Test: ./art/test/testrunner/testrunner.py -t 137 --host
Change-Id: Ic61c4487334fd2273cda9c56eb1a3b525a03edb7
parent 51fb2a08
Loading
Loading
Loading
Loading
+16 −18
Original line number Diff line number Diff line
@@ -112,37 +112,35 @@ bool Elf::GetFunctionName(uint64_t addr, std::string* name, uint64_t* func_offse
                     gnu_debugdata_interface_->GetFunctionName(addr, name, func_offset)));
}

bool Elf::GetGlobalVariable(const std::string& name, uint64_t* memory_address) {
bool Elf::GetGlobalVariableOffset(const std::string& name, uint64_t* memory_offset) {
  if (!valid_) {
    return false;
  }

  if (!interface_->GetGlobalVariable(name, memory_address) &&
  uint64_t vaddr;
  if (!interface_->GetGlobalVariable(name, &vaddr) &&
      (gnu_debugdata_interface_ == nullptr ||
       !gnu_debugdata_interface_->GetGlobalVariable(name, memory_address))) {
       !gnu_debugdata_interface_->GetGlobalVariable(name, &vaddr))) {
    return false;
  }

  // Adjust by the load bias.
  if (load_bias_ > 0 && *memory_address < static_cast<uint64_t>(load_bias_)) {
    return false;
  // Check the .data section.
  uint64_t vaddr_start = interface_->data_vaddr_start();
  if (vaddr >= vaddr_start && vaddr < interface_->data_vaddr_end()) {
    *memory_offset = vaddr - vaddr_start + interface_->data_offset();
    return true;
  }

  *memory_address -= load_bias_;

  // If this winds up in the dynamic section, then we might need to adjust
  // the address.
  uint64_t dynamic_end = interface_->dynamic_vaddr() + interface_->dynamic_size();
  if (*memory_address >= interface_->dynamic_vaddr() && *memory_address < dynamic_end) {
    if (interface_->dynamic_vaddr() > interface_->dynamic_offset()) {
      *memory_address -= interface_->dynamic_vaddr() - interface_->dynamic_offset();
    } else {
      *memory_address += interface_->dynamic_offset() - interface_->dynamic_vaddr();
    }
  }
  // Check the .dynamic section.
  vaddr_start = interface_->dynamic_vaddr_start();
  if (vaddr >= vaddr_start && vaddr < interface_->dynamic_vaddr_end()) {
    *memory_offset = vaddr - vaddr_start + interface_->dynamic_offset();
    return true;
  }

  return false;
}

std::string Elf::GetBuildID() {
  if (!valid_) {
    return "";
+15 −3
Original line number Diff line number Diff line
@@ -236,8 +236,12 @@ void ElfInterface::ReadProgramHeaders(const EhdrType& ehdr, int64_t* load_bias)

    case PT_DYNAMIC:
      dynamic_offset_ = phdr.p_offset;
      dynamic_vaddr_ = phdr.p_vaddr;
      dynamic_size_ = phdr.p_memsz;
      dynamic_vaddr_start_ = phdr.p_vaddr;
      if (__builtin_add_overflow(dynamic_vaddr_start_, phdr.p_memsz, &dynamic_vaddr_end_)) {
        dynamic_offset_ = 0;
        dynamic_vaddr_start_ = 0;
        dynamic_vaddr_end_ = 0;
      }
      break;

    default:
@@ -360,6 +364,14 @@ void ElfInterface::ReadSectionHeaders(const EhdrType& ehdr) {
            eh_frame_hdr_offset_ = shdr.sh_offset;
            eh_frame_hdr_section_bias_ = static_cast<uint64_t>(shdr.sh_addr) - shdr.sh_offset;
            eh_frame_hdr_size_ = shdr.sh_size;
          } else if (name == ".data") {
            data_offset_ = shdr.sh_offset;
            data_vaddr_start_ = shdr.sh_addr;
            if (__builtin_add_overflow(data_vaddr_start_, shdr.sh_size, &data_vaddr_end_)) {
              data_offset_ = 0;
              data_vaddr_start_ = 0;
              data_vaddr_end_ = 0;
            }
          }
        }
      }
@@ -398,7 +410,7 @@ std::string ElfInterface::GetSonameWithTemplate() {
  // Find the soname location from the dynamic headers section.
  DynType dyn;
  uint64_t offset = dynamic_offset_;
  uint64_t max_offset = offset + dynamic_size_;
  uint64_t max_offset = offset + dynamic_vaddr_end_ - dynamic_vaddr_start_;
  for (uint64_t offset = dynamic_offset_; offset < max_offset; offset += sizeof(DynType)) {
    if (!memory_->ReadFully(offset, &dyn, sizeof(dyn))) {
      last_error_.code = ERROR_MEMORY_INVALID;
+28 −31
Original line number Diff line number Diff line
@@ -39,28 +39,22 @@ void Global::SetArch(ArchEnum arch) {
  }
}

uint64_t Global::GetVariableOffset(MapInfo* info, const std::string& variable) {
  if (!search_libs_.empty()) {
    bool found = false;
    const char* lib = basename(info->name.c_str());
    for (const std::string& name : search_libs_) {
      if (name == lib) {
        found = true;
        break;
      }
    }
    if (!found) {
      return 0;
bool Global::Searchable(const std::string& name) {
  if (search_libs_.empty()) {
    return true;
  }

  if (name.empty()) {
    return false;
  }

  Elf* elf = info->GetElf(memory_, arch());
  uint64_t ptr;
  // Find first non-empty list (libraries might be loaded multiple times).
  if (elf->GetGlobalVariable(variable, &ptr) && ptr != 0) {
    return ptr + info->start;
  const char* base_name = basename(name.c_str());
  for (const std::string& lib : search_libs_) {
    if (base_name == lib) {
      return true;
    }
  }
  return 0;
  return false;
}

void Global::FindAndReadVariable(Maps* maps, const char* var_str) {
@@ -78,24 +72,27 @@ void Global::FindAndReadVariable(Maps* maps, const char* var_str) {
  //   f2000-f3000 2000 rw- /system/lib/libc.so
  MapInfo* map_start = nullptr;
  for (const auto& info : *maps) {
    if (map_start != nullptr) {
      if (map_start->name == info->name) {
    if (map_start != nullptr && map_start->name == info->name) {
      if (info->offset != 0 &&
          (info->flags & (PROT_READ | PROT_WRITE)) == (PROT_READ | PROT_WRITE)) {
          uint64_t ptr = GetVariableOffset(map_start, variable);
          if (ptr != 0 && ReadVariableData(ptr)) {
        Elf* elf = map_start->GetElf(memory_, arch());
        uint64_t ptr;
        if (elf->GetGlobalVariableOffset(variable, &ptr) && ptr != 0) {
          uint64_t offset_end = info->offset + info->end - info->start;
          if (ptr >= info->offset && ptr < offset_end) {
            ptr = info->start + ptr - info->offset;
            if (ReadVariableData(ptr)) {
              break;
          } else {
            // Failed to find the global variable, do not bother trying again.
            map_start = nullptr;
            }
          }
      } else {
        }
        map_start = nullptr;
      }
    } else {
      map_start = nullptr;
    }
    if (map_start == nullptr && (info->flags & PROT_READ) && info->offset == 0 &&
        !info->name.empty()) {
        Searchable(info->name)) {
      map_start = info.get();
    }
  }
+1 −1
Original line number Diff line number Diff line
@@ -63,7 +63,7 @@ class Elf {

  bool GetFunctionName(uint64_t addr, std::string* name, uint64_t* func_offset);

  bool GetGlobalVariable(const std::string& name, uint64_t* memory_address);
  bool GetGlobalVariableOffset(const std::string& name, uint64_t* memory_offset);

  uint64_t GetRelPc(uint64_t pc, const MapInfo* map_info);

+11 −4
Original line number Diff line number Diff line
@@ -77,8 +77,11 @@ class ElfInterface {
  void SetGnuDebugdataInterface(ElfInterface* interface) { gnu_debugdata_interface_ = interface; }

  uint64_t dynamic_offset() { return dynamic_offset_; }
  uint64_t dynamic_vaddr() { return dynamic_vaddr_; }
  uint64_t dynamic_size() { return dynamic_size_; }
  uint64_t dynamic_vaddr_start() { return dynamic_vaddr_start_; }
  uint64_t dynamic_vaddr_end() { return dynamic_vaddr_end_; }
  uint64_t data_offset() { return data_offset_; }
  uint64_t data_vaddr_start() { return data_vaddr_start_; }
  uint64_t data_vaddr_end() { return data_vaddr_end_; }
  uint64_t eh_frame_hdr_offset() { return eh_frame_hdr_offset_; }
  int64_t eh_frame_hdr_section_bias() { return eh_frame_hdr_section_bias_; }
  uint64_t eh_frame_hdr_size() { return eh_frame_hdr_size_; }
@@ -141,8 +144,12 @@ class ElfInterface {

  // Stored elf data.
  uint64_t dynamic_offset_ = 0;
  uint64_t dynamic_vaddr_ = 0;
  uint64_t dynamic_size_ = 0;
  uint64_t dynamic_vaddr_start_ = 0;
  uint64_t dynamic_vaddr_end_ = 0;

  uint64_t data_offset_ = 0;
  uint64_t data_vaddr_start_ = 0;
  uint64_t data_vaddr_end_ = 0;

  uint64_t eh_frame_hdr_offset_ = 0;
  int64_t eh_frame_hdr_section_bias_ = 0;
Loading