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

Commit c5874977 authored by Christopher Ferris's avatar Christopher Ferris Committed by android-build-merger
Browse files

Merge "Fix handling of load bias values." am: 9c1d7598 am: 8ad4f279

am: f20086b2

Change-Id: I96ad99eda3d94946458d29a27e1318e3604b7de8
parents bd2fa53d f20086b2
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -223,6 +223,7 @@ cc_test {
        "tests/files/offline/art_quick_osr_stub_arm/*",
        "tests/files/offline/bad_eh_frame_hdr_arm64/*",
        "tests/files/offline/debug_frame_first_x86/*",
        "tests/files/offline/debug_frame_load_bias_arm/*",
        "tests/files/offline/eh_frame_hdr_begin_x86_64/*",
        "tests/files/offline/jit_debug_arm/*",
        "tests/files/offline/jit_debug_x86/*",
+269 −106
Original line number Diff line number Diff line
@@ -31,6 +31,8 @@

namespace unwindstack {

static constexpr uint8_t LOG_CFA_REG = 64;

void ArmExidx::LogRawData() {
  std::string log_str("Raw Data:");
  for (const uint8_t data : data_) {
@@ -63,8 +65,10 @@ bool ArmExidx::ExtractEntryData(uint32_t entry_offset) {
  if (data == 1) {
    // This is a CANT UNWIND entry.
    status_ = ARM_STATUS_NO_UNWIND;
    if (log_) {
    if (log_type_ != ARM_LOG_NONE) {
      if (log_type_ == ARM_LOG_FULL) {
        log(log_indent_, "Raw Data: 0x00 0x00 0x00 0x01");
      }
      log(log_indent_, "[cantunwind]");
    }
    return false;
@@ -86,7 +90,7 @@ bool ArmExidx::ExtractEntryData(uint32_t entry_offset) {
      // If this didn't end with a finish op, add one.
      data_.push_back(ARM_OP_FINISH);
    }
    if (log_) {
    if (log_type_ == ARM_LOG_FULL) {
      LogRawData();
    }
    return true;
@@ -163,7 +167,7 @@ bool ArmExidx::ExtractEntryData(uint32_t entry_offset) {
    data_.push_back(ARM_OP_FINISH);
  }

  if (log_) {
  if (log_type_ == ARM_LOG_FULL) {
    LogRawData();
  }
  return true;
@@ -190,32 +194,45 @@ inline bool ArmExidx::DecodePrefix_10_00(uint8_t byte) {
  registers |= byte;
  if (registers == 0) {
    // 10000000 00000000: Refuse to unwind
    if (log_) {
    if (log_type_ != ARM_LOG_NONE) {
      log(log_indent_, "Refuse to unwind");
    }
    status_ = ARM_STATUS_NO_UNWIND;
    return false;
  }
  // 1000iiii iiiiiiii: Pop up to 12 integer registers under masks {r15-r12}, {r11-r4}
  if (log_) {
  registers <<= 4;

  if (log_type_ != ARM_LOG_NONE) {
    if (log_type_ == ARM_LOG_FULL) {
      bool add_comma = false;
      std::string msg = "pop {";
    for (size_t i = 0; i < 12; i++) {
      if (registers & (1 << i)) {
      for (size_t reg = 4; reg < 16; reg++) {
        if (registers & (1 << reg)) {
          if (add_comma) {
            msg += ", ";
          }
        msg += android::base::StringPrintf("r%zu", i + 4);
          msg += android::base::StringPrintf("r%zu", reg);
          add_comma = true;
        }
      }
      log(log_indent_, "%s}", msg.c_str());
    } else {
      uint32_t cfa_offset = __builtin_popcount(registers) * 4;
      log_cfa_offset_ += cfa_offset;
      for (size_t reg = 4; reg < 16; reg++) {
        if (registers & (1 << reg)) {
          log_regs_[reg] = cfa_offset;
          cfa_offset -= 4;
        }
      }
    }

    if (log_skip_execution_) {
      return true;
    }
  }

  registers <<= 4;
  for (size_t reg = 4; reg < 16; reg++) {
    if (registers & (1 << reg)) {
      if (!process_memory_->Read32(cfa_, &(*regs_)[reg])) {
@@ -246,15 +263,20 @@ inline bool ArmExidx::DecodePrefix_10_01(uint8_t byte) {
  if (bits == 13 || bits == 15) {
    // 10011101: Reserved as prefix for ARM register to register moves
    // 10011111: Reserved as prefix for Intel Wireless MMX register to register moves
    if (log_) {
    if (log_type_ != ARM_LOG_NONE) {
      log(log_indent_, "[Reserved]");
    }
    status_ = ARM_STATUS_RESERVED;
    return false;
  }
  // 1001nnnn: Set vsp = r[nnnn] (nnnn != 13, 15)
  if (log_) {
  if (log_type_ != ARM_LOG_NONE) {
    if (log_type_ == ARM_LOG_FULL) {
      log(log_indent_, "vsp = r%d", bits);
    } else {
      log_regs_[LOG_CFA_REG] = bits;
    }

    if (log_skip_execution_) {
      return true;
    }
@@ -270,9 +292,10 @@ inline bool ArmExidx::DecodePrefix_10_10(uint8_t byte) {

  // 10100nnn: Pop r4-r[4+nnn]
  // 10101nnn: Pop r4-r[4+nnn], r14
  if (log_) {
    std::string msg = "pop {r4";
  if (log_type_ != ARM_LOG_NONE) {
    uint8_t end_reg = byte & 0x7;
    if (log_type_ == ARM_LOG_FULL) {
      std::string msg = "pop {r4";
      if (end_reg) {
        msg += android::base::StringPrintf("-r%d", 4 + end_reg);
      }
@@ -281,6 +304,24 @@ inline bool ArmExidx::DecodePrefix_10_10(uint8_t byte) {
      } else {
        log(log_indent_, "%s}", msg.c_str());
      }
    } else {
      end_reg += 4;
      uint32_t cfa_offset = (end_reg - 3) * 4;
      if (byte & 0x8) {
        cfa_offset += 4;
      }
      log_cfa_offset_ += cfa_offset;

      for (uint8_t reg = 4; reg <= end_reg; reg++) {
        log_regs_[reg] = cfa_offset;
        cfa_offset -= 4;
      }

      if (byte & 0x8) {
        log_regs_[14] = cfa_offset;
      }
    }

    if (log_skip_execution_) {
      return true;
    }
@@ -307,8 +348,11 @@ inline bool ArmExidx::DecodePrefix_10_10(uint8_t byte) {

inline bool ArmExidx::DecodePrefix_10_11_0000() {
  // 10110000: Finish
  if (log_) {
  if (log_type_ != ARM_LOG_NONE) {
    if (log_type_ == ARM_LOG_FULL) {
      log(log_indent_, "finish");
    }

    if (log_skip_execution_) {
      status_ = ARM_STATUS_FINISH;
      return false;
@@ -326,7 +370,7 @@ inline bool ArmExidx::DecodePrefix_10_11_0001() {

  if (byte == 0) {
    // 10110001 00000000: Spare
    if (log_) {
    if (log_type_ != ARM_LOG_NONE) {
      log(log_indent_, "Spare");
    }
    status_ = ARM_STATUS_SPARE;
@@ -334,7 +378,7 @@ inline bool ArmExidx::DecodePrefix_10_11_0001() {
  }
  if (byte >> 4) {
    // 10110001 xxxxyyyy: Spare (xxxx != 0000)
    if (log_) {
    if (log_type_ != ARM_LOG_NONE) {
      log(log_indent_, "Spare");
    }
    status_ = ARM_STATUS_SPARE;
@@ -342,7 +386,8 @@ inline bool ArmExidx::DecodePrefix_10_11_0001() {
  }

  // 10110001 0000iiii: Pop integer registers under mask {r3, r2, r1, r0}
  if (log_) {
  if (log_type_ != ARM_LOG_NONE) {
    if (log_type_ == ARM_LOG_FULL) {
      bool add_comma = false;
      std::string msg = "pop {";
      for (size_t i = 0; i < 4; i++) {
@@ -355,6 +400,18 @@ inline bool ArmExidx::DecodePrefix_10_11_0001() {
        }
      }
      log(log_indent_, "%s}", msg.c_str());
    } else {
      byte &= 0xf;
      uint32_t cfa_offset = __builtin_popcount(byte) * 4;
      log_cfa_offset_ += cfa_offset;
      for (size_t reg = 0; reg < 4; reg++) {
        if (byte & (1 << reg)) {
          log_regs_[reg] = cfa_offset;
          cfa_offset -= 4;
        }
      }
    }

    if (log_skip_execution_) {
      return true;
    }
@@ -373,6 +430,15 @@ inline bool ArmExidx::DecodePrefix_10_11_0001() {
  return true;
}

inline void ArmExidx::AdjustRegisters(int32_t offset) {
  for (auto& entry : log_regs_) {
    if (entry.first >= LOG_CFA_REG) {
      break;
    }
    entry.second += offset;
  }
}

inline bool ArmExidx::DecodePrefix_10_11_0010() {
  // 10110010 uleb128: vsp = vsp + 0x204 + (uleb128 << 2)
  uint32_t result = 0;
@@ -387,8 +453,15 @@ inline bool ArmExidx::DecodePrefix_10_11_0010() {
    shift += 7;
  } while (byte & 0x80);
  result <<= 2;
  if (log_) {
    log(log_indent_, "vsp = vsp + %d", 0x204 + result);
  if (log_type_ != ARM_LOG_NONE) {
    int32_t cfa_offset = 0x204 + result;
    if (log_type_ == ARM_LOG_FULL) {
      log(log_indent_, "vsp = vsp + %d", cfa_offset);
    } else {
      log_cfa_offset_ += cfa_offset;
    }
    AdjustRegisters(cfa_offset);

    if (log_skip_execution_) {
      return true;
    }
@@ -404,14 +477,20 @@ inline bool ArmExidx::DecodePrefix_10_11_0011() {
    return false;
  }

  if (log_) {
  if (log_type_ != ARM_LOG_NONE) {
    uint8_t start_reg = byte >> 4;
    std::string msg = android::base::StringPrintf("pop {d%d", start_reg);
    uint8_t end_reg = start_reg + (byte & 0xf);

    if (log_type_ == ARM_LOG_FULL) {
      std::string msg = android::base::StringPrintf("pop {d%d", start_reg);
      if (end_reg) {
        msg += android::base::StringPrintf("-d%d", end_reg);
      }
      log(log_indent_, "%s}", msg.c_str());
    } else {
      log(log_indent_, "Unsupported DX register display");
    }

    if (log_skip_execution_) {
      return true;
    }
@@ -422,7 +501,7 @@ inline bool ArmExidx::DecodePrefix_10_11_0011() {

inline bool ArmExidx::DecodePrefix_10_11_01nn() {
  // 101101nn: Spare
  if (log_) {
  if (log_type_ != ARM_LOG_NONE) {
    log(log_indent_, "Spare");
  }
  status_ = ARM_STATUS_SPARE;
@@ -433,13 +512,18 @@ inline bool ArmExidx::DecodePrefix_10_11_1nnn(uint8_t byte) {
  CHECK((byte & ~0x07) == 0xb8);

  // 10111nnn: Pop VFP double-precision registers D[8]-D[8+nnn] by FSTMFDX
  if (log_) {
    std::string msg = "pop {d8";
  if (log_type_ != ARM_LOG_NONE) {
    if (log_type_ == ARM_LOG_FULL) {
      uint8_t last_reg = (byte & 0x7);
      std::string msg = "pop {d8";
      if (last_reg) {
        msg += android::base::StringPrintf("-d%d", last_reg + 8);
      }
      log(log_indent_, "%s}", msg.c_str());
    } else {
      log(log_indent_, "Unsupported DX register display");
    }

    if (log_skip_execution_) {
      return true;
    }
@@ -489,7 +573,8 @@ inline bool ArmExidx::DecodePrefix_11_000(uint8_t byte) {
    }

    // 11000110 sssscccc: Intel Wireless MMX pop wR[ssss]-wR[ssss+cccc]
    if (log_) {
    if (log_type_ != ARM_LOG_NONE) {
      if (log_type_ == ARM_LOG_FULL) {
        uint8_t start_reg = byte >> 4;
        std::string msg = android::base::StringPrintf("pop {wR%d", start_reg);
        uint8_t end_reg = byte & 0xf;
@@ -497,6 +582,10 @@ inline bool ArmExidx::DecodePrefix_11_000(uint8_t byte) {
          msg += android::base::StringPrintf("-wR%d", start_reg + end_reg);
        }
        log(log_indent_, "%s}", msg.c_str());
      } else {
        log(log_indent_, "Unsupported wRX register display");
      }

      if (log_skip_execution_) {
        return true;
      }
@@ -510,14 +599,15 @@ inline bool ArmExidx::DecodePrefix_11_000(uint8_t byte) {

    if (byte == 0) {
      // 11000111 00000000: Spare
      if (log_) {
      if (log_type_ != ARM_LOG_NONE) {
        log(log_indent_, "Spare");
      }
      status_ = ARM_STATUS_SPARE;
      return false;
    } else if ((byte >> 4) == 0) {
      // 11000111 0000iiii: Intel Wireless MMX pop wCGR registers {wCGR0,1,2,3}
      if (log_) {
      if (log_type_ != ARM_LOG_NONE) {
        if (log_type_ == ARM_LOG_FULL) {
          bool add_comma = false;
          std::string msg = "pop {";
          for (size_t i = 0; i < 4; i++) {
@@ -530,12 +620,19 @@ inline bool ArmExidx::DecodePrefix_11_000(uint8_t byte) {
            }
          }
          log(log_indent_, "%s}", msg.c_str());
        } else {
          log(log_indent_, "Unsupported wCGR register display");
        }

        if (log_skip_execution_) {
          return true;
        }
      }
      // Only update the cfa.
      cfa_ += __builtin_popcount(byte) * 4;
    } else {
      // 11000111 xxxxyyyy: Spare (xxxx != 0000)
      if (log_) {
      if (log_type_ != ARM_LOG_NONE) {
        log(log_indent_, "Spare");
      }
      status_ = ARM_STATUS_SPARE;
@@ -543,13 +640,18 @@ inline bool ArmExidx::DecodePrefix_11_000(uint8_t byte) {
    }
  } else {
    // 11000nnn: Intel Wireless MMX pop wR[10]-wR[10+nnn] (nnn != 6, 7)
    if (log_) {
    if (log_type_ != ARM_LOG_NONE) {
      if (log_type_ == ARM_LOG_FULL) {
        std::string msg = "pop {wR10";
        uint8_t nnn = byte & 0x7;
        if (nnn) {
          msg += android::base::StringPrintf("-wR%d", 10 + nnn);
        }
        log(log_indent_, "%s}", msg.c_str());
      } else {
        log(log_indent_, "Unsupported wRX register display");
      }

      if (log_skip_execution_) {
        return true;
      }
@@ -570,7 +672,8 @@ inline bool ArmExidx::DecodePrefix_11_001(uint8_t byte) {
      return false;
    }

    if (log_) {
    if (log_type_ != ARM_LOG_NONE) {
      if (log_type_ == ARM_LOG_FULL) {
        uint8_t start_reg = byte >> 4;
        std::string msg = android::base::StringPrintf("pop {d%d", 16 + start_reg);
        uint8_t end_reg = byte & 0xf;
@@ -578,6 +681,10 @@ inline bool ArmExidx::DecodePrefix_11_001(uint8_t byte) {
          msg += android::base::StringPrintf("-d%d", 16 + start_reg + end_reg);
        }
        log(log_indent_, "%s}", msg.c_str());
      } else {
        log(log_indent_, "Unsupported DX register display");
      }

      if (log_skip_execution_) {
        return true;
      }
@@ -590,7 +697,8 @@ inline bool ArmExidx::DecodePrefix_11_001(uint8_t byte) {
      return false;
    }

    if (log_) {
    if (log_type_ != ARM_LOG_NONE) {
      if (log_type_ == ARM_LOG_FULL) {
        uint8_t start_reg = byte >> 4;
        std::string msg = android::base::StringPrintf("pop {d%d", start_reg);
        uint8_t end_reg = byte & 0xf;
@@ -598,6 +706,10 @@ inline bool ArmExidx::DecodePrefix_11_001(uint8_t byte) {
          msg += android::base::StringPrintf("-d%d", start_reg + end_reg);
        }
        log(log_indent_, "%s}", msg.c_str());
      } else {
        log(log_indent_, "Unsupported DX register display");
      }

      if (log_skip_execution_) {
        return true;
      }
@@ -606,7 +718,7 @@ inline bool ArmExidx::DecodePrefix_11_001(uint8_t byte) {
    cfa_ += (byte & 0xf) * 8 + 8;
  } else {
    // 11001yyy: Spare (yyy != 000, 001)
    if (log_) {
    if (log_type_ != ARM_LOG_NONE) {
      log(log_indent_, "Spare");
    }
    status_ = ARM_STATUS_SPARE;
@@ -619,13 +731,18 @@ inline bool ArmExidx::DecodePrefix_11_010(uint8_t byte) {
  CHECK((byte & ~0x07) == 0xd0);

  // 11010nnn: Pop VFP double precision registers D[8]-D[8+nnn] by VPUSH
  if (log_) {
  if (log_type_ != ARM_LOG_NONE) {
    if (log_type_ == ARM_LOG_FULL) {
      std::string msg = "pop {d8";
      uint8_t end_reg = byte & 0x7;
      if (end_reg) {
        msg += android::base::StringPrintf("-d%d", 8 + end_reg);
      }
      log(log_indent_, "%s}", msg.c_str());
    } else {
      log(log_indent_, "Unsupported DX register display");
    }

    if (log_skip_execution_) {
      return true;
    }
@@ -646,7 +763,7 @@ inline bool ArmExidx::DecodePrefix_11(uint8_t byte) {
    return DecodePrefix_11_010(byte);
  default:
    // 11xxxyyy: Spare (xxx != 000, 001, 010)
    if (log_) {
    if (log_type_ != ARM_LOG_NONE) {
      log(log_indent_, "Spare");
    }
    status_ = ARM_STATUS_SPARE;
@@ -664,8 +781,15 @@ bool ArmExidx::Decode() {
  switch (byte >> 6) {
  case 0:
    // 00xxxxxx: vsp = vsp + (xxxxxxx << 2) + 4
    if (log_) {
      log(log_indent_, "vsp = vsp + %d", ((byte & 0x3f) << 2) + 4);
    if (log_type_ != ARM_LOG_NONE) {
      int32_t cfa_offset = ((byte & 0x3f) << 2) + 4;
      if (log_type_ == ARM_LOG_FULL) {
        log(log_indent_, "vsp = vsp + %d", cfa_offset);
      } else {
        log_cfa_offset_ += cfa_offset;
      }
      AdjustRegisters(cfa_offset);

      if (log_skip_execution_) {
        break;
      }
@@ -674,8 +798,15 @@ bool ArmExidx::Decode() {
    break;
  case 1:
    // 01xxxxxx: vsp = vsp - (xxxxxxx << 2) + 4
    if (log_) {
      log(log_indent_, "vsp = vsp - %d", ((byte & 0x3f) << 2) + 4);
    if (log_type_ != ARM_LOG_NONE) {
      uint32_t cfa_offset = ((byte & 0x3f) << 2) + 4;
      if (log_type_ == ARM_LOG_FULL) {
        log(log_indent_, "vsp = vsp - %d", cfa_offset);
      } else {
        log_cfa_offset_ -= cfa_offset;
      }
      AdjustRegisters(-cfa_offset);

      if (log_skip_execution_) {
        break;
      }
@@ -696,4 +827,36 @@ bool ArmExidx::Eval() {
  return status_ == ARM_STATUS_FINISH;
}

void ArmExidx::LogByReg() {
  if (log_type_ != ARM_LOG_BY_REG) {
    return;
  }

  uint8_t cfa_reg;
  if (log_regs_.count(LOG_CFA_REG) == 0) {
    cfa_reg = 13;
  } else {
    cfa_reg = log_regs_[LOG_CFA_REG];
  }

  if (log_cfa_offset_ != 0) {
    char sign = (log_cfa_offset_ > 0) ? '+' : '-';
    log(log_indent_, "cfa = r%zu %c %d", cfa_reg, sign, abs(log_cfa_offset_));
  } else {
    log(log_indent_, "cfa = r%zu", cfa_reg);
  }

  for (const auto& entry : log_regs_) {
    if (entry.first >= LOG_CFA_REG) {
      break;
    }
    if (entry.second == 0) {
      log(log_indent_, "r%zu = [cfa]", entry.first);
    } else {
      char sign = (entry.second > 0) ? '-' : '+';
      log(log_indent_, "r%zu = [cfa %c %d]", entry.first, sign, abs(entry.second));
    }
  }
}

}  // namespace unwindstack
+14 −2
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@
#include <stdint.h>

#include <deque>
#include <map>

namespace unwindstack {

@@ -44,6 +45,12 @@ enum ArmOp : uint8_t {
  ARM_OP_FINISH = 0xb0,
};

enum ArmLogType : uint8_t {
  ARM_LOG_NONE,
  ARM_LOG_FULL,
  ARM_LOG_BY_REG,
};

class ArmExidx {
 public:
  ArmExidx(RegsArm* regs, Memory* elf_memory, Memory* process_memory)
@@ -52,6 +59,8 @@ class ArmExidx {

  void LogRawData();

  void LogByReg();

  bool ExtractEntryData(uint32_t entry_offset);

  bool Eval();
@@ -71,12 +80,13 @@ class ArmExidx {
  bool pc_set() { return pc_set_; }
  void set_pc_set(bool pc_set) { pc_set_ = pc_set; }

  void set_log(bool log) { log_ = log; }
  void set_log(ArmLogType log_type) { log_type_ = log_type; }
  void set_log_skip_execution(bool skip_execution) { log_skip_execution_ = skip_execution; }
  void set_log_indent(uint8_t indent) { log_indent_ = indent; }

 private:
  bool GetByte(uint8_t* byte);
  void AdjustRegisters(int32_t offset);

  bool DecodePrefix_10_00(uint8_t byte);
  bool DecodePrefix_10_01(uint8_t byte);
@@ -103,10 +113,12 @@ class ArmExidx {
  Memory* elf_memory_;
  Memory* process_memory_;

  bool log_ = false;
  ArmLogType log_type_ = ARM_LOG_NONE;
  uint8_t log_indent_ = 0;
  bool log_skip_execution_ = false;
  bool pc_set_ = false;
  int32_t log_cfa_offset_ = 0;
  std::map<uint8_t, int32_t> log_regs_;
};

}  // namespace unwindstack
+4 −4
Original line number Diff line number Diff line
@@ -264,8 +264,8 @@ bool DwarfCfa<AddressType>::LogInstruction(uint32_t indent, uint64_t cfa_offset,
}

template <typename AddressType>
bool DwarfCfa<AddressType>::Log(uint32_t indent, uint64_t pc, uint64_t load_bias,
                                uint64_t start_offset, uint64_t end_offset) {
bool DwarfCfa<AddressType>::Log(uint32_t indent, uint64_t pc, uint64_t start_offset,
                                uint64_t end_offset) {
  memory_->set_cur_offset(start_offset);
  uint64_t cfa_offset;
  uint64_t cur_pc = fde_->pc_start;
@@ -301,8 +301,8 @@ bool DwarfCfa<AddressType>::Log(uint32_t indent, uint64_t pc, uint64_t load_bias
        break;
    }
    if (cur_pc != old_pc) {
      log(indent, "");
      log(indent, "PC 0x%" PRIx64, cur_pc + load_bias);
      log(0, "");
      log(indent, "PC 0x%" PRIx64, cur_pc);
    }
    old_pc = cur_pc;
  }
+1 −2
Original line number Diff line number Diff line
@@ -71,8 +71,7 @@ class DwarfCfa {
  bool GetLocationInfo(uint64_t pc, uint64_t start_offset, uint64_t end_offset,
                       dwarf_loc_regs_t* loc_regs);

  bool Log(uint32_t indent, uint64_t pc, uint64_t load_bias, uint64_t start_offset,
           uint64_t end_offset);
  bool Log(uint32_t indent, uint64_t pc, uint64_t start_offset, uint64_t end_offset);

  const DwarfErrorData& last_error() { return last_error_; }
  DwarfErrorCode LastErrorCode() { return last_error_.code; }
Loading