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

Commit bfec3a31 authored by Elliott Hughes's avatar Elliott Hughes Committed by Brian Carlstrom
Browse files

Add basic Darwin support to libcorkscrew.

This might not seem like much, but it's already better than Mac OS'
backtrace(3).

(cherry picked from commit 2a46f6293f19b9d6100187fbd53088088e671b88)

Change-Id: I197b06c4c19f728ad6f194b2f473bd9dcd99b8a6
parent 7382459e
Loading
Loading
Loading
Loading
+11 −8
Original line number Diff line number Diff line
@@ -59,23 +59,26 @@ include $(BUILD_SHARED_LIBRARY)

# Build test.
include $(CLEAR_VARS)
LOCAL_SRC_FILES := test.c
LOCAL_CFLAGS += -std=gnu99 -Werror -fno-inline-small-functions
LOCAL_SRC_FILES := test.cpp
LOCAL_CFLAGS += -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)
ifeq ($(HOST_ARCH),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_LDLIBS += -ldl
ifeq ($(HOST_OS),linux)
  LOCAL_SHARED_LIBRARIES += libgccdemangle # TODO: is this even needed on Linux?
  LOCAL_LDLIBS += -lrt
endif
LOCAL_CFLAGS += -std=gnu99 -Werror
LOCAL_MODULE := libcorkscrew
LOCAL_MODULE_TAGS := optional
@@ -83,11 +86,11 @@ 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_SRC_FILES := test.cpp
LOCAL_CFLAGS += -Werror
LOCAL_SHARED_LIBRARIES := libcorkscrew
LOCAL_MODULE := libcorkscrew_test
LOCAL_MODULE_TAGS := optional
include $(BUILD_HOST_EXECUTABLE)

endif # linux-x86
endif # HOST_ARCH == x86
+17 −2
Original line number Diff line number Diff line
@@ -75,13 +75,18 @@ typedef struct ucontext {

#endif /* __BIONIC_HAVE_UCONTEXT_T */

#else /* __BIONIC__ */
#elif defined(__APPLE__)

#define _XOPEN_SOURCE
#include <ucontext.h>

#else

// glibc has its own renaming of the Linux kernel's structures.
#define __USE_GNU // For REG_EBP, REG_ESP, and REG_EIP.
#include <ucontext.h>

#endif /* __ BIONIC__ */
#endif

/* Unwind state. */
typedef struct {
@@ -819,9 +824,15 @@ ssize_t unwind_backtrace_signal_arch(siginfo_t* siginfo __attribute__((unused)),
    const ucontext_t* uc = (const ucontext_t*)sigcontext;

    unwind_state_t state;
#if defined(__APPLE__)
    state.reg[DWARF_EBP] = uc->uc_mcontext->__ss.__ebp;
    state.reg[DWARF_ESP] = uc->uc_mcontext->__ss.__esp;
    state.reg[DWARF_EIP] = uc->uc_mcontext->__ss.__eip;
#else
    state.reg[DWARF_EBP] = uc->uc_mcontext.gregs[REG_EBP];
    state.reg[DWARF_ESP] = uc->uc_mcontext.gregs[REG_ESP];
    state.reg[DWARF_EIP] = uc->uc_mcontext.gregs[REG_EIP];
#endif

    memory_t memory;
    init_memory(&memory, map_info_list);
@@ -831,6 +842,9 @@ ssize_t unwind_backtrace_signal_arch(siginfo_t* siginfo __attribute__((unused)),

ssize_t unwind_backtrace_ptrace_arch(pid_t tid, const ptrace_context_t* context,
        backtrace_frame_t* backtrace, size_t ignore_depth, size_t max_depth) {
#if defined(__APPLE__)
    return -1;
#else
    pt_regs_x86_t regs;
    if (ptrace(PTRACE_GETREGS, tid, 0, &regs)) {
        return -1;
@@ -845,4 +859,5 @@ ssize_t unwind_backtrace_ptrace_arch(pid_t tid, const ptrace_context_t* context,
    init_memory_ptrace(&memory, tid);
    return unwind_backtrace_common(&memory, context->map_info_list,
            &state, backtrace, ignore_depth, max_depth);
#endif
}
+20 −10
Original line number Diff line number Diff line
@@ -33,7 +33,6 @@
#include <unwind.h>
#include <cutils/log.h>
#include <cutils/atomic.h>
#include <elf.h>

#define __USE_GNU // For dladdr(3) in glibc.
#include <dlfcn.h>
@@ -43,6 +42,15 @@
// Bionic implements and exports gettid but only implements tgkill.
extern int tgkill(int tgid, int tid, int sig);

#elif defined(__APPLE__)

#include <sys/syscall.h>

// Mac OS >= 10.6 has a system call equivalent to Linux's gettid().
static pid_t gettid() {
  return syscall(SYS_thread_selfid);
}

#else

// glibc doesn't implement or export either gettid or tgkill.
@@ -146,7 +154,9 @@ ssize_t unwind_backtrace_thread(pid_t tid, backtrace_frame_t* backtrace,

    ALOGV("Unwinding thread %d from thread %d.", tid, gettid());

#ifdef CORKSCREW_HAVE_ARCH
    // TODO: there's no tgkill(2) on Mac OS, so we'd either need the
    // mach_port_t or the pthread_t rather than the tid.
#if defined(CORKSCREW_HAVE_ARCH) && !defined(__APPLE__)
    struct sigaction act;
    struct sigaction oact;
    memset(&act, 0, sizeof(act));
@@ -305,20 +315,20 @@ void format_backtrace_line(unsigned frameNumber, const backtrace_frame_t* frame
        const backtrace_symbol_t* symbol, char* buffer, size_t bufferSize) {
    const char* mapName = symbol->map_name ? symbol->map_name : "<unknown>";
    const char* symbolName = symbol->demangled_name ? symbol->demangled_name : symbol->symbol_name;
    size_t fieldWidth = (bufferSize - 80) / 2;
    int fieldWidth = (bufferSize - 80) / 2;
    if (symbolName) {
        uint32_t pc_offset = symbol->relative_pc - symbol->relative_symbol_addr;
        if (pc_offset) {
            snprintf(buffer, bufferSize, "#%02d  pc %08x  %.*s (%.*s+%u)",
                    frameNumber, symbol->relative_pc, fieldWidth, mapName,
            snprintf(buffer, bufferSize, "#%02u  pc %p  %.*s (%.*s+%u)",
                    frameNumber, (void*) symbol->relative_pc, fieldWidth, mapName,
                    fieldWidth, symbolName, pc_offset);
        } else {
            snprintf(buffer, bufferSize, "#%02d  pc %08x  %.*s (%.*s)",
                    frameNumber, symbol->relative_pc, fieldWidth, mapName,
            snprintf(buffer, bufferSize, "#%02u  pc %p  %.*s (%.*s)",
                    frameNumber, (void*) symbol->relative_pc, fieldWidth, mapName,
                    fieldWidth, symbolName);
        }
    } else {
        snprintf(buffer, bufferSize, "#%02d  pc %08x  %.*s",
                frameNumber, symbol->relative_pc, fieldWidth, mapName);
        snprintf(buffer, bufferSize, "#%02u  pc %p  %.*s",
                frameNumber, (void*) symbol->relative_pc, fieldWidth, mapName);
    }
}
+6 −0
Original line number Diff line number Diff line
@@ -25,6 +25,12 @@ extern char *__cxa_demangle (const char *mangled, char *buf, size_t *len,
                             int *status);

char* demangle_symbol_name(const char* name) {
#if defined(__APPLE__)
    // Mac OS' __cxa_demangle demangles "f" as "float"; last tested on 10.7.
    if (name != NULL && name[0] != '_') {
        return NULL;
    }
#endif
    // __cxa_demangle handles NULL by returning NULL
    return __cxa_demangle(name, 0, 0, 0);
}
+74 −5
Original line number Diff line number Diff line
@@ -29,6 +29,67 @@
#include <cutils/log.h>
#include <sys/time.h>

#if defined(__APPLE__)

// Mac OS vmmap(1) output:
// __TEXT                 0009f000-000a1000 [    8K     8K] r-x/rwx SM=COW  /Volumes/android/dalvik-dev/out/host/darwin-x86/bin/libcorkscrew_test\n
// 012345678901234567890123456789012345678901234567890123456789
// 0         1         2         3         4         5
static map_info_t* parse_vmmap_line(const char* line) {
    unsigned long int start;
    unsigned long int end;
    char permissions[4];
    int name_pos;
    if (sscanf(line, "%*21c %lx-%lx [%*13c] %3c/%*3c SM=%*3c  %n",
               &start, &end, permissions, &name_pos) != 3) {
        return NULL;
    }

    const char* name = line + name_pos;
    size_t name_len = strlen(name);

    map_info_t* mi = calloc(1, sizeof(map_info_t) + name_len);
    if (mi != NULL) {
        mi->start = start;
        mi->end = end;
        mi->is_readable = permissions[0] == 'r';
        mi->is_writable = permissions[1] == 'w';
        mi->is_executable = permissions[2] == 'x';
        mi->data = NULL;
        memcpy(mi->name, name, name_len);
        mi->name[name_len - 1] = '\0';
        ALOGV("Parsed map: start=0x%08x, end=0x%08x, "
              "is_readable=%d, is_writable=%d is_executable=%d, name=%s",
              mi->start, mi->end,
              mi->is_readable, mi->is_writable, mi->is_executable, mi->name);
    }
    return mi;
}

map_info_t* load_map_info_list(pid_t pid) {
    char cmd[1024];
    snprintf(cmd, sizeof(cmd), "vmmap -w -resident -submap -allSplitLibs -interleaved %d", pid);
    FILE* fp = popen(cmd, "r");
    if (fp == NULL) {
        return NULL;
    }

    char line[1024];
    map_info_t* milist = NULL;
    while (fgets(line, sizeof(line), fp) != NULL) {
        map_info_t* mi = parse_vmmap_line(line);
        if (mi != NULL) {
            mi->next = milist;
            milist = mi;
        }
    }
    fclose(fp);
    return milist;
}

#else

// Linux /proc/<pid>/maps lines:
// 6f000000-6f01e000 rwxp 00000000 00:0c 16389419   /system/lib/libcomposer.so\n
// 012345678901234567890123456789012345678901234567890123456789
// 0         1         2         3         4         5
@@ -91,6 +152,8 @@ map_info_t* load_map_info_list(pid_t tid) {
    return milist;
}

#endif

void free_map_info_list(map_info_t* milist) {
    while (milist) {
        map_info_t* next = milist->next;
@@ -132,11 +195,17 @@ typedef struct {
    int64_t timestamp;
} my_map_info_data_t;

static int64_t now() {
static int64_t now_ns() {
#if defined(HAVE_POSIX_CLOCKS)
    struct timespec t;
    t.tv_sec = t.tv_nsec = 0;
    clock_gettime(CLOCK_MONOTONIC, &t);
    return t.tv_sec * 1000000000LL + t.tv_nsec;
#else
    struct timeval t;
    gettimeofday(&t, NULL);
    return t.tv_sec * 1000000000LL + t.tv_usec * 1000LL;
#endif
}

static void dec_ref(map_info_t* milist, my_map_info_data_t* data) {
@@ -150,7 +219,7 @@ static void dec_ref(map_info_t* milist, my_map_info_data_t* data) {
map_info_t* acquire_my_map_info_list() {
    pthread_mutex_lock(&g_my_map_info_list_mutex);

    int64_t time = now();
    int64_t time = now_ns();
    if (g_my_map_info_list) {
        my_map_info_data_t* data = (my_map_info_data_t*)g_my_map_info_list->data;
        int64_t age = time - data->timestamp;
Loading