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