• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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