Support libcorkscrew on x86 hosts in binaries using glibc.

Change-Id: I1f2b7f21cc7f8227dbe7d294fed88cb691a24d09
This commit is contained in:
Elliott Hughes 2012-05-18 11:56:17 -07:00
parent b7fa1fc12d
commit 71363a8075
5 changed files with 132 additions and 48 deletions

View file

@ -14,9 +14,7 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
generic_src_files := \
backtrace.c \
backtrace-helper.c \
demangle.c \
@ -24,16 +22,24 @@ LOCAL_SRC_FILES := \
ptrace.c \
symbol_table.c
ifeq ($(TARGET_ARCH),arm)
LOCAL_SRC_FILES += \
arm_src_files := \
arch-arm/backtrace-arm.c \
arch-arm/ptrace-arm.c
x86_src_files := \
arch-x86/backtrace-x86.c \
arch-x86/ptrace-x86.c
include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(generic_src_files)
ifeq ($(TARGET_ARCH),arm)
LOCAL_SRC_FILES += $(arm_src_files)
LOCAL_CFLAGS += -DCORKSCREW_HAVE_ARCH
endif
ifeq ($(TARGET_ARCH),x86)
LOCAL_SRC_FILES += \
arch-x86/backtrace-x86.c \
arch-x86/ptrace-x86.c
LOCAL_SRC_FILES += $(x86_src_files)
LOCAL_CFLAGS += -DCORKSCREW_HAVE_ARCH
endif
@ -44,3 +50,38 @@ LOCAL_MODULE := libcorkscrew
LOCAL_MODULE_TAGS := optional
include $(BUILD_SHARED_LIBRARY)
# Build test.
include $(CLEAR_VARS)
LOCAL_SRC_FILES := test.c
LOCAL_CFLAGS += -std=gnu99 -Werror -fno-inline-small-functions
LOCAL_SHARED_LIBRARIES := libcorkscrew
LOCAL_MODULE := libcorkscrew_test
LOCAL_MODULE_TAGS := optional
include $(BUILD_EXECUTABLE)
ifeq ($(HOST_OS)-$(HOST_ARCH),linux-x86)
# Build libcorkscrew.
include $(CLEAR_VARS)
LOCAL_SRC_FILES += $(generic_src_files) $(x86_src_files)
LOCAL_CFLAGS += -DCORKSCREW_HAVE_ARCH
LOCAL_SHARED_LIBRARIES += libgccdemangle
LOCAL_STATIC_LIBRARIES += libcutils
LOCAL_LDLIBS += -ldl -lrt
LOCAL_CFLAGS += -std=gnu99 -Werror
LOCAL_MODULE := libcorkscrew
LOCAL_MODULE_TAGS := optional
include $(BUILD_HOST_SHARED_LIBRARY)
# Build test.
include $(CLEAR_VARS)
LOCAL_SRC_FILES := test.c
LOCAL_CFLAGS += -std=gnu99 -Werror -fno-inline-small-functions
LOCAL_SHARED_LIBRARIES := libcorkscrew
LOCAL_MODULE := libcorkscrew_test
LOCAL_MODULE_TAGS := optional
include $(BUILD_HOST_EXECUTABLE)
endif # linux-x86

View file

