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

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

Merge "Add support for the new unwind method."

am: 172b1d00

Change-Id: Ia42e055e36053f8618dc0e2c13c2cc84bc1a148d
parents 6c2d927c 172b1d00
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -53,6 +53,8 @@ libbacktrace_sources = [
    "UnwindCurrent.cpp",
    "UnwindMap.cpp",
    "UnwindPtrace.cpp",
    "UnwindStack.cpp",
    "UnwindStackMap.cpp",
]

cc_library_headers {
@@ -84,6 +86,7 @@ cc_library {
                "libbase",
                "liblog",
                "libunwind",
                "libunwindstack",
            ],

            static_libs: ["libcutils"],
@@ -97,6 +100,7 @@ cc_library {
                "libbase",
                "liblog",
                "libunwind",
                "libunwindstack",
            ],

            static_libs: ["libcutils"],
@@ -108,6 +112,7 @@ cc_library {
                "libbase",
                "liblog",
                "libunwind",
                "libunwindstack",
            ],

            static_libs: ["libasync_safe", "libcutils"],
@@ -130,11 +135,13 @@ cc_library_shared {
        linux: {
            shared_libs: [
                "libunwind",
                "libunwindstack",
            ],
        },
        android: {
            shared_libs: [
                "libunwind",
                "libunwindstack",
            ],
        },
    }
@@ -161,6 +168,7 @@ cc_library_static {
    shared_libs = [
        "libbase",
        "libunwind",
        "libunwindstack",
        "libziparchive",
    ],
}
@@ -192,6 +200,7 @@ cc_test {
        "libcutils",
        "liblog",
        "libunwind",
        "libunwindstack",
    ],

    group_static_libs: true,
+220 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#define _GNU_SOURCE 1
#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <ucontext.h>

#include <memory>
#include <string>

#if !defined(__ANDROID__)
#include <cutils/threads.h>
#endif

#include <backtrace/Backtrace.h>
#include <unwindstack/Elf.h>
#include <unwindstack/MapInfo.h>
#include <unwindstack/Maps.h>
#include <unwindstack/Memory.h>
#include <unwindstack/Regs.h>
#include <unwindstack/RegsGetLocal.h>

#include "BacktraceLog.h"
#include "UnwindStack.h"
#include "UnwindStackMap.h"

static std::string GetFunctionName(pid_t pid, BacktraceMap* back_map, uintptr_t pc,
                                   uintptr_t* offset) {
  *offset = 0;
  unwindstack::Maps* maps = reinterpret_cast<UnwindStackMap*>(back_map)->stack_maps();

  // Get the map for this
  unwindstack::MapInfo* map_info = maps->Find(pc);
  if (map_info == nullptr || map_info->flags & PROT_DEVICE_MAP) {
    return "";
  }

  unwindstack::Elf* elf = map_info->GetElf(pid, true);

  std::string name;
  uint64_t func_offset;
  if (!elf->GetFunctionName(elf->GetRelPc(pc, map_info), &name, &func_offset)) {
    return "";
  }
  *offset = func_offset;
  return name;
}

static bool IsUnwindLibrary(const std::string& map_name) {
  const std::string library(basename(map_name.c_str()));
  return library == "libunwindstack.so" || library == "libbacktrace.so";
}

static bool Unwind(pid_t pid, unwindstack::Memory* memory, unwindstack::Regs* regs,
                   BacktraceMap* back_map, std::vector<backtrace_frame_data_t>* frames,
                   size_t num_ignore_frames) {
  unwindstack::Maps* maps = reinterpret_cast<UnwindStackMap*>(back_map)->stack_maps();
  bool adjust_rel_pc = false;
  size_t num_frames = 0;
  frames->clear();
  while (num_frames < MAX_BACKTRACE_FRAMES) {
    if (regs->pc() == 0) {
      break;
    }
    unwindstack::MapInfo* map_info = maps->Find(regs->pc());
    if (map_info == nullptr) {
      break;
    }

    unwindstack::Elf* elf = map_info->GetElf(pid, true);
    uint64_t rel_pc = regs->pc();
    if (map_info != nullptr) {
      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) {
      uint64_t adjusted_rel_pc = rel_pc;
      if (map_info != nullptr && 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;
      if (map_info != nullptr) {
        // This will point to the adjusted absolute pc. regs->pc() is
        // unaltered.
        frame->pc = map_info->start + adjusted_rel_pc;
      } else {
        frame->pc = 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.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 = "";
      }
      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) {
      num_ignore_frames--;
    }
    adjust_rel_pc = true;

    // Do not unwind through a device map.
    if (map_info->flags & PROT_DEVICE_MAP) {
      break;
    }
    unwindstack::MapInfo* sp_info = maps->Find(regs->sp());
    if (sp_info->flags & PROT_DEVICE_MAP) {
      break;
    }

    if (!elf->Step(rel_pc + map_info->elf_offset, regs, memory)) {
      break;
    }
  }

  return true;
}

UnwindStackCurrent::UnwindStackCurrent(pid_t pid, pid_t tid, BacktraceMap* map)
    : BacktraceCurrent(pid, tid, map), memory_(new unwindstack::MemoryLocal) {}

std::string UnwindStackCurrent::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) {
  return ::GetFunctionName(Pid(), GetMap(), pc, offset);
}

bool UnwindStackCurrent::UnwindFromContext(size_t num_ignore_frames, ucontext_t* ucontext) {
  std::unique_ptr<unwindstack::Regs> regs;
  if (ucontext == nullptr) {
    regs.reset(unwindstack::Regs::CreateFromLocal());
    // Fill in the registers from this function. Do it here to avoid
    // one extra function call appearing in the unwind.
    unwindstack::RegsGetLocal(regs.get());
  } else {
    regs.reset(unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::GetMachineType(), ucontext));
  }

  error_ = BACKTRACE_UNWIND_NO_ERROR;
  return ::Unwind(getpid(), memory_.get(), regs.get(), GetMap(), &frames_, num_ignore_frames);
}

