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

Commit 9dc41d5d authored by Christopher Ferris's avatar Christopher Ferris Committed by Gerrit Code Review
Browse files

Merge "Refactor the code."

parents 9c01c44b 2c43cff0
Loading
Loading
Loading
Loading
+9 −12
Original line number Diff line number Diff line
@@ -44,9 +44,6 @@ struct backtrace_frame_data_t {
  uintptr_t func_offset;  // pc relative to the start of the function, only valid if func_name is not NULL.
};

// Forward declarations.
class BacktraceImpl;

#if defined(__APPLE__)
struct __darwin_ucontext;
typedef __darwin_ucontext ucontext_t;
@@ -72,7 +69,7 @@ public:
  virtual ~Backtrace();

  // Get the current stack trace and store in the backtrace_ structure.
  virtual bool Unwind(size_t num_ignore_frames, ucontext_t* context = NULL);
  virtual bool Unwind(size_t num_ignore_frames, ucontext_t* context = NULL) = 0;

  // Get the function name and offset into the function given the pc.
  // If the string is empty, then no valid function name was found.
@@ -95,9 +92,9 @@ public:
  virtual std::string FormatFrameData(size_t frame_num);
  virtual std::string FormatFrameData(const backtrace_frame_data_t* frame);

  pid_t Pid() { return pid_; }
  pid_t Tid() { return tid_; }
  size_t NumFrames() { return frames_.size(); }
  pid_t Pid() const { return pid_; }
  pid_t Tid() const { return tid_; }
  size_t NumFrames() const { return frames_.size(); }

  const backtrace_frame_data_t* GetFrame(size_t frame_num) {
    if (frame_num >= frames_.size()) {
@@ -117,7 +114,11 @@ public:
  BacktraceMap* GetMap() { return map_; }

protected:
  Backtrace(BacktraceImpl* impl, pid_t pid, BacktraceMap* map);
  Backtrace(pid_t pid, pid_t tid, BacktraceMap* map);

  // The name returned is not demangled, GetFunctionName() takes care of
  // demangling the name.
  virtual std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) = 0;

  virtual bool VerifyReadWordArgs(uintptr_t ptr, word_t* out_value);

@@ -130,10 +131,6 @@ protected:
  bool map_shared_;

  std::vector<backtrace_frame_data_t> frames_;

  BacktraceImpl* impl_;

  friend class BacktraceImpl;
};

#endif // _BACKTRACE_BACKTRACE_H
+10 −4
Original line number Diff line number Diff line
@@ -19,13 +19,19 @@ include $(CLEAR_VARS)
LOCAL_MODULE := $(module)
LOCAL_MODULE_TAGS := $(module_tag)
LOCAL_MULTILIB := $($(module)_multilib)
ifeq ($(LOCAL_MULTILIB),both)
ifneq ($(build_target),$(filter $(build_target),SHARED_LIBRARY STATIC_LIBRRARY))
  LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
  LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
endif
endif

LOCAL_ADDITIONAL_DEPENDENCIES := \
    $(LOCAL_PATH)/Android.mk \
    $(LOCAL_PATH)/Android.build.mk \

LOCAL_CFLAGS := \
    $(common_cflags) \
    $(libbacktrace_common_cflags) \
    $($(module)_cflags) \
    $($(module)_cflags_$(build_type)) \

@@ -33,17 +39,17 @@ LOCAL_CLANG_CFLAGS += \
    $(libbacktrace_common_clang_cflags) \

LOCAL_CONLYFLAGS += \
    $(common_conlyflags) \
    $(libbacktrace_common_conlyflags) \
    $($(module)_conlyflags) \
    $($(module)_conlyflags_$(build_type)) \

LOCAL_CPPFLAGS += \
    $(common_cppflags) \
    $(libbacktrace_common_cppflags) \
    $($(module)_cppflags) \
    $($(module)_cppflags_$(build_type)) \

LOCAL_C_INCLUDES := \
    $(common_c_includes) \
    $(libbacktrace_common_c_includes) \
    $($(module)_c_includes) \
    $($(module)_c_includes_$(build_type)) \

libbacktrace/Android.mk

100755 → 100644
+13 −10
Original line number Diff line number Diff line
@@ -16,14 +16,14 @@

LOCAL_PATH:= $(call my-dir)

common_cflags := \
libbacktrace_common_cflags := \
	-Wall \
	-Werror \

common_conlyflags := \
libbacktrace_common_conlyflags := \
	-std=gnu99 \

common_cppflags := \
libbacktrace_common_cppflags := \
	-std=gnu++11 \

