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

Commit f1e55f7a authored by David Srbecky's avatar David Srbecky Committed by Gerrit Code Review
Browse files

Merge "Implement new DEX PC lookup scheme."

parents 524254f3 559c7f20
Loading
Loading
Loading
Loading
+40 −14
Original line number Diff line number Diff line
@@ -36,13 +36,45 @@ template <typename AddressType>
constexpr typename DwarfOp<AddressType>::OpCallback DwarfOp<AddressType>::kCallbackTable[256];

template <typename AddressType>
bool DwarfOp<AddressType>::Eval(uint64_t start, uint64_t end, uint8_t dwarf_version) {
  uint32_t iterations = 0;
bool DwarfOp<AddressType>::Eval(uint64_t start, uint64_t end) {
  is_register_ = false;
  stack_.clear();
  memory_->set_cur_offset(start);
  dex_pc_set_ = false;

  // Unroll the first Decode calls to be able to check for a special
  // sequence of ops and values that indicate this is the dex pc.
  // The pattern is:
  //   OP_const4u (0x0c)  'D' 'E' 'X' '1'
  //   OP_drop (0x13)
  if (memory_->cur_offset() < end) {
    if (!Decode()) {
      return false;
    }
  } else {
    return true;
  }
  bool check_for_drop;
  if (cur_op_ == 0x0c && operands_.back() == 0x31584544) {
    check_for_drop = true;
  } else {
    check_for_drop = false;
  }
  if (memory_->cur_offset() < end) {
    if (!Decode()) {
      return false;
    }
  } else {
    return true;
  }

  if (check_for_drop && cur_op_ == 0x13) {
    dex_pc_set_ = true;
  }

  uint32_t iterations = 2;
  while (memory_->cur_offset() < end) {
    if (!Decode(dwarf_version)) {
    if (!Decode()) {
      return false;
    }
    // To protect against a branch that creates an infinite loop,
@@ -56,7 +88,7 @@ bool DwarfOp<AddressType>::Eval(uint64_t start, uint64_t end, uint8_t dwarf_vers
}

template <typename AddressType>
bool DwarfOp<AddressType>::Decode(uint8_t dwarf_version) {
bool DwarfOp<AddressType>::Decode() {
  last_error_.code = DWARF_ERROR_NONE;
  if (!memory_->ReadBytes(&cur_op_, 1)) {
    last_error_.code = DWARF_ERROR_MEMORY_INVALID;
@@ -71,12 +103,6 @@ bool DwarfOp<AddressType>::Decode(uint8_t dwarf_version) {
    return false;
  }

  // Check for an unsupported opcode.
  if (dwarf_version < op->supported_version) {
    last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
    return false;
  }

  // Make sure that the required number of stack elements is available.
  if (stack_.size() < op->num_required_stack_values) {
    last_error_.code = DWARF_ERROR_STACK_INDEX_NOT_VALID;
@@ -434,22 +460,22 @@ bool DwarfOp<AddressType>::op_regx() {
template <typename AddressType>
bool DwarfOp<AddressType>::op_breg() {
  uint16_t reg = cur_op() - 0x70;
  if (reg >= regs_->total_regs()) {
  if (reg >= regs_info_->Total()) {
    last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
    return false;
  }
  stack_.push_front((*regs_)[reg] + OperandAt(0));
  stack_.push_front(regs_info_->Get(reg) + OperandAt(0));
  return true;
}

template <typename AddressType>
bool DwarfOp<AddressType>::op_bregx() {
  AddressType reg = OperandAt(0);
  if (reg >= regs_->total_regs()) {
  if (reg >= regs_info_->Total()) {
    last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
    return false;
  }
  stack_.push_front((*regs_)[reg] + OperandAt(1));
  stack_.push_front(regs_info_->Get(reg) + OperandAt(1));
  return true;
}

+114 −272

File changed.

Preview size limit exceeded, changes collapsed.

+30 −50
Original line number Diff line number Diff line
@@ -26,16 +26,14 @@
#include <unwindstack/Regs.h>

#include "DwarfCfa.h"
#include "DwarfEncoding.h"
#include "DwarfOp.h"

#include "DwarfDebugFrame.h"
#include "DwarfEhFrame.h"
#include "DwarfEncoding.h"
#include "DwarfOp.h"
#include "RegsInfo.h"

namespace unwindstack {

constexpr uint64_t DEX_PC_REG = 0x20444558;

DwarfSection::DwarfSection(Memory* memory) : memory_(memory) {}

const DwarfFde* DwarfSection::GetFdeFromPc(uint64_t pc) {
@@ -75,14 +73,17 @@ bool DwarfSection::Step(uint64_t pc, Regs* regs, Memory* process_memory, bool* f
}

template <typename AddressType>
bool DwarfSectionImpl<AddressType>::EvalExpression(const DwarfLocation& loc, uint8_t version,
                                                   Memory* regular_memory, AddressType* value) {
bool DwarfSectionImpl<AddressType>::EvalExpression(const DwarfLocation& loc, Memory* regular_memory,
                                                   AddressType* value,
                                                   RegsInfo<AddressType>* regs_info,
                                                   bool* is_dex_pc) {
  DwarfOp<AddressType> op(&memory_, regular_memory);
  op.set_regs_info(regs_info);

  // Need to evaluate the op data.
  uint64_t start = loc.values[1];
  uint64_t end = start + loc.values[0];
  if (!op.Eval(start, end, version)) {
  uint64_t end = loc.values[1];
  uint64_t start = end - loc.values[0];
  if (!op.Eval(start, end)) {
    last_error_ = op.last_error();
    return false;
  }
@@ -96,6 +97,9 @@ bool DwarfSectionImpl<AddressType>::EvalExpression(const DwarfLocation& loc, uin
    return false;
  }
  *value = op.StackAt(0);
  if (is_dex_pc != nullptr && op.dex_pc_set()) {
    *is_dex_pc = true;
  }
  return true;
}

@@ -103,12 +107,10 @@ template <typename AddressType>
struct EvalInfo {
  const dwarf_loc_regs_t* loc_regs;
  const DwarfCie* cie;
  RegsImpl<AddressType>* cur_regs;
  Memory* regular_memory;
  AddressType cfa;
  bool return_address_undefined = false;
  uint64_t reg_map = 0;
  AddressType reg_values[64];
  RegsInfo<AddressType> regs_info;
};

template <typename AddressType>
@@ -129,32 +131,18 @@ bool DwarfSectionImpl<AddressType>::EvalRegister(const DwarfLocation* loc, uint3
      break;
    case DWARF_LOCATION_REGISTER: {
      uint32_t cur_reg = loc->values[0];
      if (cur_reg >= eval_info->cur_regs->total_regs()) {
      if (cur_reg >= eval_info->regs_info.Total()) {
        last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
        return false;
      }
      AddressType* cur_reg_ptr = &(*eval_info->cur_regs)[cur_reg];
      const auto& entry = eval_info->loc_regs->find(cur_reg);
      if (entry != eval_info->loc_regs->end()) {
        if (!(eval_info->reg_map & (1 << cur_reg))) {
          eval_info->reg_map |= 1 << cur_reg;
          eval_info->reg_values[cur_reg] = *cur_reg_ptr;
          if (!EvalRegister(&entry->second, cur_reg, cur_reg_ptr, eval_info)) {
            return false;
          }
        }

        // Use the register value from before any evaluations.
        *reg_ptr = eval_info->reg_values[cur_reg] + loc->values[1];
      } else {
        *reg_ptr = *cur_reg_ptr + loc->values[1];
      }
      *reg_ptr = eval_info->regs_info.Get(cur_reg) + loc->values[1];
      break;
    }
    case DWARF_LOCATION_EXPRESSION:
    case DWARF_LOCATION_VAL_EXPRESSION: {
      AddressType value;
      if (!EvalExpression(*loc, eval_info->cie->version, regular_memory, &value)) {
      bool is_dex_pc = false;
      if (!EvalExpression(*loc, regular_memory, &value, &eval_info->regs_info, &is_dex_pc)) {
        return false;
      }
      if (loc->type == DWARF_LOCATION_EXPRESSION) {
@@ -165,6 +153,9 @@ bool DwarfSectionImpl<AddressType>::EvalRegister(const DwarfLocation* loc, uint3
        }
      } else {
        *reg_ptr = value;
        if (is_dex_pc) {
          eval_info->regs_info.regs->set_dex_pc(value);
        }
      }
      break;
    }
@@ -201,8 +192,10 @@ bool DwarfSectionImpl<AddressType>::Eval(const DwarfCie* cie, Memory* regular_me

  AddressType prev_cfa = regs->sp();

  EvalInfo<AddressType> eval_info{
      .loc_regs = &loc_regs, .cie = cie, .regular_memory = regular_memory, .cur_regs = cur_regs};
  EvalInfo<AddressType> eval_info{.loc_regs = &loc_regs,
                                  .cie = cie,
                                  .regular_memory = regular_memory,
                                  .regs_info = RegsInfo<AddressType>(cur_regs)};
  const DwarfLocation* loc = &cfa_entry->second;
  // Only a few location types are valid for the cfa.
  switch (loc->type) {
@@ -224,7 +217,7 @@ bool DwarfSectionImpl<AddressType>::Eval(const DwarfCie* cie, Memory* regular_me
    case DWARF_LOCATION_EXPRESSION:
    case DWARF_LOCATION_VAL_EXPRESSION: {
      AddressType value;
      if (!EvalExpression(*loc, cie->version, regular_memory, &value)) {
      if (!EvalExpression(*loc, regular_memory, &value, &eval_info.regs_info, nullptr)) {
        return false;
      }
      if (loc->type == DWARF_LOCATION_EXPRESSION) {
@@ -249,28 +242,15 @@ bool DwarfSectionImpl<AddressType>::Eval(const DwarfCie* cie, Memory* regular_me
    if (reg == CFA_REG) continue;

    AddressType* reg_ptr;
    AddressType dex_pc = 0;
    if (reg == DEX_PC_REG) {
      // Special register that indicates this is a dex pc.
      dex_pc = 0;
      reg_ptr = &dex_pc;
    } else if (reg >= cur_regs->total_regs() || eval_info.reg_map & (1 << reg)) {
      // Skip this unknown register, or a register that has already been
      // processed.
    if (reg >= cur_regs->total_regs()) {
      // Skip this unknown register.
      continue;
    } else {
      reg_ptr = &(*cur_regs)[reg];
      eval_info.reg_map |= 1 << reg;
      eval_info.reg_values[reg] = *reg_ptr;
    }

    reg_ptr = eval_info.regs_info.Save(reg);
    if (!EvalRegister(&entry.second, reg, reg_ptr, &eval_info)) {
      return false;
    }

    if (reg == DEX_PC_REG) {
      cur_regs->set_dex_pc(dex_pc);
    }
  }

  // Find the return address location.
+66 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 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 _LIBUNWINDSTACK_REGS_INFO_H
#define _LIBUNWINDSTACK_REGS_INFO_H

#include <stdint.h>

#include <unwindstack/Regs.h>

namespace unwindstack {

template <typename AddressType>
struct RegsInfo {
  RegsInfo(RegsImpl<AddressType>* regs) : regs(regs) {}

  RegsImpl<AddressType>* regs = nullptr;
  uint64_t saved_reg_map = 0;
  AddressType saved_regs[64];

  inline AddressType Get(uint32_t reg) {
    if (IsSaved(reg)) {
      return saved_regs[reg];
    }
    return (*regs)[reg];
  }

  inline AddressType* Save(uint32_t reg) {
    if (reg > sizeof(saved_regs) / sizeof(AddressType)) {
      // This should never happen as since all currently supported
      // architectures have the total number of registers < 64.
      abort();
    }
    saved_reg_map |= 1 << reg;
    saved_regs[reg] = (*regs)[reg];
    return &(*regs)[reg];
  }

  inline bool IsSaved(uint32_t reg) {
    if (reg > sizeof(saved_regs) / sizeof(AddressType)) {
      // This should never happen as since all currently supported
      // architectures have the total number of registers < 64.
      abort();
    }
    return saved_reg_map & (1 << reg);
  }

  inline uint16_t Total() { return regs->total_regs(); }
};

}  // namespace unwindstack

#endif  // _LIBUNWINDSTACK_REGS_INFO_H
+1 −0
Original line number Diff line number Diff line
@@ -48,6 +48,7 @@ void Unwinder::FillInDexFrame() {
  size_t frame_num = frames_.size();
  frames_.resize(frame_num + 1);
  FrameData* frame = &frames_.at(frame_num);
  frame->num = frame_num;

  uint64_t dex_pc = regs_->dex_pc();
  frame->pc = dex_pc;
Loading