1 /*
2 * Copyright (c) 2023-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 "printer.h"
17
18 #include <cinttypes>
19 #include <dlfcn.h>
20 #include <map>
21 #include <string>
22 #include <fcntl.h>
23 #include <unistd.h>
24
25 #include "dfx_config.h"
26 #include "dfx_frame_formatter.h"
27 #include "dfx_logger.h"
28 #include "dfx_ring_buffer_wrapper.h"
29 #include "dfx_signal.h"
30 #include "dfx_util.h"
31 #include "crash_exception.h"
32 #include "string_printf.h"
33 #include "string_util.h"
34 #ifndef is_ohos_lite
35 #include "parameter.h"
36 #include "parameters.h"
37 #endif
38
39 #ifndef PAGE_SIZE
40 constexpr size_t PAGE_SIZE = 4096;
41 #endif
42
43 namespace OHOS {
44 namespace HiviewDFX {
PrintDumpHeader(std::shared_ptr<ProcessDumpRequest> request,std::shared_ptr<DfxProcess> process,std::shared_ptr<Unwinder> unwinder)45 void Printer::PrintDumpHeader(std::shared_ptr<ProcessDumpRequest> request, std::shared_ptr<DfxProcess> process,
46 std::shared_ptr<Unwinder> unwinder)
47 {
48 if (process == nullptr || request == nullptr) {
49 return;
50 }
51 std::string headerInfo;
52 bool isCrash = (request->siginfo.si_signo != SIGDUMP);
53 #ifndef is_ohos_lite
54 if (isCrash) {
55 std::string buildInfo = OHOS::system::GetParameter("const.product.software.version", "Unknown");
56 headerInfo = "Build info:" + buildInfo + "\n";
57 DfxRingBufferWrapper::GetInstance().AppendMsg("Build info:" + buildInfo + "\n");
58 }
59 #endif
60 headerInfo += "Timestamp:" + GetCurrentTimeStr(request->timeStamp);
61 DfxRingBufferWrapper::GetInstance().AppendMsg("Timestamp:" + GetCurrentTimeStr(request->timeStamp));
62 headerInfo += "Pid:" + std::to_string(process->processInfo_.pid) + "\n" +
63 "Uid:" + std::to_string(process->processInfo_.uid) + "\n" +
64 "Process name:" + process->processInfo_.processName + "\n";
65 DfxRingBufferWrapper::GetInstance().AppendBuf("Pid:%d\n", process->processInfo_.pid);
66 DfxRingBufferWrapper::GetInstance().AppendBuf("Uid:%d\n", process->processInfo_.uid);
67 DfxRingBufferWrapper::GetInstance().AppendBuf("Process name:%s\n", process->processInfo_.processName.c_str());
68 if (isCrash) {
69 auto lifeCycle = DfxProcess::GetProcessLifeCycle(process->processInfo_.pid);
70 DfxRingBufferWrapper::GetInstance().AppendBuf("Process life time:%s\n", lifeCycle.c_str());
71 if (lifeCycle.empty()) {
72 ReportCrashException(request->processName, request->pid, request->uid,
73 CrashExceptionCode::CRASH_LOG_EPROCESS_LIFECYCLE);
74 }
75
76 std::string reasonInfo;
77 PrintReason(request, process, unwinder, reasonInfo);
78 headerInfo += reasonInfo + "\n";
79 auto msg = process->GetFatalMessage();
80 if (!msg.empty()) {
81 headerInfo += "LastFatalMessage:" + msg + "\n";
82 DfxRingBufferWrapper::GetInstance().AppendBuf("LastFatalMessage:%s\n", msg.c_str());
83 }
84
85 headerInfo += "Fault thread info:\n";
86 DfxRingBufferWrapper::GetInstance().AppendMsg("Fault thread info:\n");
87 }
88 DfxRingBufferWrapper::GetInstance().AppendBaseInfo(headerInfo);
89 }
90
PrintReason(std::shared_ptr<ProcessDumpRequest> request,std::shared_ptr<DfxProcess> process,std::shared_ptr<Unwinder> unwinder,std::string & reasonInfo)91 void Printer::PrintReason(std::shared_ptr<ProcessDumpRequest> request, std::shared_ptr<DfxProcess> process,
92 std::shared_ptr<Unwinder> unwinder, std::string& reasonInfo)
93 {
94 reasonInfo += "Reason:";
95 DfxRingBufferWrapper::GetInstance().AppendMsg("Reason:");
96 if (process == nullptr) {
97 DFXLOGW("process is nullptr");
98 return;
99 }
100 process->reason += DfxSignal::PrintSignal(request->siginfo);
101 uint64_t addr = (uint64_t)(request->siginfo.si_addr);
102 if (request->siginfo.si_signo == SIGSEGV &&
103 (request->siginfo.si_code == SEGV_MAPERR || request->siginfo.si_code == SEGV_ACCERR)) {
104 if (addr < PAGE_SIZE) {
105 process->reason += " probably caused by NULL pointer dereference\n";
106 DfxRingBufferWrapper::GetInstance().AppendMsg(process->reason);
107 reasonInfo += process->reason;
108 return;
109 }
110 if (unwinder == nullptr || process->keyThread_ == nullptr) {
111 DFXLOGW("%{public}s is nullptr", unwinder == nullptr ? "unwinder" : "keyThread_");
112 return;
113 }
114 std::shared_ptr<DfxMaps> maps = unwinder->GetMaps();
115 std::vector<std::shared_ptr<DfxMap>> map;
116 if (DfxRegs::CreateFromUcontext(request->context) == nullptr) {
117 DFXLOGW("regs is nullptr");
118 return;
119 }
120 std::string elfName = StringPrintf("[anon:stack:%d]", process->keyThread_->threadInfo_.tid);
121 if (maps != nullptr && maps->FindMapsByName(elfName, map)) {
122 if (map[0] != nullptr && (addr < map[0]->begin && map[0]->begin - addr <= PAGE_SIZE)) {
123 process->reason += StringPrintf(
124 " current thread stack low address = %" PRIX64_ADDR ", probably caused by stack-buffer-overflow",
125 map[0]->begin);
126 }
127 }
128 } else if (request->siginfo.si_signo == SIGSYS && request->siginfo.si_code == SYS_SECCOMP) {
129 process->reason += StringPrintf(" syscall number is %d", request->siginfo.si_syscall);
130 }
131 process->reason += "\n";
132 DfxRingBufferWrapper::GetInstance().AppendMsg(process->reason);
133 reasonInfo += process->reason;
134 }
135
PrintProcessMapsByConfig(std::shared_ptr<DfxMaps> maps)136 void Printer::PrintProcessMapsByConfig(std::shared_ptr<DfxMaps> maps)
137 {
138 if (DfxConfig::GetConfig().displayMaps) {
139 if (maps == nullptr) {
140 return;
141 }
142 auto mapsVec = maps->GetMaps();
143 DfxRingBufferWrapper::GetInstance().AppendMsg("\nMaps:\n");
144 for (auto iter = mapsVec.begin(); iter != mapsVec.end() && (*iter) != nullptr; iter++) {
145 DfxRingBufferWrapper::GetInstance().AppendMsg((*iter)->ToString());
146 }
147 }
148 }
149
PrintOtherThreadHeaderByConfig()150 void Printer::PrintOtherThreadHeaderByConfig()
151 {
152 if (DfxConfig::GetConfig().displayBacktrace) {
153 DfxRingBufferWrapper::GetInstance().AppendMsg("Other thread info:\n");
154 }
155 }
156
PrintThreadHeaderByConfig(std::shared_ptr<DfxThread> thread,bool isKeyThread)157 void Printer::PrintThreadHeaderByConfig(std::shared_ptr<DfxThread> thread, bool isKeyThread)
158 {
159 std::string headerInfo;
160 if (DfxConfig::GetConfig().displayBacktrace && thread != nullptr) {
161 DfxRingBufferWrapper::GetInstance().AppendBuf("Tid:%d, Name:%s\n",\
162 thread->threadInfo_.tid, thread->threadInfo_.threadName.c_str());
163 headerInfo = "Tid:" + std::to_string(thread->threadInfo_.tid) +
164 ", Name:" + thread->threadInfo_.threadName + "\n";
165 }
166 if (isKeyThread) {
167 DfxRingBufferWrapper::GetInstance().AppendBaseInfo(headerInfo);
168 }
169 }
170
IsLastValidFrame(const DfxFrame & frame)171 bool Printer::IsLastValidFrame(const DfxFrame& frame)
172 {
173 static uintptr_t libcStartPc = 0;
174 static uintptr_t libffrtStartEntry = 0;
175 if (((libcStartPc != 0) && (frame.pc == libcStartPc)) ||
176 ((libffrtStartEntry != 0) && (frame.pc == libffrtStartEntry))) {
177 return true;
178 }
179
180 if (frame.mapName.find("ld-musl-aarch64.so.1") != std::string::npos &&
181 frame.funcName.find("start") != std::string::npos) {
182 libcStartPc = frame.pc;
183 return true;
184 }
185
186 if (frame.mapName.find("libffrt") != std::string::npos &&
187 frame.funcName.find("CoStartEntry") != std::string::npos) {
188 libffrtStartEntry = frame.pc;
189 return true;
190 }
191
192 return false;
193 }
194
PrintThreadBacktraceByConfig(std::shared_ptr<DfxThread> thread,bool isKeyThread)195 void Printer::PrintThreadBacktraceByConfig(std::shared_ptr<DfxThread> thread, bool isKeyThread)
196 {
197 if (DfxConfig::GetConfig().displayBacktrace && thread != nullptr) {
198 const auto& frames = thread->GetFrames();
199 if (frames.size() == 0) {
200 return;
201 }
202 bool needSkip = false;
203 bool isSubmitter = true;
204 for (const auto& frame : frames) {
205 if (frame.index == 0) {
206 isSubmitter = !isSubmitter;
207 }
208 if (isSubmitter) {
209 DfxRingBufferWrapper::GetInstance().AppendMsg("========SubmitterStacktrace========\n");
210 DfxRingBufferWrapper::GetInstance().AppendBaseInfo("========SubmitterStacktrace========\n");
211 isSubmitter = false;
212 needSkip = false;
213 }
214 if (needSkip) {
215 continue;
216 }
217 DfxRingBufferWrapper::GetInstance().AppendMsg(DfxFrameFormatter::GetFrameStr(frame));
218 if (isKeyThread) {
219 DfxRingBufferWrapper::GetInstance().AppendBaseInfo(DfxFrameFormatter::GetFrameStr(frame));
220 }
221 #if defined(__aarch64__)
222 if (IsLastValidFrame(frame)) {
223 needSkip = true;
224 }
225 #endif
226 }
227 }
228 }
229
PrintThreadRegsByConfig(std::shared_ptr<DfxThread> thread)230 void Printer::PrintThreadRegsByConfig(std::shared_ptr<DfxThread> thread)
231 {
232 if (thread == nullptr) {
233 return;
234 }
235 if (DfxConfig::GetConfig().displayRegister) {
236 auto regs = thread->GetThreadRegs();
237 if (regs != nullptr) {
238 DfxRingBufferWrapper::GetInstance().AppendMsg(regs->PrintRegs());
239 }
240 }
241 }
242
PrintRegsByConfig(std::shared_ptr<DfxRegs> regs)243 void Printer::PrintRegsByConfig(std::shared_ptr<DfxRegs> regs)
244 {
245 if (regs == nullptr) {
246 return;
247 }
248 if (DfxConfig::GetConfig().displayRegister) {
249 DfxRingBufferWrapper::GetInstance().AppendMsg(regs->PrintRegs());
250 DfxRingBufferWrapper::GetInstance().AppendBaseInfo(regs->PrintRegs());
251 }
252 }
253
CollectThreadFaultStackByConfig(std::shared_ptr<DfxProcess> process,std::shared_ptr<DfxThread> thread,std::shared_ptr<Unwinder> unwinder)254 void Printer::CollectThreadFaultStackByConfig(std::shared_ptr<DfxProcess> process, std::shared_ptr<DfxThread> thread,
255 std::shared_ptr<Unwinder> unwinder)
256 {
257 if (DfxConfig::GetConfig().displayFaultStack) {
258 if (process == nullptr || thread == nullptr) {
259 return;
260 }
261 thread->InitFaultStack();
262 auto faultStack = thread->GetFaultStack();
263 if (faultStack == nullptr) {
264 return;
265 }
266 if (process->regs_ == nullptr) {
267 DFXLOGE("process regs is nullptr");
268 return;
269 }
270 faultStack->CollectRegistersBlock(process->regs_, unwinder->GetMaps());
271 }
272 }
273
PrintThreadFaultStackByConfig(std::shared_ptr<DfxThread> thread)274 void Printer::PrintThreadFaultStackByConfig(std::shared_ptr<DfxThread> thread)
275 {
276 if (DfxConfig::GetConfig().displayFaultStack) {
277 if (thread == nullptr) {
278 return;
279 }
280 auto faultStack = thread->GetFaultStack();
281 if (faultStack == nullptr) {
282 return;
283 }
284 faultStack->Print();
285 }
286 }
287
PrintLongInformation(const std::string & info)288 void Printer::PrintLongInformation(const std::string& info)
289 {
290 constexpr size_t step = 1024;
291 for (size_t i = 0; i < info.size(); i += step) {
292 DfxRingBufferWrapper::GetInstance().AppendMsg(info.substr(i, step));
293 }
294 }
295 } // namespace HiviewDFX
296 } // namespace OHOS
297