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