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

Commit 5ac39278 authored by Peter Collingbourne's avatar Peter Collingbourne
Browse files

Make GetPcAdjustment a free function.

We're now using it in contexts that don't have all of the registers available,
such as GWP-ASan and soon MTE, so it doesn't make sense to have it be a
member function of Regs.

Bug: 135772972
Change-Id: I18b104ea0adb78588d7e475d0624cefc701ba52c
parent 3ab681c9
Loading
Loading
Loading
Loading
+3 −6
Original line number Diff line number Diff line
@@ -172,15 +172,12 @@ static unwindstack::FrameData BuildFrame(unwindstack::Unwinder* unwinder, uintpt
    return frame;
  }

  unwindstack::Elf* elf =
      map_info->GetElf(unwinder->GetProcessMemory(), unwindstack::Regs::CurrentArch());
  unwindstack::ArchEnum arch = unwindstack::Regs::CurrentArch();
  unwindstack::Elf* elf = map_info->GetElf(unwinder->GetProcessMemory(), arch);

  uint64_t relative_pc = elf->GetRelPc(pc, map_info);

  // Create registers just to get PC adjustment. Doesn't matter what they point
  // to.
  unwindstack::Regs* regs = unwindstack::Regs::CreateFromLocal();
  uint64_t pc_adjustment = regs->GetPcAdjustment(relative_pc, elf);
  uint64_t pc_adjustment = unwindstack::GetPcAdjustment(relative_pc, elf, arch);
  relative_pc -= pc_adjustment;
  // The debug PC may be different if the PC comes from the JIT.
  uint64_t debug_pc = relative_pc;
+1 −1
Original line number Diff line number Diff line
@@ -106,7 +106,7 @@ bool LocalUnwinder::Unwind(std::vector<LocalFrameData>* frame_info, size_t max_f
    uint64_t step_pc = rel_pc;
    uint64_t pc_adjustment;
    if (adjust_pc) {
      pc_adjustment = regs->GetPcAdjustment(rel_pc, elf);
      pc_adjustment = GetPcAdjustment(rel_pc, elf, arch);
    } else {
      pc_adjustment = 0;
    }
+58 −0
Original line number Diff line number Diff line
@@ -121,4 +121,62 @@ Regs* Regs::CreateFromLocal() {
  return regs;
}

uint64_t GetPcAdjustment(uint64_t rel_pc, Elf* elf, ArchEnum arch) {
  switch (arch) {
    case ARCH_ARM: {
      if (!elf->valid()) {
        return 2;
      }

      uint64_t load_bias = elf->GetLoadBias();
      if (rel_pc < load_bias) {
        if (rel_pc < 2) {
          return 0;
        }
        return 2;
      }
      uint64_t adjusted_rel_pc = rel_pc - load_bias;
      if (adjusted_rel_pc < 5) {
        if (adjusted_rel_pc < 2) {
          return 0;
        }
        return 2;
      }

      if (adjusted_rel_pc & 1) {
        // This is a thumb instruction, it could be 2 or 4 bytes.
        uint32_t value;
        if (!elf->memory()->ReadFully(adjusted_rel_pc - 5, &value, sizeof(value)) ||
            (value & 0xe000f000) != 0xe000f000) {
          return 2;
        }
      }
      return 4;
    }
  case ARCH_ARM64: {
    if (rel_pc < 4) {
      return 0;
    }
    return 4;
  }
  case ARCH_MIPS:
  case ARCH_MIPS64: {
    if (rel_pc < 8) {
      return 0;
    }
    // For now, just assume no compact branches
    return 8;
  }
  case ARCH_X86:
  case ARCH_X86_64: {
    if (rel_pc == 0) {
      return 0;
    }
    return 1;
  }
  case ARCH_UNKNOWN:
    return 0;
  }
}

}  // namespace unwindstack
+0 −31
Original line number Diff line number Diff line
@@ -51,37 +51,6 @@ void RegsArm::set_sp(uint64_t sp) {
  regs_[ARM_REG_SP] = sp;
}

uint64_t RegsArm::GetPcAdjustment(uint64_t rel_pc, Elf* elf) {
  if (!elf->valid()) {
    return 2;
  }

  uint64_t load_bias = elf->GetLoadBias();
  if (rel_pc < load_bias) {
    if (rel_pc < 2) {
      return 0;
    }
    return 2;
  }
  uint64_t adjusted_rel_pc = rel_pc - load_bias;
  if (adjusted_rel_pc < 5) {
    if (adjusted_rel_pc < 2) {
      return 0;
    }
    return 2;
  }

  if (adjusted_rel_pc & 1) {
    // This is a thumb instruction, it could be 2 or 4 bytes.
    uint32_t value;
    if (!elf->memory()->ReadFully(adjusted_rel_pc - 5, &value, sizeof(value)) ||
        (value & 0xe000f000) != 0xe000f000) {
      return 2;
    }
  }
  return 4;
}

bool RegsArm::SetPcFromReturnAddress(Memory*) {
  uint32_t lr = regs_[ARM_REG_LR];
  if (regs_[ARM_REG_PC] == lr) {
+0 −7
Original line number Diff line number Diff line
@@ -52,13 +52,6 @@ void RegsArm64::set_sp(uint64_t sp) {
  regs_[ARM64_REG_SP] = sp;
}

uint64_t RegsArm64::GetPcAdjustment(uint64_t rel_pc, Elf*) {
  if (rel_pc < 4) {
    return 0;
  }
  return 4;
}

bool RegsArm64::SetPcFromReturnAddress(Memory*) {
  uint64_t lr = regs_[ARM64_REG_LR];
  if (regs_[ARM64_REG_PC] == lr) {
Loading