• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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