am ca483765
: Merge "Fix the duplication in the debugging code."
* commit 'ca483765bd0dc16294b9e67dd0de5c6d53b1bfa3': Fix the duplication in the debugging code.
This commit is contained in:
commit
75b64a1b64
@ -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 \
|
||||
@ -881,7 +882,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)
|
||||
@ -934,10 +935,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
|
||||
|
@ -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));
|
||||
|
@ -29,9 +29,9 @@
|
||||
#include <sys/cachectl.h>
|
||||
|
||||
#ifdef DEBUG
|
||||
#include <logd.h>
|
||||
#define XLOG(...) \
|
||||
__libc_android_log_print(ANDROID_LOG_DEBUG,"libc-cacheflush",__VA_ARGS__)
|
||||
#include <private/logd.h>
|
||||
#include <private/debug_format.h>
|
||||
#define XLOG(...) __libc_format_log(ANDROID_LOG_DEBUG,"libc-cacheflush",__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <private/debug_format.h>
|
||||
#include <private/logd.h>
|
||||
|
||||
// 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 */
|
||||
|
@ -30,7 +30,7 @@
|
||||
// compile under GCC 4.7
|
||||
#undef _FORTIFY_SOURCE
|
||||
|
||||
#include "linker_format.h"
|
||||
#include "debug_format.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
@ -40,8 +40,6 @@
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#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<FdOut*>(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 <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/uio.h>
|
||||
|
||||
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
|
||||
***/
|
||||
|
96
libc/bionic/debug_mapinfo.cpp
Normal file
96
libc/bionic/debug_mapinfo.cpp
Normal file
@ -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 <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#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<mapinfo_t*>(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;
|
||||
}
|
@ -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 <sys/cdefs.h>
|
||||
|
||||
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 */
|
112
libc/bionic/debug_stacktrace.cpp
Normal file
112
libc/bionic/debug_stacktrace.cpp
Normal file
@ -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 <dlfcn.h>
|
||||
#include <unistd.h>
|
||||
#include <unwind.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#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<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;
|
||||
}
|
||||
|
||||
__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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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 <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
// 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 */
|
@ -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);
|
||||
}
|
||||
|
@ -45,18 +45,19 @@
|
||||
#include <unistd.h>
|
||||
#include <unwind.h>
|
||||
|
||||
#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<hdr_t*>(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);
|
||||
}
|
||||
|
@ -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 <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#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<mapinfo*>(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;
|
||||
}
|
@ -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<MallocDebugFini>(dlsym(libc_malloc_impl_handle,
|
||||
"malloc_debug_finalize"));
|
||||
if (malloc_debug_finalize) {
|
||||
if (malloc_debug_finalize != NULL) {
|
||||
malloc_debug_finalize();
|
||||
}
|
||||
}
|
||||
|
@ -35,6 +35,8 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <private/debug_format.h>
|
||||
|
||||
#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
|
||||
|
@ -45,6 +45,7 @@
|
||||
#include <unistd.h>
|
||||
#include <unwind.h>
|
||||
|
||||
#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<void*>(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!
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -31,9 +31,7 @@
|
||||
#include <sys/system_properties.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#if HAVE_DLADDR
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
//#include <dlfcn.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@ -42,8 +40,12 @@
|
||||
#include <unwind.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "logd.h"
|
||||
#include "bionic_tls.h"
|
||||
#include "debug_mapinfo.h"
|
||||
#include "debug_stacktrace.h"
|
||||
#include "logd.h"
|
||||
|
||||
#include <private/debug_format.h>
|
||||
|
||||
/*
|
||||
* ===========================================================================
|
||||
@ -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 ; i<c; i++) {
|
||||
unsigned int relpc;
|
||||
void* offset = 0;
|
||||
const char* symbol = NULL;
|
||||
|
||||
#if HAVE_DLADDR
|
||||
Dl_info info;
|
||||
if (dladdr((void*)addrs[i], &info)) {
|
||||
offset = info.dli_saddr;
|
||||
symbol = info.dli_sname;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (symbol || index>0 || !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 <typename T>
|
||||
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<char*>(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<T*>(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<intptr_t>(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<HashEntry>();
|
||||
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<MutexInfo>();
|
||||
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<ThreadInfo>();
|
||||
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
|
@ -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;
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include <mntent.h>
|
||||
#include <netdb.h>
|
||||
#include <private/android_filesystem_config.h>
|
||||
#include <private/debug_format.h>
|
||||
#include <private/logd.h>
|
||||
#include <pthread.h>
|
||||
#include <pwd.h>
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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 <unwind.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
// =============================================================================
|
||||
// stack trace functions
|
||||
// =============================================================================
|
||||
#ifndef _DEBUG_FORMAT_H
|
||||
#define _DEBUG_FORMAT_H
|
||||
|
||||
struct stack_crawl_state_t {
|
||||
size_t count;
|
||||
intptr_t* addrs;
|
||||
};
|
||||
#include <sys/cdefs.h>
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
|
||||
__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<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;
|
||||
}
|
||||
__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 */
|
@ -13,7 +13,6 @@ LOCAL_SRC_FILES:= \
|
||||
dlfcn.cpp \
|
||||
linker.cpp \
|
||||
linker_environ.cpp \
|
||||
linker_format.cpp \
|
||||
linker_phdr.cpp \
|
||||
rt.cpp
|
||||
|
||||
|
@ -27,7 +27,6 @@
|
||||
*/
|
||||
|
||||
#include "linker.h"
|
||||
#include "linker_format.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@ -38,6 +37,7 @@
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
#include <private/debug_format.h>
|
||||
#include <private/logd.h>
|
||||
|
||||
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<uintptr_t>(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);
|
||||
}
|
||||
|
@ -41,13 +41,13 @@
|
||||
|
||||
// Private C library headers.
|
||||
#include <private/bionic_tls.h>
|
||||
#include <private/debug_format.h>
|
||||
#include <private/logd.h>
|
||||
#include <private/ScopedPthreadMutexLocker.h>
|
||||
|
||||
#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<int>(sizeof(buf))) {
|
||||
PRINT("Warning: ignoring very long library path: %s/%s\n", paths[i], name);
|
||||
continue;
|
||||
|
@ -52,19 +52,17 @@
|
||||
|
||||
/*********************************************************************/
|
||||
|
||||
#include "linker_format.h"
|
||||
#include <private/debug_format.h>
|
||||
|
||||
#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 */
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user