@ -31,40 +31,10 @@
#include <limits.h>
#include <errno.h>
#include <sys/ptrace.h>
#include <sys/exec_elf.h>
#include <cutils/log.h>
/* Machine context at the time a signal was raised. */
typedef struct ucontext {
uint32_t uc_flags;
struct ucontext* uc_link;
stack_t uc_stack;
struct sigcontext {
uint32_t gs;
uint32_t fs;
uint32_t es;
uint32_t ds;
uint32_t edi;
uint32_t esi;
uint32_t ebp;
uint32_t esp;
uint32_t ebx;
uint32_t edx;
uint32_t ecx;
uint32_t eax;
uint32_t trapno;
uint32_t err;
uint32_t eip;
uint32_t cs;
uint32_t efl;
uint32_t uesp;
uint32_t ss;
void* fpregs;
uint32_t oldmask;
uint32_t cr2;
} uc_mcontext;
uint32_t uc_sigmask;
} ucontext_t;
#define __USE_GNU // For REG_EBP, REG_ESP, and REG_EIP.
#include <ucontext.h>
/* Unwind state. */
typedef struct {
@ -114,9 +84,9 @@ ssize_t unwind_backtrace_signal_arch(siginfo_t* siginfo, void* sigcontext,
const ucontext_t* uc = (const ucontext_t*)sigcontext;
unwind_state_t state;
state.ebp = uc->uc_mcontext.ebp;
state.eip = uc->uc_mcontext.eip;
state.esp = uc->uc_mcontext.esp;
state.ebp = uc->uc_mcontext.gregs[REG_EBP];
state.esp = uc->uc_mcontext.gregs[REG_ESP];
state.eip = uc->uc_mcontext.gregs[REG_EIP];
memory_t memory;
init_memory(&memory, map_info_list);

View file

@ -27,16 +27,41 @@
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <unwind.h>
#include <sys/exec_elf.h>
#include <cutils/log.h>
#include <cutils/atomic.h>
#include <elf.h>
#if HAVE_DLADDR
#define __USE_GNU // For dladdr(3) in glibc.
#include <dlfcn.h>
#endif
#if defined(__BIONIC__)
// Bionic implements and exports gettid but only implements tgkill.
extern int tgkill(int tgid, int tid, int sig);
#else
// glibc doesn't implement or export either gettid or tgkill.
#include <unistd.h>
#include <sys/syscall.h>
static pid_t gettid() {
return syscall(__NR_gettid);
}
static int tgkill(int tgid, int tid, int sig) {
return syscall(__NR_tgkill, tgid, tid, sig);
}
#endif
typedef struct {
backtrace_frame_t* backtrace;
size_t ignore_depth;
@ -115,8 +140,6 @@ static void unwind_backtrace_thread_signal_handler(int n, siginfo_t* siginfo, vo
}
#endif
extern int tgkill(int tgid, int tid, int sig);
ssize_t unwind_backtrace_thread(pid_t tid, backtrace_frame_t* backtrace,
size_t ignore_depth, size_t max_depth) {
if (tid == gettid()) {

View file

@ -19,14 +19,22 @@
#include <corkscrew/symbol_table.h>
#include <stdbool.h>
#include <stdlib.h>
#include <elf.h>
#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/exec_elf.h>
#include <cutils/log.h>
static bool is_elf(Elf32_Ehdr* e) {
return (e->e_ident[EI_MAG0] == ELFMAG0 &&
e->e_ident[EI_MAG1] == ELFMAG1 &&
e->e_ident[EI_MAG2] == ELFMAG2 &&
e->e_ident[EI_MAG3] == ELFMAG3);
}
// Compare function for qsort
static int qcompar(const void *a, const void *b) {
const symbol_t* asym = (const symbol_t*)a;
@ -67,7 +75,7 @@ symbol_table_t* load_symbol_table(const char *filename) {
// Parse the file header
Elf32_Ehdr *hdr = (Elf32_Ehdr*)base;
if (!IS_ELF(*hdr)) {
if (!is_elf(hdr)) {
goto out_close;
}
Elf32_Shdr *shdr = (Elf32_Shdr*)(base + hdr->e_shoff);

42
libcorkscrew/test.c Normal file
View file

@ -0,0 +1,42 @@
#include <corkscrew/backtrace.h>
#include <stdio.h>
#include <stdlib.h>
void do_backtrace() {
const size_t MAX_DEPTH = 32;
backtrace_frame_t* frames = (backtrace_frame_t*) malloc(sizeof(backtrace_frame_t) * MAX_DEPTH);
ssize_t frame_count = unwind_backtrace(frames, 0, MAX_DEPTH);
fprintf(stderr, "frame_count=%d\n", (int) frame_count);
backtrace_symbol_t* backtrace_symbols = (backtrace_symbol_t*) malloc(sizeof(backtrace_symbol_t) * frame_count);
get_backtrace_symbols(frames, frame_count, backtrace_symbols);
for (size_t i = 0; i < (size_t) frame_count; ++i) {
char line[MAX_BACKTRACE_LINE_LENGTH];
format_backtrace_line(i, &frames[i], &backtrace_symbols[i],
line, MAX_BACKTRACE_LINE_LENGTH);
fprintf(stderr, " %s\n", line);
}
free_backtrace_symbols(backtrace_symbols, frame_count);
free(backtrace_symbols);
free(frames);
}
__attribute__ ((noinline)) void g() {
fprintf(stderr, "g()\n");
do_backtrace();
}
__attribute__ ((noinline)) int f(int i) {
fprintf(stderr, "f(%i)\n", i);
if (i == 0) {
g();
return 0;
}
return f(i - 1);
}
int main() {
return f(5);
}