• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 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 #include "log_parse.h"
16 
17 #include "string_util.h"
18 #include "tbox.h"
19 
20 using namespace std;
21 namespace OHOS {
22 namespace HiviewDFX {
23 const std::string LogParse::UNMATCHED_EXCEPTION = "UnMatchedException";
24 
25 // some stack function is invalid, so it should be ignored
26 const std::map<std::string, std::set<std::string>> LogParse::ignoreList_ = {
27     {"Level1", {
28         "libc.so",
29         "libc++.so",
30         "ld-musl-aarch64.so",
31         "libc_fdleak_debug.so",
32         "unknown",
33         "watchdog",
34         "kthread",
35         "rdr_system_error"}
36     },
37     {"Level2", {
38         "libart.so",
39         "__switch_to",
40         "dump_backtrace",
41         "show_stack",
42         "dump_stack"}
43     },
44     {"Level3", {
45         "panic"}
46     }
47 };
48 
49 // it is key word in app crash log, it can replace complexed info which may have safe and privacy info
50 const std::set<std::string> LogParse::exceptionList_ = {
51     "ArithmeticException",
52     "ArrayIndexOutOfBoundsException",
53     "ArrayStoreException",
54     "ClassCastException",
55     "ClassNotFoundException",
56     "CloneNotSupportedException",
57     "EnumConstantNotPresentException",
58     "IllegalAccessException",
59     "IllegalArgumentException",
60     "IllegalMonitorStateException",
61     "IllegalStateException",
62     "IllegalThreadStateException",
63     "IndexOutOfBoundsException",
64     "InstantiationException",
65     "InterruptedException",
66     "NegativeArraySizeException",
67     "NoSuchFieldException",
68     "NoSuchMethodException",
69     "NullPointerException",
70     "NumberFormatException",
71     "ReflectiveOperationException",
72     "RuntimeException",
73     "SecurityException",
74     "StringIndexOutOfBoundsException"
75 };
76 
IsIgnoreLibrary(const string & val) const77 bool LogParse::IsIgnoreLibrary(const string& val) const
78 {
79     for (auto list : ignoreList_) {
80         for (auto str : list.second) {
81             if (val.find(str, 0) != string::npos) {
82                 return true;
83             }
84         }
85     }
86     return false;
87 }
88 
89 /*
90  * Remove ignored backtrace
91  * inStack : inverted sequence with fault log
92  * outStack : filter stack
93  */
GetValidStack(int num,stack<string> & inStack,stack<string> & outStack) const94 bool LogParse::GetValidStack(int num, stack<string>& inStack, stack<string>& outStack) const
95 {
96     vector<string> validStack;
97     size_t count = static_cast<size_t>(num);
98     // count < 1: indicate stack is empty
99     if (count < 1 || inStack.empty()) {
100         return false;
101     }
102 
103     // Automatically checks if it is a stack
104     bool iStack = Tbox::IsCallStack(inStack.top());
105     if (iStack) {
106         validStack = GetValidStack(count, inStack);
107     }
108     outStack = GetStackTop(validStack, count);
109     return true;
110 }
111 
GetStackTop(const vector<string> & validStack,const size_t num) const112 stack<string> LogParse::GetStackTop(const vector<string>& validStack, const size_t num) const
113 {
114     size_t len = validStack.size();
115     stack<string> stackTop;
116     for (size_t i = 0; i < len; i++) {
117         if (i == 0 || len - i < num) {
118             stackTop.push(validStack.at(i));
119         }
120     }
121     return stackTop;
122 }
123 
StackToMultipart(stack<string> & inStack,size_t num) const124 list<vector<string>> LogParse::StackToMultipart(stack<string>& inStack, size_t num) const
125 {
126     stack<string> partStack;
127     vector<string> validPart;
128     list<vector<string>> multiPart;
129     while (!inStack.empty()) {
130         string topStr = inStack.top();
131         StringUtil::EraseString(topStr, "\t");
132         if (Tbox::HasCausedBy(topStr)) {
133             topStr = MatchExceptionLibrary(topStr);
134             if (!partStack.empty()) {
135                 validPart = GetValidStack(num, partStack);
136             }
137             validPart.insert(validPart.begin(), topStr);
138             multiPart.push_back(validPart);
139             partStack = stack<string>();
140             validPart.clear();
141             inStack.pop();
142             continue;
143         }
144         partStack.push(topStr);
145         inStack.pop();
146     }
147     if (!partStack.empty()) {
148         validPart = GetValidStack(num, partStack);
149         multiPart.push_back(validPart);
150     }
151     return multiPart;
152 }
153 
GetValidBlock(stack<string> inStack,vector<string> & lastPart) const154 string LogParse::GetValidBlock(stack<string> inStack, vector<string>& lastPart) const
155 {
156     vector<string> validStack;
157 
158     list<vector<string>> multiPart = StackToMultipart(inStack, 3); // 3 : first/second/last frame
159     size_t size = multiPart.size();
160     if (size == 0) {
161         return "";
162     }
163     if (size == 1) {
164         // only one part
165         validStack = multiPart.front();
166         if (validStack.size() > STACK_LEN_MAX) {
167             // keep the begin 28 lines and the end 2 lines
168             validStack.erase(validStack.begin() + (STACK_LEN_MAX - 2), validStack.end() - 2); // 2 : end 2 lines
169         }
170     } else if (size >= 2) { // at least 2 parts
171         for (auto part : multiPart) {
172             if (validStack.size() >= STACK_LEN_MAX) {
173                 break;
174             }
175             validStack.insert(validStack.begin(), part.begin(), part.end());
176         }
177         if (multiPart.front().size() > STACK_LEN_MAX) {
178             // keep the begin 28 lines and the end 2 lines
179             validStack.erase(validStack.begin() + (STACK_LEN_MAX - 2), validStack.end() - 2); // 2 : end 2 lines
180         } else if (validStack.size() > STACK_LEN_MAX) {
181             // keep the begin 2 lines and the end 28 lines
182             validStack.erase(validStack.begin() + 2, validStack.end() - (STACK_LEN_MAX - 2)); // 2 : begin 2 lines
183         }
184     }
185 
186     for (auto part : multiPart) {
187         // multiPart has at least 2 parts
188         if (size > 1 && !part.empty() && HasExceptionList(part.front())) {
189             part.erase(part.begin());
190         }
191         // lastPart should has at least 3 lines
192         if (!part.empty()) {
193             reverse(part.begin(), part.end());
194             lastPart = part;
195             break;
196         }
197     }
198     return Tbox::ARRAY_STR + StringUtil::VectorToString(validStack, false);
199 }
200 
GetValidStack(size_t num,stack<string> & inStack) const201 vector<string> LogParse::GetValidStack(size_t num, stack<string>& inStack) const
202 {
203     stack<string> src = inStack;
204     vector<string> validStack;
205     stack<string> outStatck;
206     string stackName;
207     size_t len = src.size();
208     for (size_t i = 0; i < len; i++) {
209         stackName = Tbox::GetStackName(src.top());  // extract function name from the stack
210         if (!IsIgnoreLibrary(stackName)) {
211             validStack.push_back(stackName);
212         }
213         src.pop();
214     }
215     if (validStack.empty()) {
216         MatchIgnoreLibrary(inStack, outStatck, num);
217         len = outStatck.size();
218         for (size_t i = 0; i < len; i++) {
219             stackName = Tbox::GetStackName(outStatck.top());
220             validStack.push_back(stackName);
221             outStatck.pop();
222         }
223     }
224     return validStack;
225 }
226 
MatchExceptionLibrary(const string & val)227 string LogParse::MatchExceptionLibrary(const string& val)
228 {
229     for (auto& str : LogParse::exceptionList_) {
230         if (val.find(str, 0) != string::npos) {
231             return str;
232         }
233     }
234     return UNMATCHED_EXCEPTION;
235 }
236 
MatchIgnoreLibrary(stack<string> inStack,stack<string> & outStack,size_t num) const237 void LogParse::MatchIgnoreLibrary(stack<string> inStack, stack<string>& outStack, size_t num) const
238 {
239     if (inStack.size() <= num) {
240         outStack = inStack;
241         return;
242     }
243     size_t count = 0;
244     for (auto it = ignoreList_.rbegin(); it != ignoreList_.rend(); ++it) {
245         if (count == ignoreList_.size() - 1) {
246             outStack = inStack;
247             return;
248         }
249 
250         stack<string> src = inStack;
251         while (src.size() > num) {
252             string name = src.top();
253             for (auto str : it->second) {
254                 if (name.find(str, 0) != string::npos) {
255                     outStack = src;
256                     return;
257                 }
258             }
259             src.pop();
260         }
261         count++;
262     }
263 }
264 
265 /*
266  * INPUT :
267  *  info : trace spliting by "\n"
268  * OUTPUT :
269  *  trace : last part trace to get Frame
270  *  return string : valid trace spliting by "\n"
271  */
GetFilterTrace(const std::string & info,std::vector<std::string> & trace,std::string eventType) const272 std::string LogParse::GetFilterTrace(const std::string& info, std::vector<std::string>& trace,
273     std::string eventType) const
274 {
275     std::string newInfo = info;
276     if (eventType == "JS_ERROR" && newInfo.find("libace_napi.z.so") != std::string::npos) {
277         newInfo = StringUtil::GetRightSubstr(info, "libace_napi.z.so");
278     }
279     StringUtil::SplitStr(newInfo, "\n", trace, false, false);
280     std::stack<std::string> traceStack;
281     for (const auto& str : trace) {
282         traceStack.push(str);
283     }
284     trace.clear();
285     return GetValidBlock(traceStack, trace);
286 }
287 
SetFrame(std::stack<std::string> & stack,std::map<std::string,std::string> & eventInfo) const288 void LogParse::SetFrame(std::stack<std::string>& stack, std::map<std::string, std::string>& eventInfo) const
289 {
290     std::vector<std::string> name = {"FIRST_FRAME", "SECOND_FRAME", "LAST_FRAME"};
291     size_t len = stack.size();
292     for (size_t i = 0; i < len; i++) {
293         if (eventInfo.find(name[i]) == eventInfo.end()) {
294             eventInfo[name[i]] = stack.top();
295         }
296         stack.pop();
297     }
298 }
299 
HasExceptionList(const string & line) const300 bool LogParse::HasExceptionList(const string& line) const
301 {
302     auto iter = exceptionList_.find(line);
303     if (line == UNMATCHED_EXCEPTION || iter != exceptionList_.end()) {
304         return true;
305     }
306     return false;
307 }
308 }
309 }