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