1 /*
2 * Copyright (c) 2025 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 #include "decorative_dump_info.h"
16 #include <cinttypes>
17 #include <dlfcn.h>
18 #include <fcntl.h>
19 #include <unistd.h>
20
21 #include "dfx_buffer_writer.h"
22 #include "dfx_log.h"
23 #include "dfx_signal.h"
24 #include "dfx_util.h"
25 #include "dump_utils.h"
26 #include "crash_exception.h"
27 #include "string_printf.h"
28 #ifndef is_ohos_lite
29 #include "parameter.h"
30 #include "parameters.h"
31 #include "hitrace/hitracechainc.h"
32 #endif
33 #include "procinfo.h"
34 #include "info/fatal_message.h"
35 namespace OHOS {
36 namespace HiviewDFX {
37 namespace {
38 #ifndef PAGE_SIZE
39 constexpr size_t PAGE_SIZE = 4096;
40 #endif
41 }
42 REGISTER_DUMP_INFO_CLASS(DumpInfoHeader);
43
Print(DfxProcess & process,const ProcessDumpRequest & request,Unwinder & unwinder)44 void DumpInfoHeader::Print(DfxProcess& process, const ProcessDumpRequest& request, Unwinder& unwinder)
45 {
46 std::string headerInfo;
47 if (request.type != ProcessDumpType::DUMP_TYPE_DUMP_CATCH) {
48 #ifndef is_ohos_lite
49 std::string buildInfo = OHOS::system::GetParameter("const.product.software.version", "Unknown");
50 headerInfo = "Build info:" + buildInfo + "\n";
51 #endif
52 headerInfo += GetCrashLogConfigInfo(request, process);
53 }
54 headerInfo += "Timestamp:" + GetCurrentTimeStr(request.timeStamp);
55 headerInfo += StringPrintf("Pid:%d\nUid:%d\n", process.GetProcessInfo().pid, process.GetProcessInfo().uid);
56 #ifndef is_ohos_lite
57 if (request.type == ProcessDumpType::DUMP_TYPE_CPP_CRASH && request.hitraceId.valid == HITRACE_ID_VALID) {
58 headerInfo += StringPrintf("HiTraceId:%" PRIx64 "\n", static_cast<uint64_t>(request.hitraceId.chainId));
59 }
60 #endif
61 headerInfo += StringPrintf("Process name:%s\n", process.GetProcessInfo().processName.c_str());
62 if (request.type != ProcessDumpType::DUMP_TYPE_DUMP_CATCH) {
63 headerInfo += ("Process life time:" + process.GetProcessLifeCycle() + "\n");
64 if (process.GetProcessLifeCycle().empty()) {
65 ReportCrashException(CrashExceptionCode::CRASH_LOG_EPROCESS_LIFECYCLE);
66 }
67 headerInfo += StringPrintf("Process Memory(kB): %" PRIu64 "(Rss)\n",
68 GetProcRssMemInfo(process.GetProcessInfo().pid));
69 headerInfo += ("Reason:" + GetReasonInfo(request, process, *unwinder.GetMaps()));
70 process.AppendFatalMessage(GetLastFatalMsg(process, request));
71 auto msg = process.GetFatalMessage();
72 if (!msg.empty()) {
73 headerInfo += "LastFatalMessage:" + msg + "\n";
74 }
75 }
76 DfxBufferWriter::GetInstance().AppendBriefDumpInfo(headerInfo);
77 DfxBufferWriter::GetInstance().WriteMsg(headerInfo);
78 DecorativeDumpInfo::Print(process, request, unwinder);
79 }
80
GetReasonInfo(const ProcessDumpRequest & request,DfxProcess & process,DfxMaps & maps)81 std::string DumpInfoHeader::GetReasonInfo(const ProcessDumpRequest& request, DfxProcess& process, DfxMaps& maps)
82 {
83 std::string reasonInfo = DfxSignal::PrintSignal(request.siginfo);
84 do {
85 uint64_t addr = reinterpret_cast<uint64_t>(request.siginfo.si_addr);
86 if (request.siginfo.si_signo == SIGSEGV &&
87 (request.siginfo.si_code == SEGV_MAPERR || request.siginfo.si_code == SEGV_ACCERR)) {
88 if (addr < PAGE_SIZE) {
89 reasonInfo += " probably caused by NULL pointer dereference";
90 break;
91 }
92 if (process.GetKeyThread() == nullptr) {
93 DFXLOGW("%{public}s is nullptr", "keyThread_");
94 break;
95 }
96 std::vector<std::shared_ptr<DfxMap>> map;
97 std::string elfName = StringPrintf("[anon:stack:%d]", process.GetKeyThread()->GetThreadInfo().tid);
98 if (!maps.FindMapsByName(elfName, map) || map[0] == nullptr) {
99 break;
100 }
101 if (addr < map[0]->begin && map[0]->begin - addr <= PAGE_SIZE) {
102 reasonInfo += StringPrintf(
103 " current thread stack low address = %" PRIX64_ADDR ", probably caused by stack-buffer-overflow",
104 map[0]->begin);
105 }
106 } else if (request.siginfo.si_signo == SIGSYS && request.siginfo.si_code == SYS_SECCOMP) {
107 reasonInfo += StringPrintf(" syscall number is %d", request.siginfo.si_syscall);
108 }
109 } while (false);
110 reasonInfo += "\n";
111 process.SetReason(reasonInfo);
112 return reasonInfo;
113 }
114
GetCrashLogConfigInfo(const ProcessDumpRequest & request,DfxProcess & process)115 std::string DumpInfoHeader::GetCrashLogConfigInfo(const ProcessDumpRequest& request, DfxProcess& process)
116 {
117 constexpr uint32_t extendPcLrMask = 0x1;
118 constexpr uint32_t simplifyVmaMask = 0x2;
119 CrashLogConfig crashLogConfig;
120 std::string crashLogConfigInfo;
121 if ((request.crashLogConfig & extendPcLrMask) == extendPcLrMask) {
122 crashLogConfig.extendPcLrPrinting = true;
123 crashLogConfigInfo += "Extend pc lr printing:true\n";
124 }
125 // 32 : cutoff size start from high 32 bit
126 uint32_t logFileCutoffSizeBytes = static_cast<uint32_t>(request.crashLogConfig >> 32);
127 if (logFileCutoffSizeBytes != 0) {
128 crashLogConfig.logFileCutoffSizeBytes = logFileCutoffSizeBytes;
129 crashLogConfigInfo += StringPrintf("Log cut off size:%" PRIu32 "B\n", crashLogConfig.logFileCutoffSizeBytes);
130 }
131 if ((request.crashLogConfig & simplifyVmaMask) == simplifyVmaMask) {
132 crashLogConfig.simplifyVmaPrinting = true;
133 crashLogConfigInfo += "Simplify maps printing:true\n";
134 }
135 if (!crashLogConfigInfo.empty()) {
136 crashLogConfigInfo = "Enabled app log configs:\n" + crashLogConfigInfo;
137 }
138 process.SetCrashLogConfig(crashLogConfig);
139 return crashLogConfigInfo;
140 }
141
GetLastFatalMsg(DfxProcess & process,const ProcessDumpRequest & request)142 std::string DumpInfoHeader::GetLastFatalMsg(DfxProcess& process, const ProcessDumpRequest& request)
143 {
144 std::string lastFatalMsg = "";
145 if (request.msg.type == MESSAGE_FATAL || request.msg.type == MESSAGE_CALLBACK) {
146 lastFatalMsg += request.msg.body;
147 }
148 lastFatalMsg += UpdateFatalMessageWhenDebugSignal(process, request);
149 lastFatalMsg += ReadCrashObjString(request);
150 return lastFatalMsg;
151 }
152
ReadCrashObjString(const ProcessDumpRequest & request) const153 std::string DumpInfoHeader::ReadCrashObjString(const ProcessDumpRequest& request) const
154 {
155 std::string content = "";
156 #ifdef __LP64__
157 if (request.type != ProcessDumpType::DUMP_TYPE_CPP_CRASH || request.crashObj == 0) {
158 DFXLOGI("crash obj not int.");
159 return content;
160 }
161 uintptr_t type = request.crashObj >> 56; // 56 :: Move 56 bit to the right
162 uintptr_t addr = request.crashObj & 0xffffffffffffff;
163 std::vector<size_t> memorylengthTable = {0, 64, 256, 1024, 2048, 4096};
164 if (type == 0) {
165 DFXLOGI("Start read string type of crashObj.");
166 constexpr int bufLen = 256;
167 content = DumpUtils::ReadStringByPtrace(request.nsPid, addr, sizeof(long) * bufLen);
168 }
169 #endif
170 return content;
171 }
172
UpdateFatalMessageWhenDebugSignal(DfxProcess & process,const ProcessDumpRequest & request)173 std::string DumpInfoHeader::UpdateFatalMessageWhenDebugSignal(DfxProcess& process, const ProcessDumpRequest& request)
174 {
175 if (request.type != ProcessDumpType::DUMP_TYPE_BADFD && request.type != ProcessDumpType::DUMP_TYPE_FDSAN &&
176 request.type != ProcessDumpType::DUMP_TYPE_JEMALLOC) {
177 return "";
178 }
179 pid_t pid = process.GetVmPid() != 0 ? process.GetVmPid() : request.nsPid;
180 if (pid == 0) {
181 DFXLOGE("invalid pid, return directly!");
182 return "";
183 }
184
185 auto debugMsgPtr = reinterpret_cast<uintptr_t>(request.siginfo.si_value.sival_ptr);
186 debug_msg_t dMsg = {0};
187 if (ReadProcMemByPid(pid, debugMsgPtr, &dMsg, sizeof(dMsg)) != sizeof(debug_msg_t)) {
188 DFXLOGE("Get debug_msg_t failed.");
189 return "";
190 }
191 auto msgPtr = reinterpret_cast<uintptr_t>(dMsg.msg);
192 auto debugMsg = DumpUtils::ReadStringByPtrace(pid, msgPtr, MAX_FATAL_MSG_SIZE);
193 if (debugMsg.empty()) {
194 DFXLOGE("Get debug_msg_t.msg failed.");
195 return "";
196 }
197 return debugMsg;
198 }
199 }
200 }
201