# The latest clang (r230699) does not allow SP/PC to be declared in inline asm lists.
@@ -41,20 +41,21 @@ endif
# The libbacktrace library.
#-------------------------------------------------------------------------
libbacktrace_src_files := \
	BacktraceImpl.cpp \
	Backtrace.cpp \
	BacktraceCurrent.cpp \
	BacktraceMap.cpp \
	BacktraceThread.cpp \
	BacktracePtrace.cpp \
	thread_utils.c \

libbacktrace_shared_libraries_target := \
	libcutils \

libbacktrace_src_files += \
	ThreadEntry.cpp \
	UnwindCurrent.cpp \
	UnwindMap.cpp \
	UnwindPtrace.cpp \

libbacktrace_shared_libraries_target := \
	libcutils \

libbacktrace_shared_libraries := \
	libbase \
	libunwind \
	libunwind-ptrace \

@@ -90,6 +91,7 @@ module := libbacktrace_test
module_tag := debug
build_type := target
build_target := SHARED_LIBRARY
libbacktrace_test_multilib := both
include $(LOCAL_PATH)/Android.build.mk
build_type := host
include $(LOCAL_PATH)/Android.build.mk
@@ -128,6 +130,7 @@ module := backtrace_test
module_tag := debug
build_type := target
build_target := NATIVE_TEST
backtrace_test_multilib := both
include $(LOCAL_PATH)/Android.build.mk
build_type := host
include $(LOCAL_PATH)/Android.build.mk
+138 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2013 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 <inttypes.h>
#include <stdint.h>
#include <stdlib.h>
#include <sys/types.h>
#include <ucontext.h>

#include <string>

#include <base/stringprintf.h>

#include <backtrace/Backtrace.h>
#include <backtrace/BacktraceMap.h>

#include "BacktraceLog.h"
#include "thread_utils.h"
#include "UnwindCurrent.h"
#include "UnwindPtrace.h"

using android::base::StringPrintf;

//-------------------------------------------------------------------------
// Backtrace functions.
//-------------------------------------------------------------------------
Backtrace::Backtrace(pid_t pid, pid_t tid, BacktraceMap* map)
    : pid_(pid), tid_(tid), map_(map), map_shared_(true) {
  if (map_ == nullptr) {
    map_ = BacktraceMap::Create(pid);
    map_shared_ = false;
  }
}

Backtrace::~Backtrace() {
  if (map_ && !map_shared_) {
    delete map_;
    map_ = nullptr;
  }
}

extern "C" char* __cxa_demangle(const char* mangled, char* buf, size_t* len,
                                int* status);

std::string Backtrace::GetFunctionName(uintptr_t pc, uintptr_t* offset) {
  std::string func_name = GetFunctionNameRaw(pc, offset);
  if (!func_name.empty()) {
#if defined(__APPLE__)
    // Mac OS' __cxa_demangle demangles "f" as "float"; last tested on 10.7.
    if (func_name[0] != '_') {
      return func_name;
    }
#endif
    char* name = __cxa_demangle(func_name.c_str(), 0, 0, 0);
    if (name) {
      func_name = name;
      free(name);
    }
  }
  return func_name;
}

bool Backtrace::VerifyReadWordArgs(uintptr_t ptr, word_t* out_value) {
  if (ptr & (sizeof(word_t)-1)) {
    BACK_LOGW("invalid pointer %p", reinterpret_cast<void*>(ptr));
    *out_value = static_cast<word_t>(-1);
    return false;
  }
  return true;
}

std::string Backtrace::FormatFrameData(size_t frame_num) {
  if (frame_num >= frames_.size()) {
    return "";
  }
  return FormatFrameData(&frames_[frame_num]);
}

std::string Backtrace::FormatFrameData(const backtrace_frame_data_t* frame) {
  const char* map_name;
  if (BacktraceMap::IsValid(frame->map) && !frame->map.name.empty()) {
    map_name = frame->map.name.c_str();
  } else {
    map_name = "<unknown>";
  }

  uintptr_t relative_pc;
  if (BacktraceMap::IsValid(frame->map)) {
    relative_pc = frame->pc - frame->map.start;
  } else {
    relative_pc = frame->pc;
  }

  std::string line(StringPrintf("#%02zu pc %" PRIPTR "  %s", frame->num, relative_pc, map_name));
  if (!frame->func_name.empty()) {
    line += " (" + frame->func_name;
    if (frame->func_offset) {
      line += StringPrintf("+%" PRIuPTR, frame->func_offset);
    }
    line += ')';
  }

  return line;
}

void Backtrace::FillInMap(uintptr_t pc, backtrace_map_t* map) {
  map_->FillIn(pc, map);
}

