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