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

Commit 2fcf4cf1 authored by Christopher Ferris's avatar Christopher Ferris
Browse files

Add error propagation into Unwinder/Elf objects.

The backtrace offline code uses these error codes to diagnose errors.
In addtion, I've had cases where seeing these errors would help diagnose
failures.

This also allows us to add a few features to indicate why an unwind
terminated (such as max frames exceeded).

Bug: 65682279

Test: Updated unit tests pass.
Change-Id: If82b5092698e8a194016d670efff1320f9b44d50
parent 335675c2
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -57,6 +57,7 @@ bool ArmExidx::ExtractEntryData(uint32_t entry_offset) {
  uint32_t data;
  if (!elf_memory_->Read32(entry_offset + 4, &data)) {
    status_ = ARM_STATUS_READ_FAILED;
    status_address_ = entry_offset + 4;
    return false;
  }
  if (data == 1) {
@@ -97,6 +98,7 @@ bool ArmExidx::ExtractEntryData(uint32_t entry_offset) {
  uint32_t addr = (entry_offset + 4) + signed_data;
  if (!elf_memory_->Read32(addr, &data)) {
    status_ = ARM_STATUS_READ_FAILED;
    status_address_ = addr;
    return false;
  }

@@ -128,6 +130,7 @@ bool ArmExidx::ExtractEntryData(uint32_t entry_offset) {
    addr += 4;
    if (!elf_memory_->Read32(addr, &data)) {
      status_ = ARM_STATUS_READ_FAILED;
      status_address_ = addr;
      return false;
    }
    num_table_words = (data >> 24) & 0xff;
@@ -145,6 +148,7 @@ bool ArmExidx::ExtractEntryData(uint32_t entry_offset) {
  for (size_t i = 0; i < num_table_words; i++) {
    if (!elf_memory_->Read32(addr, &data)) {
      status_ = ARM_STATUS_READ_FAILED;
      status_address_ = addr;
      return false;
    }
    data_.push_back((data >> 24) & 0xff);
@@ -216,6 +220,7 @@ inline bool ArmExidx::DecodePrefix_10_00(uint8_t byte) {
    if (registers & (1 << reg)) {
      if (!process_memory_->Read32(cfa_, &(*regs_)[reg])) {
        status_ = ARM_STATUS_READ_FAILED;
        status_address_ = cfa_;
        return false;
      }
      cfa_ += 4;
@@ -284,6 +289,7 @@ inline bool ArmExidx::DecodePrefix_10_10(uint8_t byte) {
  for (size_t i = 4; i <= 4 + (byte & 0x7); i++) {
    if (!process_memory_->Read32(cfa_, &(*regs_)[i])) {
      status_ = ARM_STATUS_READ_FAILED;
      status_address_ = cfa_;
      return false;
    }
    cfa_ += 4;
@@ -291,6 +297,7 @@ inline bool ArmExidx::DecodePrefix_10_10(uint8_t byte) {
  if (byte & 0x8) {
    if (!process_memory_->Read32(cfa_, &(*regs_)[ARM_REG_R14])) {
      status_ = ARM_STATUS_READ_FAILED;
      status_address_ = cfa_;
      return false;
    }
    cfa_ += 4;
@@ -357,6 +364,7 @@ inline bool ArmExidx::DecodePrefix_10_11_0001() {
    if (byte & (1 << reg)) {
      if (!process_memory_->Read32(cfa_, &(*regs_)[reg])) {
        status_ = ARM_STATUS_READ_FAILED;
        status_address_ = cfa_;
        return false;
      }
      cfa_ += 4;
+2 −0
Original line number Diff line number Diff line
@@ -61,6 +61,7 @@ class ArmExidx {
  std::deque<uint8_t>* data() { return &data_; }

  ArmStatus status() { return status_; }
  uint64_t status_address() { return status_address_; }

  RegsArm* regs() { return regs_; }

@@ -97,6 +98,7 @@ class ArmExidx {
  uint32_t cfa_ = 0;
  std::deque<uint8_t> data_;
  ArmStatus status_ = ARM_STATUS_NONE;
  uint64_t status_address_ = 0;

  Memory* elf_memory_;
  Memory* process_memory_;
+3 −3
Original line number Diff line number Diff line
@@ -14,8 +14,8 @@
 * limitations under the License.
 */

#ifndef _LIBUNWINDSTACK_ERROR_H
#define _LIBUNWINDSTACK_ERROR_H
#ifndef _LIBUNWINDSTACK_CHECK_H
#define _LIBUNWINDSTACK_CHECK_H

#include <stdlib.h>

@@ -31,4 +31,4 @@ namespace unwindstack {

}  // namespace unwindstack

#endif  // _LIBUNWINDSTACK_ERROR_H
#endif  // _LIBUNWINDSTACK_CHECK_H
+17 −12
Original line number Diff line number Diff line
@@ -23,12 +23,12 @@

#include <android-base/stringprintf.h>

#include <unwindstack/DwarfError.h>
#include <unwindstack/DwarfLocation.h>
#include <unwindstack/Log.h>

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

namespace unwindstack {
@@ -44,7 +44,8 @@ bool DwarfCfa<AddressType>::GetLocationInfo(uint64_t pc, uint64_t start_offset,
      (*loc_regs)[entry.first] = entry.second;
    }
  }
  last_error_ = DWARF_ERROR_NONE;
  last_error_.code = DWARF_ERROR_NONE;
  last_error_.address = 0;

  memory_->set_cur_offset(start_offset);
  uint64_t cfa_offset;
@@ -54,7 +55,8 @@ bool DwarfCfa<AddressType>::GetLocationInfo(uint64_t pc, uint64_t start_offset,
    // Read the cfa information.
    uint8_t cfa_value;
    if (!memory_->ReadBytes(&cfa_value, 1)) {
      last_error_ = DWARF_ERROR_MEMORY_INVALID;
      last_error_.code = DWARF_ERROR_MEMORY_INVALID;
      last_error_.address = memory_->cur_offset();
      return false;
    }
    uint8_t cfa_low = cfa_value & 0x3f;
@@ -66,7 +68,8 @@ bool DwarfCfa<AddressType>::GetLocationInfo(uint64_t pc, uint64_t start_offset,
      case 2: {
        uint64_t offset;
        if (!memory_->ReadULEB128(&offset)) {
          last_error_ = DWARF_ERROR_MEMORY_INVALID;
          last_error_.code = DWARF_ERROR_MEMORY_INVALID;
          last_error_.address = memory_->cur_offset();
          return false;
        }
        SignedType signed_offset =
@@ -78,7 +81,7 @@ bool DwarfCfa<AddressType>::GetLocationInfo(uint64_t pc, uint64_t start_offset,
      case 3: {
        if (cie_loc_regs_ == nullptr) {
          log(0, "restore while processing cie");
          last_error_ = DWARF_ERROR_ILLEGAL_STATE;
          last_error_.code = DWARF_ERROR_ILLEGAL_STATE;
          return false;
        }

@@ -93,7 +96,7 @@ bool DwarfCfa<AddressType>::GetLocationInfo(uint64_t pc, uint64_t start_offset,
      case 0: {
        const auto handle_func = DwarfCfa<AddressType>::kCallbackTable[cfa_low];
        if (handle_func == nullptr) {
          last_error_ = DWARF_ERROR_ILLEGAL_VALUE;
          last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
          return false;
        }

@@ -102,7 +105,8 @@ bool DwarfCfa<AddressType>::GetLocationInfo(uint64_t pc, uint64_t start_offset,
          if (cfa->operands[i] == DW_EH_PE_block) {
            uint64_t block_length;
            if (!memory_->ReadULEB128(&block_length)) {
              last_error_ = DWARF_ERROR_MEMORY_INVALID;
              last_error_.code = DWARF_ERROR_MEMORY_INVALID;
              last_error_.address = memory_->cur_offset();
              return false;
            }
            operands_.push_back(block_length);
@@ -111,7 +115,8 @@ bool DwarfCfa<AddressType>::GetLocationInfo(uint64_t pc, uint64_t start_offset,
          }
          uint64_t value;
          if (!memory_->ReadEncodedValue<AddressType>(cfa->operands[i], &value)) {
            last_error_ = DWARF_ERROR_MEMORY_INVALID;
            last_error_.code = DWARF_ERROR_MEMORY_INVALID;
            last_error_.address = memory_->cur_offset();
            return false;
          }
          operands_.push_back(value);
@@ -334,7 +339,7 @@ bool DwarfCfa<AddressType>::cfa_restore(dwarf_loc_regs_t* loc_regs) {
  AddressType reg = operands_[0];
  if (cie_loc_regs_ == nullptr) {
    log(0, "restore while processing cie");
    last_error_ = DWARF_ERROR_ILLEGAL_STATE;
    last_error_.code = DWARF_ERROR_ILLEGAL_STATE;
    return false;
  }
  auto reg_entry = cie_loc_regs_->find(reg);
@@ -396,7 +401,7 @@ bool DwarfCfa<AddressType>::cfa_def_cfa_register(dwarf_loc_regs_t* loc_regs) {
  auto cfa_location = loc_regs->find(CFA_REG);
  if (cfa_location == loc_regs->end() || cfa_location->second.type != DWARF_LOCATION_REGISTER) {
    log(0, "Attempt to set new register, but cfa is not already set to a register.");
    last_error_ = DWARF_ERROR_ILLEGAL_STATE;
    last_error_.code = DWARF_ERROR_ILLEGAL_STATE;
    return false;
  }

@@ -410,7 +415,7 @@ bool DwarfCfa<AddressType>::cfa_def_cfa_offset(dwarf_loc_regs_t* loc_regs) {
  auto cfa_location = loc_regs->find(CFA_REG);
  if (cfa_location == loc_regs->end() || cfa_location->second.type != DWARF_LOCATION_REGISTER) {
    log(0, "Attempt to set offset, but cfa is not set to a register.");
    last_error_ = DWARF_ERROR_ILLEGAL_STATE;
    last_error_.code = DWARF_ERROR_ILLEGAL_STATE;
    return false;
  }
  cfa_location->second.values[1] = operands_[0];
@@ -454,7 +459,7 @@ bool DwarfCfa<AddressType>::cfa_def_cfa_offset_sf(dwarf_loc_regs_t* loc_regs) {
  auto cfa_location = loc_regs->find(CFA_REG);
  if (cfa_location == loc_regs->end() || cfa_location->second.type != DWARF_LOCATION_REGISTER) {
    log(0, "Attempt to set offset, but cfa is not set to a register.");
    last_error_ = DWARF_ERROR_ILLEGAL_STATE;
    last_error_.code = DWARF_ERROR_ILLEGAL_STATE;
    return false;
  }
  SignedType offset = static_cast<SignedType>(operands_[0]) * fde_->cie->data_alignment_factor;
+5 −4
Original line number Diff line number Diff line
@@ -24,12 +24,11 @@
#include <type_traits>
#include <vector>

#include <unwindstack/DwarfError.h>
#include <unwindstack/DwarfLocation.h>
#include <unwindstack/DwarfMemory.h>
#include <unwindstack/DwarfStructs.h>

#include "DwarfError.h"

namespace unwindstack {

// DWARF Standard home: http://dwarfstd.org/
@@ -75,7 +74,9 @@ class DwarfCfa {
  bool Log(uint32_t indent, uint64_t pc, uint64_t load_bias, uint64_t start_offset,
           uint64_t end_offset);

  DwarfError last_error() { return last_error_; }
  const DwarfErrorData& last_error() { return last_error_; }
  DwarfErrorCode LastErrorCode() { return last_error_.code; }
  uint64_t LastErrorAddress() { return last_error_.address; }

  AddressType cur_pc() { return cur_pc_; }

@@ -89,7 +90,7 @@ class DwarfCfa {
  bool LogInstruction(uint32_t indent, uint64_t cfa_offset, uint8_t op, uint64_t* cur_pc);

 private:
  DwarfError last_error_;
  DwarfErrorData last_error_;
  DwarfMemory* memory_;
  const DwarfFde* fde_;

Loading