• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-2023 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 <hilog/log.h>
21 #include <libunwind_i-ohos.h>
22 #include <mutex>
23 #include <sstream>
24 #include <unistd.h>
25 #include <vector>
26 
27 #include "backtrace_local_thread.h"
28 #include "dfx_frame_format.h"
29 #include "dfx_util.h"
30 #include "directory_ex.h"
31 #include "procinfo.h"
32 
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 }
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 ret = false;
47     BacktraceLocalThread thread(tid);
48     thread.SetMaxFrameNums(maxFrameNums);
49     if (fast) {
50 #ifdef __aarch64__
51         ret = thread.Unwind(nullptr, nullptr, skipFrameNum, fast);
52 #endif
53 #if defined(__riscv) && __riscv_xlen == 64
54         ret = thread.Unwind(nullptr, nullptr, skipFrameNum, fast);
55 #endif
56     }
57     if (!ret) {
58         unw_addr_space_t as;
59         unw_init_local_address_space(&as);
60         if (as == nullptr) {
61             return ret;
62         }
63 
64         auto symbol = std::make_shared<DfxSymbols>();
65         ret = thread.Unwind(as, symbol, skipFrameNum, fast);
66 
67         unw_destroy_local_address_space(as);
68     }
69     frames.clear();
70     frames = thread.GetFrames();
71     return ret;
72 }
73 
74 #ifndef is_ohos_lite
GetBacktraceJsonByTid(std::string & out,int32_t tid,size_t skipFrameNum,bool fast,size_t maxFrameNums)75 bool GetBacktraceJsonByTid(std::string& out, int32_t tid, size_t skipFrameNum, bool fast,
76     size_t maxFrameNums)
77 {
78     std::vector<DfxFrame> frames;
79     bool ret = GetBacktraceFramesByTid(frames, tid, skipFrameNum + 1, fast, maxFrameNums);
80     out.clear();
81     out = DfxFrameFormat::GetFramesJson(frames);
82     return ret;
83 }
84 #endif
85 
GetBacktraceStringByTid(std::string & out,int32_t tid,size_t skipFrameNum,bool fast,size_t maxFrameNums)86 bool GetBacktraceStringByTid(std::string& out, int32_t tid, size_t skipFrameNum, bool fast,
87                              size_t maxFrameNums)
88 {
89     std::vector<DfxFrame> frames;
90     bool ret = GetBacktraceFramesByTid(frames, tid, skipFrameNum + 1, fast, maxFrameNums);
91     out.clear();
92     out = DfxFrameFormat::GetFramesStr(frames);
93     return ret;
94 }
95 
PrintBacktrace(int32_t fd,bool fast,size_t maxFrameNums)96 bool PrintBacktrace(int32_t fd, bool fast, size_t maxFrameNums)
97 {
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 = DfxFrameFormat::GetFrameStr(frame);
107         if (fd < 0) {
108             // print to hilog
109             HILOG_INFO(LOG_CORE, " %{public}s", line.c_str());
110         } else {
111             dprintf(fd, "    %s", line.c_str());
112         }
113         HILOG_INFO(LOG_CORE, " %{public}s", line.c_str());
114     }
115     return ret;
116 }
117 
GetBacktrace(std::string & out,bool fast,size_t maxFrameNums)118 bool GetBacktrace(std::string& out, bool fast, size_t maxFrameNums)
119 {
120     return GetBacktraceStringByTid(out, BACKTRACE_CURRENT_THREAD, 1, fast, maxFrameNums); // 1: skip current frame
121 }
122 
GetBacktrace(std::string & out,size_t skipFrameNum,bool fast,size_t maxFrameNums,bool isJson)123 bool GetBacktrace(std::string& out, size_t skipFrameNum, bool fast, size_t maxFrameNums, bool isJson)
124 {
125     if (isJson) {
126 #ifndef is_ohos_lite
127         return GetBacktraceJsonByTid(out, BACKTRACE_CURRENT_THREAD, skipFrameNum + 1, fast, maxFrameNums);
128 #endif
129     } else {
130         return GetBacktraceStringByTid(out, BACKTRACE_CURRENT_THREAD, skipFrameNum + 1, fast, maxFrameNums);
131     }
132 }
133 
PrintTrace(int32_t fd,size_t maxFrameNums)134 bool PrintTrace(int32_t fd, size_t maxFrameNums)
135 {
136     return PrintBacktrace(fd, false, maxFrameNums);
137 }
138 
GetTrace(size_t skipFrameNum,size_t maxFrameNums)139 const char* GetTrace(size_t skipFrameNum, size_t maxFrameNums)
140 {
141     static std::string trace;
142     trace.clear();
143     if (!GetBacktrace(trace, skipFrameNum, false, maxFrameNums)) {
144         HILOG_ERROR(LOG_CORE, "Failed to get trace string");
145     }
146     return trace.c_str();
147 }
148 
GetStacktraceHeader()149 static std::string GetStacktraceHeader()
150 {
151     pid_t pid = getpid();
152     std::ostringstream ss;
153     ss << "" << std::endl << "Timestamp:" << GetCurrentTimeStr();
154     ss << "Pid:" << pid << std::endl;
155     ss << "Uid:" << getuid() << std::endl;
156     std::string processName;
157     ReadProcessName(pid, processName);
158     ss << "Process name::" << processName << std::endl;
159     return ss.str();
160 }
161 
GetProcessStacktrace(size_t maxFrameNums,bool isJson)162 std::string GetProcessStacktrace(size_t maxFrameNums, bool isJson)
163 {
164     unw_addr_space_t as;
165     unw_init_local_address_space(&as);
166     if (as == nullptr) {
167         return "";
168     }
169     auto symbol = std::make_shared<DfxSymbols>();
170     std::ostringstream ss;
171     ss << std::endl << GetStacktraceHeader();
172 
173     std::function<bool(int)> func = [&](int tid) {
174         if (tid <= 0 || tid == gettid()) {
175             return false;
176         }
177         BacktraceLocalThread thread(tid);
178         thread.SetMaxFrameNums(maxFrameNums);
179         if (thread.Unwind(as, symbol, 0)) {
180             ss << thread.GetFormattedStr(true, isJson) << std::endl;
181         } else {
182             std::string msg;
183             if (tid == getpid()) {
184                 ReadProcessStatus(msg, tid);
185                 ss << msg << std::endl;
186                 msg = "";
187             }
188             ReadThreadWchan(msg, tid, true);
189             ss << msg << std::endl;
190         }
191         return true;
192     };
193 
194     std::vector<int> tids;
195     GetTidsByPidWithFunc(getpid(), tids, func);
196 
197     unw_destroy_local_address_space(as);
198     return ss.str();
199 }
200 } // namespace HiviewDFX
201 } // namespace OHOS
202