diff --git a/libc/Android.mk b/libc/Android.mk index 4bf996b08..9b2167a5c 100644 --- a/libc/Android.mk +++ b/libc/Android.mk @@ -272,6 +272,7 @@ libc_common_src_files := \ libc_bionic_src_files := \ bionic/assert.cpp \ + bionic/debug_format.cpp \ bionic/dirent.cpp \ bionic/eventfd.cpp \ bionic/__fgets_chk.cpp \ @@ -884,7 +885,7 @@ LOCAL_SRC_FILES := \ $(libc_static_common_src_files) \ bionic/dlmalloc.c \ bionic/malloc_debug_common.cpp \ - bionic/pthread_debug.c \ + bionic/pthread_debug.cpp \ bionic/libc_init_dynamic.c ifeq ($(TARGET_ARCH),arm) @@ -937,10 +938,10 @@ LOCAL_CFLAGS := \ LOCAL_C_INCLUDES := $(libc_common_c_includes) LOCAL_SRC_FILES := \ + bionic/debug_mapinfo.cpp \ + bionic/debug_stacktrace.cpp \ bionic/malloc_debug_leak.cpp \ bionic/malloc_debug_check.cpp \ - bionic/malloc_debug_check_mapinfo.cpp \ - bionic/malloc_debug_stacktrace.cpp LOCAL_MODULE:= libc_malloc_debug_leak LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk diff --git a/libc/arch-arm/bionic/atexit_legacy.c b/libc/arch-arm/bionic/atexit_legacy.c index 4abe83922..6e299ac08 100644 --- a/libc/arch-arm/bionic/atexit_legacy.c +++ b/libc/arch-arm/bionic/atexit_legacy.c @@ -50,10 +50,9 @@ atexit(void (*func)(void)) * calling library may have been dlclose()'d, causing the program to * crash. */ - static char const warning[] = - "WARNING: generic atexit() called from legacy shared library\n"; + static char const warning[] = "WARNING: generic atexit() called from legacy shared library\n"; - __libc_android_log_print(ANDROID_LOG_WARN, "libc", warning); + __libc_android_log_write(ANDROID_LOG_WARN, "libc", warning); fprintf(stderr, warning); return (__cxa_atexit((void (*)(void *))func, NULL, NULL)); diff --git a/libc/arch-mips/bionic/cacheflush.c b/libc/arch-mips/bionic/cacheflush.c index 05085b623..19116877e 100644 --- a/libc/arch-mips/bionic/cacheflush.c +++ b/libc/arch-mips/bionic/cacheflush.c @@ -29,9 +29,9 @@ #include #ifdef DEBUG -#include -#define XLOG(...) \ - __libc_android_log_print(ANDROID_LOG_DEBUG,"libc-cacheflush",__VA_ARGS__) +#include +#include +#define XLOG(...) __libc_format_log(ANDROID_LOG_DEBUG,"libc-cacheflush",__VA_ARGS__) #endif /* diff --git a/libc/bionic/assert.cpp b/libc/bionic/assert.cpp index 7c0a86018..e38c16dbc 100644 --- a/libc/bionic/assert.cpp +++ b/libc/bionic/assert.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include // We log to stderr for the benefit of "adb shell" users, and the log for the benefit @@ -39,7 +40,7 @@ void __assert(const char* file, int line, const char* failed_expression) { const char* fmt = "%s:%d: assertion \"%s\" failed\n"; - __libc_android_log_print(ANDROID_LOG_FATAL, "libc", fmt, file, line, failed_expression); + __libc_format_log(ANDROID_LOG_FATAL, "libc", fmt, file, line, failed_expression); fprintf(stderr, fmt, file, line, failed_expression); abort(); /* NOTREACHED */ @@ -47,7 +48,7 @@ void __assert(const char* file, int line, const char* failed_expression) { void __assert2(const char* file, int line, const char* function, const char* failed_expression) { const char* fmt = "%s:%d: %s: assertion \"%s\" failed\n"; - __libc_android_log_print(ANDROID_LOG_FATAL, "libc", fmt, file, line, function, failed_expression); + __libc_format_log(ANDROID_LOG_FATAL, "libc", fmt, file, line, function, failed_expression); fprintf(stderr, fmt, file, line, function, failed_expression); abort(); /* NOTREACHED */ diff --git a/linker/linker_format.cpp b/libc/bionic/debug_format.cpp similarity index 83% rename from linker/linker_format.cpp rename to libc/bionic/debug_format.cpp index e631ca1c1..e8d6a45cd 100644 --- a/linker/linker_format.cpp +++ b/libc/bionic/debug_format.cpp @@ -30,7 +30,7 @@ // compile under GCC 4.7 #undef _FORTIFY_SOURCE -#include "linker_format.h" +#include "debug_format.h" #include #include @@ -40,8 +40,6 @@ #include #include -#include "linker_debug.h" - /* define UNIT_TESTS to build this file as a single executable that runs * the formatter's unit tests */ @@ -150,47 +148,14 @@ vformat_buffer(char *buff, size_t buffsize, const char *format, va_list args) return buf_out_length(&bo); } -int -format_buffer(char *buff, size_t buffsize, const char *format, ...) -{ - va_list args; - int ret; - - va_start(args, format); - ret = vformat_buffer(buff, buffsize, format, args); - va_end(args); - - return ret; +int __libc_format_buffer(char* buffer, size_t buffer_size, const char* format, ...) { + va_list args; + va_start(args, format); + int result = vformat_buffer(buffer, buffer_size, format, args); + va_end(args); + return result; } -/* The __stack_chk_fail() function calls __libc_android_log_print() - * which calls vsnprintf(). - * - * We define our version of the function here to avoid dragging - * about 25 KB of C library routines related to formatting. - */ -int -vsnprintf(char *buff, size_t bufsize, const char *format, va_list args) -{ - return format_buffer(buff, bufsize, format, args); -} - -/* The pthread implementation uses snprintf(). If we define it here, we - * avoid pulling the stdio vfprintf() implementation into the linker - * saving about 19KB of machine code. - */ -int -snprintf(char* buff, size_t bufsize, const char* format, ...) -{ - va_list args; - int ret; - va_start(args, format); - ret = vsnprintf(buff, bufsize, format, args); - va_end(args); - return ret; -} - -#if !LINKER_DEBUG_TO_LOG /*** File descriptor output ***/ @@ -204,7 +169,7 @@ struct FdOut { static void fd_out_send(void *opaque, const char *data, int len) { - FdOut *fdo = opaque; + FdOut *fdo = reinterpret_cast(opaque); if (len < 0) len = strlen(data); @@ -240,96 +205,61 @@ fd_out_length(FdOut *fdo) } -int -format_fd(int fd, const char *format, ...) -{ - FdOut fdo; - Out* out; - va_list args; +int __libc_format_fd(int fd, const char* format, ...) { + FdOut fdo; + Out* out = fd_out_init(&fdo, fd); + if (out == NULL) { + return 0; + } - out = fd_out_init(&fdo, fd); - if (out == NULL) - return 0; + va_list args; + va_start(args, format); + out_vformat(out, format, args); + va_end(args); - va_start(args, format); - out_vformat(out, format, args); - va_end(args); - - return fd_out_length(&fdo); + return fd_out_length(&fdo); } -#else /* LINKER_DEBUG_TO_LOG */ - /*** Log output ***/ -/* We need our own version of __libc_android_log_vprint, otherwise - * the log output is completely broken. Probably due to the fact - * that the C library is not initialized yet. - * - * You can test that by setting CUSTOM_LOG_VPRINT to 0 - */ -#define CUSTOM_LOG_VPRINT 1 - -#if CUSTOM_LOG_VPRINT - #include #include #include -static int log_vprint(int prio, const char *tag, const char *fmt, va_list args) -{ - char buf[1024]; - int result; - static int log_fd = -1; +int __libc_format_log_va_list(int priority, const char* tag, const char* fmt, va_list args) { + char buf[1024]; + int result = vformat_buffer(buf, sizeof buf, fmt, args); - result = vformat_buffer(buf, sizeof buf, fmt, args); - - if (log_fd < 0) { - log_fd = open("/dev/log/main", O_WRONLY); - if (log_fd < 0) - return result; + static int log_fd = -1; + if (log_fd == -1) { + log_fd = open("/dev/log/main", O_WRONLY); + if (log_fd == -1) { + return result; } + } - { - ssize_t ret; - struct iovec vec[3]; + struct iovec vec[3]; + vec[0].iov_base = (unsigned char *) &priority; + vec[0].iov_len = 1; + vec[1].iov_base = (void *) tag; + vec[1].iov_len = strlen(tag) + 1; + vec[2].iov_base = (void *) buf; + vec[2].iov_len = strlen(buf) + 1; - vec[0].iov_base = (unsigned char *) &prio; - vec[0].iov_len = 1; - vec[1].iov_base = (void *) tag; - vec[1].iov_len = strlen(tag) + 1; - vec[2].iov_base = (void *) buf; - vec[2].iov_len = strlen(buf) + 1; + TEMP_FAILURE_RETRY(writev(log_fd, vec, 3)); - do { - ret = writev(log_fd, vec, 3); - } while ((ret < 0) && (errno == EINTR)); - } - return result; + return result; } -#define __libc_android_log_vprint log_vprint - -#else /* !CUSTOM_LOG_VPRINT */ - -extern "C" int __libc_android_log_vprint(int prio, const char* tag, const char* format, va_list ap); - -#endif /* !CUSTOM_LOG_VPRINT */ - -int -format_log(int prio, const char *tag, const char *format, ...) -{ - int ret; - va_list args; - va_start(args, format); - ret = __libc_android_log_vprint(prio, tag, format, args); - va_end(args); - return ret; +int __libc_format_log(int priority, const char* tag, const char* format, ...) { + va_list args; + va_start(args, format); + int result = __libc_format_log_va_list(priority, tag, format, args); + va_end(args); + return result; } -#endif /* LINKER_DEBUG_TO_LOG */ - /*** formatted output implementation ***/ diff --git a/libc/bionic/debug_mapinfo.cpp b/libc/bionic/debug_mapinfo.cpp new file mode 100644 index 000000000..174cc2816 --- /dev/null +++ b/libc/bionic/debug_mapinfo.cpp @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include + +#include "dlmalloc.h" +#include "debug_mapinfo.h" + +// 6f000000-6f01e000 rwxp 00000000 00:0c 16389419 /system/lib/libcomposer.so +// 012345678901234567890123456789012345678901234567890123456789 +// 0 1 2 3 4 5 + +static mapinfo_t* parse_maps_line(char* line) { + int len = strlen(line); + + if (len < 1) return 0; + line[--len] = 0; + + if (len < 50) return 0; + if (line[20] != 'x') return 0; + + mapinfo_t* mi = static_cast(dlmalloc(sizeof(mapinfo_t) + (len - 47))); + if (mi == 0) return 0; + + mi->start = strtoul(line, 0, 16); + mi->end = strtoul(line + 9, 0, 16); + mi->next = 0; + strcpy(mi->name, line + 49); + + return mi; +} + +__LIBC_HIDDEN__ mapinfo_t* mapinfo_create(int pid) { + struct mapinfo_t* milist = NULL; + char data[1024]; // Used to read lines as well as to construct the filename. + snprintf(data, sizeof(data), "/proc/%d/maps", pid); + FILE* fp = fopen(data, "r"); + if (fp != NULL) { + while (fgets(data, sizeof(data), fp) != NULL) { + mapinfo_t* mi = parse_maps_line(data); + if (mi) { + mi->next = milist; + milist = mi; + } + } + fclose(fp); + } + return milist; +} + +__LIBC_HIDDEN__ void mapinfo_destroy(mapinfo_t* mi) { + while (mi) { + mapinfo_t* del = mi; + mi = mi->next; + dlfree(del); + } +} + +// Find the containing map info for the PC. +__LIBC_HIDDEN__ const mapinfo_t* mapinfo_find(mapinfo_t* mi, unsigned pc, unsigned* rel_pc) { + *rel_pc = pc; + for (; mi != NULL; mi = mi->next) { + if ((pc >= mi->start) && (pc < mi->end)) { + *rel_pc -= mi->start; + return mi; + } + } + return NULL; +} diff --git a/libc/bionic/malloc_debug_check_mapinfo.h b/libc/bionic/debug_mapinfo.h similarity index 77% rename from libc/bionic/malloc_debug_check_mapinfo.h rename to libc/bionic/debug_mapinfo.h index e19f71ebc..6df55c54a 100644 --- a/libc/bionic/malloc_debug_check_mapinfo.h +++ b/libc/bionic/debug_mapinfo.h @@ -26,21 +26,20 @@ * SUCH DAMAGE. */ -#ifndef MALLOC_DEBUG_CHECK_MAPINFO_H -#define MALLOC_DEBUG_CHECK_MAPINFO_H +#ifndef DEBUG_MAPINFO_H +#define DEBUG_MAPINFO_H #include -struct mapinfo { - struct mapinfo* next; +struct mapinfo_t { + struct mapinfo_t* next; unsigned start; unsigned end; char name[]; }; -__LIBC_HIDDEN__ mapinfo *init_mapinfo(int pid); -__LIBC_HIDDEN__ void deinit_mapinfo(mapinfo *mi); -__LIBC_HIDDEN__ const char *map_to_name(mapinfo *mi, unsigned pc, const char* def); -__LIBC_HIDDEN__ const mapinfo *pc_to_mapinfo(mapinfo *mi, unsigned pc, unsigned *rel_pc); +__LIBC_HIDDEN__ mapinfo_t* mapinfo_create(int pid); +__LIBC_HIDDEN__ void mapinfo_destroy(mapinfo_t* mi); +__LIBC_HIDDEN__ const mapinfo_t* mapinfo_find(mapinfo_t* mi, unsigned pc, unsigned* rel_pc); -#endif /*MALLOC_DEBUG_CHECK_MAPINFO_H*/ +#endif /* DEBUG_MAPINFO_H */ diff --git a/libc/bionic/debug_stacktrace.cpp b/libc/bionic/debug_stacktrace.cpp new file mode 100644 index 000000000..4b080a480 --- /dev/null +++ b/libc/bionic/debug_stacktrace.cpp @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "debug_stacktrace.h" + +#include +#include +#include +#include + +#include "debug_format.h" +#include "debug_mapinfo.h" +#include "logd.h" + +/* depends how the system includes define this */ +#ifdef HAVE_UNWIND_CONTEXT_STRUCT +typedef struct _Unwind_Context __unwind_context; +#else +typedef _Unwind_Context __unwind_context; +#endif + +static _Unwind_Reason_Code trace_function(__unwind_context* context, void* arg) { + stack_crawl_state_t* state = static_cast(arg); + if (state->count) { + intptr_t ip = (intptr_t)_Unwind_GetIP(context); + if (ip) { + state->addrs[0] = ip; + state->addrs++; + state->count--; + return _URC_NO_REASON; + } + } + // If we run out of space to record the address or 0 has been seen, stop + // unwinding the stack. + return _URC_END_OF_STACK; +} + +__LIBC_HIDDEN__ int get_backtrace(intptr_t* addrs, size_t max_entries) { + stack_crawl_state_t state; + state.count = max_entries; + state.addrs = addrs; + _Unwind_Backtrace(trace_function, &state); + return max_entries - state.count; +} + +__LIBC_HIDDEN__ void log_backtrace(mapinfo_t* map_info, intptr_t* addrs, size_t c) { + intptr_t self_bt[16]; + if (addrs == NULL) { + c = get_backtrace(self_bt, 16); + addrs = self_bt; + } + + __libc_format_log(ANDROID_LOG_ERROR, "libc", + "*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n"); + + int index = 0; + for (size_t i = 0 ; i < c; ++i) { + void* offset = 0; + const char* symbol = NULL; + + Dl_info info; + if (dladdr((void*) addrs[i], &info) != 0) { + offset = info.dli_saddr; + symbol = info.dli_sname; + } + + // This test is a bit sketchy, but it allows us to skip the + // stack trace entries due to this debugging code. it works + // because those don't have a symbol (they're not exported). + if (symbol != NULL || index > 0) { + unsigned int rel_pc; + const mapinfo_t* mi = mapinfo_find(map_info, addrs[i], &rel_pc); + const char* soname = mi ? mi->name : info.dli_fname; + if (soname == NULL) { + soname = "unknown"; + } + if (symbol) { + __libc_format_log(ANDROID_LOG_ERROR, "libc", " #%02d pc %08x %s (%s+0x%x)", + index, rel_pc, soname, symbol, addrs[i] - (intptr_t)offset); + } else { + __libc_format_log(ANDROID_LOG_ERROR, "libc", " #%02d pc %08x %s", + index, rel_pc, soname); + } + ++index; + } + } +} diff --git a/linker/linker_format.h b/libc/bionic/debug_stacktrace.h similarity index 71% rename from linker/linker_format.h rename to libc/bionic/debug_stacktrace.h index 862e439d8..3c66ea635 100644 --- a/linker/linker_format.h +++ b/libc/bionic/debug_stacktrace.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 The Android Open Source Project + * Copyright (C) 2013 The Android Open Source Project * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -26,17 +26,20 @@ * SUCH DAMAGE. */ -#ifndef _LINKER_FORMAT_H -#define _LINKER_FORMAT_H +#ifndef DEBUG_STACKTRACE_H +#define DEBUG_STACKTRACE_H -#include -#include +#include +#include -// Formatting routines for the dynamic linker's debug traces -// We want to avoid dragging the whole C library fprintf() -// implementation into the dynamic linker since this creates -// issues (it uses malloc()/free()) and increases code size. -int format_buffer(char* buffer, size_t buffer_size, const char* format, ...) - __attribute__((__format__(printf, 3, 4))); +struct stack_crawl_state_t { + size_t count; + intptr_t* addrs; +}; -#endif /* _LINKER_FORMAT_H */ +struct mapinfo_t; + +__LIBC_HIDDEN__ int get_backtrace(intptr_t* stack_frames, size_t max_entries); +__LIBC_HIDDEN__ void log_backtrace(mapinfo_t* map_info, intptr_t* stack_frames, size_t frame_count); + +#endif /* DEBUG_STACKTRACE_H */ diff --git a/libc/bionic/logd_write.c b/libc/bionic/logd_write.c index 71a6f8e80..11c0e68b6 100644 --- a/libc/bionic/logd_write.c +++ b/libc/bionic/logd_write.c @@ -250,9 +250,7 @@ void __libc_android_log_event_uid(int32_t tag) __LIBC_HIDDEN__ void __fortify_chk_fail(const char *msg, uint32_t tag) { - __libc_android_log_print(ANDROID_LOG_FATAL, "libc", - "FORTIFY_SOURCE: %s. Calling abort().\n", - msg); + __libc_format_log(ANDROID_LOG_FATAL, "libc", "FORTIFY_SOURCE: %s. Calling abort().\n", msg); if (tag != 0) { __libc_android_log_event_uid(tag); } diff --git a/libc/bionic/malloc_debug_check.cpp b/libc/bionic/malloc_debug_check.cpp index 5ad3486f3..60ee0cc20 100644 --- a/libc/bionic/malloc_debug_check.cpp +++ b/libc/bionic/malloc_debug_check.cpp @@ -45,18 +45,19 @@ #include #include +#include "debug_mapinfo.h" +#include "debug_stacktrace.h" #include "dlmalloc.h" #include "logd.h" -#include "malloc_debug_check_mapinfo.h" #include "malloc_debug_common.h" #include "ScopedPthreadMutexLocker.h" -static mapinfo *milist; +static mapinfo_t* gMapInfo; /* libc.debug.malloc.backlog */ extern unsigned int malloc_double_free_backlog; -#define MAX_BACKTRACE_DEPTH 15 +#define MAX_BACKTRACE_DEPTH 16 #define ALLOCATION_TAG 0x1ee7d00d #define BACKLOG_TAG 0xbabecafe #define FREE_POISON 0xa5 @@ -67,20 +68,10 @@ extern unsigned int malloc_double_free_backlog; #define REAR_GUARD_LEN (1<<5) static void log_message(const char* format, ...) { - extern const MallocDebug __libc_malloc_default_dispatch; - extern const MallocDebug* __libc_malloc_dispatch; - extern pthread_mutex_t gAllocationsMutex; - - va_list args; - { - ScopedPthreadMutexLocker locker(&gAllocationsMutex); - const MallocDebug* current_dispatch = __libc_malloc_dispatch; - __libc_malloc_dispatch = &__libc_malloc_default_dispatch; - va_start(args, format); - __libc_android_log_vprint(ANDROID_LOG_ERROR, "libc", format, args); - va_end(args); - __libc_malloc_dispatch = current_dispatch; - } + va_list args; + va_start(args, format); + __libc_format_log_va_list(ANDROID_LOG_ERROR, "libc", format, args); + va_end(args); } struct hdr_t { @@ -121,28 +112,6 @@ static hdr_t *backlog_tail; static hdr_t *backlog_head; static pthread_mutex_t backlog_lock = PTHREAD_MUTEX_INITIALIZER; -extern __LIBC_HIDDEN__ int get_backtrace(intptr_t* addrs, size_t max_entries); - -static void print_backtrace(const intptr_t *bt, unsigned int depth) { - const mapinfo *mi; - unsigned int cnt; - unsigned int rel_pc; - intptr_t self_bt[MAX_BACKTRACE_DEPTH]; - - if (!bt) { - depth = get_backtrace(self_bt, MAX_BACKTRACE_DEPTH); - bt = self_bt; - } - - log_message("*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n"); - for (cnt = 0; cnt < depth && cnt < MAX_BACKTRACE_DEPTH; cnt++) { - mi = pc_to_mapinfo(milist, bt[cnt], &rel_pc); - log_message("\t#%02d pc %08x %s\n", cnt, - mi ? (intptr_t)rel_pc : bt[cnt], - mi ? mi->name : "(unknown)"); - } -} - static inline void init_front_guard(hdr_t *hdr) { memset(hdr->front_guard, FRONT_GUARD, FRONT_GUARD_LEN); } @@ -292,11 +261,11 @@ static inline int check_allocation_locked(hdr_t *hdr, int *safe) { if (!valid && *safe) { log_message("+++ ALLOCATION %p SIZE %d ALLOCATED HERE:\n", user(hdr), hdr->size); - print_backtrace(hdr->bt, hdr->bt_depth); + log_backtrace(gMapInfo, hdr->bt, hdr->bt_depth); if (hdr->tag == BACKLOG_TAG) { log_message("+++ ALLOCATION %p SIZE %d FREED HERE:\n", user(hdr), hdr->size); - print_backtrace(hdr->freed_bt, hdr->freed_bt_depth); + log_backtrace(gMapInfo, hdr->freed_bt, hdr->freed_bt_depth); } } @@ -381,18 +350,18 @@ extern "C" void chk_free(void *ptr) { user(hdr), hdr->size); log_message("+++ ALLOCATION %p SIZE %d ALLOCATED HERE:\n", user(hdr), hdr->size); - print_backtrace(hdr->bt, hdr->bt_depth); + log_backtrace(gMapInfo, hdr->bt, hdr->bt_depth); /* hdr->freed_bt_depth should be nonzero here */ log_message("+++ ALLOCATION %p SIZE %d FIRST FREED HERE:\n", user(hdr), hdr->size); - print_backtrace(hdr->freed_bt, hdr->freed_bt_depth); + log_backtrace(gMapInfo, hdr->freed_bt, hdr->freed_bt_depth); log_message("+++ ALLOCATION %p SIZE %d NOW BEING FREED HERE:\n", user(hdr), hdr->size); - print_backtrace(bt, depth); + log_backtrace(gMapInfo, bt, depth); } else { log_message("+++ ALLOCATION %p IS CORRUPTED OR NOT ALLOCATED VIA TRACKER!\n", user(hdr)); - print_backtrace(bt, depth); + log_backtrace(gMapInfo, bt, depth); /* Leak here so that we do not crash */ //dlfree(user(hdr)); } @@ -428,14 +397,14 @@ extern "C" void *chk_realloc(void *ptr, size_t size) { user(hdr), size, hdr->size); log_message("+++ ALLOCATION %p SIZE %d ALLOCATED HERE:\n", user(hdr), hdr->size); - print_backtrace(hdr->bt, hdr->bt_depth); + log_backtrace(gMapInfo, hdr->bt, hdr->bt_depth); /* hdr->freed_bt_depth should be nonzero here */ log_message("+++ ALLOCATION %p SIZE %d FIRST FREED HERE:\n", user(hdr), hdr->size); - print_backtrace(hdr->freed_bt, hdr->freed_bt_depth); + log_backtrace(gMapInfo, hdr->freed_bt, hdr->freed_bt_depth); log_message("+++ ALLOCATION %p SIZE %d NOW BEING REALLOCATED HERE:\n", user(hdr), hdr->size); - print_backtrace(bt, depth); + log_backtrace(gMapInfo, bt, depth); /* We take the memory out of the backlog and fall through so the * reallocation below succeeds. Since we didn't really free it, we @@ -445,7 +414,7 @@ extern "C" void *chk_realloc(void *ptr, size_t size) { } else { log_message("+++ REALLOCATION %p SIZE %d IS CORRUPTED OR NOT ALLOCATED VIA TRACKER!\n", user(hdr), size); - print_backtrace(bt, depth); + log_backtrace(gMapInfo, bt, depth); // just get a whole new allocation and leak the old one return dlrealloc(0, size); // return dlrealloc(user(hdr), size); // assuming it was allocated externally @@ -467,8 +436,7 @@ extern "C" void *chk_calloc(int nmemb, size_t size) { size_t total_size = nmemb * size; hdr_t* hdr = static_cast(dlcalloc(1, sizeof(hdr_t) + total_size + sizeof(ftr_t))); if (hdr) { - hdr->bt_depth = get_backtrace( - hdr->bt, MAX_BACKTRACE_DEPTH); + hdr->bt_depth = get_backtrace(hdr->bt, MAX_BACKTRACE_DEPTH); add(hdr, total_size); return user(hdr); } @@ -476,21 +444,20 @@ extern "C" void *chk_calloc(int nmemb, size_t size) { } static void heaptracker_free_leaked_memory() { + size_t total = num; if (num) { - log_message("+++ THERE ARE %d LEAKED ALLOCATIONS\n", num); + log_message("+++ Leaked allocations: %d\n", num); } hdr_t *del = NULL; while (head) { int safe; del = head; - log_message("+++ DELETING %d BYTES OF LEAKED MEMORY AT %p (%d REMAINING)\n", - del->size, user(del), num); + log_message("+++ Leaked block of size %d at %p (leak %d of %d)\n", + del->size, user(del), 1 + total - num, total); if (del_leak(del, &safe)) { /* safe == 1, because the allocation is valid */ - log_message("+++ ALLOCATION %p SIZE %d ALLOCATED HERE:\n", - user(del), del->size); - print_backtrace(del->bt, del->bt_depth); + log_backtrace(gMapInfo, del->bt, del->bt_depth); } dlfree(del); } @@ -507,13 +474,14 @@ static void heaptracker_free_leaked_memory() { * See comments on MallocDebugInit in malloc_debug_common.h */ extern "C" int malloc_debug_initialize() { - if (!malloc_double_free_backlog) - malloc_double_free_backlog = BACKLOG_DEFAULT_LEN; - milist = init_mapinfo(getpid()); - return 0; + if (!malloc_double_free_backlog) { + malloc_double_free_backlog = BACKLOG_DEFAULT_LEN; + } + gMapInfo = mapinfo_create(getpid()); + return 0; } extern "C" void malloc_debug_finalize() { - heaptracker_free_leaked_memory(); - deinit_mapinfo(milist); + heaptracker_free_leaked_memory(); + mapinfo_destroy(gMapInfo); } diff --git a/libc/bionic/malloc_debug_check_mapinfo.cpp b/libc/bionic/malloc_debug_check_mapinfo.cpp deleted file mode 100644 index 8cc2c9948..000000000 --- a/libc/bionic/malloc_debug_check_mapinfo.cpp +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -#include -#include - -#include "dlmalloc.h" -#include "malloc_debug_check_mapinfo.h" - -// 6f000000-6f01e000 rwxp 00000000 00:0c 16389419 /system/lib/libcomposer.so -// 012345678901234567890123456789012345678901234567890123456789 -// 0 1 2 3 4 5 - -static mapinfo* parse_maps_line(char* line) { - int len = strlen(line); - - if (len < 1) return 0; - line[--len] = 0; - - if (len < 50) return 0; - if (line[20] != 'x') return 0; - - mapinfo* mi = static_cast(dlmalloc(sizeof(mapinfo) + (len - 47))); - if (mi == 0) return 0; - - mi->start = strtoul(line, 0, 16); - mi->end = strtoul(line + 9, 0, 16); - /* To be filled in parse_elf_info if the mapped section starts with - * elf_header - */ - mi->next = 0; - strcpy(mi->name, line + 49); - - return mi; -} - -__LIBC_HIDDEN__ -mapinfo *init_mapinfo(int pid) { - struct mapinfo *milist = NULL; - char data[1024]; // Used to read lines as well as to construct the filename. - snprintf(data, sizeof(data), "/proc/%d/maps", pid); - FILE *fp = fopen(data, "r"); - if (fp) { - while (fgets(data, sizeof(data), fp)) { - mapinfo *mi = parse_maps_line(data); - if (mi) { - mi->next = milist; - milist = mi; - } - } - fclose(fp); - } - - return milist; -} - -__LIBC_HIDDEN__ -void deinit_mapinfo(mapinfo *mi) { - mapinfo *del; - while (mi) { - del = mi; - mi = mi->next; - dlfree(del); - } -} - -/* Map a pc address to the name of the containing ELF file */ -__LIBC_HIDDEN__ -const char *map_to_name(mapinfo *mi, unsigned pc, const char* def) { - while (mi) { - if ((pc >= mi->start) && (pc < mi->end)) { - return mi->name; - } - mi = mi->next; - } - return def; -} - -/* Find the containing map info for the pc */ -__LIBC_HIDDEN__ -const mapinfo *pc_to_mapinfo(mapinfo *mi, unsigned pc, unsigned *rel_pc) { - *rel_pc = pc; - while (mi) { - if ((pc >= mi->start) && (pc < mi->end)) { - // Only calculate the relative offset for shared libraries - if (strstr(mi->name, ".so")) { - *rel_pc -= mi->start; - } - return mi; - } - mi = mi->next; - } - return NULL; -} diff --git a/libc/bionic/malloc_debug_common.cpp b/libc/bionic/malloc_debug_common.cpp index 624a40e26..bba0472e3 100644 --- a/libc/bionic/malloc_debug_common.cpp +++ b/libc/bionic/malloc_debug_common.cpp @@ -294,8 +294,8 @@ static void* libc_malloc_impl_handle = NULL; unsigned int malloc_double_free_backlog; static void InitMalloc(MallocDebug* table, int debug_level, const char* prefix) { - __libc_android_log_print(ANDROID_LOG_INFO, "libc", "%s: using libc.debug.malloc %d (%s)\n", - __progname, debug_level, prefix); + __libc_format_log(ANDROID_LOG_INFO, "libc", "%s: using libc.debug.malloc %d (%s)\n", + __progname, debug_level, prefix); char symbol[128]; @@ -429,7 +429,7 @@ static void malloc_init_impl() { dlclose(libc_malloc_impl_handle); return; } - if (malloc_debug_initialize()) { + if (malloc_debug_initialize() == -1) { dlclose(libc_malloc_impl_handle); return; } @@ -487,11 +487,19 @@ static void malloc_init_impl() { } static void malloc_fini_impl() { - if (libc_malloc_impl_handle) { + // Our BSD stdio implementation doesn't close the standard streams, it only flushes them. + // And it doesn't do that until its atexit handler (_cleanup) is run, and we run first! + // It's great that other unclosed FILE*s show up as malloc leaks, but we need to manually + // clean up the standard streams ourselves. + fclose(stdin); + fclose(stdout); + fclose(stderr); + + if (libc_malloc_impl_handle != NULL) { MallocDebugFini malloc_debug_finalize = reinterpret_cast(dlsym(libc_malloc_impl_handle, "malloc_debug_finalize")); - if (malloc_debug_finalize) { + if (malloc_debug_finalize != NULL) { malloc_debug_finalize(); } } diff --git a/libc/bionic/malloc_debug_common.h b/libc/bionic/malloc_debug_common.h index 78ad5e595..3d12f8737 100644 --- a/libc/bionic/malloc_debug_common.h +++ b/libc/bionic/malloc_debug_common.h @@ -35,6 +35,8 @@ #include +#include + #define HASHTABLE_SIZE 1543 #define BACKTRACE_SIZE 32 /* flag definitions, currently sharing storage with "size" */ @@ -97,10 +99,10 @@ typedef void (*MallocDebugFini)(); // ============================================================================= #define debug_log(format, ...) \ - __libc_android_log_print(ANDROID_LOG_DEBUG, "malloc_leak_check", (format), ##__VA_ARGS__ ) + __libc_format_log(ANDROID_LOG_DEBUG, "malloc_leak_check", (format), ##__VA_ARGS__ ) #define error_log(format, ...) \ - __libc_android_log_print(ANDROID_LOG_ERROR, "malloc_leak_check", (format), ##__VA_ARGS__ ) + __libc_format_log(ANDROID_LOG_ERROR, "malloc_leak_check", (format), ##__VA_ARGS__ ) #define info_log(format, ...) \ - __libc_android_log_print(ANDROID_LOG_INFO, "malloc_leak_check", (format), ##__VA_ARGS__ ) + __libc_format_log(ANDROID_LOG_INFO, "malloc_leak_check", (format), ##__VA_ARGS__ ) #endif // MALLOC_DEBUG_COMMON_H diff --git a/libc/bionic/malloc_debug_leak.cpp b/libc/bionic/malloc_debug_leak.cpp index 090a98185..68b6ae285 100644 --- a/libc/bionic/malloc_debug_leak.cpp +++ b/libc/bionic/malloc_debug_leak.cpp @@ -45,6 +45,7 @@ #include #include +#include "debug_stacktrace.h" #include "dlmalloc.h" #include "logd.h" #include "malloc_debug_common.h" @@ -255,8 +256,6 @@ extern "C" void* fill_memalign(size_t alignment, size_t bytes) { static void* MEMALIGN_GUARD = reinterpret_cast(0xA1A41520); -extern __LIBC_HIDDEN__ int get_backtrace(intptr_t* addrs, size_t max_entries); - extern "C" void* leak_malloc(size_t bytes) { // allocate enough space infront of the allocation to store the pointer for // the alloc structure. This will making free'ing the structer really fast! diff --git a/libc/bionic/malloc_debug_qemu.cpp b/libc/bionic/malloc_debug_qemu.cpp index e586b1bc0..812a45120 100644 --- a/libc/bionic/malloc_debug_qemu.cpp +++ b/libc/bionic/malloc_debug_qemu.cpp @@ -257,8 +257,8 @@ static void dump_malloc_descriptor(char* str, INFO_TRACING_ENABLED) /* Prints a string to the emulator's stdout. - * In early stages of system loading, logging mesages via - * __libc_android_log_print API is not available, because ADB API has not been + * In early stages of system loading, logging messages to logcat + * is not available, because ADB API has not been * hooked up yet. So, in order to see such messages we need to print them to * the emulator's stdout. * Parameters passed to this macro are the same as parameters for printf @@ -289,8 +289,7 @@ static void dump_malloc_descriptor(char* str, */ #define qemu_debug_log(format, ...) \ do { \ - __libc_android_log_print(ANDROID_LOG_DEBUG, "memcheck", \ - (format), ##__VA_ARGS__); \ + __libc_format_log(ANDROID_LOG_DEBUG, "memcheck", (format), ##__VA_ARGS__); \ if (tracing_flags & DEBUG_TRACING_ENABLED) { \ qemu_log(ANDROID_LOG_DEBUG, (format), ##__VA_ARGS__); \ } \ @@ -298,8 +297,7 @@ static void dump_malloc_descriptor(char* str, #define qemu_error_log(format, ...) \ do { \ - __libc_android_log_print(ANDROID_LOG_ERROR, "memcheck", \ - (format), ##__VA_ARGS__); \ + __libc_format_log(ANDROID_LOG_ERROR, "memcheck", (format), ##__VA_ARGS__); \ if (tracing_flags & ERROR_TRACING_ENABLED) { \ qemu_log(ANDROID_LOG_ERROR, (format), ##__VA_ARGS__); \ } \ @@ -307,8 +305,7 @@ static void dump_malloc_descriptor(char* str, #define qemu_info_log(format, ...) \ do { \ - __libc_android_log_print(ANDROID_LOG_INFO, "memcheck", \ - (format), ##__VA_ARGS__); \ + __libc_format_log(ANDROID_LOG_INFO, "memcheck", (format), ##__VA_ARGS__); \ if (tracing_flags & INFO_TRACING_ENABLED) { \ qemu_log(ANDROID_LOG_INFO, (format), ##__VA_ARGS__); \ } \ @@ -318,20 +315,19 @@ static void dump_malloc_descriptor(char* str, * Param: * type - Message type: debug, error, or info * desc - MallocDesc instance to dump. - * frmt + rest - Formats message preceding dumped descriptor. + * fmt + rest - Formats message preceding dumped descriptor. */ -#define log_mdesc(type, desc, frmt, ...) \ +#define log_mdesc(type, desc, fmt, ...) \ do { \ if (tracing_enabled(type)) { \ char log_str[4096]; \ - size_t str_len; \ - snprintf(log_str, sizeof(log_str), frmt, ##__VA_ARGS__); \ + __libc_format_buffer(log_str, sizeof(log_str), fmt, ##__VA_ARGS__); \ log_str[sizeof(log_str) - 1] = '\0'; \ - str_len = strlen(log_str); \ + size_t str_len = strlen(log_str); \ dump_malloc_descriptor(log_str + str_len, \ sizeof(log_str) - str_len, \ (desc)); \ - type##_log(log_str); \ + type##_log("%s", log_str); \ } \ } while (0) diff --git a/libc/bionic/pthread.c b/libc/bionic/pthread.c index f29472379..f2a7ebe44 100644 --- a/libc/bionic/pthread.c +++ b/libc/bionic/pthread.c @@ -50,6 +50,7 @@ #include "bionic_pthread.h" #include "bionic_ssp.h" #include "bionic_tls.h" +#include "debug_format.h" #include "pthread_internal.h" #include "thread_private.h" @@ -229,7 +230,7 @@ int _init_thread(pthread_internal_t* thread, pid_t kernel_id, const pthread_attr // For backwards compatibility reasons, we just warn about failures here. // error = errno; const char* msg = "pthread_create sched_setscheduler call failed: %s\n"; - __libc_android_log_print(ANDROID_LOG_WARN, "libc", msg, strerror(errno)); + __libc_format_log(ANDROID_LOG_WARN, "libc", msg, strerror(errno)); } } diff --git a/libc/bionic/pthread_debug.c b/libc/bionic/pthread_debug.cpp similarity index 76% rename from libc/bionic/pthread_debug.c rename to libc/bionic/pthread_debug.cpp index 7ee208c15..c55721110 100644 --- a/libc/bionic/pthread_debug.c +++ b/libc/bionic/pthread_debug.cpp @@ -31,9 +31,7 @@ #include #include -#if HAVE_DLADDR -#include -#endif +//#include #include #include #include @@ -42,8 +40,12 @@ #include #include -#include "logd.h" #include "bionic_tls.h" +#include "debug_mapinfo.h" +#include "debug_stacktrace.h" +#include "logd.h" + +#include /* * =========================================================================== @@ -97,20 +99,16 @@ the lock has been acquired. // ============================================================================= #define LOGD(format, ...) \ - __libc_android_log_print(ANDROID_LOG_DEBUG, \ - "pthread_debug", (format), ##__VA_ARGS__ ) + __libc_format_log(ANDROID_LOG_DEBUG, "pthread_debug", (format), ##__VA_ARGS__ ) #define LOGW(format, ...) \ - __libc_android_log_print(ANDROID_LOG_WARN, \ - "pthread_debug", (format), ##__VA_ARGS__ ) + __libc_format_log(ANDROID_LOG_WARN, "pthread_debug", (format), ##__VA_ARGS__ ) #define LOGE(format, ...) \ - __libc_android_log_print(ANDROID_LOG_ERROR, \ - "pthread_debug", (format), ##__VA_ARGS__ ) + __libc_format_log(ANDROID_LOG_ERROR, "pthread_debug", (format), ##__VA_ARGS__ ) #define LOGI(format, ...) \ - __libc_android_log_print(ANDROID_LOG_INFO, \ - "pthread_debug", (format), ##__VA_ARGS__ ) + __libc_format_log(ANDROID_LOG_INFO, "pthread_debug", (format), ##__VA_ARGS__ ) static const char* const kStartBanner = "==============================================================="; @@ -120,185 +118,9 @@ static const char* const kEndBanner = extern char* __progname; -// ============================================================================= -// map info functions -// ============================================================================= - -typedef struct mapinfo { - struct mapinfo *next; - unsigned start; - unsigned end; - char name[]; -} mapinfo; - -static mapinfo* sMapInfo = NULL; - -static mapinfo *parse_maps_line(char *line) -{ - mapinfo *mi; - int len = strlen(line); - - if(len < 1) return 0; - line[--len] = 0; - - if(len < 50) return 0; - if(line[20] != 'x') return 0; - - mi = malloc(sizeof(mapinfo) + (len - 47)); - if(mi == 0) return 0; - - mi->start = strtoul(line, 0, 16); - mi->end = strtoul(line + 9, 0, 16); - /* To be filled in parse_elf_info if the mapped section starts with - * elf_header - */ - mi->next = 0; - strcpy(mi->name, line + 49); - - return mi; -} - -static mapinfo *init_mapinfo(int pid) -{ - struct mapinfo *milist = NULL; - char data[1024]; - sprintf(data, "/proc/%d/maps", pid); - FILE *fp = fopen(data, "r"); - if(fp) { - while(fgets(data, sizeof(data), fp)) { - mapinfo *mi = parse_maps_line(data); - if(mi) { - mi->next = milist; - milist = mi; - } - } - fclose(fp); - } - - return milist; -} - -static void deinit_mapinfo(mapinfo *mi) -{ - mapinfo *del; - while(mi) { - del = mi; - mi = mi->next; - free(del); - } -} - -/* Find the containing map info for the pc */ -static const mapinfo *pc_to_mapinfo(mapinfo *mi, unsigned pc, unsigned *rel_pc) -{ - *rel_pc = pc; - while(mi) { - if((pc >= mi->start) && (pc < mi->end)){ - // Only calculate the relative offset for shared libraries - if (strstr(mi->name, ".so")) { - *rel_pc -= mi->start; - } - return mi; - } - mi = mi->next; - } - return NULL; -} - -// ============================================================================= -// stack trace functions -// ============================================================================= - #define STACK_TRACE_DEPTH 16 -typedef struct -{ - size_t count; - intptr_t* addrs; -} stack_crawl_state_t; - -/* depends how the system includes define this */ -#ifdef HAVE_UNWIND_CONTEXT_STRUCT -typedef struct _Unwind_Context __unwind_context; -#else -typedef _Unwind_Context __unwind_context; -#endif - -static _Unwind_Reason_Code trace_function(__unwind_context *context, void *arg) -{ - stack_crawl_state_t* state = (stack_crawl_state_t*)arg; - if (state->count) { - intptr_t ip = (intptr_t)_Unwind_GetIP(context); - if (ip) { - state->addrs[0] = ip; - state->addrs++; - state->count--; - return _URC_NO_REASON; - } - } - /* - * If we run out of space to record the address or 0 has been seen, stop - * unwinding the stack. - */ - return _URC_END_OF_STACK; -} - -static inline -int get_backtrace(intptr_t* addrs, size_t max_entries) -{ - stack_crawl_state_t state; - state.count = max_entries; - state.addrs = (intptr_t*)addrs; - _Unwind_Backtrace(trace_function, (void*)&state); - return max_entries - state.count; -} - -static void log_backtrace(intptr_t* addrs, size_t c) -{ - int index = 0; - size_t i; - for (i=0 ; i0 || !HAVE_DLADDR) { - /* - * this test is a bit sketchy, but it allows us to skip the - * stack trace entries due to this debugging code. it works - * because those don't have a symbol (they're not exported) - */ - mapinfo const* mi = pc_to_mapinfo(sMapInfo, addrs[i], &relpc); - char const* soname = mi ? mi->name : NULL; -#if HAVE_DLADDR - if (!soname) - soname = info.dli_fname; -#endif - if (!soname) - soname = "unknown"; - - if (symbol) { - LOGW(" " - "#%02d pc %08lx %s (%s+0x%x)", - index, relpc, soname, symbol, - addrs[i] - (intptr_t)offset); - } else { - LOGW(" " - "#%02d pc %08lx %s", - index, relpc, soname); - } - index++; - } - } -} +static mapinfo_t* gMapInfo; /****************************************************************************/ @@ -322,18 +144,21 @@ static pthread_mutex_t sDbgLock = PTHREAD_MUTEX_INITIALIZER; static size_t sDbgAllocOffset = DBG_ALLOC_BLOCK_SIZE; static char* sDbgAllocPtr = NULL; -static void* DbgAllocLocked(size_t size) { +template +static T* DbgAllocLocked(size_t count = 1) { + size_t size = sizeof(T) * count; if ((sDbgAllocOffset + size) > DBG_ALLOC_BLOCK_SIZE) { sDbgAllocOffset = 0; - sDbgAllocPtr = mmap(NULL, DBG_ALLOC_BLOCK_SIZE, PROT_READ|PROT_WRITE, - MAP_ANON | MAP_PRIVATE, 0, 0); + sDbgAllocPtr = reinterpret_cast(mmap(NULL, DBG_ALLOC_BLOCK_SIZE, + PROT_READ|PROT_WRITE, + MAP_ANON | MAP_PRIVATE, 0, 0)); if (sDbgAllocPtr == MAP_FAILED) { return NULL; } } void* addr = sDbgAllocPtr + sDbgAllocOffset; sDbgAllocOffset += size; - return addr; + return reinterpret_cast(addr); } static void* debug_realloc(void *ptr, size_t size, size_t old_size) { @@ -460,9 +285,9 @@ static int pthread_mutex_unlock_unchecked(pthread_mutex_t *mutex) { /****************************************************************************/ -static void dup_backtrace(CallStack* stack, int count, intptr_t const* addrs) { +static void dup_backtrace(CallStack* stack, size_t count, intptr_t const* addrs) { stack->depth = count; - stack->addrs = DbgAllocLocked(count * sizeof(intptr_t)); + stack->addrs = DbgAllocLocked(count); memcpy(stack->addrs, addrs, count * sizeof(intptr_t)); } @@ -545,9 +370,9 @@ static int traverseTree(MutexInfo* obj, MutexInfo const* objParent) /* Turn off prediction temporarily in this thread while logging */ sPthreadDebugDisabledThread = gettid(); - if (sMapInfo == NULL) { - // note: we're protected by sDbgLock - sMapInfo = init_mapinfo(getpid()); + if (gMapInfo == NULL) { + // note: we're protected by sDbgLock. + gMapInfo = mapinfo_create(getpid()); } LOGW("%s\n", kStartBanner); @@ -555,7 +380,7 @@ static int traverseTree(MutexInfo* obj, MutexInfo const* objParent) LOGW("Illegal lock attempt:\n"); LOGW("--- pthread_mutex_t at %p\n", obj->mutex); stackDepth = get_backtrace(addrs, STACK_TRACE_DEPTH); - log_backtrace(addrs, stackDepth); + log_backtrace(gMapInfo, addrs, stackDepth); LOGW("+++ Currently held locks in this thread (in reverse order):"); MutexInfo* cur = obj; @@ -566,7 +391,7 @@ static int traverseTree(MutexInfo* obj, MutexInfo const* objParent) if (parent->owner == ourtid) { LOGW("--- pthread_mutex_t at %p\n", parent->mutex); if (sPthreadDebugLevel >= CAPTURE_CALLSTACK) { - log_backtrace(parent->stackTrace, parent->stackDepth); + log_backtrace(gMapInfo, parent->stackTrace, parent->stackDepth); } cur = parent; break; @@ -589,13 +414,13 @@ static int traverseTree(MutexInfo* obj, MutexInfo const* objParent) if (sPthreadDebugLevel >= CAPTURE_CALLSTACK) { int index = historyListHas(&obj->parents, objParent); if ((size_t)index < (size_t)obj->stacks.count) { - log_backtrace( - obj->stacks.stack[index].addrs, - obj->stacks.stack[index].depth); + log_backtrace(gMapInfo, + obj->stacks.stack[index].addrs, + obj->stacks.stack[index].depth); } else { - log_backtrace( - obj->stackTrace, - obj->stackDepth); + log_backtrace(gMapInfo, + obj->stackTrace, + obj->stackDepth); } } result = 0; @@ -640,8 +465,8 @@ static void mutex_lock_checked(MutexInfo* mrl, MutexInfo* object) linkParentToChild(mrl, object); if (!traverseTree(object, mrl)) { - deinit_mapinfo(sMapInfo); - sMapInfo = NULL; + mapinfo_destroy(gMapInfo); + gMapInfo = NULL; LOGW("%s\n", kEndBanner); unlinkParentFromChild(mrl, object); // reenable pthread debugging for this thread @@ -758,7 +583,7 @@ static HashEntry* hashmap_lookup(HashTable* table, if (entry == NULL) { // create a new entry - entry = (HashEntry*)DbgAllocLocked(sizeof(HashEntry)); + entry = DbgAllocLocked(); entry->data = NULL; entry->slot = slot; entry->prev = NULL; @@ -785,8 +610,9 @@ static MutexInfo* get_mutex_info(pthread_mutex_t *mutex) &mutex, sizeof(mutex), &MutexInfo_equals); if (entry->data == NULL) { - entry->data = (MutexInfo*)DbgAllocLocked(sizeof(MutexInfo)); - initMutexInfo(entry->data, mutex); + MutexInfo* mutex_info = DbgAllocLocked(); + entry->data = mutex_info; + initMutexInfo(mutex_info, mutex); } pthread_mutex_unlock_unchecked(&sDbgLock); @@ -808,8 +634,9 @@ static ThreadInfo* get_thread_info(pid_t pid) &pid, sizeof(pid), &ThreadInfo_equals); if (entry->data == NULL) { - entry->data = (ThreadInfo*)DbgAllocLocked(sizeof(ThreadInfo)); - initThreadInfo(entry->data, pid); + ThreadInfo* thread_info = DbgAllocLocked(); + entry->data = thread_info; + initThreadInfo(thread_info, pid); } pthread_mutex_unlock_unchecked(&sDbgLock); @@ -848,8 +675,7 @@ static MutexInfo* get_most_recently_locked() { * after system properties have been initialized */ -__LIBC_HIDDEN__ -void pthread_debug_init(void) { +extern "C" __LIBC_HIDDEN__ void pthread_debug_init() { char env[PROP_VALUE_MAX]; if (__system_property_get("debug.libc.pthread", env)) { int level = atoi(env); @@ -872,8 +698,7 @@ void pthread_debug_init(void) { * the checks before the lock is held.) */ -__LIBC_HIDDEN__ -void pthread_debug_mutex_lock_check(pthread_mutex_t *mutex) +extern "C" __LIBC_HIDDEN__ void pthread_debug_mutex_lock_check(pthread_mutex_t *mutex) { if (sPthreadDebugLevel == 0) return; // prediction disabled for this thread @@ -890,8 +715,7 @@ void pthread_debug_mutex_lock_check(pthread_mutex_t *mutex) * still held (ie: before calling the real unlock) */ -__LIBC_HIDDEN__ -void pthread_debug_mutex_unlock_check(pthread_mutex_t *mutex) +extern "C" __LIBC_HIDDEN__ void pthread_debug_mutex_unlock_check(pthread_mutex_t *mutex) { if (sPthreadDebugLevel == 0) return; // prediction disabled for this thread diff --git a/libc/bionic/ssp.cpp b/libc/bionic/ssp.cpp index fdf88328b..08c36c54e 100644 --- a/libc/bionic/ssp.cpp +++ b/libc/bionic/ssp.cpp @@ -63,8 +63,8 @@ void __stack_chk_fail() { path[count] = '\0'; } - // Do a best effort at logging. This ends up calling writev(2). - __libc_android_log_print(ANDROID_LOG_FATAL, path, "stack corruption detected: aborted"); + // Do a best effort at logging. + __libc_android_log_write(ANDROID_LOG_FATAL, path, "stack corruption detected: aborted"); // Make sure there is no default action for SIGABRT. struct sigaction sa; diff --git a/libc/bionic/stubs.cpp b/libc/bionic/stubs.cpp index 48281b413..3f24d1bd5 100644 --- a/libc/bionic/stubs.cpp +++ b/libc/bionic/stubs.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -435,7 +436,7 @@ protoent* getprotobynumber(int /*proto*/) { static void unimplemented_stub(const char* function) { const char* fmt = "%s(3) is not implemented on Android\n"; - __libc_android_log_print(ANDROID_LOG_WARN, "libc", fmt, function); + __libc_format_log(ANDROID_LOG_WARN, "libc", fmt, function); fprintf(stderr, fmt, function); } diff --git a/libc/bionic/malloc_debug_stacktrace.cpp b/libc/private/debug_format.h similarity index 50% rename from libc/bionic/malloc_debug_stacktrace.cpp rename to libc/private/debug_format.h index 32b8ac0d6..0bc114834 100644 --- a/libc/bionic/malloc_debug_stacktrace.cpp +++ b/libc/private/debug_format.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 The Android Open Source Project + * Copyright (C) 2010 The Android Open Source Project * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -25,48 +25,31 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ -#include -#include -// ============================================================================= -// stack trace functions -// ============================================================================= +#ifndef _DEBUG_FORMAT_H +#define _DEBUG_FORMAT_H -struct stack_crawl_state_t { - size_t count; - intptr_t* addrs; -}; +#include +#include +#include +__BEGIN_DECLS -/* depends how the system includes define this */ -#ifdef HAVE_UNWIND_CONTEXT_STRUCT -typedef struct _Unwind_Context __unwind_context; -#else -typedef _Unwind_Context __unwind_context; -#endif +// Formatting routines for the C library's internal debugging. +// Unlike the usual alternatives, these don't allocate. -static _Unwind_Reason_Code trace_function(__unwind_context* context, void* arg) { - stack_crawl_state_t* state = static_cast(arg); - if (state->count) { - intptr_t ip = (intptr_t)_Unwind_GetIP(context); - if (ip) { - state->addrs[0] = ip; - state->addrs++; - state->count--; - return _URC_NO_REASON; - } - } - /* - * If we run out of space to record the address or 0 has been seen, stop - * unwinding the stack. - */ - return _URC_END_OF_STACK; -} +__LIBC_HIDDEN__ int __libc_format_buffer(char* buffer, size_t buffer_size, const char* format, ...) + __attribute__((__format__(printf, 3, 4))); -__LIBC_HIDDEN__ int get_backtrace(intptr_t* addrs, size_t max_entries) { - stack_crawl_state_t state; - state.count = max_entries; - state.addrs = addrs; - _Unwind_Backtrace(trace_function, &state); - return max_entries - state.count; -} +__LIBC_HIDDEN__ int __libc_format_fd(int fd, const char* format, ...) + __attribute__((__format__(printf, 2, 3))); + +__LIBC_HIDDEN__ int __libc_format_log(int priority, const char* tag, const char* format, ...) + __attribute__((__format__(printf, 3, 4))); + +__LIBC_HIDDEN__ int __libc_format_log_va_list(int priority, const char* tag, const char* format, + va_list ap); + +__END_DECLS + +#endif /* _DEBUG_FORMAT_H */ diff --git a/linker/Android.mk b/linker/Android.mk index dfa77e9a7..ea4319125 100644 --- a/linker/Android.mk +++ b/linker/Android.mk @@ -13,7 +13,6 @@ LOCAL_SRC_FILES:= \ dlfcn.cpp \ linker.cpp \ linker_environ.cpp \ - linker_format.cpp \ linker_phdr.cpp \ rt.cpp diff --git a/linker/debugger.cpp b/linker/debugger.cpp index 5fd5cb73c..a14e30a8c 100644 --- a/linker/debugger.cpp +++ b/linker/debugger.cpp @@ -27,7 +27,6 @@ */ #include "linker.h" -#include "linker_format.h" #include #include @@ -38,6 +37,7 @@ #include #include +#include #include extern "C" int tgkill(int tgid, int tid, int sig); @@ -135,12 +135,12 @@ static void logSignalSummary(int signum, const siginfo_t* info) { char buffer[128]; // "info" will be NULL if the siginfo_t information was not available. if (info != NULL) { - format_buffer(buffer, sizeof(buffer), + __libc_format_buffer(buffer, sizeof(buffer), "Fatal signal %d (%s) at 0x%08x (code=%d), thread %d (%s)", signum, signame, reinterpret_cast(info->si_addr), info->si_code, gettid(), threadname); } else { - format_buffer(buffer, sizeof(buffer), + __libc_format_buffer(buffer, sizeof(buffer), "Fatal signal %d (%s), thread %d (%s)", signum, signame, gettid(), threadname); } @@ -215,7 +215,7 @@ void debugger_signal_handler(int n, siginfo_t* info, void*) { if (ret < 0) { /* read or write failed -- broken connection? */ - format_buffer(msgbuf, sizeof(msgbuf), + __libc_format_buffer(msgbuf, sizeof(msgbuf), "Failed while talking to debuggerd: %s", strerror(errno)); __libc_android_log_write(ANDROID_LOG_FATAL, "libc", msgbuf); } @@ -223,7 +223,7 @@ void debugger_signal_handler(int n, siginfo_t* info, void*) { close(s); } else { /* socket failed; maybe process ran out of fds */ - format_buffer(msgbuf, sizeof(msgbuf), + __libc_format_buffer(msgbuf, sizeof(msgbuf), "Unable to open connection to debuggerd: %s", strerror(errno)); __libc_android_log_write(ANDROID_LOG_FATAL, "libc", msgbuf); } diff --git a/linker/linker.cpp b/linker/linker.cpp index 0a89b7224..c8a2a84d8 100755 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -41,13 +41,13 @@ // Private C library headers. #include +#include #include #include #include "linker.h" #include "linker_debug.h" #include "linker_environ.h" -#include "linker_format.h" #include "linker_phdr.h" /* Assume average path length of 64 and max 8 paths */ @@ -159,7 +159,7 @@ static char tmp_err_buf[768]; static char __linker_dl_err_buf[768]; #define DL_ERR(fmt, x...) \ do { \ - format_buffer(__linker_dl_err_buf, sizeof(__linker_dl_err_buf), fmt, ##x); \ + __libc_format_buffer(__linker_dl_err_buf, sizeof(__linker_dl_err_buf), fmt, ##x); \ /* If LD_DEBUG is set high enough, send every dlerror(3) message to the log. */ \ DEBUG(fmt "\n", ##x); \ } while(0) @@ -674,7 +674,7 @@ static void dump(soinfo *si) static int open_library_on_path(const char* name, const char* const paths[]) { char buf[512]; for (size_t i = 0; paths[i] != NULL; ++i) { - int n = format_buffer(buf, sizeof(buf), "%s/%s", paths[i], name); + int n = __libc_format_buffer(buf, sizeof(buf), "%s/%s", paths[i], name); if (n < 0 || n >= static_cast(sizeof(buf))) { PRINT("Warning: ignoring very long library path: %s/%s\n", paths[i], name); continue; diff --git a/linker/linker_debug.h b/linker/linker_debug.h index 0a3710bc2..b326d0069 100644 --- a/linker/linker_debug.h +++ b/linker/linker_debug.h @@ -52,19 +52,17 @@ /*********************************************************************/ -#include "linker_format.h" +#include #if LINKER_DEBUG_TO_LOG -extern int format_log(int, const char*, const char*, ...) __attribute__((__format__(printf, 3, 4))); #define _PRINTVF(v,x...) \ do { \ - if (debug_verbosity > (v)) format_log(5-(v),"linker",x); \ + if (debug_verbosity > (v)) __libc_format_log(5-(v),"linker",x); \ } while (0) #else /* !LINKER_DEBUG_TO_LOG */ -extern int format_fd(int, const char *, ...) __attribute__((__format__(printf, 2, 3))); #define _PRINTVF(v,x...) \ do { \ - if (debug_verbosity > (v)) format_fd(1, x); \ + if (debug_verbosity > (v)) __libc_format_fd(1, x); \ } while (0) #endif /* !LINKER_DEBUG_TO_LOG */