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 <securec.h>
20 #include <string>
21 #include <sys/stat.h>
22 #include <vector>
23
24 #include "constants.h"
25 #include "faultlog_info.h"
26 #include "string_util.h"
27 #include "time_util.h"
28
29 namespace OHOS {
30 namespace HiviewDFX {
31 namespace {
32 constexpr int DEFAULT_BUFFER_SIZE = 64;
33 constexpr uint64_t TIME_RATIO = 1000;
34 constexpr const char* const DEFAULT_FAULTLOG_TEMP_FOLDER = "/data/log/faultlog/temp/";
35 constexpr const char* const DEFAULT_FAULTLOG_FOLDER = "/data/log/faultlog/";
36 constexpr const char* const DEFAULT_FAULTLOG_TEST = "/data/test/";
37 } // namespace
38
GetFormatedTime(uint64_t target)39 std::string GetFormatedTime(uint64_t target)
40 {
41 time_t now = time(nullptr);
42 if (target > static_cast<uint64_t>(now)) {
43 target = target / TIME_RATIO; // 1000 : convert millisecond to seconds
44 }
45
46 time_t out = static_cast<time_t>(target);
47 struct tm tmStruct {0};
48 struct tm* timeInfo = localtime_r(&out, &tmStruct);
49 if (timeInfo == nullptr) {
50 return "00000000000000";
51 }
52
53 char buf[DEFAULT_BUFFER_SIZE] = {0};
54 strftime(buf, DEFAULT_BUFFER_SIZE - 1, "%Y%m%d%H%M%S", timeInfo);
55 return std::string(buf, strlen(buf));
56 }
57
GetFormatedTimeWithMillsec(uint64_t time)58 std::string GetFormatedTimeWithMillsec(uint64_t time)
59 {
60 char millBuf[DEFAULT_BUFFER_SIZE] = {0};
61 int ret = snprintf_s(millBuf, sizeof(millBuf), sizeof(millBuf) - 1, "%03lu", time % TIME_RATIO);
62 if (ret <= 0) {
63 return GetFormatedTime(time) + "000";
64 }
65 std::string millStr(millBuf);
66 return GetFormatedTime(time) + millStr;
67 }
68
GetFaultNameByType(int32_t faultType,bool asFileName)69 std::string GetFaultNameByType(int32_t faultType, bool asFileName)
70 {
71 switch (faultType) {
72 case FaultLogType::JS_CRASH:
73 return asFileName ? "jscrash" : "JS_ERROR";
74 case FaultLogType::CPP_CRASH:
75 return asFileName ? "cppcrash" : "CPP_CRASH";
76 case FaultLogType::APP_FREEZE:
77 return asFileName ? "appfreeze" : "APP_FREEZE";
78 case FaultLogType::SYS_FREEZE:
79 return asFileName ? "sysfreeze" : "SYS_FREEZE";
80 case FaultLogType::SYS_WARNING:
81 return asFileName ? "syswarning" : "SYS_WARNING";
82 case FaultLogType::RUST_PANIC:
83 return asFileName ? "rustpanic" : "RUST_PANIC";
84 case FaultLogType::ADDR_SANITIZER:
85 return asFileName ? "sanitizer" : "ADDR_SANITIZER";
86 case FaultLogType::CJ_ERROR:
87 return asFileName ? "cjerror" : "CJ_ERROR";
88 default:
89 break;
90 }
91 return "Unknown";
92 }
93
GetFaultLogName(const FaultLogInfo & info)94 std::string GetFaultLogName(const FaultLogInfo& info)
95 {
96 std::string name = info.module;
97 if (name.find("/") != std::string::npos) {
98 name = info.module.substr(info.module.find_last_of("/") + 1);
99 }
100
101 std::string ret = "";
102 if (info.faultLogType == FaultLogType::ADDR_SANITIZER) {
103 if (info.sanitizerType.compare("TSAN") == 0) {
104 ret.append("tsan");
105 } else if (info.sanitizerType.compare("UBSAN") == 0) {
106 ret.append("ubsan");
107 } else if (info.sanitizerType.compare("GWP-ASAN") == 0) {
108 ret.append("gwpasan");
109 } else if (info.sanitizerType.compare("HWASAN") == 0) {
110 ret.append("hwasan");
111 } else if (info.sanitizerType.compare("ASAN") == 0) {
112 ret.append("asan");
113 } else {
114 ret.append("sanitizer");
115 }
116 } else {
117 ret.append(GetFaultNameByType(info.faultLogType, true));
118 }
119 ret.append("-");
120 ret.append(name);
121 ret.append("-");
122 ret.append(std::to_string(info.id));
123 ret.append("-");
124 ret.append(GetFormatedTimeWithMillsec(info.time));
125 ret.append(".log");
126 return ret;
127 }
128
GetLogTypeByName(const std::string & type)129 int32_t GetLogTypeByName(const std::string& type)
130 {
131 if (type == "jscrash") {
132 return FaultLogType::JS_CRASH;
133 } else if (type == "cppcrash") {
134 return FaultLogType::CPP_CRASH;
135 } else if (type == "appfreeze") {
136 return FaultLogType::APP_FREEZE;
137 } else if (type == "sysfreeze") {
138 return FaultLogType::SYS_FREEZE;
139 } else if (type == "syswarning") {
140 return FaultLogType::SYS_WARNING;
141 } else if (type == "sanitizer") {
142 return FaultLogType::ADDR_SANITIZER;
143 } else if (type == "cjerror") {
144 return FaultLogType::CJ_ERROR;
145 } else if (type == "all" || type == "ALL") {
146 return FaultLogType::ALL;
147 } else {
148 return -1;
149 }
150 }
151
ExtractInfoFromFileName(const std::string & fileName)152 FaultLogInfo ExtractInfoFromFileName(const std::string& fileName)
153 {
154 // FileName LogType-PackageName-Uid-YYYYMMDDHHMMSS
155 FaultLogInfo info;
156 std::vector<std::string> splitStr;
157 const int32_t idxOfType = 0;
158 const int32_t idxOfMoudle = 1;
159 const int32_t idxOfUid = 2;
160 const int32_t idxOfTime = 3;
161 const int32_t expectedVecSize = 4;
162 const size_t tailWithMillSecLen = 7u;
163 const size_t tailWithLogLen = 4u;
164 StringUtil::SplitStr(fileName, "-", splitStr);
165 if (splitStr.size() == expectedVecSize) {
166 info.faultLogType = GetLogTypeByName(splitStr[idxOfType]);
167 info.module = splitStr[idxOfMoudle];
168 StringUtil::ConvertStringTo<int32_t>(splitStr[idxOfUid], info.id);
169 size_t timeStampStrLen = splitStr[idxOfTime].length();
170 if (timeStampStrLen > tailWithMillSecLen &&
171 splitStr[idxOfTime].substr(timeStampStrLen - tailWithLogLen).compare(".log") == 0) {
172 info.time = TimeUtil::StrToTimeStamp(splitStr[idxOfTime].substr(0, timeStampStrLen - tailWithMillSecLen),
173 "%Y%m%d%H%M%S");
174 } else {
175 info.time = TimeUtil::StrToTimeStamp(splitStr[idxOfTime], "%Y%m%d%H%M%S");
176 }
177 }
178 info.pid = 0;
179 return info;
180 }
181
ExtractInfoFromTempFile(const std::string & fileName)182 FaultLogInfo ExtractInfoFromTempFile(const std::string& fileName)
183 {
184 // FileName LogType-pid-time
185 FaultLogInfo info;
186 std::vector<std::string> splitStr;
187 const int32_t expectedVecSize = 3;
188 StringUtil::SplitStr(fileName, "-", splitStr);
189 if (splitStr.size() == expectedVecSize) {
190 info.faultLogType = GetLogTypeByName(splitStr[0]); // 0 : index of log type
191 StringUtil::ConvertStringTo<int32_t>(splitStr[1], info.pid); // 1 : index of pid
192 StringUtil::ConvertStringTo<int64_t>(splitStr[2], info.time); // 2 : index of timestamp
193 }
194 return info;
195 }
196
RegulateModuleNameIfNeed(const std::string & name)197 std::string RegulateModuleNameIfNeed(const std::string& name)
198 {
199 std::vector<std::string> splitStr;
200 StringUtil::SplitStr(name, "/", splitStr);
201 auto size = splitStr.size();
202 if (size > 0) {
203 return splitStr[size - 1];
204 }
205 return name;
206 }
207
GetFileLastAccessTimeStamp(const std::string & fileName)208 time_t GetFileLastAccessTimeStamp(const std::string& fileName)
209 {
210 struct stat fileInfo;
211 if (stat(fileName.c_str(), &fileInfo) != 0) {
212 return 0;
213 }
214 return fileInfo.st_atime;
215 }
216
GetCppCrashTempLogName(const FaultLogInfo & info)217 std::string GetCppCrashTempLogName(const FaultLogInfo& info)
218 {
219 return std::string(DEFAULT_FAULTLOG_TEMP_FOLDER) +
220 "cppcrash-" +
221 std::to_string(info.pid) +
222 "-" +
223 std::to_string(info.time);
224 }
225
GetDebugSignalTempLogName(const FaultLogInfo & info)226 std::string GetDebugSignalTempLogName(const FaultLogInfo& info)
227 {
228 return std::string(DEFAULT_FAULTLOG_TEMP_FOLDER) +
229 "stacktrace-" +
230 std::to_string(info.pid) +
231 "-" +
232 std::to_string(info.time);
233 }
234
GetSanitizerTempLogName(int32_t pid,int64_t happenTime)235 std::string GetSanitizerTempLogName(int32_t pid, int64_t happenTime)
236 {
237 return std::string(DEFAULT_FAULTLOG_TEMP_FOLDER) +
238 "sanitizer-" +
239 std::to_string(pid) +
240 "-" +
241 std::to_string(happenTime);
242 }
243
GetThreadStack(const std::string & path,int32_t threadId)244 std::string GetThreadStack(const std::string& path, int32_t threadId)
245 {
246 std::string stack;
247 if (path.empty()) {
248 return stack;
249 }
250 char realPath[PATH_MAX] = {0};
251 if (realpath(path.c_str(), realPath) == nullptr) {
252 return stack;
253 }
254 if (strncmp(realPath, FaultLogger::FAULTLOG_BASE_FOLDER, strlen(FaultLogger::FAULTLOG_BASE_FOLDER)) != 0) {
255 return stack;
256 }
257
258 std::ifstream logFile(realPath);
259 if (!logFile.is_open()) {
260 return stack;
261 }
262 std::string regTidString = "^Tid:" + std::to_string(threadId) + ", Name:(.{0,32})$";
263 std::regex regTid(regTidString);
264 std::regex regStack(R"(^#\d{2,3} (pc|at) .{0,1024}$)");
265 std::string line;
266 while (std::getline(logFile, line)) {
267 if (!logFile.good()) {
268 break;
269 }
270
271 if (!std::regex_match(line, regTid)) {
272 continue;
273 }
274
275 do {
276 stack.append(line + "\n");
277 if (!logFile.good()) {
278 break;
279 }
280 } while (std::getline(logFile, line) && std::regex_match(line, regStack));
281 break;
282 }
283
284 return stack;
285 }
286
IsValidPath(const std::string & path)287 bool IsValidPath(const std::string& path)
288 {
289 if (path.size() == 0) {
290 return true;
291 }
292 char realPath[PATH_MAX] = {0};
293 if (realpath(path.c_str(), realPath) == nullptr) {
294 return false;
295 }
296 if (strncmp(realPath, DEFAULT_FAULTLOG_FOLDER, strlen(DEFAULT_FAULTLOG_FOLDER)) == 0 ||
297 strncmp(realPath, DEFAULT_FAULTLOG_TEST, strlen(DEFAULT_FAULTLOG_TEST)) == 0) {
298 return true;
299 }
300 return false;
301 }
302 } // namespace HiviewDFX
303 } // namespace OHOS
304