1/* 2 * Copyright (c) 2022-2024 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16#include "backtrace_local.h" 17 18#include <cstring> 19#include <dirent.h> 20#include <mutex> 21#include <unistd.h> 22#include <vector> 23 24#include "backtrace_local_thread.h" 25#include "elapsed_time.h" 26#include "dfx_frame_formatter.h" 27#include "dfx_kernel_stack.h" 28#include "dfx_log.h" 29#include "dfx_util.h" 30#include "directory_ex.h" 31#include "procinfo.h" 32#include "unwinder.h" 33 34namespace OHOS { 35namespace HiviewDFX { 36namespace { 37#undef LOG_DOMAIN 38#undef LOG_TAG 39#define LOG_TAG "DfxBacktrace" 40#define LOG_DOMAIN 0xD002D11 41 42std::string GetThreadHead(int32_t tid) 43{ 44 std::string threadName; 45 if (tid == BACKTRACE_CURRENT_THREAD) { 46 tid = gettid(); 47 } 48 ReadThreadName(tid, threadName); 49 std::string threadHead = "Tid:" + std::to_string(tid) + ", Name:" + threadName + "\n"; 50 return threadHead; 51} 52} 53 54bool GetBacktraceFramesByTid(std::vector<DfxFrame>& frames, int32_t tid, size_t skipFrameNum, bool fast, 55 size_t maxFrameNums) 56{ 57 std::shared_ptr<Unwinder> unwinder = nullptr; 58#ifdef __aarch64__ 59 if (fast || (tid != BACKTRACE_CURRENT_THREAD)) { 60 unwinder = std::make_shared<Unwinder>(false); 61 } 62#endif 63 if (unwinder == nullptr) { 64 unwinder = std::make_shared<Unwinder>(); 65 } 66 BacktraceLocalThread thread(tid, unwinder); 67 bool ret = thread.Unwind(fast, maxFrameNums, skipFrameNum + 1); 68 frames = thread.GetFrames(); 69 return ret; 70} 71 72bool GetBacktraceStringByTid(std::string& out, int32_t tid, size_t skipFrameNum, bool fast, 73 size_t maxFrameNums, bool enableKernelStack) 74{ 75 std::vector<DfxFrame> frames; 76 bool ret = GetBacktraceFramesByTid(frames, tid, skipFrameNum + 1, fast, maxFrameNums); 77 if (!ret && enableKernelStack) { 78 std::string msg = ""; 79 DfxThreadStack threadStack; 80 if (DfxGetKernelStack(tid, msg) == 0 && FormatThreadKernelStack(msg, threadStack)) { 81 frames = threadStack.frames; 82 ret = true; 83 DFXLOGI("Failed to get tid(%{public}d) user stack, try kernel", tid); 84 } 85 } 86 if (ret) { 87 out.clear(); 88 std::string threadHead = GetThreadHead(tid); 89 out = threadHead + Unwinder::GetFramesStr(frames); 90 } 91 return ret; 92} 93 94bool PrintBacktrace(int32_t fd, bool fast, size_t maxFrameNums) 95{ 96 DFXLOGI("Receive PrintBacktrace request."); 97 std::vector<DfxFrame> frames; 98 bool ret = GetBacktraceFramesByTid(frames, 99 BACKTRACE_CURRENT_THREAD, 1, fast, maxFrameNums); // 1: skip current frame 100 if (!ret) { 101 return false; 102 } 103 104 for (auto const& frame : frames) { 105 auto line = DfxFrameFormatter::GetFrameStr(frame); 106 if (fd >= 0) { 107 dprintf(fd, " %s", line.c_str()); 108 } 109 DFXLOGI(" %{public}s", line.c_str()); 110 } 111 return ret; 112} 113 114bool GetBacktrace(std::string& out, bool fast, size_t maxFrameNums) 115{ 116 ElapsedTime et; 117 bool ret = GetBacktraceStringByTid(out, BACKTRACE_CURRENT_THREAD, 1, 118 fast, maxFrameNums, false); // 1: skip current frame 119 DFXLOGI("GetBacktrace elapsed time: %{public}" PRId64 " ms", et.Elapsed<std::chrono::milliseconds>()); 120 return ret; 121} 122 123bool GetBacktrace(std::string& out, size_t skipFrameNum, bool fast, size_t maxFrameNums) 124{ 125 ElapsedTime et; 126 bool ret = GetBacktraceStringByTid(out, BACKTRACE_CURRENT_THREAD, skipFrameNum + 1, fast, maxFrameNums, false); 127 DFXLOGI("GetBacktrace with skip, elapsed time: %{public}" PRId64 " ms", et.Elapsed<std::chrono::milliseconds>()); 128 return ret; 129} 130 131bool PrintTrace(int32_t fd, size_t maxFrameNums) 132{ 133 return PrintBacktrace(fd, false, maxFrameNums); 134} 135 136const char* GetTrace(size_t skipFrameNum, size_t maxFrameNums) 137{ 138 static std::string trace; 139 trace.clear(); 140 if (!GetBacktrace(trace, skipFrameNum, false, maxFrameNums)) { 141 DFXLOGE("Failed to get trace string"); 142 } 143 return trace.c_str(); 144} 145 146std::string GetProcessStacktrace(size_t maxFrameNums, bool enableKernelStack) 147{ 148 auto unwinder = std::make_shared<Unwinder>(); 149 std::string ss = "\n" + GetStacktraceHeader(); 150 std::function<bool(int)> func = [&](int tid) { 151 if (tid <= 0 || tid == gettid()) { 152 return false; 153 } 154 BacktraceLocalThread thread(tid, unwinder); 155 if (thread.Unwind(false, maxFrameNums, 0)) { 156 ss += thread.GetFormattedStr(true) + "\n"; 157 } else if (enableKernelStack) { 158 std::string msg = ""; 159 DfxThreadStack threadStack; 160 if (DfxGetKernelStack(tid, msg) == 0 && FormatThreadKernelStack(msg, threadStack)) { 161 thread.SetFrames(threadStack.frames); 162 ss += thread.GetFormattedStr(true) + "\n"; 163 DFXLOGI("Failed to get tid(%{public}d) user stack, try kernel", tid); 164 } 165 } 166 return true; 167 }; 168 169 std::vector<int> tids; 170 GetTidsByPidWithFunc(getpid(), tids, func); 171 172 return ss; 173} 174} // namespace HiviewDFX 175} // namespace OHOS 176