1 /*
2 * Copyright (c) 2021 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 "faultlog_formatter.h"
16
17 #include <cstdint>
18 #include <fstream>
19 #include <list>
20 #include "parameters.h"
21 #include <sstream>
22 #include <string>
23 #include <unistd.h>
24
25 #include "faultlog_info.h"
26 #include "faultlog_util.h"
27 #include "file_util.h"
28 #include "string_util.h"
29
30 namespace OHOS {
31 namespace HiviewDFX {
32 namespace FaultLogger {
33 namespace {
34 constexpr int LOG_MAP_KEY = 0;
35 constexpr int LOG_MAP_VALUE = 1;
36 constexpr const char* const DEVICE_INFO[] = {"DEVICE_INFO", "Device info:"};
37 constexpr const char* const BUILD_INFO[] = {"BUILD_INFO", "Build info:"};
38 constexpr const char* const MODULE_NAME[] = {"MODULE", "Module name:"};
39 constexpr const char* const PROCESS_NAME[] = {"PNAME", "Process name:"};
40 constexpr const char* const MODULE_PID[] = {"PID", "Pid:"};
41 constexpr const char* const MODULE_UID[] = {"UID", "Uid:"};
42 constexpr const char* const MODULE_VERSION[] = {"VERSION", "Version:"};
43 constexpr const char* const FAULT_TYPE[] = {"FAULT_TYPE", "Fault type:"};
44 constexpr const char* const SYSVMTYPE[] = {"SYSVMTYPE", "SYSVMTYPE:"};
45 constexpr const char* const APPVMTYPE[] = {"APPVMTYPE", "APPVMTYPE:"};
46 constexpr const char* const FOREGROUND[] = {"FOREGROUND", "Foreground:"};
47 constexpr const char* const LIFETIME[] = {"LIFETIME", "Up time:"};
48 constexpr const char* const REASON[] = {"REASON", "Reason:"};
49 constexpr const char* const FAULT_MESSAGE[] = {"FAULT_MESSAGE", "Fault message:"};
50 constexpr const char* const STACKTRACE[] = {"TRUSTSTACK", "Selected stacktrace:\n"};
51 constexpr const char* const ROOT_CAUSE[] = {"BINDERMAX", "Blocked chain:\n"};
52 constexpr const char* const MSG_QUEUE_INFO[] = {"MSG_QUEUE_INFO", "Message queue info:\n"};
53 constexpr const char* const BINDER_TRANSACTION_INFO[] = {"BINDER_TRANSACTION_INFO", "Binder transaction info:\n"};
54 constexpr const char* const PROCESS_STACKTRACE[] = {"PROCESS_STACKTRACE", "Process stacktrace:\n"};
55 constexpr const char* const OTHER_THREAD_INFO[] = {"OTHER_THREAD_INFO", "Other thread info:\n"};
56 constexpr const char* const KEY_THREAD_INFO[] = {"KEY_THREAD_INFO", "Fault thread info:\n"};
57 constexpr const char* const KEY_THREAD_REGISTERS[] = {"KEY_THREAD_REGISTERS", "Registers:\n"};
58 constexpr const char* const MEMORY_USAGE[] = {"MEM_USAGE", "Memory Usage:\n"};
59 constexpr const char* const CPU_USAGE[] = {"FAULTCPU", "CPU Usage:"};
60 constexpr const char* const TRACE_ID[] = {"TRACEID", "Trace-Id:"};
61 constexpr const char* const SUMMARY[] = {"SUMMARY", "Summary:\n"};
62 constexpr const char* const TIMESTAMP[] = {"TIMESTAMP", "Timestamp:"};
63 constexpr const char* const MEMORY_NEAR_REGISTERS[] = {"MEMORY_NEAR_REGISTERS", "Memory near registers:\n"};
64 constexpr const char* const PRE_INSTALL[] = {"PRE_INSTALL", "PreInstalled:"};
65 constexpr const char* const VERSION_CODE[] = {"VERSION_CODE", "VersionCode:"};
66 constexpr const char* const FINGERPRINT[] = {"fingerPrint", "Fingerprint:"};
67 constexpr const char* const APPEND_ORIGIN_LOG[] = {"APPEND_ORIGIN_LOG", ""};
68
69 auto CPP_CRASH_LOG_SEQUENCE = {
70 DEVICE_INFO, BUILD_INFO, FINGERPRINT, MODULE_NAME, MODULE_VERSION, VERSION_CODE,
71 PRE_INSTALL, FOREGROUND, APPEND_ORIGIN_LOG, MODULE_PID, MODULE_UID, FAULT_TYPE,
72 SYSVMTYPE, APPVMTYPE, REASON, FAULT_MESSAGE, TRACE_ID, PROCESS_NAME, KEY_THREAD_INFO,
73 SUMMARY, KEY_THREAD_REGISTERS, OTHER_THREAD_INFO, MEMORY_NEAR_REGISTERS
74 };
75
76 auto JAVASCRIPT_CRASH_LOG_SEQUENCE = {
77 DEVICE_INFO, BUILD_INFO, FINGERPRINT, TIMESTAMP, MODULE_NAME, MODULE_VERSION, VERSION_CODE,
78 PRE_INSTALL, FOREGROUND, MODULE_PID, MODULE_UID, FAULT_TYPE, FAULT_MESSAGE, SYSVMTYPE, APPVMTYPE,
79 LIFETIME, REASON, TRACE_ID, SUMMARY
80 };
81
82 auto APP_FREEZE_LOG_SEQUENCE = {
83 DEVICE_INFO, BUILD_INFO, FINGERPRINT, TIMESTAMP, MODULE_NAME, MODULE_VERSION, VERSION_CODE,
84 PRE_INSTALL, FOREGROUND, MODULE_PID, MODULE_UID, FAULT_TYPE, SYSVMTYPE,
85 APPVMTYPE, REASON, TRACE_ID, CPU_USAGE, MEMORY_USAGE, ROOT_CAUSE, STACKTRACE,
86 MSG_QUEUE_INFO, BINDER_TRANSACTION_INFO, PROCESS_STACKTRACE, SUMMARY
87 };
88
89 auto SYS_FREEZE_LOG_SEQUENCE = {
90 DEVICE_INFO, BUILD_INFO, FINGERPRINT, TIMESTAMP, MODULE_NAME, MODULE_VERSION, FOREGROUND,
91 MODULE_PID, MODULE_UID, FAULT_TYPE, SYSVMTYPE, APPVMTYPE, REASON,
92 TRACE_ID, CPU_USAGE, MEMORY_USAGE, ROOT_CAUSE, STACKTRACE,
93 MSG_QUEUE_INFO, BINDER_TRANSACTION_INFO, PROCESS_STACKTRACE, SUMMARY
94 };
95
96 auto SYS_WARNING_LOG_SEQUENCE = {
97 DEVICE_INFO, BUILD_INFO, FINGERPRINT, TIMESTAMP, MODULE_NAME, MODULE_VERSION, FOREGROUND,
98 MODULE_PID, MODULE_UID, FAULT_TYPE, SYSVMTYPE, APPVMTYPE, REASON,
99 TRACE_ID, CPU_USAGE, MEMORY_USAGE, ROOT_CAUSE, STACKTRACE,
100 MSG_QUEUE_INFO, BINDER_TRANSACTION_INFO, PROCESS_STACKTRACE, SUMMARY
101 };
102
103 auto RUST_PANIC_LOG_SEQUENCE = {
104 DEVICE_INFO, BUILD_INFO, FINGERPRINT, TIMESTAMP, MODULE_NAME, MODULE_VERSION, MODULE_PID,
105 MODULE_UID, FAULT_TYPE, FAULT_MESSAGE, APPVMTYPE, REASON, SUMMARY
106 };
107
108 auto ADDR_SANITIZER_LOG_SEQUENCE = {
109 DEVICE_INFO, BUILD_INFO, FINGERPRINT, TIMESTAMP, MODULE_NAME, MODULE_VERSION, MODULE_PID,
110 MODULE_UID, FAULT_TYPE, FAULT_MESSAGE, APPVMTYPE, REASON, SUMMARY
111 };
112 }
GetLogParseList(int32_t logType)113 std::list<const char* const*> GetLogParseList(int32_t logType)
114 {
115 switch (logType) {
116 case FaultLogType::CPP_CRASH:
117 return CPP_CRASH_LOG_SEQUENCE;
118 case FaultLogType::JS_CRASH:
119 return JAVASCRIPT_CRASH_LOG_SEQUENCE;
120 case FaultLogType::APP_FREEZE:
121 return APP_FREEZE_LOG_SEQUENCE;
122 case FaultLogType::SYS_FREEZE:
123 return SYS_FREEZE_LOG_SEQUENCE;
124 case FaultLogType::SYS_WARNING:
125 return SYS_WARNING_LOG_SEQUENCE;
126 case FaultLogType::RUST_PANIC:
127 return RUST_PANIC_LOG_SEQUENCE;
128 case FaultLogType::ADDR_SANITIZER:
129 return ADDR_SANITIZER_LOG_SEQUENCE;
130 default:
131 return {};
132 }
133 }
134
GetSummaryByType(int32_t logType, std::map<std::string, std::string> sections)135 std::string GetSummaryByType(int32_t logType, std::map<std::string, std::string> sections)
136 {
137 std::string summary = "";
138 switch (logType) {
139 case FaultLogType::JS_CRASH:
140 case FaultLogType::APP_FREEZE:
141 case FaultLogType::SYS_FREEZE:
142 case FaultLogType::SYS_WARNING:
143 summary = sections[STACKTRACE[LOG_MAP_KEY]];
144 break;
145 case FaultLogType::CPP_CRASH:
146 summary = sections[KEY_THREAD_INFO[LOG_MAP_KEY]];
147 break;
148 case FaultLogType::ADDR_SANITIZER:
149 default:
150 summary = "Could not figure out summary for this fault.";
151 break;
152 }
153
154 return summary;
155 }
156
ParseFaultLogLine(const std::list<const char* const*>& parseList, const std::string& line, const std::string& multline, std::string& multlineName, FaultLogInfo& info)157 bool ParseFaultLogLine(const std::list<const char* const*>& parseList, const std::string& line,
158 const std::string& multline, std::string& multlineName, FaultLogInfo& info)
159 {
160 for (auto &item : parseList) {
161 if (strlen(item[LOG_MAP_VALUE]) <= 1) {
162 continue;
163 }
164 std::string sectionHead = std::string(item[LOG_MAP_VALUE], strlen(item[LOG_MAP_VALUE]) - 1);
165 if (line.find(sectionHead) == std::string::npos) {
166 continue;
167 }
168 if (!line.empty() && line.at(line.size() - 1) == ':') {
169 if ((item[LOG_MAP_KEY] != multlineName) && (!multline.empty())) {
170 info.sectionMap[multlineName] = multline;
171 }
172 multlineName = item[LOG_MAP_KEY];
173 } else {
174 info.sectionMap[item[LOG_MAP_KEY]] = line.substr(line.find_first_of(":") + 1);
175 }
176 return false;
177 }
178 return true;
179 }
180
WriteStackTraceFromLog(int32_t fd, const std::string& pidStr, const std::string& path)181 void WriteStackTraceFromLog(int32_t fd, const std::string& pidStr, const std::string& path)
182 {
183 std::string realPath;
184 if (!FileUtil::PathToRealPath(path, realPath)) {
185 FileUtil::SaveStringToFd(fd, "Log file not exist.\n");
186 return;
187 }
188
189 std::ifstream logFile(realPath);
190 std::string line;
191 bool startWrite = false;
192 while (std::getline(logFile, line)) {
193 if (!logFile.good()) {
194 break;
195 }
196
197 if (line.empty()) {
198 continue;
199 }
200
201 if ((line.find("----- pid") != std::string::npos) &&
202 (line.find(pidStr) != std::string::npos)) {
203 startWrite = true;
204 }
205
206 if ((line.find("----- end") != std::string::npos) &&
207 (line.find(pidStr) != std::string::npos)) {
208 FileUtil::SaveStringToFd(fd, line + "\n");
209 break;
210 }
211
212 if (startWrite) {
213 FileUtil::SaveStringToFd(fd, line + "\n");
214 }
215 }
216 }
217
WriteDfxLogToFile(int32_t fd)218 void WriteDfxLogToFile(int32_t fd)
219 {
220 std::string dfxStr = std::string("Generated by HiviewDFX@OpenHarmony\n");
221 std::string sepStr = std::string("================================================================\n");
222 FileUtil::SaveStringToFd(fd, dfxStr);
223 FileUtil::SaveStringToFd(fd, sepStr);
224 }
225
WriteFaultLogToFile(int32_t fd, int32_t logType, std::map<std::string, std::string> sections)226 void WriteFaultLogToFile(int32_t fd, int32_t logType, std::map<std::string, std::string> sections)
227 {
228 auto seq = GetLogParseList(logType);
229 for (auto &item : seq) {
230 auto value = sections[item[LOG_MAP_KEY]];
231 if (!value.empty()) {
232 std::string keyStr = item[LOG_MAP_KEY];
233 if (keyStr.find(APPEND_ORIGIN_LOG[LOG_MAP_KEY]) != std::string::npos) {
234 if (WriteLogToFile(fd, value)) {
235 break;
236 }
237 }
238
239 // Does not require adding an identifier header for Summary section
240 if (keyStr.find(SUMMARY[LOG_MAP_KEY]) == std::string::npos) {
241 FileUtil::SaveStringToFd(fd, item[LOG_MAP_VALUE]);
242 }
243
244 if (value.back() != '\n') {
245 value.append("\n");
246 }
247 FileUtil::SaveStringToFd(fd, value);
248 }
249 }
250
251 if (!sections["KEYLOGFILE"].empty()) {
252 FileUtil::SaveStringToFd(fd, "Additional Logs:\n");
253 WriteStackTraceFromLog(fd, sections["PID"], sections["KEYLOGFILE"]);
254 }
255 }
256
UpdateFaultLogInfoFromTempFile(FaultLogInfo& info)257 static void UpdateFaultLogInfoFromTempFile(FaultLogInfo& info)
258 {
259 if (!info.module.empty()) {
260 return;
261 }
262
263 StringUtil::ConvertStringTo<int32_t>(info.sectionMap[MODULE_UID[LOG_MAP_KEY]], info.id);
264 info.module = info.sectionMap[PROCESS_NAME[LOG_MAP_KEY]];
265 info.reason = info.sectionMap[REASON[LOG_MAP_KEY]];
266 info.summary = info.sectionMap[KEY_THREAD_INFO[LOG_MAP_KEY]];
267 info.registers = info.sectionMap[KEY_THREAD_REGISTERS[LOG_MAP_KEY]];
268 info.otherThreadInfo = info.sectionMap[OTHER_THREAD_INFO[LOG_MAP_KEY]];
269 size_t removeStartPos = info.summary.find("Tid:");
270 size_t removeEndPos = info.summary.find("Name:");
271 if (removeStartPos != std::string::npos && removeEndPos != std::string::npos) {
272 auto iterator = info.summary.begin() + removeEndPos;
273 while (iterator != info.summary.end() && *iterator != '\n') {
274 if (isdigit(*iterator)) {
275 iterator = info.summary.erase(iterator);
276 } else {
277 iterator++;
278 }
279 }
280 info.summary.replace(removeStartPos, removeEndPos - removeStartPos + 1, "Thread n");
281 }
282 }
283
ParseFaultLogInfoFromFile(const std::string &path, bool isTempFile)284 FaultLogInfo ParseFaultLogInfoFromFile(const std::string &path, bool isTempFile)
285 {
286 auto fileName = FileUtil::ExtractFileName(path);
287 FaultLogInfo info;
288 if (!isTempFile) {
289 info = ExtractInfoFromFileName(fileName);
290 } else {
291 info = ExtractInfoFromTempFile(fileName);
292 }
293
294 auto parseList = GetLogParseList(info.faultLogType);
295 std::ifstream logFile(path);
296 std::string line;
297 std::string multline;
298 std::string multlineName;
299 while (std::getline(logFile, line)) {
300 if (!logFile.good()) {
301 break;
302 }
303
304 if (line.empty()) {
305 continue;
306 }
307
308 if (ParseFaultLogLine(parseList, line, multline, multlineName, info)) {
309 multline.append(line).append("\n");
310 } else {
311 multline.clear();
312 }
313 }
314
315 if (!multline.empty() && !multlineName.empty()) {
316 info.sectionMap[multlineName] = multline;
317 }
318 UpdateFaultLogInfoFromTempFile(info);
319 return info;
320 }
321
WriteLogToFile(int32_t fd, const std::string& path)322 bool WriteLogToFile(int32_t fd, const std::string& path)
323 {
324 if ((fd < 0) || path.empty()) {
325 return false;
326 }
327
328 std::string line;
329 std::ifstream logFile(path);
330 bool hasFindFirstLine = false;
331 while (std::getline(logFile, line)) {
332 if (logFile.eof()) {
333 break;
334 }
335 if (!logFile.good()) {
336 return false;
337 }
338 if (!hasFindFirstLine && line.find("Build info:") != std::string::npos) {
339 continue;
340 }
341 hasFindFirstLine = true;
342 FileUtil::SaveStringToFd(fd, line);
343 FileUtil::SaveStringToFd(fd, "\n");
344 }
345 return true;
346 }
347
IsFaultLogLimit()348 bool IsFaultLogLimit()
349 {
350 std::string isDev = OHOS::system::GetParameter("const.security.developermode.state", "");
351 std::string isBeta = OHOS::system::GetParameter("const.logsystem.versiontype", "");
352 if ((isDev == "true") || (isBeta == "beta")) {
353 return false;
354 }
355 return true;
356 }
357
LimitCppCrashLog(int32_t fd, int32_t logType)358 void LimitCppCrashLog(int32_t fd, int32_t logType)
359 {
360 if ((fd < 0) || (logType != FaultLogType::CPP_CRASH) || !IsFaultLogLimit()) {
361 return;
362 }
363 constexpr int maxLogSize = 512 * 1024;
364 off_t endPos = lseek(fd, 0, SEEK_END);
365 if ((endPos == -1) || (endPos <= maxLogSize)) {
366 return;
367 }
368
369 if (ftruncate(fd, maxLogSize) < 0) {
370 return;
371 }
372 endPos = lseek(fd, maxLogSize, SEEK_SET);
373 if (endPos != -1) {
374 FileUtil::SaveStringToFd(fd, "\ncpp crash log is limit output.\n");
375 }
376 }
377 } // namespace FaultLogger
378 } // namespace HiviewDFX
379 } // namespace OHOS
380