11e980b6bc8315d00a07312b25486531247abd98cElliott Hughes/* 21e980b6bc8315d00a07312b25486531247abd98cElliott Hughes * Copyright (C) 2012 The Android Open Source Project 31e980b6bc8315d00a07312b25486531247abd98cElliott Hughes * All rights reserved. 41e980b6bc8315d00a07312b25486531247abd98cElliott Hughes * 51e980b6bc8315d00a07312b25486531247abd98cElliott Hughes * Redistribution and use in source and binary forms, with or without 61e980b6bc8315d00a07312b25486531247abd98cElliott Hughes * modification, are permitted provided that the following conditions 71e980b6bc8315d00a07312b25486531247abd98cElliott Hughes * are met: 81e980b6bc8315d00a07312b25486531247abd98cElliott Hughes * * Redistributions of source code must retain the above copyright 91e980b6bc8315d00a07312b25486531247abd98cElliott Hughes * notice, this list of conditions and the following disclaimer. 101e980b6bc8315d00a07312b25486531247abd98cElliott Hughes * * Redistributions in binary form must reproduce the above copyright 111e980b6bc8315d00a07312b25486531247abd98cElliott Hughes * notice, this list of conditions and the following disclaimer in 121e980b6bc8315d00a07312b25486531247abd98cElliott Hughes * the documentation and/or other materials provided with the 131e980b6bc8315d00a07312b25486531247abd98cElliott Hughes * distribution. 141e980b6bc8315d00a07312b25486531247abd98cElliott Hughes * 151e980b6bc8315d00a07312b25486531247abd98cElliott Hughes * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 161e980b6bc8315d00a07312b25486531247abd98cElliott Hughes * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 171e980b6bc8315d00a07312b25486531247abd98cElliott Hughes * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 181e980b6bc8315d00a07312b25486531247abd98cElliott Hughes * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 191e980b6bc8315d00a07312b25486531247abd98cElliott Hughes * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 201e980b6bc8315d00a07312b25486531247abd98cElliott Hughes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 211e980b6bc8315d00a07312b25486531247abd98cElliott Hughes * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 221e980b6bc8315d00a07312b25486531247abd98cElliott Hughes * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 231e980b6bc8315d00a07312b25486531247abd98cElliott Hughes * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 241e980b6bc8315d00a07312b25486531247abd98cElliott Hughes * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 251e980b6bc8315d00a07312b25486531247abd98cElliott Hughes * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 261e980b6bc8315d00a07312b25486531247abd98cElliott Hughes * SUCH DAMAGE. 271e980b6bc8315d00a07312b25486531247abd98cElliott Hughes */ 281e980b6bc8315d00a07312b25486531247abd98cElliott Hughes 291e980b6bc8315d00a07312b25486531247abd98cElliott Hughes#include "debug_stacktrace.h" 301e980b6bc8315d00a07312b25486531247abd98cElliott Hughes 311e980b6bc8315d00a07312b25486531247abd98cElliott Hughes#include <dlfcn.h> 32c7c5f85ead6a58eadd511c728a9020a493bc128fElliott Hughes#include <inttypes.h> 3305fc1d7050d5451aea08dc5f504d2670287b2d43Elliott Hughes#include <malloc.h> 341e980b6bc8315d00a07312b25486531247abd98cElliott Hughes#include <unistd.h> 351e980b6bc8315d00a07312b25486531247abd98cElliott Hughes#include <unwind.h> 361e980b6bc8315d00a07312b25486531247abd98cElliott Hughes#include <sys/types.h> 371e980b6bc8315d00a07312b25486531247abd98cElliott Hughes 381e980b6bc8315d00a07312b25486531247abd98cElliott Hughes#include "debug_mapinfo.h" 39861c0ef37bcfcae56d88572cb01c18bcfe1fadedChristopher Ferris#include "malloc_debug_disable.h" 40eb847bc8666842a3cfc9c06e8458ad1abebebaf0Elliott Hughes#include "private/libc_logging.h" 411e980b6bc8315d00a07312b25486531247abd98cElliott Hughes 42ba76572789740ec1a04da30dd89121ef5cb0bf44Elliott Hughes#if defined(__LP64__) 43ba76572789740ec1a04da30dd89121ef5cb0bf44Elliott Hughes#define PAD_PTR "016" PRIxPTR 44ba76572789740ec1a04da30dd89121ef5cb0bf44Elliott Hughes#else 45ba76572789740ec1a04da30dd89121ef5cb0bf44Elliott Hughes#define PAD_PTR "08" PRIxPTR 46ba76572789740ec1a04da30dd89121ef5cb0bf44Elliott Hughes#endif 47ba76572789740ec1a04da30dd89121ef5cb0bf44Elliott Hughes 481e980b6bc8315d00a07312b25486531247abd98cElliott Hughestypedef struct _Unwind_Context __unwind_context; 491e980b6bc8315d00a07312b25486531247abd98cElliott Hughes 506e54c3e519892ca13f15bdcea0d431befbadac25Elliott Hughesextern "C" char* __cxa_demangle(const char*, char*, size_t*, int*); 516e54c3e519892ca13f15bdcea0d431befbadac25Elliott Hughes 521728b2396591853345507a063ed6075dfd251706Elliott Hughesstatic mapinfo_t* g_map_info = NULL; 5335b621c5f4c79959cd36fec0153c2c9c43ebe5f0Elliott Hughes 5435b621c5f4c79959cd36fec0153c2c9c43ebe5f0Elliott Hughes__LIBC_HIDDEN__ void backtrace_startup() { 55861c0ef37bcfcae56d88572cb01c18bcfe1fadedChristopher Ferris ScopedDisableDebugCalls disable; 56861c0ef37bcfcae56d88572cb01c18bcfe1fadedChristopher Ferris 571728b2396591853345507a063ed6075dfd251706Elliott Hughes g_map_info = mapinfo_create(getpid()); 5835b621c5f4c79959cd36fec0153c2c9c43ebe5f0Elliott Hughes} 5935b621c5f4c79959cd36fec0153c2c9c43ebe5f0Elliott Hughes 6035b621c5f4c79959cd36fec0153c2c9c43ebe5f0Elliott Hughes__LIBC_HIDDEN__ void backtrace_shutdown() { 61861c0ef37bcfcae56d88572cb01c18bcfe1fadedChristopher Ferris ScopedDisableDebugCalls disable; 62861c0ef37bcfcae56d88572cb01c18bcfe1fadedChristopher Ferris 631728b2396591853345507a063ed6075dfd251706Elliott Hughes mapinfo_destroy(g_map_info); 6435b621c5f4c79959cd36fec0153c2c9c43ebe5f0Elliott Hughes} 6535b621c5f4c79959cd36fec0153c2c9c43ebe5f0Elliott Hughes 6635b621c5f4c79959cd36fec0153c2c9c43ebe5f0Elliott Hughesstruct stack_crawl_state_t { 6735b621c5f4c79959cd36fec0153c2c9c43ebe5f0Elliott Hughes uintptr_t* frames; 6835b621c5f4c79959cd36fec0153c2c9c43ebe5f0Elliott Hughes size_t frame_count; 6935b621c5f4c79959cd36fec0153c2c9c43ebe5f0Elliott Hughes size_t max_depth; 7035b621c5f4c79959cd36fec0153c2c9c43ebe5f0Elliott Hughes bool have_skipped_self; 7135b621c5f4c79959cd36fec0153c2c9c43ebe5f0Elliott Hughes 7235b621c5f4c79959cd36fec0153c2c9c43ebe5f0Elliott Hughes stack_crawl_state_t(uintptr_t* frames, size_t max_depth) 7335b621c5f4c79959cd36fec0153c2c9c43ebe5f0Elliott Hughes : frames(frames), frame_count(0), max_depth(max_depth), have_skipped_self(false) { 7435b621c5f4c79959cd36fec0153c2c9c43ebe5f0Elliott Hughes } 7535b621c5f4c79959cd36fec0153c2c9c43ebe5f0Elliott Hughes}; 7635b621c5f4c79959cd36fec0153c2c9c43ebe5f0Elliott Hughes 771e980b6bc8315d00a07312b25486531247abd98cElliott Hughesstatic _Unwind_Reason_Code trace_function(__unwind_context* context, void* arg) { 781e980b6bc8315d00a07312b25486531247abd98cElliott Hughes stack_crawl_state_t* state = static_cast<stack_crawl_state_t*>(arg); 7935b621c5f4c79959cd36fec0153c2c9c43ebe5f0Elliott Hughes 8035b621c5f4c79959cd36fec0153c2c9c43ebe5f0Elliott Hughes uintptr_t ip = _Unwind_GetIP(context); 8135b621c5f4c79959cd36fec0153c2c9c43ebe5f0Elliott Hughes 8235b621c5f4c79959cd36fec0153c2c9c43ebe5f0Elliott Hughes // The first stack frame is get_backtrace itself. Skip it. 8335b621c5f4c79959cd36fec0153c2c9c43ebe5f0Elliott Hughes if (ip != 0 && !state->have_skipped_self) { 8435b621c5f4c79959cd36fec0153c2c9c43ebe5f0Elliott Hughes state->have_skipped_self = true; 8535b621c5f4c79959cd36fec0153c2c9c43ebe5f0Elliott Hughes return _URC_NO_REASON; 861e980b6bc8315d00a07312b25486531247abd98cElliott Hughes } 8735b621c5f4c79959cd36fec0153c2c9c43ebe5f0Elliott Hughes 88861c0ef37bcfcae56d88572cb01c18bcfe1fadedChristopher Ferris#if defined(__arm__) 8952171b9bdcb2aa1efe9c4deab37c029699fe763dBen Cheng /* 9052171b9bdcb2aa1efe9c4deab37c029699fe763dBen Cheng * The instruction pointer is pointing at the instruction after the bl(x), and 9152171b9bdcb2aa1efe9c4deab37c029699fe763dBen Cheng * the _Unwind_Backtrace routine already masks the Thumb mode indicator (LSB 9252171b9bdcb2aa1efe9c4deab37c029699fe763dBen Cheng * in PC). So we need to do a quick check here to find out if the previous 9352171b9bdcb2aa1efe9c4deab37c029699fe763dBen Cheng * instruction is a Thumb-mode BLX(2). If so subtract 2 otherwise 4 from PC. 9452171b9bdcb2aa1efe9c4deab37c029699fe763dBen Cheng */ 9552171b9bdcb2aa1efe9c4deab37c029699fe763dBen Cheng if (ip != 0) { 9652171b9bdcb2aa1efe9c4deab37c029699fe763dBen Cheng short* ptr = reinterpret_cast<short*>(ip); 9752171b9bdcb2aa1efe9c4deab37c029699fe763dBen Cheng // Thumb BLX(2) 9863dd03ccedc316724c40e140067e612932e4420eBen Cheng if ((*(ptr-1) & 0xff80) == 0x4780) { 9952171b9bdcb2aa1efe9c4deab37c029699fe763dBen Cheng ip -= 2; 10052171b9bdcb2aa1efe9c4deab37c029699fe763dBen Cheng } else { 10152171b9bdcb2aa1efe9c4deab37c029699fe763dBen Cheng ip -= 4; 10252171b9bdcb2aa1efe9c4deab37c029699fe763dBen Cheng } 10352171b9bdcb2aa1efe9c4deab37c029699fe763dBen Cheng } 10452171b9bdcb2aa1efe9c4deab37c029699fe763dBen Cheng#endif 10552171b9bdcb2aa1efe9c4deab37c029699fe763dBen Cheng 10635b621c5f4c79959cd36fec0153c2c9c43ebe5f0Elliott Hughes state->frames[state->frame_count++] = ip; 10735b621c5f4c79959cd36fec0153c2c9c43ebe5f0Elliott Hughes return (state->frame_count >= state->max_depth) ? _URC_END_OF_STACK : _URC_NO_REASON; 1081e980b6bc8315d00a07312b25486531247abd98cElliott Hughes} 1091e980b6bc8315d00a07312b25486531247abd98cElliott Hughes 11035b621c5f4c79959cd36fec0153c2c9c43ebe5f0Elliott Hughes__LIBC_HIDDEN__ int get_backtrace(uintptr_t* frames, size_t max_depth) { 111861c0ef37bcfcae56d88572cb01c18bcfe1fadedChristopher Ferris ScopedDisableDebugCalls disable; 112861c0ef37bcfcae56d88572cb01c18bcfe1fadedChristopher Ferris 11335b621c5f4c79959cd36fec0153c2c9c43ebe5f0Elliott Hughes stack_crawl_state_t state(frames, max_depth); 1141e980b6bc8315d00a07312b25486531247abd98cElliott Hughes _Unwind_Backtrace(trace_function, &state); 11535b621c5f4c79959cd36fec0153c2c9c43ebe5f0Elliott Hughes return state.frame_count; 1161e980b6bc8315d00a07312b25486531247abd98cElliott Hughes} 1171e980b6bc8315d00a07312b25486531247abd98cElliott Hughes 11835b621c5f4c79959cd36fec0153c2c9c43ebe5f0Elliott Hughes__LIBC_HIDDEN__ void log_backtrace(uintptr_t* frames, size_t frame_count) { 119861c0ef37bcfcae56d88572cb01c18bcfe1fadedChristopher Ferris ScopedDisableDebugCalls disable; 120861c0ef37bcfcae56d88572cb01c18bcfe1fadedChristopher Ferris 121239e7a0756fddf3698bf72cab10d7f382421090bElliott Hughes uintptr_t self_bt[16]; 12235b621c5f4c79959cd36fec0153c2c9c43ebe5f0Elliott Hughes if (frames == NULL) { 12335b621c5f4c79959cd36fec0153c2c9c43ebe5f0Elliott Hughes frame_count = get_backtrace(self_bt, 16); 12435b621c5f4c79959cd36fec0153c2c9c43ebe5f0Elliott Hughes frames = self_bt; 1251e980b6bc8315d00a07312b25486531247abd98cElliott Hughes } 1261e980b6bc8315d00a07312b25486531247abd98cElliott Hughes 1271e980b6bc8315d00a07312b25486531247abd98cElliott Hughes __libc_format_log(ANDROID_LOG_ERROR, "libc", 1281e980b6bc8315d00a07312b25486531247abd98cElliott Hughes "*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n"); 1291e980b6bc8315d00a07312b25486531247abd98cElliott Hughes 13035b621c5f4c79959cd36fec0153c2c9c43ebe5f0Elliott Hughes for (size_t i = 0 ; i < frame_count; ++i) { 131c7c5f85ead6a58eadd511c728a9020a493bc128fElliott Hughes uintptr_t offset = 0; 1321e980b6bc8315d00a07312b25486531247abd98cElliott Hughes const char* symbol = NULL; 1331e980b6bc8315d00a07312b25486531247abd98cElliott Hughes 1341e980b6bc8315d00a07312b25486531247abd98cElliott Hughes Dl_info info; 13535b621c5f4c79959cd36fec0153c2c9c43ebe5f0Elliott Hughes if (dladdr((void*) frames[i], &info) != 0) { 136c7c5f85ead6a58eadd511c728a9020a493bc128fElliott Hughes offset = reinterpret_cast<uintptr_t>(info.dli_saddr); 1371e980b6bc8315d00a07312b25486531247abd98cElliott Hughes symbol = info.dli_sname; 1381e980b6bc8315d00a07312b25486531247abd98cElliott Hughes } 1391e980b6bc8315d00a07312b25486531247abd98cElliott Hughes 140861c0ef37bcfcae56d88572cb01c18bcfe1fadedChristopher Ferris uintptr_t rel_pc = offset; 1411728b2396591853345507a063ed6075dfd251706Elliott Hughes const mapinfo_t* mi = (g_map_info != NULL) ? mapinfo_find(g_map_info, frames[i], &rel_pc) : NULL; 14235b621c5f4c79959cd36fec0153c2c9c43ebe5f0Elliott Hughes const char* soname = (mi != NULL) ? mi->name : info.dli_fname; 14335b621c5f4c79959cd36fec0153c2c9c43ebe5f0Elliott Hughes if (soname == NULL) { 14435b621c5f4c79959cd36fec0153c2c9c43ebe5f0Elliott Hughes soname = "<unknown>"; 14535b621c5f4c79959cd36fec0153c2c9c43ebe5f0Elliott Hughes } 14635b621c5f4c79959cd36fec0153c2c9c43ebe5f0Elliott Hughes if (symbol != NULL) { 1476e54c3e519892ca13f15bdcea0d431befbadac25Elliott Hughes char* demangled_symbol = __cxa_demangle(symbol, NULL, NULL, NULL); 14835b621c5f4c79959cd36fec0153c2c9c43ebe5f0Elliott Hughes const char* best_name = (demangled_symbol != NULL) ? demangled_symbol : symbol; 14935b621c5f4c79959cd36fec0153c2c9c43ebe5f0Elliott Hughes 150c7c5f85ead6a58eadd511c728a9020a493bc128fElliott Hughes __libc_format_log(ANDROID_LOG_ERROR, "libc", 151ba76572789740ec1a04da30dd89121ef5cb0bf44Elliott Hughes " #%02zd pc %" PAD_PTR " %s (%s+%" PRIuPTR ")", 152ba76572789740ec1a04da30dd89121ef5cb0bf44Elliott Hughes i, rel_pc, soname, best_name, frames[i] - offset); 15335b621c5f4c79959cd36fec0153c2c9c43ebe5f0Elliott Hughes 15435b621c5f4c79959cd36fec0153c2c9c43ebe5f0Elliott Hughes free(demangled_symbol); 15535b621c5f4c79959cd36fec0153c2c9c43ebe5f0Elliott Hughes } else { 156c7c5f85ead6a58eadd511c728a9020a493bc128fElliott Hughes __libc_format_log(ANDROID_LOG_ERROR, "libc", 157ba76572789740ec1a04da30dd89121ef5cb0bf44Elliott Hughes " #%02zd pc %" PAD_PTR " %s", 158ba76572789740ec1a04da30dd89121ef5cb0bf44Elliott Hughes i, rel_pc, soname); 1591e980b6bc8315d00a07312b25486531247abd98cElliott Hughes } 1601e980b6bc8315d00a07312b25486531247abd98cElliott Hughes } 1611e980b6bc8315d00a07312b25486531247abd98cElliott Hughes} 162