1800b99b8Sopenharmony_ci/*
2800b99b8Sopenharmony_ci * Copyright (c) 2023-2024 Huawei Device Co., Ltd.
3800b99b8Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4800b99b8Sopenharmony_ci * you may not use this file except in compliance with the License.
5800b99b8Sopenharmony_ci * You may obtain a copy of the License at
6800b99b8Sopenharmony_ci *
7800b99b8Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0
8800b99b8Sopenharmony_ci *
9800b99b8Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10800b99b8Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11800b99b8Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12800b99b8Sopenharmony_ci * See the License for the specific language governing permissions and
13800b99b8Sopenharmony_ci * limitations under the License.
14800b99b8Sopenharmony_ci */
15800b99b8Sopenharmony_ci
16800b99b8Sopenharmony_ci#include "printer.h"
17800b99b8Sopenharmony_ci
18800b99b8Sopenharmony_ci#include <cinttypes>
19800b99b8Sopenharmony_ci#include <dlfcn.h>
20800b99b8Sopenharmony_ci#include <map>
21800b99b8Sopenharmony_ci#include <string>
22800b99b8Sopenharmony_ci#include <fcntl.h>
23800b99b8Sopenharmony_ci#include <unistd.h>
24800b99b8Sopenharmony_ci
25800b99b8Sopenharmony_ci#include "dfx_config.h"
26800b99b8Sopenharmony_ci#include "dfx_frame_formatter.h"
27800b99b8Sopenharmony_ci#include "dfx_logger.h"
28800b99b8Sopenharmony_ci#include "dfx_ring_buffer_wrapper.h"
29800b99b8Sopenharmony_ci#include "dfx_signal.h"
30800b99b8Sopenharmony_ci#include "dfx_util.h"
31800b99b8Sopenharmony_ci#include "string_printf.h"
32800b99b8Sopenharmony_ci#include "string_util.h"
33800b99b8Sopenharmony_ci#ifndef is_ohos_lite
34800b99b8Sopenharmony_ci#include "parameter.h"
35800b99b8Sopenharmony_ci#include "parameters.h"
36800b99b8Sopenharmony_ci#endif
37800b99b8Sopenharmony_ci
38800b99b8Sopenharmony_ci#ifndef PAGE_SIZE
39800b99b8Sopenharmony_ciconstexpr size_t PAGE_SIZE = 4096;
40800b99b8Sopenharmony_ci#endif
41800b99b8Sopenharmony_ci
42800b99b8Sopenharmony_cinamespace OHOS {
43800b99b8Sopenharmony_cinamespace HiviewDFX {
44800b99b8Sopenharmony_civoid Printer::PrintDumpHeader(std::shared_ptr<ProcessDumpRequest> request, std::shared_ptr<DfxProcess> process,
45800b99b8Sopenharmony_ci                              std::shared_ptr<Unwinder> unwinder)
46800b99b8Sopenharmony_ci{
47800b99b8Sopenharmony_ci    if (process == nullptr || request == nullptr) {
48800b99b8Sopenharmony_ci        return;
49800b99b8Sopenharmony_ci    }
50800b99b8Sopenharmony_ci    std::string headerInfo;
51800b99b8Sopenharmony_ci    bool isCrash = (request->siginfo.si_signo != SIGDUMP);
52800b99b8Sopenharmony_ci#ifndef is_ohos_lite
53800b99b8Sopenharmony_ci    if (isCrash) {
54800b99b8Sopenharmony_ci        std::string buildInfo = OHOS::system::GetParameter("const.product.software.version", "Unknown");
55800b99b8Sopenharmony_ci        headerInfo = "Build info:" + buildInfo + "\n";
56800b99b8Sopenharmony_ci        DfxRingBufferWrapper::GetInstance().AppendMsg("Build info:" + buildInfo + "\n");
57800b99b8Sopenharmony_ci    }
58800b99b8Sopenharmony_ci#endif
59800b99b8Sopenharmony_ci    headerInfo += "Timestamp:" + GetCurrentTimeStr(request->timeStamp);
60800b99b8Sopenharmony_ci    DfxRingBufferWrapper::GetInstance().AppendMsg("Timestamp:" + GetCurrentTimeStr(request->timeStamp));
61800b99b8Sopenharmony_ci    headerInfo += "Pid:" + std::to_string(process->processInfo_.pid) + "\n" +
62800b99b8Sopenharmony_ci                  "Uid:" + std::to_string(process->processInfo_.uid) + "\n" +
63800b99b8Sopenharmony_ci                  "Process name:" + process->processInfo_.processName + "\n";
64800b99b8Sopenharmony_ci    DfxRingBufferWrapper::GetInstance().AppendBuf("Pid:%d\n", process->processInfo_.pid);
65800b99b8Sopenharmony_ci    DfxRingBufferWrapper::GetInstance().AppendBuf("Uid:%d\n", process->processInfo_.uid);
66800b99b8Sopenharmony_ci    DfxRingBufferWrapper::GetInstance().AppendBuf("Process name:%s\n", process->processInfo_.processName.c_str());
67800b99b8Sopenharmony_ci    if (isCrash) {
68800b99b8Sopenharmony_ci        DfxRingBufferWrapper::GetInstance().AppendBuf("Process life time:%s\n",
69800b99b8Sopenharmony_ci            DfxProcess::GetProcessLifeCycle(process->processInfo_.pid).c_str());
70800b99b8Sopenharmony_ci
71800b99b8Sopenharmony_ci        std::string reasonInfo;
72800b99b8Sopenharmony_ci        PrintReason(request, process, unwinder, reasonInfo);
73800b99b8Sopenharmony_ci        headerInfo += reasonInfo + "\n";
74800b99b8Sopenharmony_ci        auto msg = process->GetFatalMessage();
75800b99b8Sopenharmony_ci        if (!msg.empty()) {
76800b99b8Sopenharmony_ci            headerInfo += "LastFatalMessage:" + msg + "\n";
77800b99b8Sopenharmony_ci            DfxRingBufferWrapper::GetInstance().AppendBuf("LastFatalMessage:%s\n", msg.c_str());
78800b99b8Sopenharmony_ci        }
79800b99b8Sopenharmony_ci
80800b99b8Sopenharmony_ci        auto traceId = request->traceInfo;
81800b99b8Sopenharmony_ci        if (traceId.chainId != 0) {
82800b99b8Sopenharmony_ci            headerInfo += StringPrintf("TraceId:%" PRIX64"\n", traceId.chainId);
83800b99b8Sopenharmony_ci            DfxRingBufferWrapper::GetInstance().AppendBuf("TraceId:%llx\n",
84800b99b8Sopenharmony_ci                static_cast<unsigned long long>(traceId.chainId));
85800b99b8Sopenharmony_ci        }
86800b99b8Sopenharmony_ci
87800b99b8Sopenharmony_ci        headerInfo += "Fault thread info:\n";
88800b99b8Sopenharmony_ci        DfxRingBufferWrapper::GetInstance().AppendMsg("Fault thread info:\n");
89800b99b8Sopenharmony_ci    }
90800b99b8Sopenharmony_ci    DfxRingBufferWrapper::GetInstance().AppendBaseInfo(headerInfo);
91800b99b8Sopenharmony_ci}
92800b99b8Sopenharmony_ci
93800b99b8Sopenharmony_cistatic void FillReasonAccordingMsgType(const ProcessDumpRequest &request, std::string& reason)
94800b99b8Sopenharmony_ci{
95800b99b8Sopenharmony_ci    switch (request.msg.type) {
96800b99b8Sopenharmony_ci        case MESSAGE_FDSAN_DEBUG:
97800b99b8Sopenharmony_ci            reason += "DEBUG SIGNAL(FDSAN)";
98800b99b8Sopenharmony_ci            break;
99800b99b8Sopenharmony_ci        case MESSAGE_JEMALLOC:
100800b99b8Sopenharmony_ci            reason += "DEBUG SIGNAL(JEMALLOC)";
101800b99b8Sopenharmony_ci            break;
102800b99b8Sopenharmony_ci        case MESSAGE_BADFD:
103800b99b8Sopenharmony_ci            reason += "DEBUG SIGNAL(BADFD)";
104800b99b8Sopenharmony_ci            break;
105800b99b8Sopenharmony_ci        default:
106800b99b8Sopenharmony_ci            reason += DfxSignal::PrintSignal(request.siginfo);
107800b99b8Sopenharmony_ci            break;
108800b99b8Sopenharmony_ci    }
109800b99b8Sopenharmony_ci}
110800b99b8Sopenharmony_ci
111800b99b8Sopenharmony_civoid Printer::PrintReason(std::shared_ptr<ProcessDumpRequest> request, std::shared_ptr<DfxProcess> process,
112800b99b8Sopenharmony_ci                          std::shared_ptr<Unwinder> unwinder, std::string& reasonInfo)
113800b99b8Sopenharmony_ci{
114800b99b8Sopenharmony_ci    reasonInfo += "Reason:";
115800b99b8Sopenharmony_ci    DfxRingBufferWrapper::GetInstance().AppendMsg("Reason:");
116800b99b8Sopenharmony_ci    if (process == nullptr) {
117800b99b8Sopenharmony_ci        DFXLOGW("process is nullptr");
118800b99b8Sopenharmony_ci        return;
119800b99b8Sopenharmony_ci    }
120800b99b8Sopenharmony_ci    FillReasonAccordingMsgType(*request, process->reason);
121800b99b8Sopenharmony_ci    uint64_t addr = (uint64_t)(request->siginfo.si_addr);
122800b99b8Sopenharmony_ci    if (request->siginfo.si_signo == SIGSEGV &&
123800b99b8Sopenharmony_ci        (request->siginfo.si_code == SEGV_MAPERR || request->siginfo.si_code == SEGV_ACCERR)) {
124800b99b8Sopenharmony_ci        if (addr < PAGE_SIZE) {
125800b99b8Sopenharmony_ci            process->reason += " probably caused by NULL pointer dereference\n";
126800b99b8Sopenharmony_ci            DfxRingBufferWrapper::GetInstance().AppendMsg(process->reason);
127800b99b8Sopenharmony_ci            reasonInfo += process->reason;
128800b99b8Sopenharmony_ci            return;
129800b99b8Sopenharmony_ci        }
130800b99b8Sopenharmony_ci        bool keyThreadEmpty = (request->dumpMode == SPLIT_MODE && process->vmThread_ == nullptr) ||
131800b99b8Sopenharmony_ci            process->keyThread_ == nullptr;
132800b99b8Sopenharmony_ci        if (unwinder == nullptr || keyThreadEmpty) {
133800b99b8Sopenharmony_ci            DFXLOGW("%{public}s is nullptr", unwinder == nullptr ? "unwinder" : "keyThread_");
134800b99b8Sopenharmony_ci            return;
135800b99b8Sopenharmony_ci        }
136800b99b8Sopenharmony_ci        std::shared_ptr<DfxMaps> maps = unwinder->GetMaps();
137800b99b8Sopenharmony_ci        std::vector<std::shared_ptr<DfxMap>> map;
138800b99b8Sopenharmony_ci        if (DfxRegs::CreateFromUcontext(request->context) == nullptr) {
139800b99b8Sopenharmony_ci            DFXLOGW("regs is nullptr");
140800b99b8Sopenharmony_ci            return;
141800b99b8Sopenharmony_ci        }
142800b99b8Sopenharmony_ci        std::string elfName = StringPrintf("[anon:stack:%d]", process->keyThread_->threadInfo_.tid);
143800b99b8Sopenharmony_ci        if (maps != nullptr && maps->FindMapsByName(elfName, map)) {
144800b99b8Sopenharmony_ci            if (map[0] != nullptr && (addr < map[0]->begin && map[0]->begin - addr <= PAGE_SIZE)) {
145800b99b8Sopenharmony_ci                process->reason += StringPrintf(
146800b99b8Sopenharmony_ci                    " current thread stack low address = %" PRIX64_ADDR ", probably caused by stack-buffer-overflow",
147800b99b8Sopenharmony_ci                    map[0]->begin);
148800b99b8Sopenharmony_ci            }
149800b99b8Sopenharmony_ci        }
150800b99b8Sopenharmony_ci    } else if (request->siginfo.si_signo == SIGSYS && request->siginfo.si_code == SYS_SECCOMP) {
151800b99b8Sopenharmony_ci        process->reason += StringPrintf(" syscall number is %d", request->siginfo.si_syscall);
152800b99b8Sopenharmony_ci    }
153800b99b8Sopenharmony_ci    process->reason += "\n";
154800b99b8Sopenharmony_ci    DfxRingBufferWrapper::GetInstance().AppendMsg(process->reason);
155800b99b8Sopenharmony_ci    reasonInfo += process->reason;
156800b99b8Sopenharmony_ci}
157800b99b8Sopenharmony_ci
158800b99b8Sopenharmony_civoid Printer::PrintProcessMapsByConfig(std::shared_ptr<DfxMaps> maps)
159800b99b8Sopenharmony_ci{
160800b99b8Sopenharmony_ci    if (DfxConfig::GetConfig().displayMaps) {
161800b99b8Sopenharmony_ci        if (maps == nullptr) {
162800b99b8Sopenharmony_ci            return;
163800b99b8Sopenharmony_ci        }
164800b99b8Sopenharmony_ci        auto mapsVec = maps->GetMaps();
165800b99b8Sopenharmony_ci        DfxRingBufferWrapper::GetInstance().AppendMsg("\nMaps:\n");
166800b99b8Sopenharmony_ci        for (auto iter = mapsVec.begin(); iter != mapsVec.end() && (*iter) != nullptr; iter++) {
167800b99b8Sopenharmony_ci            DfxRingBufferWrapper::GetInstance().AppendMsg((*iter)->ToString());
168800b99b8Sopenharmony_ci        }
169800b99b8Sopenharmony_ci    }
170800b99b8Sopenharmony_ci}
171800b99b8Sopenharmony_ci
172800b99b8Sopenharmony_civoid Printer::PrintOtherThreadHeaderByConfig()
173800b99b8Sopenharmony_ci{
174800b99b8Sopenharmony_ci    if (DfxConfig::GetConfig().displayBacktrace) {
175800b99b8Sopenharmony_ci        DfxRingBufferWrapper::GetInstance().AppendMsg("Other thread info:\n");
176800b99b8Sopenharmony_ci    }
177800b99b8Sopenharmony_ci}
178800b99b8Sopenharmony_ci
179800b99b8Sopenharmony_civoid Printer::PrintThreadHeaderByConfig(std::shared_ptr<DfxThread> thread, bool isKeyThread)
180800b99b8Sopenharmony_ci{
181800b99b8Sopenharmony_ci    std::string headerInfo;
182800b99b8Sopenharmony_ci    if (DfxConfig::GetConfig().displayBacktrace && thread != nullptr) {
183800b99b8Sopenharmony_ci        DfxRingBufferWrapper::GetInstance().AppendBuf("Tid:%d, Name:%s\n",\
184800b99b8Sopenharmony_ci            thread->threadInfo_.tid, thread->threadInfo_.threadName.c_str());
185800b99b8Sopenharmony_ci        headerInfo = "Tid:" + std::to_string(thread->threadInfo_.tid) +
186800b99b8Sopenharmony_ci            ", Name:" + thread->threadInfo_.threadName + "\n";
187800b99b8Sopenharmony_ci    }
188800b99b8Sopenharmony_ci    if (isKeyThread) {
189800b99b8Sopenharmony_ci        DfxRingBufferWrapper::GetInstance().AppendBaseInfo(headerInfo);
190800b99b8Sopenharmony_ci    }
191800b99b8Sopenharmony_ci}
192800b99b8Sopenharmony_ci
193800b99b8Sopenharmony_cibool Printer::IsLastValidFrame(const DfxFrame& frame)
194800b99b8Sopenharmony_ci{
195800b99b8Sopenharmony_ci    static uintptr_t libcStartPc = 0;
196800b99b8Sopenharmony_ci    static uintptr_t libffrtStartEntry = 0;
197800b99b8Sopenharmony_ci    if (((libcStartPc != 0) && (frame.pc == libcStartPc)) ||
198800b99b8Sopenharmony_ci        ((libffrtStartEntry != 0) && (frame.pc == libffrtStartEntry))) {
199800b99b8Sopenharmony_ci        return true;
200800b99b8Sopenharmony_ci    }
201800b99b8Sopenharmony_ci
202800b99b8Sopenharmony_ci    if (frame.mapName.find("ld-musl-aarch64.so.1") != std::string::npos &&
203800b99b8Sopenharmony_ci        frame.funcName.find("start") != std::string::npos) {
204800b99b8Sopenharmony_ci        libcStartPc = frame.pc;
205800b99b8Sopenharmony_ci        return true;
206800b99b8Sopenharmony_ci    }
207800b99b8Sopenharmony_ci
208800b99b8Sopenharmony_ci    if (frame.mapName.find("libffrt") != std::string::npos &&
209800b99b8Sopenharmony_ci        frame.funcName.find("CoStartEntry") != std::string::npos) {
210800b99b8Sopenharmony_ci        libffrtStartEntry = frame.pc;
211800b99b8Sopenharmony_ci        return true;
212800b99b8Sopenharmony_ci    }
213800b99b8Sopenharmony_ci
214800b99b8Sopenharmony_ci    return false;
215800b99b8Sopenharmony_ci}
216800b99b8Sopenharmony_ci
217800b99b8Sopenharmony_civoid Printer::PrintThreadBacktraceByConfig(std::shared_ptr<DfxThread> thread, bool isKeyThread)
218800b99b8Sopenharmony_ci{
219800b99b8Sopenharmony_ci    if (DfxConfig::GetConfig().displayBacktrace && thread != nullptr) {
220800b99b8Sopenharmony_ci        const auto& frames = thread->GetFrames();
221800b99b8Sopenharmony_ci        if (frames.size() == 0) {
222800b99b8Sopenharmony_ci            return;
223800b99b8Sopenharmony_ci        }
224800b99b8Sopenharmony_ci        bool needSkip = false;
225800b99b8Sopenharmony_ci        bool isSubmitter = true;
226800b99b8Sopenharmony_ci        for (const auto& frame : frames) {
227800b99b8Sopenharmony_ci            if (frame.index == 0) {
228800b99b8Sopenharmony_ci                isSubmitter = !isSubmitter;
229800b99b8Sopenharmony_ci            }
230800b99b8Sopenharmony_ci            if (isSubmitter) {
231800b99b8Sopenharmony_ci                DfxRingBufferWrapper::GetInstance().AppendMsg("========SubmitterStacktrace========\n");
232800b99b8Sopenharmony_ci                DfxRingBufferWrapper::GetInstance().AppendBaseInfo("========SubmitterStacktrace========\n");
233800b99b8Sopenharmony_ci                isSubmitter = false;
234800b99b8Sopenharmony_ci                needSkip = false;
235800b99b8Sopenharmony_ci            }
236800b99b8Sopenharmony_ci            if (needSkip) {
237800b99b8Sopenharmony_ci                continue;
238800b99b8Sopenharmony_ci            }
239800b99b8Sopenharmony_ci            DfxRingBufferWrapper::GetInstance().AppendMsg(DfxFrameFormatter::GetFrameStr(frame));
240800b99b8Sopenharmony_ci            if (isKeyThread) {
241800b99b8Sopenharmony_ci                DfxRingBufferWrapper::GetInstance().AppendBaseInfo(DfxFrameFormatter::GetFrameStr(frame));
242800b99b8Sopenharmony_ci            }
243800b99b8Sopenharmony_ci#if defined(__aarch64__)
244800b99b8Sopenharmony_ci            if (IsLastValidFrame(frame)) {
245800b99b8Sopenharmony_ci                needSkip = true;
246800b99b8Sopenharmony_ci            }
247800b99b8Sopenharmony_ci#endif
248800b99b8Sopenharmony_ci        }
249800b99b8Sopenharmony_ci    }
250800b99b8Sopenharmony_ci}
251800b99b8Sopenharmony_ci
252800b99b8Sopenharmony_civoid Printer::PrintThreadRegsByConfig(std::shared_ptr<DfxThread> thread)
253800b99b8Sopenharmony_ci{
254800b99b8Sopenharmony_ci    if (thread == nullptr) {
255800b99b8Sopenharmony_ci        return;
256800b99b8Sopenharmony_ci    }
257800b99b8Sopenharmony_ci    if (DfxConfig::GetConfig().displayRegister) {
258800b99b8Sopenharmony_ci        auto regs = thread->GetThreadRegs();
259800b99b8Sopenharmony_ci        if (regs != nullptr) {
260800b99b8Sopenharmony_ci            DfxRingBufferWrapper::GetInstance().AppendMsg(regs->PrintRegs());
261800b99b8Sopenharmony_ci        }
262800b99b8Sopenharmony_ci    }
263800b99b8Sopenharmony_ci}
264800b99b8Sopenharmony_ci
265800b99b8Sopenharmony_civoid Printer::PrintRegsByConfig(std::shared_ptr<DfxRegs> regs)
266800b99b8Sopenharmony_ci{
267800b99b8Sopenharmony_ci    if (regs == nullptr) {
268800b99b8Sopenharmony_ci        return;
269800b99b8Sopenharmony_ci    }
270800b99b8Sopenharmony_ci    if (DfxConfig::GetConfig().displayRegister) {
271800b99b8Sopenharmony_ci        DfxRingBufferWrapper::GetInstance().AppendMsg(regs->PrintRegs());
272800b99b8Sopenharmony_ci        DfxRingBufferWrapper::GetInstance().AppendBaseInfo(regs->PrintRegs());
273800b99b8Sopenharmony_ci    }
274800b99b8Sopenharmony_ci}
275800b99b8Sopenharmony_ci
276800b99b8Sopenharmony_civoid Printer::PrintThreadFaultStackByConfig(std::shared_ptr<DfxProcess> process, std::shared_ptr<DfxThread> thread,
277800b99b8Sopenharmony_ci                                            std::shared_ptr<Unwinder> unwinder)
278800b99b8Sopenharmony_ci{
279800b99b8Sopenharmony_ci    if (DfxConfig::GetConfig().displayFaultStack) {
280800b99b8Sopenharmony_ci        if (process == nullptr || thread == nullptr) {
281800b99b8Sopenharmony_ci            return;
282800b99b8Sopenharmony_ci        }
283800b99b8Sopenharmony_ci        thread->InitFaultStack();
284800b99b8Sopenharmony_ci        auto faultStack = thread->GetFaultStack();
285800b99b8Sopenharmony_ci        if (faultStack == nullptr) {
286800b99b8Sopenharmony_ci            return;
287800b99b8Sopenharmony_ci        }
288800b99b8Sopenharmony_ci        if (process->regs_ == nullptr) {
289800b99b8Sopenharmony_ci            DFXLOGE("process regs is nullptr");
290800b99b8Sopenharmony_ci            return;
291800b99b8Sopenharmony_ci        }
292800b99b8Sopenharmony_ci        faultStack->CollectRegistersBlock(process->regs_, unwinder->GetMaps());
293800b99b8Sopenharmony_ci        faultStack->Print();
294800b99b8Sopenharmony_ci    }
295800b99b8Sopenharmony_ci}
296800b99b8Sopenharmony_ci
297800b99b8Sopenharmony_civoid Printer::PrintThreadOpenFiles(std::shared_ptr<DfxProcess> process)
298800b99b8Sopenharmony_ci{
299800b99b8Sopenharmony_ci    if (process == nullptr || process->openFiles.empty()) {
300800b99b8Sopenharmony_ci        return;
301800b99b8Sopenharmony_ci    }
302800b99b8Sopenharmony_ci
303800b99b8Sopenharmony_ci    DfxRingBufferWrapper::GetInstance().AppendMsg("OpenFiles:\n");
304800b99b8Sopenharmony_ci    std::string infos = process->openFiles;
305800b99b8Sopenharmony_ci    constexpr size_t step = 1024;
306800b99b8Sopenharmony_ci    for (size_t i = 0; i < infos.size(); i += step) {
307800b99b8Sopenharmony_ci        DfxRingBufferWrapper::GetInstance().AppendMsg(infos.substr(i, step));
308800b99b8Sopenharmony_ci    }
309800b99b8Sopenharmony_ci}
310800b99b8Sopenharmony_ci} // namespace HiviewDFX
311800b99b8Sopenharmony_ci} // namespace OHOS
312