1020a203aSopenharmony_ci/*
2020a203aSopenharmony_ci * Copyright (c) 2022 Huawei Device Co., Ltd.
3020a203aSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4020a203aSopenharmony_ci * you may not use this file except in compliance with the License.
5020a203aSopenharmony_ci * You may obtain a copy of the License at
6020a203aSopenharmony_ci *
7020a203aSopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8020a203aSopenharmony_ci *
9020a203aSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10020a203aSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11020a203aSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12020a203aSopenharmony_ci * See the License for the specific language governing permissions and
13020a203aSopenharmony_ci * limitations under the License.
14020a203aSopenharmony_ci */
15020a203aSopenharmony_ci#include "log_parse.h"
16020a203aSopenharmony_ci
17020a203aSopenharmony_ci#include "string_util.h"
18020a203aSopenharmony_ci#include "tbox.h"
19020a203aSopenharmony_ci
20020a203aSopenharmony_ciusing namespace std;
21020a203aSopenharmony_cinamespace OHOS {
22020a203aSopenharmony_cinamespace HiviewDFX {
23020a203aSopenharmony_ciconst std::string LogParse::UNMATCHED_EXCEPTION = "UnMatchedException";
24020a203aSopenharmony_ci
25020a203aSopenharmony_ci// some stack function is invalid, so it should be ignored
26020a203aSopenharmony_ciconst std::map<std::string, std::set<std::string>> LogParse::ignoreList_ = {
27020a203aSopenharmony_ci    {"Level1", {
28020a203aSopenharmony_ci        "libc.so",
29020a203aSopenharmony_ci        "libc++.so",
30020a203aSopenharmony_ci        "ld-musl-aarch64.so",
31020a203aSopenharmony_ci        "libc_fdleak_debug.so",
32020a203aSopenharmony_ci        "unknown",
33020a203aSopenharmony_ci        "watchdog",
34020a203aSopenharmony_ci        "kthread",
35020a203aSopenharmony_ci        "rdr_system_error"}
36020a203aSopenharmony_ci    },
37020a203aSopenharmony_ci    {"Level2", {
38020a203aSopenharmony_ci        "libart.so",
39020a203aSopenharmony_ci        "__switch_to",
40020a203aSopenharmony_ci        "dump_backtrace",
41020a203aSopenharmony_ci        "show_stack",
42020a203aSopenharmony_ci        "dump_stack"}
43020a203aSopenharmony_ci    },
44020a203aSopenharmony_ci    {"Level3", {
45020a203aSopenharmony_ci        "panic"}
46020a203aSopenharmony_ci    }
47020a203aSopenharmony_ci};
48020a203aSopenharmony_ci
49020a203aSopenharmony_ci// it is key word in app crash log, it can replace complexed info which may have safe and privacy info
50020a203aSopenharmony_ciconst std::set<std::string> LogParse::exceptionList_ = {
51020a203aSopenharmony_ci    "ArithmeticException",
52020a203aSopenharmony_ci    "ArrayIndexOutOfBoundsException",
53020a203aSopenharmony_ci    "ArrayStoreException",
54020a203aSopenharmony_ci    "ClassCastException",
55020a203aSopenharmony_ci    "ClassNotFoundException",
56020a203aSopenharmony_ci    "CloneNotSupportedException",
57020a203aSopenharmony_ci    "EnumConstantNotPresentException",
58020a203aSopenharmony_ci    "IllegalAccessException",
59020a203aSopenharmony_ci    "IllegalArgumentException",
60020a203aSopenharmony_ci    "IllegalMonitorStateException",
61020a203aSopenharmony_ci    "IllegalStateException",
62020a203aSopenharmony_ci    "IllegalThreadStateException",
63020a203aSopenharmony_ci    "IndexOutOfBoundsException",
64020a203aSopenharmony_ci    "InstantiationException",
65020a203aSopenharmony_ci    "InterruptedException",
66020a203aSopenharmony_ci    "NegativeArraySizeException",
67020a203aSopenharmony_ci    "NoSuchFieldException",
68020a203aSopenharmony_ci    "NoSuchMethodException",
69020a203aSopenharmony_ci    "NullPointerException",
70020a203aSopenharmony_ci    "NumberFormatException",
71020a203aSopenharmony_ci    "ReflectiveOperationException",
72020a203aSopenharmony_ci    "RuntimeException",
73020a203aSopenharmony_ci    "SecurityException",
74020a203aSopenharmony_ci    "StringIndexOutOfBoundsException"
75020a203aSopenharmony_ci};
76020a203aSopenharmony_ci
77020a203aSopenharmony_cibool LogParse::IsIgnoreLibrary(const string& val) const
78020a203aSopenharmony_ci{
79020a203aSopenharmony_ci    for (auto list : ignoreList_) {
80020a203aSopenharmony_ci        for (auto str : list.second) {
81020a203aSopenharmony_ci            if (val.find(str, 0) != string::npos) {
82020a203aSopenharmony_ci                return true;
83020a203aSopenharmony_ci            }
84020a203aSopenharmony_ci        }
85020a203aSopenharmony_ci    }
86020a203aSopenharmony_ci    return false;
87020a203aSopenharmony_ci}
88020a203aSopenharmony_ci
89020a203aSopenharmony_ci/*
90020a203aSopenharmony_ci * Remove ignored backtrace
91020a203aSopenharmony_ci * inStack : inverted sequence with fault log
92020a203aSopenharmony_ci * outStack : filter stack
93020a203aSopenharmony_ci */
94020a203aSopenharmony_cibool LogParse::GetValidStack(int num, stack<string>& inStack, stack<string>& outStack) const
95020a203aSopenharmony_ci{
96020a203aSopenharmony_ci    vector<string> validStack;
97020a203aSopenharmony_ci    size_t count = static_cast<size_t>(num);
98020a203aSopenharmony_ci    // count < 1: indicate stack is empty
99020a203aSopenharmony_ci    if (count < 1 || inStack.empty()) {
100020a203aSopenharmony_ci        return false;
101020a203aSopenharmony_ci    }
102020a203aSopenharmony_ci
103020a203aSopenharmony_ci    // Automatically checks if it is a stack
104020a203aSopenharmony_ci    bool iStack = Tbox::IsCallStack(inStack.top());
105020a203aSopenharmony_ci    if (iStack) {
106020a203aSopenharmony_ci        validStack = GetValidStack(count, inStack);
107020a203aSopenharmony_ci    }
108020a203aSopenharmony_ci    outStack = GetStackTop(validStack, count);
109020a203aSopenharmony_ci    return true;
110020a203aSopenharmony_ci}
111020a203aSopenharmony_ci
112020a203aSopenharmony_cistack<string> LogParse::GetStackTop(const vector<string>& validStack, const size_t num) const
113020a203aSopenharmony_ci{
114020a203aSopenharmony_ci    size_t len = validStack.size();
115020a203aSopenharmony_ci    stack<string> stackTop;
116020a203aSopenharmony_ci    for (size_t i = 0; i < len; i++) {
117020a203aSopenharmony_ci        if (i == 0 || len - i < num) {
118020a203aSopenharmony_ci            stackTop.push(validStack.at(i));
119020a203aSopenharmony_ci        }
120020a203aSopenharmony_ci    }
121020a203aSopenharmony_ci    return stackTop;
122020a203aSopenharmony_ci}
123020a203aSopenharmony_ci
124020a203aSopenharmony_cilist<vector<string>> LogParse::StackToMultipart(stack<string>& inStack, size_t num) const
125020a203aSopenharmony_ci{
126020a203aSopenharmony_ci    stack<string> partStack;
127020a203aSopenharmony_ci    vector<string> validPart;
128020a203aSopenharmony_ci    list<vector<string>> multiPart;
129020a203aSopenharmony_ci    while (!inStack.empty()) {
130020a203aSopenharmony_ci        string topStr = inStack.top();
131020a203aSopenharmony_ci        StringUtil::EraseString(topStr, "\t");
132020a203aSopenharmony_ci        if (Tbox::HasCausedBy(topStr)) {
133020a203aSopenharmony_ci            topStr = MatchExceptionLibrary(topStr);
134020a203aSopenharmony_ci            if (!partStack.empty()) {
135020a203aSopenharmony_ci                validPart = GetValidStack(num, partStack);
136020a203aSopenharmony_ci            }
137020a203aSopenharmony_ci            validPart.insert(validPart.begin(), topStr);
138020a203aSopenharmony_ci            multiPart.push_back(validPart);
139020a203aSopenharmony_ci            partStack = stack<string>();
140020a203aSopenharmony_ci            validPart.clear();
141020a203aSopenharmony_ci            inStack.pop();
142020a203aSopenharmony_ci            continue;
143020a203aSopenharmony_ci        }
144020a203aSopenharmony_ci        partStack.push(topStr);
145020a203aSopenharmony_ci        inStack.pop();
146020a203aSopenharmony_ci    }
147020a203aSopenharmony_ci    if (!partStack.empty()) {
148020a203aSopenharmony_ci        validPart = GetValidStack(num, partStack);
149020a203aSopenharmony_ci        multiPart.push_back(validPart);
150020a203aSopenharmony_ci    }
151020a203aSopenharmony_ci    return multiPart;
152020a203aSopenharmony_ci}
153020a203aSopenharmony_ci
154020a203aSopenharmony_cistring LogParse::GetValidBlock(stack<string> inStack, vector<string>& lastPart) const
155020a203aSopenharmony_ci{
156020a203aSopenharmony_ci    vector<string> validStack;
157020a203aSopenharmony_ci
158020a203aSopenharmony_ci    list<vector<string>> multiPart = StackToMultipart(inStack, 3); // 3 : first/second/last frame
159020a203aSopenharmony_ci    size_t size = multiPart.size();
160020a203aSopenharmony_ci    if (size == 0) {
161020a203aSopenharmony_ci        return "";
162020a203aSopenharmony_ci    }
163020a203aSopenharmony_ci    if (size == 1) {
164020a203aSopenharmony_ci        // only one part
165020a203aSopenharmony_ci        validStack = multiPart.front();
166020a203aSopenharmony_ci        if (validStack.size() > STACK_LEN_MAX) {
167020a203aSopenharmony_ci            // keep the begin 28 lines and the end 2 lines
168020a203aSopenharmony_ci            validStack.erase(validStack.begin() + (STACK_LEN_MAX - 2), validStack.end() - 2); // 2 : end 2 lines
169020a203aSopenharmony_ci        }
170020a203aSopenharmony_ci    } else if (size >= 2) { // at least 2 parts
171020a203aSopenharmony_ci        for (auto part : multiPart) {
172020a203aSopenharmony_ci            if (validStack.size() >= STACK_LEN_MAX) {
173020a203aSopenharmony_ci                break;
174020a203aSopenharmony_ci            }
175020a203aSopenharmony_ci            validStack.insert(validStack.begin(), part.begin(), part.end());
176020a203aSopenharmony_ci        }
177020a203aSopenharmony_ci        if (multiPart.front().size() > STACK_LEN_MAX) {
178020a203aSopenharmony_ci            // keep the begin 28 lines and the end 2 lines
179020a203aSopenharmony_ci            validStack.erase(validStack.begin() + (STACK_LEN_MAX - 2), validStack.end() - 2); // 2 : end 2 lines
180020a203aSopenharmony_ci        } else if (validStack.size() > STACK_LEN_MAX) {
181020a203aSopenharmony_ci            // keep the begin 2 lines and the end 28 lines
182020a203aSopenharmony_ci            validStack.erase(validStack.begin() + 2, validStack.end() - (STACK_LEN_MAX - 2)); // 2 : begin 2 lines
183020a203aSopenharmony_ci        }
184020a203aSopenharmony_ci    }
185020a203aSopenharmony_ci
186020a203aSopenharmony_ci    for (auto part : multiPart) {
187020a203aSopenharmony_ci        // multiPart has at least 2 parts
188020a203aSopenharmony_ci        if (size > 1 && !part.empty() && HasExceptionList(part.front())) {
189020a203aSopenharmony_ci            part.erase(part.begin());
190020a203aSopenharmony_ci        }
191020a203aSopenharmony_ci        // lastPart should has at least 3 lines
192020a203aSopenharmony_ci        if (!part.empty()) {
193020a203aSopenharmony_ci            reverse(part.begin(), part.end());
194020a203aSopenharmony_ci            lastPart = part;
195020a203aSopenharmony_ci            break;
196020a203aSopenharmony_ci        }
197020a203aSopenharmony_ci    }
198020a203aSopenharmony_ci    return Tbox::ARRAY_STR + StringUtil::VectorToString(validStack, false);
199020a203aSopenharmony_ci}
200020a203aSopenharmony_ci
201020a203aSopenharmony_civector<string> LogParse::GetValidStack(size_t num, stack<string>& inStack) const
202020a203aSopenharmony_ci{
203020a203aSopenharmony_ci    stack<string> src = inStack;
204020a203aSopenharmony_ci    vector<string> validStack;
205020a203aSopenharmony_ci    stack<string> outStatck;
206020a203aSopenharmony_ci    string stackName;
207020a203aSopenharmony_ci    size_t len = src.size();
208020a203aSopenharmony_ci    for (size_t i = 0; i < len; i++) {
209020a203aSopenharmony_ci        stackName = Tbox::GetStackName(src.top());  // extract function name from the stack
210020a203aSopenharmony_ci        if (!IsIgnoreLibrary(stackName)) {
211020a203aSopenharmony_ci            validStack.push_back(stackName);
212020a203aSopenharmony_ci        }
213020a203aSopenharmony_ci        src.pop();
214020a203aSopenharmony_ci    }
215020a203aSopenharmony_ci    if (validStack.empty()) {
216020a203aSopenharmony_ci        MatchIgnoreLibrary(inStack, outStatck, num);
217020a203aSopenharmony_ci        len = outStatck.size();
218020a203aSopenharmony_ci        for (size_t i = 0; i < len; i++) {
219020a203aSopenharmony_ci            stackName = Tbox::GetStackName(outStatck.top());
220020a203aSopenharmony_ci            validStack.push_back(stackName);
221020a203aSopenharmony_ci            outStatck.pop();
222020a203aSopenharmony_ci        }
223020a203aSopenharmony_ci    }
224020a203aSopenharmony_ci    return validStack;
225020a203aSopenharmony_ci}
226020a203aSopenharmony_ci
227020a203aSopenharmony_cistring LogParse::MatchExceptionLibrary(const string& val)
228020a203aSopenharmony_ci{
229020a203aSopenharmony_ci    for (auto& str : LogParse::exceptionList_) {
230020a203aSopenharmony_ci        if (val.find(str, 0) != string::npos) {
231020a203aSopenharmony_ci            return str;
232020a203aSopenharmony_ci        }
233020a203aSopenharmony_ci    }
234020a203aSopenharmony_ci    return UNMATCHED_EXCEPTION;
235020a203aSopenharmony_ci}
236020a203aSopenharmony_ci
237020a203aSopenharmony_civoid LogParse::MatchIgnoreLibrary(stack<string> inStack, stack<string>& outStack, size_t num) const
238020a203aSopenharmony_ci{
239020a203aSopenharmony_ci    if (inStack.size() <= num) {
240020a203aSopenharmony_ci        outStack = inStack;
241020a203aSopenharmony_ci        return;
242020a203aSopenharmony_ci    }
243020a203aSopenharmony_ci    size_t count = 0;
244020a203aSopenharmony_ci    for (auto it = ignoreList_.rbegin(); it != ignoreList_.rend(); ++it) {
245020a203aSopenharmony_ci        if (count == ignoreList_.size() - 1) {
246020a203aSopenharmony_ci            outStack = inStack;
247020a203aSopenharmony_ci            return;
248020a203aSopenharmony_ci        }
249020a203aSopenharmony_ci
250020a203aSopenharmony_ci        stack<string> src = inStack;
251020a203aSopenharmony_ci        while (src.size() > num) {
252020a203aSopenharmony_ci            string name = src.top();
253020a203aSopenharmony_ci            for (auto str : it->second) {
254020a203aSopenharmony_ci                if (name.find(str, 0) != string::npos) {
255020a203aSopenharmony_ci                    outStack = src;
256020a203aSopenharmony_ci                    return;
257020a203aSopenharmony_ci                }
258020a203aSopenharmony_ci            }
259020a203aSopenharmony_ci            src.pop();
260020a203aSopenharmony_ci        }
261020a203aSopenharmony_ci        count++;
262020a203aSopenharmony_ci    }
263020a203aSopenharmony_ci}
264020a203aSopenharmony_ci
265020a203aSopenharmony_ci/*
266020a203aSopenharmony_ci * INPUT :
267020a203aSopenharmony_ci *  info : trace spliting by "\n"
268020a203aSopenharmony_ci * OUTPUT :
269020a203aSopenharmony_ci *  trace : last part trace to get Frame
270020a203aSopenharmony_ci *  return string : valid trace spliting by "\n"
271020a203aSopenharmony_ci */
272020a203aSopenharmony_cistd::string LogParse::GetFilterTrace(const std::string& info, std::vector<std::string>& trace,
273020a203aSopenharmony_ci    std::string eventType) const
274020a203aSopenharmony_ci{
275020a203aSopenharmony_ci    std::string newInfo = info;
276020a203aSopenharmony_ci    if (eventType == "JS_ERROR" && newInfo.find("libace_napi.z.so") != std::string::npos) {
277020a203aSopenharmony_ci        newInfo = StringUtil::GetRightSubstr(info, "libace_napi.z.so");
278020a203aSopenharmony_ci    }
279020a203aSopenharmony_ci    StringUtil::SplitStr(newInfo, "\n", trace, false, false);
280020a203aSopenharmony_ci    std::stack<std::string> traceStack;
281020a203aSopenharmony_ci    for (const auto& str : trace) {
282020a203aSopenharmony_ci        traceStack.push(str);
283020a203aSopenharmony_ci    }
284020a203aSopenharmony_ci    trace.clear();
285020a203aSopenharmony_ci    return GetValidBlock(traceStack, trace);
286020a203aSopenharmony_ci}
287020a203aSopenharmony_ci
288020a203aSopenharmony_civoid LogParse::SetFrame(std::stack<std::string>& stack, std::map<std::string, std::string>& eventInfo) const
289020a203aSopenharmony_ci{
290020a203aSopenharmony_ci    std::vector<std::string> name = {"FIRST_FRAME", "SECOND_FRAME", "LAST_FRAME"};
291020a203aSopenharmony_ci    size_t len = stack.size();
292020a203aSopenharmony_ci    for (size_t i = 0; i < len; i++) {
293020a203aSopenharmony_ci        if (eventInfo.find(name[i]) == eventInfo.end()) {
294020a203aSopenharmony_ci            eventInfo[name[i]] = stack.top();
295020a203aSopenharmony_ci        }
296020a203aSopenharmony_ci        stack.pop();
297020a203aSopenharmony_ci    }
298020a203aSopenharmony_ci}
299020a203aSopenharmony_ci
300020a203aSopenharmony_cibool LogParse::HasExceptionList(const string& line) const
301020a203aSopenharmony_ci{
302020a203aSopenharmony_ci    auto iter = exceptionList_.find(line);
303020a203aSopenharmony_ci    if (line == UNMATCHED_EXCEPTION || iter != exceptionList_.end()) {
304020a203aSopenharmony_ci        return true;
305020a203aSopenharmony_ci    }
306020a203aSopenharmony_ci    return false;
307020a203aSopenharmony_ci}
308020a203aSopenharmony_ci}
309020a203aSopenharmony_ci}