UnwindStackPtrace::UnwindStackPtrace(pid_t pid, pid_t tid, BacktraceMap* map)
    : BacktracePtrace(pid, tid, map), memory_(new unwindstack::MemoryRemote(pid)) {}

std::string UnwindStackPtrace::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) {
  return ::GetFunctionName(Pid(), GetMap(), pc, offset);
}

bool UnwindStackPtrace::Unwind(size_t num_ignore_frames, ucontext_t* context) {
  std::unique_ptr<unwindstack::Regs> regs;
  if (context == nullptr) {
    uint32_t machine_type;
    regs.reset(unwindstack::Regs::RemoteGet(Tid(), &machine_type));
  } else {
    regs.reset(unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::GetMachineType(), context));
  }

  error_ = BACKTRACE_UNWIND_NO_ERROR;
  return ::Unwind(Pid(), memory_.get(), regs.get(), GetMap(), &frames_, num_ignore_frames);
}

Backtrace* Backtrace::CreateNew(pid_t pid, pid_t tid, BacktraceMap* map) {
  if (pid == BACKTRACE_CURRENT_PROCESS) {
    pid = getpid();
    if (tid == BACKTRACE_CURRENT_THREAD) {
      tid = gettid();
    }
  } else if (tid == BACKTRACE_CURRENT_THREAD) {
    tid = pid;
  }

  if (map == nullptr) {
// This would cause the wrong type of map object to be created, so disallow.
#if defined(__ANDROID__)
    __assert2(__FILE__, __LINE__, __PRETTY_FUNCTION__,
              "Backtrace::CreateNew() must be called with a real map pointer.");
#else
    BACK_LOGE("Backtrace::CreateNew() must be called with a real map pointer.");
    abort();
#endif
  }

  if (pid == getpid()) {
    return new UnwindStackCurrent(pid, tid, map);
  } else {
    return new UnwindStackPtrace(pid, tid, map);
  }
}
+56 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef _LIBBACKTRACE_UNWIND_STACK_H
#define _LIBBACKTRACE_UNWIND_STACK_H

#include <stdint.h>

#include <string>

#include <backtrace/BacktraceMap.h>
#include <unwindstack/Memory.h>

