1 /*
2 * Copyright (c) 2021-2023 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 <cstdint>
17 #include <ctime>
18 #include <mutex>
19 #include <string>
20 #include <sys/stat.h>
21 #include <vector>
22
23 #include "constants.h"
24 #include "faultlog_info.h"
25 #include "string_util.h"
26 #include "time_util.h"
27
28 namespace OHOS {
29 namespace HiviewDFX {
30 namespace {
31 constexpr int DEFAULT_BUFFER_SIZE = 64;
32 } // namespace
33
GetFormatedTime(uint64_t target)34 std::string GetFormatedTime(uint64_t target)
35 {
36 time_t now = time(nullptr);
37 if (target > static_cast<uint64_t>(now)) {
38 target = target / 1000; // 1000 : convert millisecond to seconds
39 }
40
41 time_t out = static_cast<time_t>(target);
42 struct tm tmStruct {0};
43 struct tm* timeInfo = localtime_r(&out, &tmStruct);
44 if (timeInfo == nullptr) {
45 return "00000000000000";
46 }
47
48 char buf[DEFAULT_BUFFER_SIZE] = {0};
49 strftime(buf, DEFAULT_BUFFER_SIZE - 1, "%Y%m%d%H%M%S", timeInfo);
50 return std::string(buf, strlen(buf));
51 }
52
GetFaultNameByType(int32_t faultType,bool asFileName)53 std::string GetFaultNameByType(int32_t faultType, bool asFileName)
54 {
55 switch (faultType) {
56 case FaultLogType::JS_CRASH:
57 return asFileName ? "jscrash" : "JS_ERROR";
58 case FaultLogType::CPP_CRASH:
59 return asFileName ? "cppcrash" : "CPP_CRASH";
60 case FaultLogType::APP_FREEZE:
61 return asFileName ? "appfreeze" : "APP_FREEZE";
62 case FaultLogType::SYS_FREEZE:
63 return asFileName ? "sysfreeze" : "SYS_FREEZE";
64 case FaultLogType::SYS_WARNING:
65 return asFileName ? "syswarning" : "SYS_WARNING";
66 case FaultLogType::RUST_PANIC:
67 return asFileName ? "rustpanic" : "RUST_PANIC";
68 case FaultLogType::ADDR_SANITIZER:
69 return asFileName ? "sanitizer" : "ADDR_SANITIZER";
70 default:
71 break;
72 }
73 return "Unknown";
74 }
75
GetFaultLogName(const FaultLogInfo & info)76 std::string GetFaultLogName(const FaultLogInfo& info)
77 {
78 std::string name = info.module;
79 if (name.find("/") != std::string::npos) {
80 name = info.module.substr(info.module.find_last_of("/") + 1);
81 }
82
83 std::string ret = "";
84 if (info.faultLogType == FaultLogType::ADDR_SANITIZER) {
85 if (info.reason.compare("TSAN") == 0) {
86 ret.append("tsan");
87 } else if (info.reason.compare("UBSAN") == 0) {
88 ret.append("ubsan");
89 } else if (info.reason.compare("GWP-ASAN") == 0) {
90 ret.append("gwpasan");
91 } else if (info.reason.find("HWASAN") != std::string::npos) {
92 ret.append("hwasan");
93 } else if (info.reason.find("ASAN") != std::string::npos) {
94 ret.append("asan");
95 } else {
96 ret.append("sanitizer");
97 }
98 } else {
99 ret.append(GetFaultNameByType(info.faultLogType, true));
100 }
101 ret.append("-");
102 ret.append(name);
103 ret.append("-");
104 ret.append(std::to_string(info.id));
105 ret.append("-");
106 ret.append(GetFormatedTime(info.time));
107 return ret;
108 }
109
GetLogTypeByName(const std::string & type)110 int32_t GetLogTypeByName(const std::string& type)
111 {
112 if (type == "jscrash") {
113 return FaultLogType::JS_CRASH;
114 } else if (type == "cppcrash") {
115 return FaultLogType::CPP_CRASH;
116 } else if (type == "appfreeze") {
117 return FaultLogType::APP_FREEZE;
118 } else if (type == "sysfreeze") {
119 return FaultLogType::SYS_FREEZE;
120 } else if (type == "syswarning") {
121 return FaultLogType::SYS_WARNING;
122 } else if (type == "sanitizer") {
123 return FaultLogType::ADDR_SANITIZER;
124 } else if (type == "all" || type == "ALL") {
125 return FaultLogType::ALL;
126 } else {
127 return -1;
128 }
129 }
130
ExtractInfoFromFileName(const std::string & fileName)131 FaultLogInfo ExtractInfoFromFileName(const std::string& fileName)
132 {
133 // FileName LogType-PackageName-Uid-YYYYMMDDHHMMSS
134 FaultLogInfo info;
135 std::vector<std::string> splitStr;
136 const int32_t expectedVecSize = 4;
137 StringUtil::SplitStr(fileName, "-", splitStr);
138 if (splitStr.size() == expectedVecSize) {
139 info.faultLogType = GetLogTypeByName(splitStr[0]); // 0 : index of log type
140 info.module = splitStr[1]; // 1 : index of module name
141 StringUtil::ConvertStringTo<int32_t>(splitStr[2], info.id); // 2 : index of uid
142 info.time = TimeUtil::StrToTimeStamp(splitStr[3], "%Y%m%d%H%M%S"); // 3 : index of timestamp
143 }
144 info.pid = 0;
145 return info;
146 }
147
ExtractInfoFromTempFile(const std::string & fileName)148 FaultLogInfo ExtractInfoFromTempFile(const std::string& fileName)
149 {
150 // FileName LogType-pid-time
151 FaultLogInfo info;
152 std::vector<std::string> splitStr;
153 const int32_t expectedVecSize = 3;
154 StringUtil::SplitStr(fileName, "-", splitStr);
155 if (splitStr.size() == expectedVecSize) {
156 info.faultLogType = GetLogTypeByName(splitStr[0]); // 0 : index of log type
157 StringUtil::ConvertStringTo<int32_t>(splitStr[1], info.pid); // 1 : index of pid
158 StringUtil::ConvertStringTo<int64_t>(splitStr[2], info.time); // 2 : index of timestamp
159 }
160 return info;
161 }
162
RegulateModuleNameIfNeed(const std::string & name)163 std::string RegulateModuleNameIfNeed(const std::string& name)
164 {
165 std::vector<std::string> splitStr;
166 StringUtil::SplitStr(name, "/", splitStr);
167 auto size = splitStr.size();
168 if (size > 0) {
169 return splitStr[size - 1];
170 }
171 return name;
172 }
173
GetFileLastAccessTimeStamp(const std::string & fileName)174 time_t GetFileLastAccessTimeStamp(const std::string& fileName)
175 {
176 struct stat fileInfo;
177 if (stat(fileName.c_str(), &fileInfo) != 0) {
178 return 0;
179 }
180 return fileInfo.st_atime;
181 }
182
GetCppCrashTempLogName(const FaultLogInfo & info)183 std::string GetCppCrashTempLogName(const FaultLogInfo& info)
184 {
185 return std::string(FaultLogger::DEFAULT_FAULTLOG_TEMP_FOLDER) +
186 "cppcrash-" +
187 std::to_string(info.pid) +
188 "-" +
189 std::to_string(info.time);
190 }
191
GetThreadStack(const std::string & path,int32_t threadId)192 std::string GetThreadStack(const std::string& path, int32_t threadId)
193 {
194 std::string stack;
195 if (path.empty()) {
196 return stack;
197 }
198 char realPath[PATH_MAX] = {0};
199 if (realpath(path.c_str(), realPath) == nullptr) {
200 return stack;
201 }
202 if (strncmp(realPath, FaultLogger::FAULTLOG_BASE_FOLDER, strlen(FaultLogger::FAULTLOG_BASE_FOLDER)) != 0) {
203 return stack;
204 }
205
206 std::ifstream logFile(realPath);
207 if (!logFile.is_open()) {
208 return stack;
209 }
210 std::string regTidString = "^Tid:" + std::to_string(threadId) + ", Name:(.{0,32})$";
211 std::regex regTid(regTidString);
212 std::regex regStack(R"(^#\d{2,3} (pc|at) .{0,1024}$)");
213 std::string line;
214 while (std::getline(logFile, line)) {
215 if (!logFile.good()) {
216 break;
217 }
218
219 if (!std::regex_match(line, regTid)) {
220 continue;
221 }
222
223 do {
224 stack.append(line + "\n");
225 if (!logFile.good()) {
226 break;
227 }
228 } while (std::getline(logFile, line) && std::regex_match(line, regStack));
229 break;
230 }
231
232 return stack;
233 }
234 } // namespace HiviewDFX
235 } // namespace OHOS
236