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

Commit 33913ebf authored by Christopher Ferris's avatar Christopher Ferris Committed by Gerrit Code Review
Browse files

Merge "Add signal handling to the register object."

parents 4f59afe9 a019665b
Loading
Loading
Loading
Loading
+6 −4
Original line number Diff line number Diff line
@@ -96,7 +96,8 @@ bool Elf::GetFunctionName(uint64_t addr, std::string* name, uint64_t* func_offse
}

bool Elf::Step(uint64_t rel_pc, Regs* regs, Memory* process_memory) {
  return valid_ && (interface_->Step(rel_pc, regs, process_memory) ||
  return valid_ && (regs->StepIfSignalHandler(process_memory) ||
                    interface_->Step(rel_pc, regs, process_memory) ||
                    (gnu_debugdata_interface_ &&
                     gnu_debugdata_interface_->Step(rel_pc, regs, process_memory)));
}
@@ -147,21 +148,22 @@ ElfInterface* Elf::CreateInterfaceFromMemory(Memory* memory) {
    machine_type_ = e_machine;
    if (e_machine == EM_ARM) {
      interface.reset(new ElfInterfaceArm(memory));
    } else {
    } else if (e_machine == EM_386) {
      interface.reset(new ElfInterface32(memory));
    } else {
      ALOGI("32 bit elf that is neither arm nor x86: e_machine = %d\n", e_machine);
      return nullptr;
    }
  } else if (class_type_ == ELFCLASS64) {
    Elf64_Half e_machine;
    if (!memory->Read(EI_NIDENT + sizeof(Elf64_Half), &e_machine, sizeof(e_machine))) {
      return nullptr;
    }

    if (e_machine != EM_AARCH64 && e_machine != EM_X86_64) {
      // Unsupported.
      ALOGI("64 bit elf that is neither aarch64 nor x86_64: e_machine = %d\n", e_machine);
      return nullptr;
    }

    machine_type_ = e_machine;
    interface.reset(new ElfInterface64(memory));
  }
+208 −32
Original line number Diff line number Diff line
@@ -258,49 +258,51 @@ static Regs* CreateFromArm64Ucontext(void* ucontext) {
  return regs;
}

void RegsX86::SetFromUcontext(x86_ucontext_t* ucontext) {
  // Put the registers in the expected order.
  regs_[X86_REG_EDI] = ucontext->uc_mcontext.edi;
  regs_[X86_REG_ESI] = ucontext->uc_mcontext.esi;
  regs_[X86_REG_EBP] = ucontext->uc_mcontext.ebp;
  regs_[X86_REG_ESP] = ucontext->uc_mcontext.esp;
  regs_[X86_REG_EBX] = ucontext->uc_mcontext.ebx;
  regs_[X86_REG_EDX] = ucontext->uc_mcontext.edx;
  regs_[X86_REG_ECX] = ucontext->uc_mcontext.ecx;
  regs_[X86_REG_EAX] = ucontext->uc_mcontext.eax;
  regs_[X86_REG_EIP] = ucontext->uc_mcontext.eip;
  SetFromRaw();
}

static Regs* CreateFromX86Ucontext(void* ucontext) {
  x86_ucontext_t* x86_ucontext = reinterpret_cast<x86_ucontext_t*>(ucontext);

  RegsX86* regs = new RegsX86();
  // Put the registers in the expected order.
  (*regs)[X86_REG_GS] = x86_ucontext->uc_mcontext.gs;
  (*regs)[X86_REG_FS] = x86_ucontext->uc_mcontext.fs;
  (*regs)[X86_REG_ES] = x86_ucontext->uc_mcontext.es;
  (*regs)[X86_REG_DS] = x86_ucontext->uc_mcontext.ds;
  (*regs)[X86_REG_EDI] = x86_ucontext->uc_mcontext.edi;
  (*regs)[X86_REG_ESI] = x86_ucontext->uc_mcontext.esi;
  (*regs)[X86_REG_EBP] = x86_ucontext->uc_mcontext.ebp;
  (*regs)[X86_REG_ESP] = x86_ucontext->uc_mcontext.esp;
  (*regs)[X86_REG_EBX] = x86_ucontext->uc_mcontext.ebx;
  (*regs)[X86_REG_EDX] = x86_ucontext->uc_mcontext.edx;
  (*regs)[X86_REG_ECX] = x86_ucontext->uc_mcontext.ecx;
  (*regs)[X86_REG_EAX] = x86_ucontext->uc_mcontext.eax;
  (*regs)[X86_REG_EIP] = x86_ucontext->uc_mcontext.eip;
  regs->SetFromRaw();
  regs->SetFromUcontext(x86_ucontext);
  return regs;
}

static Regs* CreateFromX86_64Ucontext(void* ucontext) {
  x86_64_ucontext_t* x86_64_ucontext = reinterpret_cast<x86_64_ucontext_t*>(ucontext);

  RegsX86_64* regs = new RegsX86_64();
  // Put the registers in the expected order.

void RegsX86_64::SetFromUcontext(x86_64_ucontext_t* ucontext) {
  // R8-R15
  memcpy(&(*regs)[X86_64_REG_R8], &x86_64_ucontext->uc_mcontext.r8, 8 * sizeof(uint64_t));
  memcpy(&regs_[X86_64_REG_R8], &ucontext->uc_mcontext.r8, 8 * sizeof(uint64_t));

  // Rest of the registers.
  (*regs)[X86_64_REG_RDI] = x86_64_ucontext->uc_mcontext.rdi;
  (*regs)[X86_64_REG_RSI] = x86_64_ucontext->uc_mcontext.rsi;
  (*regs)[X86_64_REG_RBP] = x86_64_ucontext->uc_mcontext.rbp;
  (*regs)[X86_64_REG_RBX] = x86_64_ucontext->uc_mcontext.rbx;
  (*regs)[X86_64_REG_RDX] = x86_64_ucontext->uc_mcontext.rdx;
  (*regs)[X86_64_REG_RAX] = x86_64_ucontext->uc_mcontext.rax;
  (*regs)[X86_64_REG_RCX] = x86_64_ucontext->uc_mcontext.rcx;
  (*regs)[X86_64_REG_RSP] = x86_64_ucontext->uc_mcontext.rsp;
  (*regs)[X86_64_REG_RIP] = x86_64_ucontext->uc_mcontext.rip;
  regs_[X86_64_REG_RDI] = ucontext->uc_mcontext.rdi;
  regs_[X86_64_REG_RSI] = ucontext->uc_mcontext.rsi;
  regs_[X86_64_REG_RBP] = ucontext->uc_mcontext.rbp;
  regs_[X86_64_REG_RBX] = ucontext->uc_mcontext.rbx;
  regs_[X86_64_REG_RDX] = ucontext->uc_mcontext.rdx;
  regs_[X86_64_REG_RAX] = ucontext->uc_mcontext.rax;
  regs_[X86_64_REG_RCX] = ucontext->uc_mcontext.rcx;
  regs_[X86_64_REG_RSP] = ucontext->uc_mcontext.rsp;
  regs_[X86_64_REG_RIP] = ucontext->uc_mcontext.rip;

  regs->SetFromRaw();
  SetFromRaw();
}

static Regs* CreateFromX86_64Ucontext(void* ucontext) {
  x86_64_ucontext_t* x86_64_ucontext = reinterpret_cast<x86_64_ucontext_t*>(ucontext);

  RegsX86_64* regs = new RegsX86_64();
  regs->SetFromUcontext(x86_64_ucontext);
  return regs;
}

@@ -348,4 +350,178 @@ Regs* Regs::CreateFromLocal() {
  return regs;
}

bool RegsArm::StepIfSignalHandler(Memory* memory) {
  uint32_t data;
  if (!memory->Read(pc(), &data, sizeof(data))) {
    return false;
  }

  uint64_t offset = 0;
  if (data == 0xe3a07077 || data == 0xef900077 || data == 0xdf002777) {
    // non-RT sigreturn call.
    // __restore:
    //
    // Form 1 (arm):
    // 0x77 0x70              mov r7, #0x77
    // 0xa0 0xe3              svc 0x00000000
    //
    // Form 2 (arm):
    // 0x77 0x00 0x90 0xef    svc 0x00900077
    //
    // Form 3 (thumb):
    // 0x77 0x27              movs r7, #77
    // 0x00 0xdf              svc 0
    if (!memory->Read(sp(), &data, sizeof(data))) {
      return false;
    }
    if (data == 0x5ac3c35a) {
      // SP + uc_mcontext offset + r0 offset.
      offset = sp() + 0x14 + 0xc;
    } else {
      // SP + r0 offset
      offset = sp() + 0xc;
    }
  } else if (data == 0xe3a070ad || data == 0xef9000ad || data == 0xdf0027ad) {
    // RT sigreturn call.
    // __restore_rt:
    //
    // Form 1 (arm):
    // 0xad 0x70      mov r7, #0xad
    // 0xa0 0xe3      svc 0x00000000
    //
    // Form 2 (arm):
    // 0xad 0x00 0x90 0xef    svc 0x009000ad
    //
    // Form 3 (thumb):
    // 0xad 0x27              movs r7, #ad
    // 0x00 0xdf              svc 0
    if (!memory->Read(sp(), &data, sizeof(data))) {
      return false;
    }
    if (data == sp() + 8) {
      // SP + 8 + sizeof(siginfo_t) + uc_mcontext_offset + r0 offset
      offset = sp() + 8 + 0x80 + 0x14 + 0xc;
    } else {
      // SP + sizeof(siginfo_t) + uc_mcontext_offset + r0 offset
      offset = sp() + 0x80 + 0x14 + 0xc;
    }
  }
  if (offset == 0) {
    return false;
  }

  if (!memory->Read(offset, regs_.data(), sizeof(uint32_t) * ARM_REG_LAST)) {
    return false;
  }
  SetFromRaw();
  return true;
}

bool RegsArm64::StepIfSignalHandler(Memory* memory) {
  uint64_t data;
  if (!memory->Read(pc(), &data, sizeof(data))) {
    return false;
  }

  // Look for the kernel sigreturn function.
  // __kernel_rt_sigreturn:
  // 0xd2801168     mov x8, #0x8b
  // 0xd4000001     svc #0x0
  if (data != 0xd4000001d2801168ULL) {
    return false;
  }

  // SP + sizeof(siginfo_t) + uc_mcontext offset + X0 offset.
  if (!memory->Read(sp() + 0x80 + 0xb0 + 0x08, regs_.data(), sizeof(uint64_t) * ARM64_REG_LAST)) {
    return false;
  }

  SetFromRaw();
  return true;
}

bool RegsX86::StepIfSignalHandler(Memory* memory) {
  uint64_t data;
  if (!memory->Read(pc(), &data, sizeof(data))) {
    return false;
  }

  if (data == 0x80cd00000077b858ULL) {
    // Without SA_SIGINFO set, the return sequence is:
    //
    //   __restore:
    //   0x58                            pop %eax
    //   0xb8 0x77 0x00 0x00 0x00        movl 0x77,%eax
    //   0xcd 0x80                       int 0x80
    //
    // SP points at arguments:
    //   int signum
    //   struct sigcontext (same format as mcontext)
    struct x86_mcontext_t context;
    if (!memory->Read(sp() + 4, &context, sizeof(context))) {
      return false;
    }
    regs_[X86_REG_EBP] = context.ebp;
    regs_[X86_REG_ESP] = context.esp;
    regs_[X86_REG_EBX] = context.ebx;
    regs_[X86_REG_EDX] = context.edx;
    regs_[X86_REG_ECX] = context.ecx;
    regs_[X86_REG_EAX] = context.eax;
    regs_[X86_REG_EIP] = context.eip;
    SetFromRaw();
    return true;
  } else if ((data & 0x00ffffffffffffffULL) == 0x0080cd000000adb8ULL) {
    // With SA_SIGINFO set, the return sequence is:
    //
    //   __restore_rt:
    //   0xb8 0xad 0x00 0x00 0x00        movl 0xad,%eax
    //   0xcd 0x80                       int 0x80
    //
    // SP points at arguments:
    //   int signum
    //   siginfo*
    //   ucontext*

    // Get the location of the sigcontext data.
    uint32_t ptr;
    if (!memory->Read(sp() + 8, &ptr, sizeof(ptr))) {
      return false;
    }
    // Only read the portion of the data structure we care about.
    x86_ucontext_t x86_ucontext;
    if (!memory->Read(ptr + 0x14, &x86_ucontext.uc_mcontext, sizeof(x86_mcontext_t))) {
      return false;
    }
    SetFromUcontext(&x86_ucontext);
    return true;
  }
  return false;
}

bool RegsX86_64::StepIfSignalHandler(Memory* memory) {
  uint64_t data;
  if (!memory->Read(pc(), &data, sizeof(data)) || data != 0x0f0000000fc0c748) {
    return false;
  }

  uint16_t data2;
  if (!memory->Read(pc() + 8, &data2, sizeof(data2)) || data2 != 0x0f05) {
    return false;
  }

  // __restore_rt:
  // 0x48 0xc7 0xc0 0x0f 0x00 0x00 0x00   mov $0xf,%rax
  // 0x0f 0x05                            syscall
  // 0x0f                                 nopl 0x0($rax)

  // Read the mcontext data from the stack.
  // sp points to the ucontext data structure, read only the mcontext part.
  x86_64_ucontext_t x86_64_ucontext;
  if (!memory->Read(sp() + 0x28, &x86_64_ucontext.uc_mcontext, sizeof(x86_64_mcontext_t))) {
    return false;
  }
  SetFromUcontext(&x86_64_ucontext);
  return true;
}

}  // namespace unwindstack
+2 −2
Original line number Diff line number Diff line
@@ -170,13 +170,13 @@ struct x86_64_mcontext_t {
  // Only care about the registers, skip everything else.
};

typedef struct x86_64_ucontext {
struct x86_64_ucontext_t {
  uint64_t uc_flags;  // unsigned long
  uint64_t uc_link;   // struct ucontext*
  x86_64_stack_t uc_stack;
  x86_64_mcontext_t uc_mcontext;
  // Nothing else is used, so don't define it.
} x86_64_ucontext_t;
};
//-------------------------------------------------------------------

}  // namespace unwindstack
+16 −0
Original line number Diff line number Diff line
@@ -27,6 +27,8 @@ namespace unwindstack {
class Elf;
struct MapInfo;
class Memory;
struct x86_ucontext_t;
struct x86_64_ucontext_t;

class Regs {
 public:
@@ -55,6 +57,8 @@ class Regs {

  virtual uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) = 0;

  virtual bool StepIfSignalHandler(Memory*) = 0;

  virtual void SetFromRaw() = 0;

  uint16_t sp_reg() { return sp_reg_; }
@@ -104,6 +108,8 @@ class RegsArm : public RegsImpl<uint32_t> {
  uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) override;

  void SetFromRaw() override;

  bool StepIfSignalHandler(Memory* memory) override;
};

class RegsArm64 : public RegsImpl<uint64_t> {
@@ -114,6 +120,8 @@ class RegsArm64 : public RegsImpl<uint64_t> {
  uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) override;

  void SetFromRaw() override;

  bool StepIfSignalHandler(Memory* memory) override;
};

class RegsX86 : public RegsImpl<uint32_t> {
@@ -124,6 +132,10 @@ class RegsX86 : public RegsImpl<uint32_t> {
  uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) override;

  void SetFromRaw() override;

  bool StepIfSignalHandler(Memory* memory) override;

  void SetFromUcontext(x86_ucontext_t* ucontext);
};

class RegsX86_64 : public RegsImpl<uint64_t> {
@@ -134,6 +146,10 @@ class RegsX86_64 : public RegsImpl<uint64_t> {
  uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) override;

  void SetFromRaw() override;

  bool StepIfSignalHandler(Memory* memory) override;

  void SetFromUcontext(x86_64_ucontext_t* ucontext);
};

}  // namespace unwindstack
+27 −0
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@
#include <unwindstack/MapInfo.h>

#include "ElfTestUtils.h"
#include "LogFake.h"
#include "MemoryFake.h"

#if !defined(PT_ARM_EXIDX)
@@ -131,6 +132,32 @@ TEST_F(ElfTest, elf_invalid) {
  ASSERT_FALSE(elf.Step(0, nullptr, nullptr));
}

TEST_F(ElfTest, elf32_invalid_machine) {
  Elf elf(memory_);

  InitElf32(EM_PPC);

  ResetLogs();
  ASSERT_FALSE(elf.Init());

  ASSERT_EQ("", GetFakeLogBuf());
  ASSERT_EQ("4 unwind 32 bit elf that is neither arm nor x86: e_machine = 20\n\n",
            GetFakeLogPrint());
}

TEST_F(ElfTest, elf64_invalid_machine) {
  Elf elf(memory_);

  InitElf64(EM_PPC64);

  ResetLogs();
  ASSERT_FALSE(elf.Init());

  ASSERT_EQ("", GetFakeLogBuf());
  ASSERT_EQ("4 unwind 64 bit elf that is neither aarch64 nor x86_64: e_machine = 21\n\n",
            GetFakeLogPrint());
}

TEST_F(ElfTest, elf_arm) {
  Elf elf(memory_);

Loading