#include "BacktraceCurrent.h"
#include "BacktracePtrace.h"

class UnwindStackCurrent : public BacktraceCurrent {
 public:
  UnwindStackCurrent(pid_t pid, pid_t tid, BacktraceMap* map);
  virtual ~UnwindStackCurrent() = default;

  std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) override;

  bool UnwindFromContext(size_t num_ignore_frames, ucontext_t* ucontext) override;

 private:
  std::unique_ptr<unwindstack::Memory> memory_;
};

class UnwindStackPtrace : public BacktracePtrace {
 public:
  UnwindStackPtrace(pid_t pid, pid_t tid, BacktraceMap* map);
  virtual ~UnwindStackPtrace() = default;

  bool Unwind(size_t num_ignore_frames, ucontext_t* context) override;

  std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset);

 private:
  std::unique_ptr<unwindstack::Memory> memory_;
};

#endif  // _LIBBACKTRACE_UNWIND_STACK_H
+94 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <stdint.h>
#include <stdlib.h>
#include <sys/types.h>

#include <backtrace/BacktraceMap.h>
#include <unwindstack/Elf.h>
#include <unwindstack/MapInfo.h>
#include <unwindstack/Maps.h>

#include "UnwindStackMap.h"

//-------------------------------------------------------------------------
UnwindStackMap::UnwindStackMap(pid_t pid) : BacktraceMap(pid) {}

bool UnwindStackMap::Build() {
  if (pid_ == 0) {
    pid_ = getpid();
    stack_maps_.reset(new unwindstack::LocalMaps);
  } else {
    stack_maps_.reset(new unwindstack::RemoteMaps(pid_));
  }

  if (!stack_maps_->Parse()) {
    return false;
  }

  // Iterate through the maps and fill in the backtrace_map_t structure.
  for (auto& map_info : *stack_maps_) {
    backtrace_map_t map;
    map.start = map_info.start;
    map.end = map_info.end;
    map.offset = map_info.offset;
    // Set to -1 so that it is demand loaded.
    map.load_bias = static_cast<uintptr_t>(-1);
    map.flags = map_info.flags;
    map.name = map_info.name;

    maps_.push_back(map);
  }

  return true;
}

void UnwindStackMap::FillIn(uintptr_t addr, backtrace_map_t* map) {
  BacktraceMap::FillIn(addr, map);
  if (map->load_bias != static_cast<uintptr_t>(-1)) {
    return;
  }

  // Fill in the load_bias.
  unwindstack::MapInfo* map_info = stack_maps_->Find(addr);
  if (map_info == nullptr) {
    return;
  }
  unwindstack::Elf* elf = map_info->GetElf(pid_, true);
  map->load_bias = elf->GetLoadBias();
}

//-------------------------------------------------------------------------
// BacktraceMap create function.
//-------------------------------------------------------------------------
BacktraceMap* BacktraceMap::CreateNew(pid_t pid, bool uncached) {
  BacktraceMap* map;

  if (uncached) {
    // Force use of the base class to parse the maps when this call is made.
    map = new BacktraceMap(pid);
  } else if (pid == getpid()) {
    map = new UnwindStackMap(0);
  } else {
    map = new UnwindStackMap(pid);
  }
  if (!map->Build()) {
    delete map;
    return nullptr;
  }
  return map;
}
+41 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef _LIBBACKTRACE_UNWINDSTACK_MAP_H
#define _LIBBACKTRACE_UNWINDSTACK_MAP_H

#include <stdint.h>
#include <sys/types.h>

#include <backtrace/BacktraceMap.h>
#include <unwindstack/Maps.h>

class UnwindStackMap : public BacktraceMap {
 public:
  explicit UnwindStackMap(pid_t pid);
  ~UnwindStackMap() = default;

  bool Build() override;

  void FillIn(uintptr_t addr, backtrace_map_t* map) override;

  unwindstack::Maps* stack_maps() { return stack_maps_.get(); }

 protected:
  std::unique_ptr<unwindstack::Maps> stack_maps_;
};

#endif  // _LIBBACKTRACE_UNWINDSTACK_MAP_H
Loading