Backtrace* Backtrace::Create(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 (pid == getpid()) {
    return new UnwindCurrent(pid, tid, map);
  } else {
    return new UnwindPtrace(pid, tid, map);
  }
}
+144 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2013 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 <errno.h>
#include <stdint.h>
#include <string.h>
#include <sys/param.h>
#include <sys/ptrace.h>
#include <sys/types.h>
#include <ucontext.h>
#include <unistd.h>

#include <string>

#include <backtrace/Backtrace.h>
#include <backtrace/BacktraceMap.h>

#include "BacktraceCurrent.h"
#include "BacktraceLog.h"
#include "ThreadEntry.h"
#include "thread_utils.h"

bool BacktraceCurrent::ReadWord(uintptr_t ptr, word_t* out_value) {
  if (!VerifyReadWordArgs(ptr, out_value)) {
    return false;
  }

  backtrace_map_t map;
  FillInMap(ptr, &map);
  if (BacktraceMap::IsValid(map) && map.flags & PROT_READ) {
    *out_value = *reinterpret_cast<word_t*>(ptr);
    return true;
  } else {
    BACK_LOGW("pointer %p not in a readable map", reinterpret_cast<void*>(ptr));
    *out_value = static_cast<word_t>(-1);
    return false;
  }
}

size_t BacktraceCurrent::Read(uintptr_t addr, uint8_t* buffer, size_t bytes) {
  backtrace_map_t map;
  FillInMap(addr, &map);
  if (!BacktraceMap::IsValid(map) || !(map.flags & PROT_READ)) {
    return 0;
  }
  bytes = MIN(map.end - addr, bytes);
  memcpy(buffer, reinterpret_cast<uint8_t*>(addr), bytes);
  return bytes;
}

bool BacktraceCurrent::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) {
  if (ucontext) {
    return UnwindFromContext(num_ignore_frames, ucontext);
  }

  if (Tid() != gettid()) {
    return UnwindThread(num_ignore_frames);
  }

  return UnwindFromContext(num_ignore_frames, nullptr);
}

static pthread_mutex_t g_sigaction_mutex = PTHREAD_MUTEX_INITIALIZER;

static void SignalHandler(int, siginfo_t*, void* sigcontext) {
  ThreadEntry* entry = ThreadEntry::Get(getpid(), gettid(), false);
  if (!entry) {
    BACK_LOGW("Unable to find pid %d tid %d information", getpid(), gettid());
    return;
  }

  entry->CopyUcontextFromSigcontext(sigcontext);

  // Indicate the ucontext is now valid.
  entry->Wake();

  // Pause the thread until the unwind is complete. This avoids having
  // the thread run ahead causing problems.
  // The number indicates that we are waiting for the second Wake() call
  // overall which is made by the thread requesting an unwind.
  entry->Wait(2);

  ThreadEntry::Remove(entry);
}

bool BacktraceCurrent::UnwindThread(size_t num_ignore_frames) {
  // Prevent multiple threads trying to set the trigger action on different
  // threads at the same time.
  pthread_mutex_lock(&g_sigaction_mutex);

  ThreadEntry* entry = ThreadEntry::Get(Pid(), Tid());
  entry->Lock();

  struct sigaction act, oldact;
  memset(&act, 0, sizeof(act));
  act.sa_sigaction = SignalHandler;
  act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
  sigemptyset(&act.sa_mask);
  if (sigaction(THREAD_SIGNAL, &act, &oldact) != 0) {
    BACK_LOGW("sigaction failed %s", strerror(errno));
    entry->Unlock();
    ThreadEntry::Remove(entry);
    pthread_mutex_unlock(&g_sigaction_mutex);
    return false;
  }

  if (tgkill(Pid(), Tid(), THREAD_SIGNAL) != 0) {
    BACK_LOGW("tgkill %d failed: %s", Tid(), strerror(errno));
    sigaction(THREAD_SIGNAL, &oldact, nullptr);
    entry->Unlock();
    ThreadEntry::Remove(entry);
    pthread_mutex_unlock(&g_sigaction_mutex);
    return false;
  }

  // Wait for the thread to get the ucontext. The number indicates
  // that we are waiting for the first Wake() call made by the thread.
  entry->Wait(1);

  // After the thread has received the signal, allow other unwinders to
  // continue.
  sigaction(THREAD_SIGNAL, &oldact, nullptr);
  pthread_mutex_unlock(&g_sigaction_mutex);

  bool unwind_done = UnwindFromContext(num_ignore_frames, entry->GetUcontext());

  // Tell the signal handler to exit and release the entry.
  entry->Wake();

  return unwind_done;
}
Loading