1 /*
2  * Copyright (c) 2024 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 
17 #include "ecmascript/platform/aot_crash_info.h"
18 #if defined(PANDA_TARGET_OHOS) && !defined(STANDALONE_MODE)
19 #include "parameters.h"
20 #endif
21 
22 namespace panda::ecmascript {
23 #ifdef JIT_ESCAPE_ENABLE
24 static struct sigaction s_oldSa[SIGSYS + 1]; // SIGSYS = 31
GetSignalHandler(int signal, siginfo_t *info, void *context)25 void GetSignalHandler(int signal, siginfo_t *info, void *context)
26 {
27     [[maybe_unused]] ucontext_t *ucontext = reinterpret_cast<ucontext_t*>(context);
28     [[maybe_unused]] mcontext_t &mcontext = ucontext->uc_mcontext;
29     uintptr_t pc = 0;
30 #if defined(PANDA_TARGET_AMD64)
31     pc = static_cast<uintptr_t>(mcontext.gregs[REG_RIP]);
32 #elif defined(PANDA_TARGET_ARM64)
33     pc = static_cast<uintptr_t>(mcontext.pc);
34 #endif
35     if (JsStackInfo::loader == nullptr) {
36         ecmascript::JsStackInfo::BuildCrashInfo(false);
37     } else if (!JsStackInfo::loader->InsideStub(pc) && !JsStackInfo::loader->InsideAOT(pc)) {
38         ecmascript::JsStackInfo::BuildCrashInfo(false);
39     } else {
40         ecmascript::JsStackInfo::BuildCrashInfo(false, pc);
41     }
42     sigaction(signal, &s_oldSa[signal], nullptr);
43     int rc = syscall(SYS_rt_tgsigqueueinfo, getpid(), syscall(SYS_gettid), info->si_signo, info);
44     if (rc != 0) {
45         LOG_ECMA(ERROR) << "GetSignalHandler() failed to resend signal during crash";
46     }
47 }
48 
SignalReg(int signo)49 void SignalReg(int signo)
50 {
51     sigaction(signo, nullptr, &s_oldSa[signo]);
52     struct sigaction newAction;
53     newAction.sa_flags = SA_RESTART | SA_SIGINFO;
54     newAction.sa_sigaction = GetSignalHandler;
55     sigaction(signo, &newAction, nullptr);
56 }
57 #endif
58 
SignalAllReg()59 void SignalAllReg()
60 {
61 #ifdef JIT_ESCAPE_ENABLE
62     SignalReg(SIGABRT);
63     SignalReg(SIGBUS);
64     SignalReg(SIGSEGV);
65     SignalReg(SIGILL);
66     SignalReg(SIGKILL);
67     SignalReg(SIGSTKFLT);
68     SignalReg(SIGFPE);
69     SignalReg(SIGTRAP);
70 #endif
71 }
72 
IsAotEscapedOrNotInEnableList(EcmaVM *vm, const std::string &bundleName) const73 bool AotCrashInfo::IsAotEscapedOrNotInEnableList(EcmaVM *vm, const std::string &bundleName) const
74 {
75     if (!vm->GetJSOptions().WasAOTOutputFileSet() &&
76         !ohos::EnableAotJitListHelper::GetInstance()->IsEnableAot(bundleName)) {
77         LOG_ECMA(INFO) << "Stop load AOT because it's not in enable list";
78         return true;
79     }
80     if (IsAotEscaped()) {
81         LOG_ECMA(INFO) << "Stop load AOT because there are more crashes";
82         return true;
83     }
84     return false;
85 }
86 
IsAotEscapedOrCompiledOnce(AotCompilerPreprocessor &cPreprocessor, int32_t &ret) const87 bool AotCrashInfo::IsAotEscapedOrCompiledOnce(AotCompilerPreprocessor &cPreprocessor, int32_t &ret) const
88 {
89     if (!cPreprocessor.GetMainPkgArgs()) {
90         return false;
91     }
92     std::string pgoRealPath = cPreprocessor.GetMainPkgArgs()->GetPgoDir();
93     pgoRealPath.append(ohos::OhosConstants::PATH_SEPARATOR);
94     pgoRealPath.append(ohos::OhosConstants::AOT_RUNTIME_INFO_NAME);
95     if (ohos::EnableAotJitListHelper::GetInstance()->IsAotCompileSuccessOnce(pgoRealPath)) {
96         ret = 0;
97         LOG_ECMA(INFO) << "Aot has compile success once or escaped.";
98         return true;
99     }
100     if (IsAotEscaped(pgoRealPath)) {
101         ret = -1;
102         LOG_ECMA(INFO) << "Aot has escaped";
103         return true;
104     }
105     return false;
106 }
107 
SetOptionPGOProfiler(JSRuntimeOptions *options, const std::string &bundleName) const108 void AotCrashInfo::SetOptionPGOProfiler(JSRuntimeOptions *options, const std::string &bundleName) const
109 {
110 #ifdef AOT_ESCAPE_ENABLE
111     if (ohos::EnableAotJitListHelper::GetInstance()->IsEnableAot(bundleName)) {
112         options->SetEnablePGOProfiler(true);
113         if (options->GetAOTHasException() ||
114             ohos::EnableAotJitListHelper::GetInstance()->IsAotCompileSuccessOnce() ||
115             IsAotEscaped()) {
116             options->SetEnablePGOProfiler(false);
117             LOG_ECMA(INFO) << "Aot has compile success once or escaped.";
118         }
119     }
120 #endif
121     (void)options;
122     (void)bundleName;
123 }
124 
IsAotEscaped(const std::string &pgoRealPath)125 bool AotCrashInfo::IsAotEscaped(const std::string &pgoRealPath)
126 {
127     if (AotCrashInfo::GetAotEscapeDisable()) {
128         return false;
129     }
130     auto escapeMap = ohos::AotRuntimeInfo::GetInstance().CollectCrashSum(pgoRealPath);
131     int totalCrashes = escapeMap[ohos::RuntimeInfoType::AOT_CRASH] +
132                        escapeMap[ohos::RuntimeInfoType::JIT] +
133                        escapeMap[ohos::RuntimeInfoType::OTHERS] +
134                        escapeMap[ohos::RuntimeInfoType::JS];
135     return totalCrashes >= OPT_CODE_CRASH_THRESHOLD;
136 }
137 
IsJitEscape()138 bool AotCrashInfo::IsJitEscape()
139 {
140     auto escapeMap = ohos::AotRuntimeInfo::GetInstance().CollectCrashSum();
141     int totalCrashes = escapeMap[ohos::RuntimeInfoType::AOT_CRASH] +
142                        escapeMap[ohos::RuntimeInfoType::JIT] +
143                        escapeMap[ohos::RuntimeInfoType::OTHERS] +
144                        escapeMap[ohos::RuntimeInfoType::JS];
145     return totalCrashes >= OPT_CODE_CRASH_THRESHOLD;
146 }
147 
GetAotEscapeDisable()148 bool AotCrashInfo::GetAotEscapeDisable()
149 {
150 #if defined(PANDA_TARGET_OHOS) && !defined(STANDALONE_MODE)
151         return OHOS::system::GetBoolParameter(AOT_ESCAPE_DISABLE, false);
152 #endif
153         return false;
154 }
155 
GetSandBoxPath()156 std::string AotCrashInfo::GetSandBoxPath()
157 {
158     return ohos::OhosConstants::SANDBOX_ARK_PROFILE_PATH;
159 }
160 
GetAotCrashCount()161 int AotCrashInfo::GetAotCrashCount()
162 {
163     return AOT_CRASH_COUNT;
164 }
165 
GetJitCrashCount()166 int AotCrashInfo::GetJitCrashCount()
167 {
168     return JIT_CRASH_COUNT;
169 }
170 
GetJsCrashCount()171 int AotCrashInfo::GetJsCrashCount()
172 {
173     return JS_CRASH_COUNT;
174 }
175 
GetOthersCrashCount()176 int AotCrashInfo::GetOthersCrashCount()
177 {
178     return OTHERS_CRASH_COUNT;
179 }
180 
181 }  // namespace panda::ecmascript
182