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

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

Merge "Add a new unwind method on error."

am: 9b91324c

Change-Id: I99aca55a9ae9ffd2c7220885ec033486996b31a6
parents 6d0d6c34 9b91324c
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -114,6 +114,11 @@ noinline int do_action_on_thread(const char* arg) {
    return reinterpret_cast<uintptr_t>(result);
}

noinline int crash_null() {
  int (*null_func)() = nullptr;
  return null_func();
}

noinline int crash3(int a) {
    *reinterpret_cast<int*>(0xdead) = a;
    return a*4;
@@ -169,6 +174,7 @@ static int usage() {
    fprintf(stderr, "  nostack               crash with a NULL stack pointer\n");
    fprintf(stderr, "\n");
    fprintf(stderr, "  heap-usage            cause a libc abort by abusing a heap function\n");
    fprintf(stderr, "  call-null             cause a crash by calling through a nullptr\n");
    fprintf(stderr, "  leak                  leak memory until we get OOM-killed\n");
    fprintf(stderr, "\n");
    fprintf(stderr, "  abort                 call abort()\n");
@@ -239,6 +245,8 @@ noinline int do_action(const char* arg) {
        crashnostack();
    } else if (!strcasecmp(arg, "exit")) {
        exit(1);
    } else if (!strcasecmp(arg, "call-null")) {
      return crash_null();
    } else if (!strcasecmp(arg, "crash") || !strcmp(arg, "SIGSEGV")) {
        return crash(42);
    } else if (!strcasecmp(arg, "abort")) {
+105 −53
Original line number Diff line number Diff line
@@ -68,6 +68,32 @@ static bool IsUnwindLibrary(const std::string& map_name) {
  return library == "libunwindstack.so" || library == "libbacktrace.so";
}

static void SetFrameInfo(unwindstack::Regs* regs, unwindstack::MapInfo* map_info,
                         uint64_t adjusted_rel_pc, backtrace_frame_data_t* frame) {
  // This will point to the adjusted absolute pc. regs->pc() is
  // unaltered.
  frame->pc = map_info->start + adjusted_rel_pc;
  frame->sp = regs->sp();
  frame->rel_pc = adjusted_rel_pc;
  frame->stack_size = 0;

  frame->map.start = map_info->start;
  frame->map.end = map_info->end;
  frame->map.offset = map_info->offset;
  frame->map.flags = map_info->flags;
  frame->map.name = map_info->name;

  unwindstack::Elf* elf = map_info->elf;
  frame->map.load_bias = elf->GetLoadBias();
  uint64_t func_offset = 0;
  if (elf->GetFunctionName(adjusted_rel_pc, &frame->func_name, &func_offset)) {
    frame->func_name = demangle(frame->func_name.c_str());
  } else {
    frame->func_name = "";
  }
  frame->func_offset = func_offset;
}

static bool Unwind(unwindstack::Regs* regs, BacktraceMap* back_map,
                   std::vector<backtrace_frame_data_t>* frames, size_t num_ignore_frames) {
  UnwindStackMap* stack_map = reinterpret_cast<UnwindStackMap*>(back_map);
@@ -75,70 +101,96 @@ static bool Unwind(unwindstack::Regs* regs, BacktraceMap* back_map,
  bool adjust_rel_pc = false;
  size_t num_frames = 0;
  frames->clear();
  bool return_address_attempted = false;
  auto process_memory = stack_map->process_memory();
  while (num_frames < MAX_BACKTRACE_FRAMES) {
    if (regs->pc() == 0) {
      break;
    }
    unwindstack::MapInfo* map_info = maps->Find(regs->pc());
    bool stepped;
    bool in_device_map = false;
    if (map_info == nullptr) {
      break;
      stepped = false;
      if (num_ignore_frames == 0) {
        frames->resize(num_frames + 1);
        backtrace_frame_data_t* frame = &frames->at(num_frames);
        frame->pc = regs->pc();
        frame->sp = regs->sp();
        frame->rel_pc = frame->pc;
        num_frames++;
      } else {
        num_ignore_frames--;
      }

    unwindstack::Elf* elf = map_info->GetElf(stack_map->process_memory(), true);
    } else {
      unwindstack::Elf* elf = map_info->GetElf(process_memory, true);
      uint64_t rel_pc = elf->GetRelPc(regs->pc(), map_info);

    bool skip_frame = num_frames == 0 && IsUnwindLibrary(map_info->name);
    if (num_ignore_frames == 0 && !skip_frame) {
      if (frames->size() != 0 || !IsUnwindLibrary(map_info->name)) {
        if (num_ignore_frames == 0) {
          uint64_t adjusted_rel_pc = rel_pc;
          if (adjust_rel_pc) {
            adjusted_rel_pc = regs->GetAdjustedPc(rel_pc, elf);
          }

          frames->resize(num_frames + 1);
          backtrace_frame_data_t* frame = &frames->at(num_frames);
          frame->num = num_frames;
      // This will point to the adjusted absolute pc. regs->pc() is
      // unaltered.
      frame->pc = map_info->start + adjusted_rel_pc;
      frame->sp = regs->sp();
      frame->rel_pc = adjusted_rel_pc;
      frame->stack_size = 0;
          SetFrameInfo(regs, map_info, adjusted_rel_pc, frame);

      frame->map.start = map_info->start;
      frame->map.end = map_info->end;
      frame->map.offset = map_info->offset;
      frame->map.load_bias = elf->GetLoadBias();
      frame->map.flags = map_info->flags;
      frame->map.name = map_info->name;

      uint64_t func_offset = 0;
      if (elf->GetFunctionName(adjusted_rel_pc, &frame->func_name, &func_offset)) {
        frame->func_name = demangle(frame->func_name.c_str());
      } else {
        frame->func_name = "";
      }
      frame->func_offset = func_offset;
          if (num_frames > 0) {
            // Set the stack size for the previous frame.
            backtrace_frame_data_t* prev = &frames->at(num_frames - 1);
            prev->stack_size = frame->sp - prev->sp;
          }
          num_frames++;
    } else if (!skip_frame && num_ignore_frames > 0) {
        } else {
          num_ignore_frames--;
        }
    adjust_rel_pc = true;
      }

    // Do not unwind through a device map.
      if (map_info->flags & PROT_DEVICE_MAP) {
      break;
    }
        // Do not stop here, fall through in case we are
        // in the speculative unwind path and need to remove
        // some of the speculative frames.
        stepped = false;
        in_device_map = true;
      } else {
        unwindstack::MapInfo* sp_info = maps->Find(regs->sp());
        if (sp_info->flags & PROT_DEVICE_MAP) {
          // Do not stop here, fall through in case we are
          // in the speculative unwind path and need to remove
          // some of the speculative frames.
          stepped = false;
          in_device_map = true;
        } else {
          bool finished;
          stepped = elf->Step(rel_pc + map_info->elf_offset, regs, process_memory.get(), &finished);
          if (stepped && finished) {
            break;
          }
        }
      }
    }
    adjust_rel_pc = true;

    if (!elf->Step(rel_pc + map_info->elf_offset, regs, stack_map->process_memory().get())) {
    if (!stepped) {
      if (return_address_attempted) {
        // Remove the speculative frame.
        if (frames->size() > 0) {
          frames->pop_back();
        }
        break;
      } else if (in_device_map) {
        // Do not attempt any other unwinding, pc or sp is in a device
        // map.
        break;
      } else {
        // Stepping didn't work, try this secondary method.
        if (!regs->SetPcFromReturnAddress(process_memory.get())) {
          break;
        }
        return_address_attempted = true;
      }
    } else {
      return_address_attempted = false;
    }
  }

+34 −22
Original line number Diff line number Diff line
@@ -82,6 +82,14 @@ struct dump_thread_t {
  int32_t done;
};

typedef Backtrace* (*create_func_t)(pid_t, pid_t, BacktraceMap*);
typedef BacktraceMap* (*map_create_func_t)(pid_t, bool);

static void VerifyLevelDump(Backtrace* backtrace, create_func_t create_func = nullptr,
                            map_create_func_t map_func = nullptr);
static void VerifyMaxDump(Backtrace* backtrace, create_func_t create_func = nullptr,
                          map_create_func_t map_func = nullptr);

static uint64_t NanoTime() {
  struct timespec t = { 0, 0 };
  clock_gettime(CLOCK_MONOTONIC, &t);
@@ -147,7 +155,7 @@ static bool ReadyLevelBacktrace(Backtrace* backtrace) {
  return found;
}

static void VerifyLevelDump(Backtrace* backtrace) {
static void VerifyLevelDump(Backtrace* backtrace, create_func_t, map_create_func_t) {
  ASSERT_GT(backtrace->NumFrames(), static_cast<size_t>(0))
    << DumpFrames(backtrace);
  ASSERT_LT(backtrace->NumFrames(), static_cast<size_t>(MAX_BACKTRACE_FRAMES))
@@ -189,7 +197,7 @@ static bool ReadyMaxBacktrace(Backtrace* backtrace) {
  return (backtrace->NumFrames() == MAX_BACKTRACE_FRAMES);
}

static void VerifyMaxDump(Backtrace* backtrace) {
static void VerifyMaxDump(Backtrace* backtrace, create_func_t, map_create_func_t) {
  ASSERT_EQ(backtrace->NumFrames(), static_cast<size_t>(MAX_BACKTRACE_FRAMES))
    << DumpFrames(backtrace);
  // Verify that the last frame is our recursive call.
@@ -251,10 +259,14 @@ TEST(libbacktrace, local_trace) {

static void VerifyIgnoreFrames(Backtrace* bt_all, Backtrace* bt_ign1, Backtrace* bt_ign2,
                               const char* cur_proc) {
  EXPECT_EQ(bt_all->NumFrames(), bt_ign1->NumFrames() + 1)
    << "All backtrace:\n" << DumpFrames(bt_all) << "Ignore 1 backtrace:\n" << DumpFrames(bt_ign1);
  EXPECT_EQ(bt_all->NumFrames(), bt_ign2->NumFrames() + 2)
    << "All backtrace:\n" << DumpFrames(bt_all) << "Ignore 2 backtrace:\n" << DumpFrames(bt_ign2);
  ASSERT_EQ(bt_all->NumFrames(), bt_ign1->NumFrames() + 1) << "All backtrace:\n"
                                                           << DumpFrames(bt_all)
                                                           << "Ignore 1 backtrace:\n"
                                                           << DumpFrames(bt_ign1);
  ASSERT_EQ(bt_all->NumFrames(), bt_ign2->NumFrames() + 2) << "All backtrace:\n"
                                                           << DumpFrames(bt_all)
                                                           << "Ignore 2 backtrace:\n"
                                                           << DumpFrames(bt_ign2);

  // Check all of the frames are the same > the current frame.
  bool check = (cur_proc == nullptr);
@@ -305,9 +317,8 @@ TEST(libbacktrace, local_max_trace) {
}

static void VerifyProcTest(pid_t pid, pid_t tid, bool (*ReadyFunc)(Backtrace*),
                           void (*VerifyFunc)(Backtrace*),
                           Backtrace* (*back_func)(pid_t, pid_t, BacktraceMap*),
                           BacktraceMap* (*map_func)(pid_t, bool)) {
                           void (*VerifyFunc)(Backtrace*, create_func_t, map_create_func_t),
                           create_func_t create_func, map_create_func_t map_create_func) {
  pid_t ptrace_tid;
  if (tid < 0) {
    ptrace_tid = pid;
@@ -324,13 +335,13 @@ static void VerifyProcTest(pid_t pid, pid_t tid, bool (*ReadyFunc)(Backtrace*),
      WaitForStop(ptrace_tid);

      std::unique_ptr<BacktraceMap> map;
      map.reset(map_func(pid, false));
      std::unique_ptr<Backtrace> backtrace(back_func(pid, tid, map.get()));
      map.reset(map_create_func(pid, false));
      std::unique_ptr<Backtrace> backtrace(create_func(pid, tid, map.get()));
      ASSERT_TRUE(backtrace.get() != nullptr);
      ASSERT_TRUE(backtrace->Unwind(0));
      ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, backtrace->GetError());
      if (ReadyFunc(backtrace.get())) {
        VerifyFunc(backtrace.get());
        VerifyFunc(backtrace.get(), create_func, map_create_func);
        verified = true;
      } else {
        last_dump = DumpFrames(backtrace.get());
@@ -399,13 +410,15 @@ TEST(libbacktrace, ptrace_max_trace_new) {
  ASSERT_EQ(waitpid(pid, &status, 0), pid);
}

static void VerifyProcessIgnoreFrames(Backtrace* bt_all) {
  std::unique_ptr<Backtrace> ign1(Backtrace::Create(bt_all->Pid(), BACKTRACE_CURRENT_THREAD));
static void VerifyProcessIgnoreFrames(Backtrace* bt_all, create_func_t create_func,
                                      map_create_func_t map_create_func) {
  std::unique_ptr<BacktraceMap> map(map_create_func(bt_all->Pid(), false));
  std::unique_ptr<Backtrace> ign1(create_func(bt_all->Pid(), BACKTRACE_CURRENT_THREAD, map.get()));
  ASSERT_TRUE(ign1.get() != nullptr);
  ASSERT_TRUE(ign1->Unwind(1));
  ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, ign1->GetError());

  std::unique_ptr<Backtrace> ign2(Backtrace::Create(bt_all->Pid(), BACKTRACE_CURRENT_THREAD));
  std::unique_ptr<Backtrace> ign2(create_func(bt_all->Pid(), BACKTRACE_CURRENT_THREAD, map.get()));
  ASSERT_TRUE(ign2.get() != nullptr);
  ASSERT_TRUE(ign2->Unwind(2));
  ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, ign2->GetError());
@@ -1702,9 +1715,8 @@ static void SetValueAndLoop(void* data) {
    ;
}

static void UnwindThroughSignal(bool use_action,
                                Backtrace* (*back_func)(pid_t, pid_t, BacktraceMap*),
                                BacktraceMap* (*map_func)(pid_t, bool)) {
static void UnwindThroughSignal(bool use_action, create_func_t create_func,
                                map_create_func_t map_create_func) {
  volatile int value = 0;
  pid_t pid;
  if ((pid = fork()) == 0) {
@@ -1730,8 +1742,8 @@ static void UnwindThroughSignal(bool use_action,

    WaitForStop(pid);

    std::unique_ptr<BacktraceMap> map(map_func(pid, false));
    std::unique_ptr<Backtrace> backtrace(back_func(pid, pid, map.get()));
    std::unique_ptr<BacktraceMap> map(map_create_func(pid, false));
    std::unique_ptr<Backtrace> backtrace(create_func(pid, pid, map.get()));

    size_t bytes_read = backtrace->Read(reinterpret_cast<uintptr_t>(const_cast<int*>(&value)),
                                        reinterpret_cast<uint8_t*>(&read_value), sizeof(read_value));
@@ -1758,9 +1770,9 @@ static void UnwindThroughSignal(bool use_action,

    WaitForStop(pid);

    map.reset(map_func(pid, false));
    map.reset(map_create_func(pid, false));
    ASSERT_TRUE(map.get() != nullptr);
    backtrace.reset(back_func(pid, pid, map.get()));
    backtrace.reset(create_func(pid, pid, map.get()));
    ASSERT_TRUE(backtrace->Unwind(0));
    bool found = false;
    for (frame_iter = backtrace->begin(); frame_iter != backtrace->end(); ++frame_iter) {
+1 −0
Original line number Diff line number Diff line
@@ -61,6 +61,7 @@ cc_library {
        "Maps.cpp",
        "Memory.cpp",
        "Regs.cpp",
        "Unwinder.cpp",
        "Symbols.cpp",
    ],

+8 −5
Original line number Diff line number Diff line
@@ -47,7 +47,7 @@ const DwarfFde* DwarfSection::GetFdeFromPc(uint64_t pc) {
  return nullptr;
}

bool DwarfSection::Step(uint64_t pc, Regs* regs, Memory* process_memory) {
bool DwarfSection::Step(uint64_t pc, Regs* regs, Memory* process_memory, bool* finished) {
  last_error_ = DWARF_ERROR_NONE;
  const DwarfFde* fde = GetFdeFromPc(pc);
  if (fde == nullptr || fde->cie == nullptr) {
@@ -62,7 +62,7 @@ bool DwarfSection::Step(uint64_t pc, Regs* regs, Memory* process_memory) {
  }

  // Now eval the actual registers.
  return Eval(fde->cie, process_memory, loc_regs, regs);
  return Eval(fde->cie, process_memory, loc_regs, regs, finished);
}

template <typename AddressType>
@@ -92,7 +92,8 @@ bool DwarfSectionImpl<AddressType>::EvalExpression(const DwarfLocation& loc, uin

template <typename AddressType>
bool DwarfSectionImpl<AddressType>::Eval(const DwarfCie* cie, Memory* regular_memory,
                                         const dwarf_loc_regs_t& loc_regs, Regs* regs) {
                                         const dwarf_loc_regs_t& loc_regs, Regs* regs,
                                         bool* finished) {
  RegsImpl<AddressType>* cur_regs = reinterpret_cast<RegsImpl<AddressType>*>(regs);
  if (cie->return_address_register >= cur_regs->total_regs()) {
    last_error_ = DWARF_ERROR_ILLEGAL_VALUE;
@@ -224,12 +225,14 @@ bool DwarfSectionImpl<AddressType>::Eval(const DwarfCie* cie, Memory* regular_me
  // Find the return address location.
  if (return_address_undefined) {
    cur_regs->set_pc(0);
    *finished = true;
  } else {
    cur_regs->set_pc((*cur_regs)[cie->return_address_register]);
    *finished = false;
  }
  cur_regs->set_sp(cfa);
  // Stop if the cfa and pc are the same.
  return prev_cfa != cfa || prev_pc != cur_regs->pc();
  // Return false if the unwind is not finished or the cfa and pc didn't change.
  return *finished || prev_cfa != cfa || prev_pc != cur_regs->pc();
}

template <typename AddressType>
Loading