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