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 22namespace panda::ecmascript { 23#ifdef JIT_ESCAPE_ENABLE 24static struct sigaction s_oldSa[SIGSYS + 1]; // SIGSYS = 31 25void 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 49void 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 59void 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 73bool 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 87bool 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 108void 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 125bool 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 138bool 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 148bool 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 156std::string AotCrashInfo::GetSandBoxPath() 157{ 158 return ohos::OhosConstants::SANDBOX_ARK_PROFILE_PATH; 159} 160 161int AotCrashInfo::GetAotCrashCount() 162{ 163 return AOT_CRASH_COUNT; 164} 165 166int AotCrashInfo::GetJitCrashCount() 167{ 168 return JIT_CRASH_COUNT; 169} 170 171int AotCrashInfo::GetJsCrashCount() 172{ 173 return JS_CRASH_COUNT; 174} 175 176int AotCrashInfo::GetOthersCrashCount() 177{ 178 return OTHERS_CRASH_COUNT; 179} 180 181} // namespace panda::ecmascript 182