117e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris/* 217e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris * Copyright (C) 2013 The Android Open Source Project 317e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris * 417e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris * Licensed under the Apache License, Version 2.0 (the "License"); 517e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris * you may not use this file except in compliance with the License. 617e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris * You may obtain a copy of the License at 717e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris * 817e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris * http://www.apache.org/licenses/LICENSE-2.0 917e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris * 1017e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris * Unless required by applicable law or agreed to in writing, software 1117e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris * distributed under the License is distributed on an "AS IS" BASIS, 1217e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1317e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris * See the License for the specific language governing permissions and 1417e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris * limitations under the License. 1517e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris */ 1617e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris 1746756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris#include <backtrace/Backtrace.h> 1846756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris#include <backtrace/BacktraceMap.h> 1917e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris 2017e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris#include <sys/types.h> 2117e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris#include <string.h> 22c58287d60166ebdb1bd39fa40e5524c868c73a9bChristopher Ferris#include <ucontext.h> 2317e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris 2417e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris#include <libunwind.h> 2517e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris#include <libunwind-ptrace.h> 2617e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris 27e29609106033a48a6128664668d22bf4fb42a7eeChristopher Ferris#include "BacktraceLog.h" 28df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris#include "UnwindMap.h" 2917e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris#include "UnwindPtrace.h" 3017e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris 3117e91d44edf5e6476a477a200bcd89d4327358a3Christopher FerrisUnwindPtrace::UnwindPtrace() : addr_space_(NULL), upt_info_(NULL) { 3217e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris} 3317e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris 3417e91d44edf5e6476a477a200bcd89d4327358a3Christopher FerrisUnwindPtrace::~UnwindPtrace() { 3517e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris if (upt_info_) { 3617e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris _UPT_destroy(upt_info_); 3717e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris upt_info_ = NULL; 3817e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris } 3917e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris if (addr_space_) { 40df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris // Remove the map from the address space before destroying it. 41df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris // It will be freed in the UnwindMap destructor. 42df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris unw_map_set(addr_space_, NULL); 43df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris 4417e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris unw_destroy_addr_space(addr_space_); 4517e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris addr_space_ = NULL; 4617e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris } 4717e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris} 4817e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris 49a2efd3ac7abe223aa7a8ba8b5ba448216c4953b4Christopher Ferrisbool UnwindPtrace::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) { 50a2efd3ac7abe223aa7a8ba8b5ba448216c4953b4Christopher Ferris if (ucontext) { 51a2efd3ac7abe223aa7a8ba8b5ba448216c4953b4Christopher Ferris BACK_LOGW("Unwinding from a specified context not supported yet."); 52a2efd3ac7abe223aa7a8ba8b5ba448216c4953b4Christopher Ferris return false; 53a2efd3ac7abe223aa7a8ba8b5ba448216c4953b4Christopher Ferris } 54a2efd3ac7abe223aa7a8ba8b5ba448216c4953b4Christopher Ferris 5517e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris addr_space_ = unw_create_addr_space(&_UPT_accessors, 0); 5617e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris if (!addr_space_) { 578ed46278bee3cfc4c216f3a1524744019b693200Christopher Ferris BACK_LOGW("unw_create_addr_space failed."); 5817e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris return false; 5917e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris } 6017e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris 61df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris UnwindMap* map = static_cast<UnwindMap*>(GetMap()); 62df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris unw_map_set(addr_space_, map->GetMapCursor()); 63df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris 64df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris upt_info_ = reinterpret_cast<struct UPT_info*>(_UPT_create(Tid())); 6517e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris if (!upt_info_) { 668ed46278bee3cfc4c216f3a1524744019b693200Christopher Ferris BACK_LOGW("Failed to create upt info."); 6717e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris return false; 6817e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris } 6917e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris 7017e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris unw_cursor_t cursor; 7117e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris int ret = unw_init_remote(&cursor, addr_space_, upt_info_); 7217e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris if (ret < 0) { 738ed46278bee3cfc4c216f3a1524744019b693200Christopher Ferris BACK_LOGW("unw_init_remote failed %d", ret); 7417e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris return false; 7517e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris } 7617e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris 7746756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris std::vector<backtrace_frame_data_t>* frames = GetFrames(); 7846756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris frames->reserve(MAX_BACKTRACE_FRAMES); 7946756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris size_t num_frames = 0; 8017e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris do { 8117e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris unw_word_t pc; 8217e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris ret = unw_get_reg(&cursor, UNW_REG_IP, &pc); 8317e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris if (ret < 0) { 848ed46278bee3cfc4c216f3a1524744019b693200Christopher Ferris BACK_LOGW("Failed to read IP %d", ret); 8517e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris break; 8617e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris } 8717e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris unw_word_t sp; 8817e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris ret = unw_get_reg(&cursor, UNW_REG_SP, &sp); 8917e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris if (ret < 0) { 908ed46278bee3cfc4c216f3a1524744019b693200Christopher Ferris BACK_LOGW("Failed to read SP %d", ret); 9117e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris break; 9217e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris } 9317e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris 9417e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris if (num_ignore_frames == 0) { 9546756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris frames->resize(num_frames+1); 9646756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris backtrace_frame_data_t* frame = &frames->at(num_frames); 9720303f856f1f1cdb5af58af0b116b8c598f0ea5cChristopher Ferris frame->num = num_frames; 9817e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris frame->pc = static_cast<uintptr_t>(pc); 9917e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris frame->sp = static_cast<uintptr_t>(sp); 10017e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris frame->stack_size = 0; 10117e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris 10217e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris if (num_frames > 0) { 10346756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris backtrace_frame_data_t* prev = &frames->at(num_frames-1); 10417e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris prev->stack_size = frame->sp - prev->sp; 10517e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris } 10617e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris 107df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris frame->func_name = GetFunctionName(frame->pc, &frame->func_offset); 10817e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris 109df2906186b6952c57b1f662bfef0b65c9f8c2e0dChristopher Ferris frame->map = FindMap(frame->pc); 11017e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris 11146756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris num_frames++; 11217e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris } else { 11317e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris num_ignore_frames--; 11417e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris } 11517e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris ret = unw_step (&cursor); 11646756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris } while (ret > 0 && num_frames < MAX_BACKTRACE_FRAMES); 11717e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris 11817e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris return true; 11917e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris} 12017e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris 12117e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferrisstd::string UnwindPtrace::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) { 12217e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris *offset = 0; 12317e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris char buf[512]; 12417e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris unw_word_t value; 12517e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris if (unw_get_proc_name_by_ip(addr_space_, pc, buf, sizeof(buf), &value, 12617e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris upt_info_) >= 0 && buf[0] != '\0') { 12717e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris *offset = static_cast<uintptr_t>(value); 12817e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris return buf; 12917e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris } 13017e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris return ""; 13117e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris} 13217e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris 13317e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris//------------------------------------------------------------------------- 13417e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris// C++ object creation function. 13517e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris//------------------------------------------------------------------------- 13646756821c4fe238f12a6e5ea18c356398f8d8795Christopher FerrisBacktrace* CreatePtraceObj(pid_t pid, pid_t tid, BacktraceMap* map) { 13746756821c4fe238f12a6e5ea18c356398f8d8795Christopher Ferris return new BacktracePtrace(new UnwindPtrace(), pid, tid, map); 13817e91d44edf5e6476a477a200bcd89d4327358a3Christopher Ferris} 139