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 <mutex>
20 #include <vector>
21
22 #include <unistd.h>
23
24 #include "backtrace_local_thread.h"
25 #include "dfx_frame.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 "elapsed_time.h"
32 #include "procinfo.h"
33 #include "unwinder.h"
34
35 namespace OHOS {
36 namespace HiviewDFX {
37 namespace {
38 #undef LOG_DOMAIN
39 #undef LOG_TAG
40 #define LOG_TAG "DfxBacktrace"
41 #define LOG_DOMAIN 0xD002D11
42
GetBacktraceFramesByTid(std::vector<DfxFrame> & frames,int32_t tid,size_t skipFrameNum,bool fast,size_t maxFrameNums)43 bool GetBacktraceFramesByTid(std::vector<DfxFrame>& frames, int32_t tid, size_t skipFrameNum, bool fast,
44 size_t maxFrameNums)
45 {
46 bool isNeedMaps = true;
47 #if (defined(__aarch64__) || defined(__loongarch_lp64))
48 isNeedMaps = !fast && tid == BACKTRACE_CURRENT_THREAD;
49 #endif
50 Unwinder unwinder(isNeedMaps);
51 BacktraceLocalThread thread(tid);
52 bool ret = thread.Unwind(unwinder, fast, maxFrameNums, skipFrameNum + 1);
53 frames = thread.GetFrames();
54 return ret;
55 }
56 }
57
GetBacktraceStringByTid(std::string & out,int32_t tid,size_t skipFrameNum,bool fast,size_t maxFrameNums,bool enableKernelStack)58 bool GetBacktraceStringByTid(std::string& out, int32_t tid, size_t skipFrameNum, bool fast,
59 size_t maxFrameNums, bool enableKernelStack)
60 {
61 std::vector<DfxFrame> frames;
62 bool ret = GetBacktraceFramesByTid(frames, tid, skipFrameNum + 1, fast, maxFrameNums);
63 if (!ret && enableKernelStack) {
64 std::string msg = "";
65 DfxThreadStack threadStack;
66 if (DfxGetKernelStack(tid, msg) == 0 && FormatThreadKernelStack(msg, threadStack)) {
67 frames = std::move(threadStack.frames);
68 ret = true;
69 DFXLOGI("Failed to get tid(%{public}d) user stack, try kernel", tid);
70 if (IsBetaVersion()) {
71 DFXLOGI("%{public}s", msg.c_str());
72 }
73 }
74 }
75 if (ret) {
76 out.clear();
77 std::string threadHead = GetThreadHead(tid);
78 out = threadHead + Unwinder::GetFramesStr(frames);
79 }
80 return ret;
81 }
82
PrintBacktrace(int32_t fd,bool fast,size_t maxFrameNums)83 bool PrintBacktrace(int32_t fd, bool fast, size_t maxFrameNums)
84 {
85 DFXLOGI("Receive PrintBacktrace request.");
86 std::vector<DfxFrame> frames;
87 bool ret = GetBacktraceFramesByTid(frames,
88 BACKTRACE_CURRENT_THREAD, 2, fast, maxFrameNums); // 2: skip current frame and PrintBacktrace frame
89 if (!ret) {
90 return false;
91 }
92
93 for (auto const& frame : frames) {
94 auto line = DfxFrameFormatter::GetFrameStr(frame);
95 if (fd >= 0) {
96 dprintf(fd, " %s", line.c_str());
97 }
98 DFXLOGI(" %{public}s", line.c_str());
99 }
100 return ret;
101 }
102
GetBacktrace(std::string & out,bool fast,size_t maxFrameNums)103 AT_NOINLINE bool GetBacktrace(std::string& out, bool fast, size_t maxFrameNums)
104 {
105 ElapsedTime et;
106 bool ret = GetBacktraceStringByTid(out, BACKTRACE_CURRENT_THREAD, 2,
107 fast, maxFrameNums, false); // 2: skip current frame and GetBacktrace frame
108 DFXLOGI("GetBacktrace elapsed time: %{public}" PRId64 " ms", et.Elapsed<std::chrono::milliseconds>());
109 return ret;
110 }
111
GetBacktrace(std::string & out,size_t skipFrameNum,bool fast,size_t maxFrameNums)112 AT_NOINLINE bool GetBacktrace(std::string& out, size_t skipFrameNum, bool fast, size_t maxFrameNums)
113 {
114 ElapsedTime et;
115 bool ret = GetBacktraceStringByTid(out, BACKTRACE_CURRENT_THREAD, skipFrameNum + 1, fast, maxFrameNums, false);
116 DFXLOGI("GetBacktrace with skip, elapsed time: %{public}" PRId64 " ms", et.Elapsed<std::chrono::milliseconds>());
117 return ret;
118 }
119
PrintTrace(int32_t fd,size_t maxFrameNums)120 bool PrintTrace(int32_t fd, size_t maxFrameNums)
121 {
122 return PrintBacktrace(fd, false, maxFrameNums);
123 }
124
GetTrace(size_t skipFrameNum,size_t maxFrameNums)125 const char* GetTrace(size_t skipFrameNum, size_t maxFrameNums)
126 {
127 static std::string trace;
128 trace.clear();
129 if (!GetBacktrace(trace, skipFrameNum, false, maxFrameNums)) {
130 DFXLOGE("Failed to get trace string");
131 }
132 return trace.c_str();
133 }
134
GetProcessStacktrace(size_t maxFrameNums,bool enableKernelStack,bool includeThreadInfo)135 std::string GetProcessStacktrace(size_t maxFrameNums, bool enableKernelStack, bool includeThreadInfo)
136 {
137 std::string ss = "\n" + GetStacktraceHeader();
138 Unwinder unwinder{};
139 std::function<bool(int)> func = [&](int tid) {
140 if (tid <= 0 || tid == gettid()) {
141 return false;
142 }
143 BacktraceLocalThread thread(tid, includeThreadInfo);
144 if (thread.Unwind(unwinder, false, maxFrameNums, 0)) {
145 ss += thread.GetFormattedStr(true) + "\n";
146 return true;
147 }
148 if (!enableKernelStack) {
149 return true;
150 }
151 std::string msg = "";
152 DfxThreadStack threadStack;
153 if (DfxGetKernelStack(tid, msg) == 0 && FormatThreadKernelStack(msg, threadStack)) {
154 thread.SetFrames(threadStack.frames);
155 ss += thread.GetFormattedStr(true) + "\n";
156 DFXLOGI("Failed to get tid(%{public}d) user stack, try kernel", tid);
157 if (IsBetaVersion()) {
158 DFXLOGI("%{public}s", msg.c_str());
159 }
160 }
161 return true;
162 };
163
164 std::vector<int> tids;
165 GetTidsByPidWithFunc(getpid(), tids, func);
166
167 return ss;
168 }
169 } // namespace HiviewDFX
170 } // namespace OHOS
171