LP64: Enable debuggerd/libbacktrace/libunwind.
Change-Id: I2e432839f86c33c2adbaac8cc12ca8961956044b Signed-off-by: Pavel Chupin <pavel.v.chupin@intel.com>
This commit is contained in:
parent
e97dad0d95
commit
c6c194ced0
11 changed files with 129 additions and 83 deletions
|
@ -1,6 +1,6 @@
|
|||
# Copyright 2005 The Android Open Source Project
|
||||
|
||||
ifneq ($(filter arm mips x86,$(TARGET_ARCH)),)
|
||||
ifneq ($(filter arm mips x86 x86_64,$(TARGET_ARCH)),)
|
||||
|
||||
LOCAL_PATH:= $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
|
@ -19,6 +19,7 @@ LOCAL_CFLAGS := \
|
|||
-Wall \
|
||||
-Wno-array-bounds \
|
||||
-Werror \
|
||||
-Wno-unused-parameter \
|
||||
|
||||
LOCAL_MODULE := debuggerd
|
||||
|
||||
|
|
45
debuggerd/tombstone.cpp
Normal file → Executable file
45
debuggerd/tombstone.cpp
Normal file → Executable file
|
@ -179,9 +179,9 @@ static void dump_fault_addr(log_t* log, pid_t tid, int sig) {
|
|||
if (ptrace(PTRACE_GETSIGINFO, tid, 0, &si)){
|
||||
_LOG(log, SCOPE_AT_FAULT, "cannot get siginfo: %s\n", strerror(errno));
|
||||
} else if (signal_has_address(sig)) {
|
||||
_LOG(log, SCOPE_AT_FAULT, "signal %d (%s), code %d (%s), fault addr %0*" PRIxPTR "\n",
|
||||
_LOG(log, SCOPE_AT_FAULT, "signal %d (%s), code %d (%s), fault addr %" PRIPTR "\n",
|
||||
sig, get_signame(sig), si.si_code, get_sigcode(sig, si.si_code),
|
||||
sizeof(uintptr_t)*2, reinterpret_cast<uintptr_t>(si.si_addr));
|
||||
reinterpret_cast<uintptr_t>(si.si_addr));
|
||||
} else {
|
||||
_LOG(log, SCOPE_AT_FAULT, "signal %d (%s), code %d (%s), fault addr --------\n",
|
||||
sig, get_signame(sig), si.si_code, get_sigcode(sig, si.si_code));
|
||||
|
@ -226,7 +226,7 @@ static void dump_thread_info(log_t* log, pid_t pid, pid_t tid, int scope_flags)
|
|||
static void dump_stack_segment(
|
||||
Backtrace* backtrace, log_t* log, int scope_flags, uintptr_t* sp, size_t words, int label) {
|
||||
for (size_t i = 0; i < words; i++) {
|
||||
uint32_t stack_content;
|
||||
word_t stack_content;
|
||||
if (!backtrace->ReadWord(*sp, &stack_content)) {
|
||||
break;
|
||||
}
|
||||
|
@ -243,32 +243,32 @@ static void dump_stack_segment(
|
|||
if (!func_name.empty()) {
|
||||
if (!i && label >= 0) {
|
||||
if (offset) {
|
||||
_LOG(log, scope_flags, " #%02d %08x %08x %s (%s+%u)\n",
|
||||
_LOG(log, scope_flags, " #%02d %" PRIPTR " %" PRIPTR " %s (%s+%" PRIxPTR "u)\n",
|
||||
label, *sp, stack_content, map_name, func_name.c_str(), offset);
|
||||
} else {
|
||||
_LOG(log, scope_flags, " #%02d %08x %08x %s (%s)\n",
|
||||
_LOG(log, scope_flags, " #%02d %" PRIPTR " %" PRIPTR " %s (%s)\n",
|
||||
label, *sp, stack_content, map_name, func_name.c_str());
|
||||
}
|
||||
} else {
|
||||
if (offset) {
|
||||
_LOG(log, scope_flags, " %08x %08x %s (%s+%u)\n",
|
||||
_LOG(log, scope_flags, " %" PRIPTR " %" PRIPTR " %s (%s+%" PRIxPTR "u)\n",
|
||||
*sp, stack_content, map_name, func_name.c_str(), offset);
|
||||
} else {
|
||||
_LOG(log, scope_flags, " %08x %08x %s (%s)\n",
|
||||
_LOG(log, scope_flags, " %" PRIPTR " %" PRIPTR " %s (%s)\n",
|
||||
*sp, stack_content, map_name, func_name.c_str());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!i && label >= 0) {
|
||||
_LOG(log, scope_flags, " #%02d %08x %08x %s\n",
|
||||
_LOG(log, scope_flags, " #%02d %" PRIPTR " %" PRIPTR " %s\n",
|
||||
label, *sp, stack_content, map_name);
|
||||
} else {
|
||||
_LOG(log, scope_flags, " %08x %08x %s\n",
|
||||
_LOG(log, scope_flags, " %" PRIPTR " %" PRIPTR " %s\n",
|
||||
*sp, stack_content, map_name);
|
||||
}
|
||||
}
|
||||
|
||||
*sp += sizeof(uint32_t);
|
||||
*sp += sizeof(word_t);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -291,7 +291,7 @@ static void dump_stack(Backtrace* backtrace, log_t* log, int scope_flags) {
|
|||
scope_flags |= SCOPE_SENSITIVE;
|
||||
|
||||
// Dump a few words before the first frame.
|
||||
uintptr_t sp = backtrace->GetFrame(first)->sp - STACK_WORDS * sizeof(uint32_t);
|
||||
word_t sp = backtrace->GetFrame(first)->sp - STACK_WORDS * sizeof(word_t);
|
||||
dump_stack_segment(backtrace, log, scope_flags, &sp, STACK_WORDS, -1);
|
||||
|
||||
// Dump a few words from all successive frames.
|
||||
|
@ -311,7 +311,7 @@ static void dump_stack(Backtrace* backtrace, log_t* log, int scope_flags) {
|
|||
_LOG(log, scope_flags, " ........ ........\n");
|
||||
}
|
||||
} else {
|
||||
size_t words = frame->stack_size / sizeof(uint32_t);
|
||||
size_t words = frame->stack_size / sizeof(word_t);
|
||||
if (words == 0) {
|
||||
words = 1;
|
||||
} else if (words > STACK_WORDS) {
|
||||
|
@ -334,7 +334,7 @@ static void dump_backtrace_and_stack(Backtrace* backtrace, log_t* log, int scope
|
|||
|
||||
static void dump_map(log_t* log, const backtrace_map_t* map, const char* what, int scope_flags) {
|
||||
if (map != NULL) {
|
||||
_LOG(log, scope_flags, " %08x-%08x %c%c%c %s\n", map->start, map->end,
|
||||
_LOG(log, scope_flags, " %" PRIPTR "-%" PRIPTR " %c%c%c %s\n", map->start, map->end,
|
||||
(map->flags & PROT_READ) ? 'r' : '-', (map->flags & PROT_WRITE) ? 'w' : '-',
|
||||
(map->flags & PROT_EXEC) ? 'x' : '-', map->name.c_str());
|
||||
} else {
|
||||
|
@ -573,24 +573,15 @@ static void dump_abort_message(Backtrace* backtrace, log_t* log, uintptr_t addre
|
|||
memset(msg, 0, sizeof(msg));
|
||||
char* p = &msg[0];
|
||||
while (p < &msg[sizeof(msg)]) {
|
||||
uint32_t data;
|
||||
word_t data;
|
||||
size_t len = sizeof(word_t);
|
||||
if (!backtrace->ReadWord(address, &data)) {
|
||||
break;
|
||||
}
|
||||
address += sizeof(uint32_t);
|
||||
address += sizeof(word_t);
|
||||
|
||||
if ((*p++ = (data >> 0) & 0xff) == 0) {
|
||||
break;
|
||||
}
|
||||
if ((*p++ = (data >> 8) & 0xff) == 0) {
|
||||
break;
|
||||
}
|
||||
if ((*p++ = (data >> 16) & 0xff) == 0) {
|
||||
break;
|
||||
}
|
||||
if ((*p++ = (data >> 24) & 0xff) == 0) {
|
||||
break;
|
||||
}
|
||||
while (len > 0 && (*p++ = (data >> (sizeof(word_t) - len) * 8) & 0xff) != 0)
|
||||
len--;
|
||||
}
|
||||
msg[sizeof(msg) - 1] = '\0';
|
||||
|
||||
|
|
|
@ -14,19 +14,17 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "utility.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <log/logd.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/wait.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "utility.h"
|
||||
#include <backtrace/Backtrace.h>
|
||||
#include <log/logd.h>
|
||||
|
||||
const int sleep_time_usec = 50000; // 0.05 seconds
|
||||
const int max_total_sleep_usec = 10000000; // 10 seconds
|
||||
|
@ -34,7 +32,7 @@ const int max_total_sleep_usec = 10000000; // 10 seconds
|
|||
static int write_to_am(int fd, const char* buf, int len) {
|
||||
int to_write = len;
|
||||
while (to_write > 0) {
|
||||
int written = TEMP_FAILURE_RETRY( write(fd, buf + len - to_write, to_write) );
|
||||
int written = TEMP_FAILURE_RETRY(write(fd, buf + len - to_write, to_write));
|
||||
if (written < 0) {
|
||||
// hard failure
|
||||
LOG("AM write failure (%d / %s)\n", errno, strerror(errno));
|
||||
|
@ -46,34 +44,28 @@ static int write_to_am(int fd, const char* buf, int len) {
|
|||
}
|
||||
|
||||
void _LOG(log_t* log, int scopeFlags, const char* fmt, ...) {
|
||||
char buf[512];
|
||||
bool want_tfd_write;
|
||||
bool want_log_write;
|
||||
bool want_amfd_write;
|
||||
int len = 0;
|
||||
bool want_tfd_write = log && log->tfd >= 0;
|
||||
bool want_log_write = IS_AT_FAULT(scopeFlags) && (!log || !log->quiet);
|
||||
bool want_amfd_write = IS_AT_FAULT(scopeFlags) && !IS_SENSITIVE(scopeFlags) && log && log->amfd >= 0;
|
||||
|
||||
char buf[512];
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(buf, sizeof(buf), fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
// where is the information going to go?
|
||||
want_tfd_write = log && log->tfd >= 0;
|
||||
want_log_write = IS_AT_FAULT(scopeFlags) && (!log || !log->quiet);
|
||||
want_amfd_write = IS_AT_FAULT(scopeFlags) && !IS_SENSITIVE(scopeFlags) && log && log->amfd >= 0;
|
||||
|
||||
// if we're going to need the literal string, generate it once here
|
||||
if (want_tfd_write || want_amfd_write) {
|
||||
vsnprintf(buf, sizeof(buf), fmt, ap);
|
||||
len = strlen(buf);
|
||||
size_t len = strlen(buf);
|
||||
if (len <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (want_tfd_write) {
|
||||
write(log->tfd, buf, len);
|
||||
TEMP_FAILURE_RETRY(write(log->tfd, buf, len));
|
||||
}
|
||||
|
||||
if (want_log_write) {
|
||||
// whatever goes to logcat also goes to the Activity Manager
|
||||
__android_log_vprint(ANDROID_LOG_INFO, "DEBUG", fmt, ap);
|
||||
if (want_amfd_write && len > 0) {
|
||||
__android_log_write(ANDROID_LOG_INFO, "DEBUG", buf);
|
||||
if (want_amfd_write) {
|
||||
int written = write_to_am(log->amfd, buf, len);
|
||||
if (written <= 0) {
|
||||
// timeout or other failure on write; stop informing the activity manager
|
||||
|
@ -81,7 +73,6 @@ void _LOG(log_t* log, int scopeFlags, const char* fmt, ...) {
|
|||
}
|
||||
}
|
||||
}
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
int wait_for_signal(pid_t tid, int* total_sleep_time_usec) {
|
||||
|
|
|
@ -18,9 +18,8 @@
|
|||
#ifndef _DEBUGGERD_UTILITY_H
|
||||
#define _DEBUGGERD_UTILITY_H
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
typedef struct {
|
||||
/* tombstone file descriptor */
|
||||
|
@ -61,14 +60,6 @@ void _LOG(log_t* log, int scopeFlags, const char *fmt, ...)
|
|||
#define XLOG2(fmt...) do {} while(0)
|
||||
#endif
|
||||
|
||||
#if __LP64__
|
||||
#define PRIPTR "016" PRIxPTR
|
||||
typedef uint64_t word_t;
|
||||
#else
|
||||
#define PRIPTR "08" PRIxPTR
|
||||
typedef uint32_t word_t;
|
||||
#endif
|
||||
|
||||
int wait_for_signal(pid_t tid, int* total_sleep_time_usec);
|
||||
void wait_for_stop(pid_t tid, int* total_sleep_time_usec);
|
||||
|
||||
|
|
15
debuggerd/x86_64/crashglue.S
Normal file
15
debuggerd/x86_64/crashglue.S
Normal file
|
@ -0,0 +1,15 @@
|
|||
.globl crash1
|
||||
.globl crashnostack
|
||||
|
||||
crash1:
|
||||
movl $0xa5a50000, %eax
|
||||
movl $0xa5a50001, %ebx
|
||||
movl $0xa5a50002, %ecx
|
||||
|
||||
movl $0, %edx
|
||||
jmp *%rdx
|
||||
|
||||
|
||||
crashnostack:
|
||||
movl $0, %ebp
|
||||
jmp *%rbp
|
51
debuggerd/x86_64/machine.cpp
Executable file
51
debuggerd/x86_64/machine.cpp
Executable file
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
** Copyright 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 <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/user.h>
|
||||
|
||||
#include "../utility.h"
|
||||
#include "../machine.h"
|
||||
|
||||
void dump_memory_and_code(log_t* log, pid_t tid, int scope_flags) {
|
||||
}
|
||||
|
||||
void dump_registers(log_t* log, pid_t tid, int scope_flags) {
|
||||
struct user_regs_struct r;
|
||||
if (ptrace(PTRACE_GETREGS, tid, 0, &r) == -1) {
|
||||
_LOG(log, scope_flags, "cannot get registers: %s\n", strerror(errno));
|
||||
return;
|
||||
}
|
||||
_LOG(log, scope_flags, " rax %016lx rbx %016lx rcx %016lx rdx %016lx\n",
|
||||
r.rax, r.rbx, r.rcx, r.rdx);
|
||||
_LOG(log, scope_flags, " rsi %016lx rdi %016lx\n",
|
||||
r.rsi, r.rdi);
|
||||
_LOG(log, scope_flags, " r8 %016lx r9 %016lx r10 %016lx r11 %016lx\n",
|
||||
r.r8, r.r9, r.r10, r.r11);
|
||||
_LOG(log, scope_flags, " r12 %016lx r13 %016lx r14 %016lx r15 %016lx\n",
|
||||
r.r12, r.r13, r.r14, r.r15);
|
||||
_LOG(log, scope_flags, " cs %016lx ss %016lx\n",
|
||||
r.cs, r.ss);
|
||||
_LOG(log, scope_flags, " rip %016lx rbp %016lx rsp %016lx eflags %016lx\n",
|
||||
r.rip, r.rbp, r.rsp, r.eflags);
|
||||
}
|
|
@ -17,6 +17,7 @@
|
|||
#ifndef _BACKTRACE_BACKTRACE_H
|
||||
#define _BACKTRACE_BACKTRACE_H
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <string>
|
||||
|
@ -25,6 +26,14 @@
|
|||
#include <backtrace/backtrace_constants.h>
|
||||
#include <backtrace/BacktraceMap.h>
|
||||
|
||||
#if __LP64__
|
||||
#define PRIPTR "016" PRIxPTR
|
||||
typedef uint64_t word_t;
|
||||
#else
|
||||
#define PRIPTR "08" PRIxPTR
|
||||
typedef uint32_t word_t;
|
||||
#endif
|
||||
|
||||
struct backtrace_frame_data_t {
|
||||
size_t num; // The current fame number.
|
||||
uintptr_t pc; // The absolute pc.
|
||||
|
@ -65,7 +74,7 @@ public:
|
|||
virtual const backtrace_map_t* FindMap(uintptr_t pc);
|
||||
|
||||
// Read the data at a specific address.
|
||||
virtual bool ReadWord(uintptr_t ptr, uint32_t* out_value) = 0;
|
||||
virtual bool ReadWord(uintptr_t ptr, word_t* out_value) = 0;
|
||||
|
||||
// Create a string representing the formatted line of backtrace information
|
||||
// for a single frame.
|
||||
|
@ -96,7 +105,7 @@ public:
|
|||
protected:
|
||||
Backtrace(BacktraceImpl* impl, pid_t pid, BacktraceMap* map);
|
||||
|
||||
virtual bool VerifyReadWordArgs(uintptr_t ptr, uint32_t* out_value);
|
||||
virtual bool VerifyReadWordArgs(uintptr_t ptr, word_t* out_value);
|
||||
|
||||
bool BuildMap();
|
||||
|
||||
|
|
2
libbacktrace/Android.mk
Normal file → Executable file
2
libbacktrace/Android.mk
Normal file → Executable file
|
@ -23,7 +23,7 @@ common_shared_libs := \
|
|||
liblog \
|
||||
|
||||
# To enable using libunwind on each arch, add it to this list.
|
||||
libunwind_architectures := arm arm64 x86
|
||||
libunwind_architectures := arm arm64 x86 x86_64
|
||||
|
||||
ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),$(libunwind_architectures)))
|
||||
|
||||
|
|
|
@ -21,8 +21,6 @@
|
|||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <backtrace/Backtrace.h>
|
||||
|
@ -81,10 +79,10 @@ std::string Backtrace::GetFunctionName(uintptr_t pc, uintptr_t* offset) {
|
|||
return func_name;
|
||||
}
|
||||
|
||||
bool Backtrace::VerifyReadWordArgs(uintptr_t ptr, uint32_t* out_value) {
|
||||
if (ptr & 3) {
|
||||
bool Backtrace::VerifyReadWordArgs(uintptr_t ptr, word_t* out_value) {
|
||||
if (ptr & (sizeof(word_t)-1)) {
|
||||
BACK_LOGW("invalid pointer %p", (void*)ptr);
|
||||
*out_value = (uint32_t)-1;
|
||||
*out_value = (word_t)-1;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -142,18 +140,18 @@ BacktraceCurrent::BacktraceCurrent(
|
|||
BacktraceCurrent::~BacktraceCurrent() {
|
||||
}
|
||||
|
||||
bool BacktraceCurrent::ReadWord(uintptr_t ptr, uint32_t* out_value) {
|
||||
bool BacktraceCurrent::ReadWord(uintptr_t ptr, word_t* out_value) {
|
||||
if (!VerifyReadWordArgs(ptr, out_value)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const backtrace_map_t* map = FindMap(ptr);
|
||||
if (map && map->flags & PROT_READ) {
|
||||
*out_value = *reinterpret_cast<uint32_t*>(ptr);
|
||||
*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<uint32_t>(-1);
|
||||
*out_value = static_cast<word_t>(-1);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -170,7 +168,7 @@ BacktracePtrace::BacktracePtrace(
|
|||
BacktracePtrace::~BacktracePtrace() {
|
||||
}
|
||||
|
||||
bool BacktracePtrace::ReadWord(uintptr_t ptr, uint32_t* out_value) {
|
||||
bool BacktracePtrace::ReadWord(uintptr_t ptr, word_t* out_value) {
|
||||
if (!VerifyReadWordArgs(ptr, out_value)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -183,7 +181,7 @@ bool BacktracePtrace::ReadWord(uintptr_t ptr, uint32_t* out_value) {
|
|||
// To disambiguate -1 from a valid result, we clear errno beforehand.
|
||||
errno = 0;
|
||||
*out_value = ptrace(PTRACE_PEEKTEXT, Tid(), reinterpret_cast<void*>(ptr), NULL);
|
||||
if (*out_value == static_cast<uint32_t>(-1) && errno) {
|
||||
if (*out_value == static_cast<word_t>(-1) && errno) {
|
||||
BACK_LOGW("invalid pointer %p reading from tid %d, ptrace() strerror(errno)=%s",
|
||||
reinterpret_cast<void*>(ptr), Tid(), strerror(errno));
|
||||
return false;
|
||||
|
|
4
libbacktrace/BacktraceImpl.h
Normal file → Executable file
4
libbacktrace/BacktraceImpl.h
Normal file → Executable file
|
@ -61,7 +61,7 @@ public:
|
|||
BacktraceCurrent(BacktraceImpl* impl, BacktraceMap* map);
|
||||
virtual ~BacktraceCurrent();
|
||||
|
||||
bool ReadWord(uintptr_t ptr, uint32_t* out_value);
|
||||
bool ReadWord(uintptr_t ptr, word_t* out_value);
|
||||
};
|
||||
|
||||
class BacktracePtrace : public Backtrace {
|
||||
|
@ -69,7 +69,7 @@ public:
|
|||
BacktracePtrace(BacktraceImpl* impl, pid_t pid, pid_t tid, BacktraceMap* map);
|
||||
virtual ~BacktracePtrace();
|
||||
|
||||
bool ReadWord(uintptr_t ptr, uint32_t* out_value);
|
||||
bool ReadWord(uintptr_t ptr, word_t* out_value);
|
||||
};
|
||||
|
||||
Backtrace* CreateCurrentObj(BacktraceMap* map);
|
||||
|
|
3
libbacktrace/UnwindCurrent.cpp
Normal file → Executable file
3
libbacktrace/UnwindCurrent.cpp
Normal file → Executable file
|
@ -16,6 +16,7 @@
|
|||
|
||||
#define LOG_TAG "libbacktrace"
|
||||
|
||||
#include <sys/ucontext.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <backtrace/Backtrace.h>
|
||||
|
@ -27,8 +28,6 @@
|
|||
#include "UnwindCurrent.h"
|
||||
#include "UnwindMap.h"
|
||||
|
||||
#include <ucontext.h>
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// UnwindCurrent functions.
|
||||
//-------------------------------------------------------------------------
|
||||
|
|
Loading…
Reference in a new issue