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