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