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#include <sys/time.h> 17 18#include "ecmascript/dfx/stackinfo/js_stackinfo.h" 19#include "ecmascript/platform/aot_crash_info.h" 20#include "ecmascript/platform/os.h" 21#include "ecmascript/stubs/runtime_stubs-inl.h" 22#include "ecmascript/jit/jit.h" 23#if defined(PANDA_TARGET_OHOS) 24#include "ecmascript/extractortool/src/extractor.h" 25#endif 26#if defined(ENABLE_EXCEPTION_BACKTRACE) 27#include "ecmascript/platform/backtrace.h" 28#endif 29 30namespace panda::ecmascript { 31[[maybe_unused]] static bool g_needCheck = true; 32std::unordered_map<EntityId, std::string> JsStackInfo::nameMap; 33std::unordered_map<EntityId, std::vector<uint8>> JsStackInfo::machineCodeMap; 34JSStackTrace *JSStackTrace::trace_ = nullptr; 35std::mutex JSStackTrace::mutex_; 36 37bool IsFastJitFunctionFrame(const FrameType frameType) 38{ 39 return frameType == FrameType::FASTJIT_FUNCTION_FRAME || frameType == FrameType::FASTJIT_FAST_CALL_FUNCTION_FRAME; 40} 41 42bool IsFastJitFunctionFrame(uintptr_t frameType) 43{ 44 return static_cast<FrameType>(frameType) == FrameType::FASTJIT_FUNCTION_FRAME || 45 static_cast<FrameType>(frameType) == FrameType::FASTJIT_FAST_CALL_FUNCTION_FRAME; 46} 47 48std::string JsStackInfo::BuildMethodTrace(Method *method, uint32_t pcOffset, LastBuilderCache &lastCache, 49 bool enableStackSourceFile) 50{ 51 std::string data; 52 data.reserve(InitialLength); 53 data.append(" at "); 54 std::string name = method->ParseFunctionName(); 55 if (name.empty()) { 56 data.append("anonymous ("); 57 } else { 58 data.append(name).append(" ("); 59 } 60 // source file 61 DebugInfoExtractor *debugExtractor = nullptr; 62 const JSPandaFile *pandaFile = method->GetJSPandaFile(); 63 if (pandaFile == lastCache.pf) { 64 debugExtractor = lastCache.extractor; 65 } else { 66 debugExtractor = JSPandaFileManager::GetInstance()->GetJSPtExtractor(pandaFile); 67 lastCache.pf = pandaFile; 68 lastCache.extractor = debugExtractor; 69 } 70 if (enableStackSourceFile) { 71 const std::string &sourceFile = debugExtractor->GetSourceFile(method->GetMethodId()); 72 if (sourceFile.empty()) { 73 data.push_back('?'); 74 } else { 75 data += sourceFile; 76 } 77 } else { 78 data.append("hidden"); 79 } 80 81 data.push_back(':'); 82 // line number and column number 83 auto callbackLineFunc = [&data](int32_t line) -> bool { 84 data += std::to_string(line + 1); 85 data.push_back(':'); 86 return true; 87 }; 88 auto callbackColumnFunc = [&data](int32_t column) -> bool { 89 data += std::to_string(column + 1); 90 return true; 91 }; 92 panda_file::File::EntityId methodId = method->GetMethodId(); 93 if (!debugExtractor->MatchLineWithOffset(callbackLineFunc, methodId, pcOffset) || 94 !debugExtractor->MatchColumnWithOffset(callbackColumnFunc, methodId, pcOffset)) { 95 data.push_back('?'); 96 } 97 data.append(")\n"); 98 return data; 99} 100 101std::string JsStackInfo::BuildInlinedMethodTrace(const JSPandaFile *pf, std::map<uint32_t, uint32_t> &methodOffsets) 102{ 103 std::string data; 104 std::map<uint32_t, uint32_t>::reverse_iterator it; 105 for (it = methodOffsets.rbegin(); it != methodOffsets.rend(); it++) { 106 uint32_t methodId = it->second; 107 std::string name; 108 if (methodId == 0) { 109 name = "unknown"; 110 } else { 111 name = std::string(MethodLiteral::GetMethodName(pf, EntityId(methodId))); 112 if (name == "") { 113 name = "anonymous"; 114 } 115 } 116 data.append(" at "); 117 data.append(name); 118 data.append(" (maybe inlined)."); 119 data.append(" depth: "); 120 data.append(std::to_string(it->first)); 121 122 data.push_back('\n'); 123 } 124 return data; 125} 126 127void JsStackInfo::DumpJitCode(JSThread *thread) 128{ 129 JSTaggedType exception = thread->GetException().GetRawData(); 130 auto &jitCodeMaps = thread->GetJitCodeMaps(); 131 auto jitCode = jitCodeMaps.find(exception); 132 if (jitCode == jitCodeMaps.end()) { 133 return; 134 } 135 std::set<MachineCode*> memos; 136 JsJitDumpElf jitDumpElf; 137 jitDumpElf.Init(); 138 int64 idx = 0; 139 size_t offset = 0; 140 auto jitCodeVec = jitCodeMaps[exception]; 141 for (size_t i = 0; i < jitCodeVec->size(); i++) { 142 auto item = (*jitCodeVec)[i]; 143 auto machineCode = std::get<0>(item); 144 std::string methodName = std::get<1>(item); 145 uintptr_t pcOffset = std::get<2>(item); 146 auto res = memos.insert(machineCode); 147 if (res.second) { 148 LOG_ECMA(ERROR) << "jit : js crash at method : " << methodName << ", offset :" << pcOffset; 149 char *funcAddr = reinterpret_cast<char *>(machineCode->GetFuncAddr()); 150 size_t len = machineCode->GetTextSize(); 151 std::vector<uint8> vec(len); 152 if (memmove_s(vec.data(), len, funcAddr, len) != EOK) { 153 LOG_ECMA(ERROR) << "Fail to get machineCode on function addr: " << funcAddr; 154 } 155 jitDumpElf.AppendData(vec); 156 jitDumpElf.AppendSymbolToSymTab(idx++, offset, len, methodName); 157 offset += len; 158 } 159 } 160 std::string fileName = "jitCode-" + std::to_string(getpid()); 161 std::string realOutPath; 162 std::string sanboxPath = panda::os::file::File::GetExtendedFilePath(AotCrashInfo::GetSandBoxPath()); 163 if (!ecmascript::RealPath(sanboxPath, realOutPath, false)) { 164 return; 165 } 166 std::string outFile = realOutPath + "/" + fileName; 167 int fd = open(outFile.c_str(), O_RDWR | O_CREAT | O_TRUNC, 0644); 168 jitDumpElf.WriteJitElfFile(fd); 169 close(fd); 170} 171 172void AssembleJitCodeMap(JSThread *thread, const JSHandle<JSObject> &jsErrorObj, JSFunction *func, Method *method, 173 uintptr_t offset) 174{ 175 ASSERT(!jsErrorObj.GetTaggedValue().IsUndefined()); 176 JSTaggedValue machineCodeTagVal = func->GetMachineCode(); 177 MachineCode *machineCode = MachineCode::Cast(machineCodeTagVal.GetTaggedObject()); 178 std::string methodName = method->ParseFunctionName(); 179 if (methodName.empty()) { 180 methodName = "anonymous"; 181 } 182 thread->SetJitCodeMap(jsErrorObj.GetTaggedValue().GetRawData(), machineCode, methodName, offset); 183} 184 185std::string JsStackInfo::BuildJsStackTrace(JSThread *thread, bool needNative, const JSHandle<JSObject> &jsErrorObj) 186{ 187 std::string data; 188 data.reserve(InitialDeeps * InitialLength); 189 JSTaggedType *current = const_cast<JSTaggedType *>(thread->GetCurrentFrame()); 190 FrameIterator it(current, thread); 191 uintptr_t baselineNativePc = 0; 192 193 LastBuilderCache lastCache; 194 for (; !it.Done(); it.Advance<GCVisitedFlag::HYBRID_STACK>()) { 195 if (it.GetFrameType() == FrameType::BASELINE_BUILTIN_FRAME) { 196 auto *frame = it.GetFrame<BaselineBuiltinFrame>(); 197 baselineNativePc = frame->GetReturnAddr(); 198 continue; 199 } 200 if (!it.IsJSFrame()) { 201 continue; 202 } 203 auto method = it.CheckAndGetMethod(); 204 if (method == nullptr) { 205 continue; 206 } 207 if (!method->IsNativeWithCallField()) { 208 uint32_t pcOffset = 0; 209 if (it.GetFrameType() == FrameType::ASM_INTERPRETER_FRAME && baselineNativePc != 0) { 210 // the pcOffste in baseline frame slot is always uint64::max(), so pcOffset should be computed 211 JSHandle<JSFunction> function(thread, it.GetFunction()); 212 pcOffset = RuntimeStubs::RuntimeGetBytecodePcOfstForBaseline(function, baselineNativePc); 213 baselineNativePc = 0; 214 } else { 215 pcOffset = it.GetBytecodeOffset(); 216 } 217 data += BuildJsStackTraceInfo(thread, method, it, pcOffset, jsErrorObj, lastCache); 218 } else if (needNative) { 219 auto addr = method->GetNativePointer(); 220 std::stringstream strm; 221 strm << addr; 222 data.append(" at native method (").append(strm.str()).append(")\n"); 223 } 224 } 225 if (data.empty()) { 226#if defined(ENABLE_EXCEPTION_BACKTRACE) 227 std::ostringstream stack; 228 Backtrace(stack); 229 data = stack.str(); 230#endif 231 } 232 return data; 233} 234 235std::string JsStackInfo::BuildJsStackTraceInfo(JSThread *thread, Method *method, FrameIterator &it, 236 uint32_t pcOffset, const JSHandle<JSObject> &jsErrorObj, 237 LastBuilderCache &lastCache) 238{ 239 const JSPandaFile *pf = method->GetJSPandaFile(); 240 std::map<uint32_t, uint32_t> methodOffsets = it.GetInlinedMethodInfo(); 241 FrameType frameType = it.GetFrameType(); 242 if (IsFastJitFunctionFrame(frameType)) { 243 JSFunction *func = static_cast<JSFunction*>(it.GetFunction().GetTaggedObject()); 244 if (!jsErrorObj.GetTaggedValue().IsUndefined()) { 245 AssembleJitCodeMap(thread, jsErrorObj, func, method, it.GetOptimizedReturnAddr()); 246 } 247 } 248 return BuildInlinedMethodTrace(pf, methodOffsets) + 249 BuildMethodTrace(method, pcOffset, lastCache, thread->GetEnableStackSourceFile()); 250} 251 252void JsStackInfo::BuildCrashInfo(bool isJsCrash, uintptr_t pc, JSThread *thread) 253{ 254 if (JsStackInfo::loader == nullptr || JsStackInfo::options == nullptr) { 255 return; 256 } 257 if (!JsStackInfo::loader->IsEnableAOT() && !Jit::GetInstance()->IsEnableFastJit() && 258 !JsStackInfo::options->IsEnablePGOProfiler()) { 259 return; 260 } 261 ohos::RuntimeInfoType type; 262 if (isJsCrash) { 263 type = ohos::RuntimeInfoType::JS; 264 } else if (pc != 0 && JsStackInfo::loader != nullptr && JsStackInfo::loader->InsideAOT(pc)) { 265 type = ohos::RuntimeInfoType::AOT_CRASH; 266 } else { 267 type = ohos::RuntimeInfoType::OTHERS; 268 } 269 ohos::AotRuntimeInfo::GetInstance().BuildCrashRuntimeInfo(type); 270 if (isJsCrash && thread != nullptr) { 271 DumpJitCode(thread); 272 } 273} 274 275std::vector<struct JsFrameInfo> JsStackInfo::BuildJsStackInfo(JSThread *thread, bool currentStack) 276{ 277 std::vector<struct JsFrameInfo> jsFrame; 278 uintptr_t *native = nullptr; 279 JSTaggedType *current = const_cast<JSTaggedType *>(thread->GetCurrentFrame()); 280 FrameIterator it(current, thread); 281 for (; !it.Done(); it.Advance<GCVisitedFlag::HYBRID_STACK>()) { 282 if (!it.IsJSFrame()) { 283 continue; 284 } 285 auto method = it.CheckAndGetMethod(); 286 if (method == nullptr) { 287 continue; 288 } 289 struct JsFrameInfo frameInfo; 290 if (native != nullptr) { 291 frameInfo.nativePointer = native; 292 native = nullptr; 293 } 294 if (!method->IsNativeWithCallField()) { 295 std::string name = method->ParseFunctionName(); 296 if (name.empty()) { 297 frameInfo.functionName = "anonymous"; 298 } else { 299 frameInfo.functionName = name; 300 } 301 // source file 302 DebugInfoExtractor *debugExtractor = 303 JSPandaFileManager::GetInstance()->GetJSPtExtractor(method->GetJSPandaFile()); 304 const std::string &sourceFile = debugExtractor->GetSourceFile(method->GetMethodId()); 305 if (sourceFile.empty()) { 306 frameInfo.fileName = "?"; 307 } else { 308 frameInfo.fileName = sourceFile; 309 } 310 // line number and column number 311 int lineNumber = 0; 312 auto callbackLineFunc = [&frameInfo, &lineNumber](int32_t line) -> bool { 313 lineNumber = line + 1; 314 frameInfo.pos = std::to_string(lineNumber) + ":"; 315 return true; 316 }; 317 auto callbackColumnFunc = [&frameInfo](int32_t column) -> bool { 318 frameInfo.pos += std::to_string(column + 1); 319 return true; 320 }; 321 panda_file::File::EntityId methodId = method->GetMethodId(); 322 uint32_t offset = it.GetBytecodeOffset(); 323 if (!debugExtractor->MatchLineWithOffset(callbackLineFunc, methodId, offset) || 324 !debugExtractor->MatchColumnWithOffset(callbackColumnFunc, methodId, offset)) { 325 frameInfo.pos = "?"; 326 } 327 jsFrame.push_back(std::move(frameInfo)); 328 if (currentStack) { 329 return jsFrame; 330 } 331 } else { 332 JSTaggedValue function = it.GetFunction(); 333 JSHandle<JSTaggedValue> extraInfoValue( 334 thread, JSFunctionBase::Cast(function.GetTaggedObject())->GetFunctionExtraInfo()); 335 if (extraInfoValue->IsJSNativePointer()) { 336 JSHandle<JSNativePointer> extraInfo(extraInfoValue); 337 native = reinterpret_cast<uintptr_t *>(extraInfo->GetData()); 338 } 339 } 340 } 341 return jsFrame; 342} 343 344bool ReadUintptrFromAddr(int pid, uintptr_t addr, uintptr_t &value, bool needCheckRegion) 345{ 346 if (pid == getpid()) { 347 if (needCheckRegion) { 348 bool flag = false; 349 auto callback = [addr, &flag](Region *region) { 350 uintptr_t regionBegin = region->GetBegin(); 351 uintptr_t regionEnd = region->GetEnd(); 352 if (regionBegin <= addr && addr <= regionEnd) { 353 flag = true; 354 } 355 }; 356 if (JsStackInfo::loader != nullptr) { 357 const Heap *heap = JsStackInfo::loader->GetHeap(); 358 if (heap != nullptr) { 359 heap->EnumerateRegions(callback); 360 } 361 } 362 if (!flag) { 363 LOG_ECMA(ERROR) << "addr not in Region, addr: " << addr; 364 return false; 365 } 366 } 367 value = *(reinterpret_cast<uintptr_t *>(addr)); 368 return true; 369 } 370 long *retAddr = reinterpret_cast<long *>(&value); 371 // note: big endian 372 for (size_t i = 0; i < sizeof(uintptr_t) / sizeof(long); i++) { 373 *retAddr = PtracePeektext(pid, addr); 374 if (*retAddr == -1) { 375 LOG_ECMA(ERROR) << "ReadFromAddr ERROR, addr: " << addr; 376 return false; 377 } 378 addr += sizeof(long); 379 retAddr++; 380 } 381 return true; 382} 383 384bool GetTypeOffsetAndPrevOffsetFromFrameType(uintptr_t frameType, uintptr_t &typeOffset, uintptr_t &prevOffset) 385{ 386 FrameType type = static_cast<FrameType>(frameType); 387 switch (type) { 388 case FrameType::OPTIMIZED_FRAME: 389 typeOffset = OptimizedFrame::GetTypeOffset(); 390 prevOffset = OptimizedFrame::GetPrevOffset(); 391 break; 392 case FrameType::OPTIMIZED_ENTRY_FRAME: 393 typeOffset = OptimizedEntryFrame::GetTypeOffset(); 394 prevOffset = OptimizedEntryFrame::GetLeaveFrameFpOffset(); 395 break; 396 case FrameType::BASELINE_BUILTIN_FRAME: 397 typeOffset = BaselineBuiltinFrame::GetTypeOffset(); 398 prevOffset = BaselineBuiltinFrame::GetPrevOffset(); 399 break; 400 case FrameType::ASM_BRIDGE_FRAME: 401 typeOffset = AsmBridgeFrame::GetTypeOffset(); 402 prevOffset = AsmBridgeFrame::GetPrevOffset(); 403 break; 404 case FrameType::OPTIMIZED_JS_FUNCTION_UNFOLD_ARGV_FRAME: 405 typeOffset = OptimizedJSFunctionUnfoldArgVFrame::GetTypeOffset(); 406 prevOffset = OptimizedJSFunctionUnfoldArgVFrame::GetPrevOffset(); 407 break; 408 case FrameType::OPTIMIZED_JS_FUNCTION_ARGS_CONFIG_FRAME: 409 case FrameType::OPTIMIZED_JS_FAST_CALL_FUNCTION_FRAME: 410 case FrameType::OPTIMIZED_JS_FUNCTION_FRAME: 411 typeOffset = OptimizedJSFunctionFrame::GetTypeOffset(); 412 prevOffset = OptimizedJSFunctionFrame::GetPrevOffset(); 413 break; 414 case FrameType::LEAVE_FRAME: 415 typeOffset = OptimizedLeaveFrame::GetTypeOffset(); 416 prevOffset = OptimizedLeaveFrame::GetPrevOffset(); 417 break; 418 case FrameType::LEAVE_FRAME_WITH_ARGV: 419 typeOffset = OptimizedWithArgvLeaveFrame::GetTypeOffset(); 420 prevOffset = OptimizedWithArgvLeaveFrame::GetPrevOffset(); 421 break; 422 case FrameType::BUILTIN_CALL_LEAVE_FRAME: 423 typeOffset = OptimizedBuiltinLeaveFrame::GetTypeOffset(); 424 prevOffset = OptimizedBuiltinLeaveFrame::GetPrevOffset(); 425 break; 426 case FrameType::INTERPRETER_FRAME: 427 case FrameType::INTERPRETER_FAST_NEW_FRAME: 428 typeOffset = InterpretedFrame::GetTypeOffset(); 429 prevOffset = InterpretedFrame::GetPrevOffset(); 430 break; 431 case FrameType::INTERPRETER_BUILTIN_FRAME: 432 typeOffset = InterpretedBuiltinFrame::GetTypeOffset(); 433 prevOffset = InterpretedBuiltinFrame::GetPrevOffset(); 434 break; 435 case FrameType::INTERPRETER_CONSTRUCTOR_FRAME: 436 case FrameType::ASM_INTERPRETER_FRAME: 437 typeOffset = AsmInterpretedFrame::GetTypeOffset(); 438 prevOffset = AsmInterpretedFrame::GetPrevOffset(); 439 break; 440 case FrameType::BUILTIN_FRAME: 441 case FrameType::BUILTIN_ENTRY_FRAME: 442 typeOffset = BuiltinFrame::GetTypeOffset(); 443 prevOffset = BuiltinFrame::GetPrevOffset(); 444 break; 445 case FrameType::BUILTIN_FRAME_WITH_ARGV: 446 case FrameType::BUILTIN_FRAME_WITH_ARGV_STACK_OVER_FLOW_FRAME: 447 typeOffset = BuiltinWithArgvFrame::GetTypeOffset(); 448 prevOffset = BuiltinWithArgvFrame::GetPrevOffset(); 449 break; 450 case FrameType::INTERPRETER_ENTRY_FRAME: 451 typeOffset = InterpretedEntryFrame::GetTypeOffset(); 452 prevOffset = InterpretedEntryFrame::GetPrevOffset(); 453 break; 454 case FrameType::ASM_INTERPRETER_ENTRY_FRAME: 455 typeOffset = AsmInterpretedEntryFrame::GetTypeOffset(); 456 prevOffset = AsmInterpretedEntryFrame::GetPrevOffset(); 457 break; 458 case FrameType::ASM_INTERPRETER_BRIDGE_FRAME: 459 typeOffset = AsmInterpretedBridgeFrame::GetTypeOffset(); 460 prevOffset = AsmInterpretedBridgeFrame::GetPrevOffset(); 461 break; 462 case FrameType::FASTJIT_FUNCTION_FRAME: 463 case FrameType::FASTJIT_FAST_CALL_FUNCTION_FRAME: 464 typeOffset = FASTJITFunctionFrame::GetTypeOffset(); 465 prevOffset = FASTJITFunctionFrame::GetPrevOffset(); 466 break; 467 default: 468 return false; 469 } 470 return true; 471} 472 473bool ArkFrameCheck(uintptr_t frameType) 474{ 475 return static_cast<FrameType>(frameType) == FrameType::OPTIMIZED_ENTRY_FRAME || 476 static_cast<FrameType>(frameType) == FrameType::ASM_INTERPRETER_ENTRY_FRAME; 477} 478 479bool IsJsFunctionFrame(uintptr_t frameType) 480{ 481 return static_cast<FrameType>(frameType) == FrameType::ASM_INTERPRETER_FRAME || 482 static_cast<FrameType>(frameType) == FrameType::INTERPRETER_CONSTRUCTOR_FRAME || 483 static_cast<FrameType>(frameType) == FrameType::INTERPRETER_FRAME || 484 static_cast<FrameType>(frameType) == FrameType::INTERPRETER_FAST_NEW_FRAME; 485} 486 487bool IsNativeFunctionFrame(uintptr_t frameType) 488{ 489 return static_cast<FrameType>(frameType) == FrameType::OPTIMIZED_FRAME || 490 static_cast<FrameType>(frameType) == FrameType::BASELINE_BUILTIN_FRAME || 491 static_cast<FrameType>(frameType) == FrameType::ASM_BRIDGE_FRAME || 492 static_cast<FrameType>(frameType) == FrameType::OPTIMIZED_JS_FUNCTION_UNFOLD_ARGV_FRAME || 493 static_cast<FrameType>(frameType) == FrameType::OPTIMIZED_JS_FUNCTION_ARGS_CONFIG_FRAME || 494 static_cast<FrameType>(frameType) == FrameType::OPTIMIZED_JS_FAST_CALL_FUNCTION_FRAME || 495 static_cast<FrameType>(frameType) == FrameType::OPTIMIZED_JS_FUNCTION_FRAME || 496 static_cast<FrameType>(frameType) == FrameType::LEAVE_FRAME || 497 static_cast<FrameType>(frameType) == FrameType::LEAVE_FRAME_WITH_ARGV || 498 static_cast<FrameType>(frameType) == FrameType::BUILTIN_CALL_LEAVE_FRAME || 499 static_cast<FrameType>(frameType) == FrameType::BUILTIN_FRAME || 500 static_cast<FrameType>(frameType) == FrameType::BUILTIN_ENTRY_FRAME || 501 static_cast<FrameType>(frameType) == FrameType::BUILTIN_FRAME_WITH_ARGV || 502 static_cast<FrameType>(frameType) == FrameType::BUILTIN_FRAME_WITH_ARGV_STACK_OVER_FLOW_FRAME || 503 static_cast<FrameType>(frameType) == FrameType::ASM_INTERPRETER_BRIDGE_FRAME; 504} 505 506bool IsAotFunctionFrame(uintptr_t frameType) 507{ 508 return static_cast<FrameType>(frameType) == FrameType::OPTIMIZED_JS_FUNCTION_FRAME || 509 static_cast<FrameType>(frameType) == FrameType::OPTIMIZED_JS_FAST_CALL_FUNCTION_FRAME; 510} 511 512std::optional<MethodInfo> JSStackTrace::ReadMethodInfo(panda_file::MethodDataAccessor &mda) 513{ 514 uintptr_t methodId = mda.GetMethodId().GetOffset(); 515 auto codeId = mda.GetCodeId(); 516 if (!codeId) { 517 return std::nullopt; 518 } 519 panda_file::CodeDataAccessor cda(mda.GetPandaFile(), codeId.value()); 520 uint32_t codeSize = cda.GetCodeSize(); 521 uintptr_t codeBegin = reinterpret_cast<uintptr_t>(cda.GetInstructions()); 522 return std::make_optional<MethodInfo>(methodId, codeBegin, codeSize); 523} 524 525CVector<MethodInfo> JSStackTrace::ReadAllMethodInfos(std::shared_ptr<JSPandaFile> jsPandaFile) 526{ 527 CVector<MethodInfo> result; 528 if (jsPandaFile == nullptr) { 529 LOG_ECMA(ERROR) << "Failed to read all methods info."; 530 return result; 531 } 532 const panda_file::File *pf = jsPandaFile->GetPandaFile(); 533 Span<const uint32_t> classIndexes = jsPandaFile->GetClasses(); 534 for (const uint32_t index : classIndexes) { 535 panda_file::File::EntityId classId(index); 536 if (jsPandaFile->IsExternal(classId)) { 537 continue; 538 } 539 panda_file::ClassDataAccessor cda(*pf, classId); 540 cda.EnumerateMethods([&result, jsPandaFile](panda_file::MethodDataAccessor &mda) { 541 auto info = JSStackTrace::ReadMethodInfo(mda); 542 if (!info) { 543 return; 544 } 545 result.push_back(info.value()); 546 }); 547 } 548 549 std::sort(result.begin(), result.end()); 550 return result; 551} 552 553std::optional<CodeInfo> JSStackTrace::TranslateByteCodePc(uintptr_t realPc, const CVector<MethodInfo> &vec) 554{ 555 if (vec.size() == 0) { 556 LOG_ECMA(ERROR) << "Translate bytecode pc failed, vec is empty."; 557 return std::nullopt; 558 } 559 int32_t left = 0; 560 int32_t right = static_cast<int32_t>(vec.size()) - 1; 561 for (; left <= right;) { 562 int32_t mid = (left + right) / 2; 563 bool isRight = realPc >= (vec[mid].codeBegin + vec[mid].codeSize); 564 bool isLeft = realPc < vec[mid].codeBegin; 565 // codeBegin <= realPc < codeBegin + codeSize 566 if (!isRight && !isLeft) { 567 return std::make_optional<CodeInfo>(realPc - vec[mid].codeBegin, vec[mid].methodId, vec[mid].codeSize); 568 } else if (isRight) { 569 left = mid + 1; 570 } else { 571 right = mid -1; 572 } 573 } 574 LOG_ECMA(ERROR) << "Translate bytecode pc failed, pc: " << std::hex << realPc; 575 return std::nullopt; 576} 577 578void SaveFuncName(EntityId entityId, const std::string &name) 579{ 580 size_t length = 256; // maximum stack length 581 if (JsStackInfo::nameMap.size() > length) { 582 auto it = JsStackInfo::nameMap.begin(); 583 JsStackInfo::nameMap.erase(it); 584 } 585 JsStackInfo::nameMap.emplace(entityId, name); 586} 587 588template<typename T> 589void ParseJsFrameInfo(JSPandaFile *jsPandaFile, DebugInfoExtractor *debugExtractor, 590 EntityId methodId, uintptr_t offset, T &jsFrame, SourceMap *sourceMap) 591{ 592 if (jsPandaFile == nullptr) { 593 LOG_ECMA(ERROR) << "Parse jsFrame info failed, jsPandaFile is nullptr."; 594 return; 595 } 596 std::string name = MethodLiteral::ParseFunctionName(jsPandaFile, methodId); 597 name = name.empty() ? "anonymous" : name; 598 SaveFuncName(methodId, name); 599 std::string url = debugExtractor->GetSourceFile(methodId); 600 601 // line number and column number 602 int lineNumber = 0; 603 int columnNumber = 0; 604 auto callbackLineFunc = [&lineNumber](int32_t line) -> bool { 605 lineNumber = line + 1; 606 return true; 607 }; 608 auto callbackColumnFunc = [&columnNumber](int32_t column) -> bool { 609 columnNumber = column + 1; 610 return true; 611 }; 612 613 if (!debugExtractor->MatchLineWithOffset(callbackLineFunc, methodId, offset) || 614 !debugExtractor->MatchColumnWithOffset(callbackColumnFunc, methodId, offset)) { 615 lineNumber = 0; 616 columnNumber = 0; 617 } 618 619 if (sourceMap != nullptr) { 620 sourceMap->TranslateUrlPositionBySourceMap(url, lineNumber, columnNumber); 621 } 622 623 size_t urlSize = url.size() + 1; 624 size_t nameSize = name.size() + 1; 625 if (strcpy_s(jsFrame.url, urlSize, url.c_str()) != EOK || 626 strcpy_s(jsFrame.functionName, nameSize, name.c_str()) != EOK) { 627 LOG_ECMA(FATAL) << "jsFrame strcpy_s failed"; 628 UNREACHABLE(); 629 } 630 jsFrame.line = lineNumber; 631 jsFrame.column = columnNumber; 632} 633 634bool ArkParseJsFrameInfo(uintptr_t byteCodePc, uintptr_t methodId, uintptr_t mapBase, uintptr_t loadOffset, 635 uint8_t *data, uint64_t dataSize, uintptr_t extractorptr, JsFunction *jsFunction) 636{ 637 if (data == nullptr) { 638 LOG_ECMA(ERROR) << "Parse JSframe info failed, buffer is nullptr."; 639 return false; 640 } 641 loadOffset = loadOffset % PageSize(); 642 auto extractor = reinterpret_cast<JSSymbolExtractor*>(extractorptr); 643 if (extractor == nullptr) { 644 LOG_ECMA(ERROR) << "Parse JSframe info failed, extractor is nullptr."; 645 return false; 646 } 647 auto jsPandaFile = extractor->GetJSPandaFile(data, dataSize); 648 if (jsPandaFile == nullptr) { 649 LOG_ECMA(ERROR) << "Parse JSframe info failed, panda file is nullptr."; 650 return false; 651 } 652 auto debugExtractor = extractor->GetDebugExtractor(); 653 auto methodInfos = extractor->GetMethodInfos(); 654 if (methodInfos.empty()) { 655 LOG_ECMA(ERROR) << "Read all method info from JSPandaFile failed, methodInfos is empty."; 656 return false; 657 } 658 uintptr_t realOffset = byteCodePc - mapBase - loadOffset; 659 uintptr_t pfBasePtr = reinterpret_cast<uintptr_t>(jsPandaFile->GetBase()); 660 auto codeInfo = JSStackTrace::TranslateByteCodePc(realOffset + pfBasePtr, methodInfos); 661 if (!codeInfo) { 662 LOG_ECMA(ERROR) << std::hex << "Failed to get methodId, pc: " << byteCodePc; 663 return false; 664 } 665 if (!methodId) { 666 methodId = codeInfo->methodId; 667 } 668 auto offset = codeInfo->offset; 669 ParseJsFrameInfo(jsPandaFile, debugExtractor, EntityId(methodId), offset, *jsFunction, extractor->GetSourceMap()); 670 671 jsFunction->codeBegin = byteCodePc - offset; 672 jsFunction->codeSize = codeInfo->codeSize; 673 return true; 674} 675 676bool ArkTranslateJsFrameInfo(uint8_t *data, size_t dataSize, JsFunction *jsFunction) 677{ 678 SourceMap sourceMap; 679 std::string strUrl = jsFunction->url; 680 sourceMap.Init(data, dataSize); 681 bool ret = sourceMap.TranslateUrlPositionBySourceMap(strUrl, jsFunction->line, jsFunction->column); 682 size_t strUrlSize = strUrl.size() + 1; 683 if (strcpy_s(jsFunction->url, strUrlSize, strUrl.c_str()) != EOK) { 684 LOG_FULL(FATAL) << "strcpy_s failed"; 685 UNREACHABLE(); 686 } 687 return ret; 688} 689 690uintptr_t GetBytecodeOffset(void *ctx, ReadMemFunc readMem, uintptr_t frameType, uintptr_t currentPtr) 691{ 692 // currentPtr points to the frametype. 693 uintptr_t bytecodePc = 0; 694 FrameType type = static_cast<FrameType>(frameType); 695 switch (type) { 696 // return bytecode pc 697 case FrameType::ASM_INTERPRETER_FRAME: 698 case FrameType::INTERPRETER_CONSTRUCTOR_FRAME: { 699 currentPtr -= AsmInterpretedFrame::GetTypeOffset(); 700 currentPtr += AsmInterpretedFrame::GetPcOffset(false); 701 readMem(ctx, currentPtr, &bytecodePc); 702 return bytecodePc; 703 } 704 case FrameType::INTERPRETER_FRAME: 705 case FrameType::INTERPRETER_FAST_NEW_FRAME: { 706 currentPtr -= InterpretedFrame::GetTypeOffset(); 707 currentPtr += InterpretedFrame::GetPcOffset(false); 708 readMem(ctx, currentPtr, &bytecodePc); 709 return bytecodePc; 710 } 711 case FrameType::FASTJIT_FUNCTION_FRAME: 712 case FrameType::FASTJIT_FAST_CALL_FUNCTION_FRAME: { 713 currentPtr -= FASTJITFunctionFrame::GetTypeOffset(); 714 readMem(ctx, currentPtr, &bytecodePc); 715 return bytecodePc; 716 } 717 // return returnaddr 718 case FrameType::OPTIMIZED_JS_FAST_CALL_FUNCTION_FRAME: 719 case FrameType::OPTIMIZED_JS_FUNCTION_FRAME: 720 case FrameType::OPTIMIZED_JS_FUNCTION_ARGS_CONFIG_FRAME: { 721 currentPtr -= OptimizedJSFunctionFrame::GetTypeOffset(); 722 currentPtr += OptimizedJSFunctionFrame::GetReturnAddrOffset(); 723 readMem(ctx, currentPtr, &bytecodePc); 724 return bytecodePc; 725 } 726 case FrameType::BUILTIN_FRAME: 727 case FrameType::BUILTIN_ENTRY_FRAME: { 728 currentPtr -= BuiltinFrame::GetTypeOffset(); 729 currentPtr += BuiltinFrame::GetReturnAddrOffset(); 730 readMem(ctx, currentPtr, &bytecodePc); 731 return bytecodePc; 732 } 733 case FrameType::BUILTIN_FRAME_WITH_ARGV: 734 case FrameType::BUILTIN_FRAME_WITH_ARGV_STACK_OVER_FLOW_FRAME: { 735 currentPtr -= BuiltinWithArgvFrame::GetTypeOffset(); 736 currentPtr += BuiltinWithArgvFrame::GetReturnAddrOffset(); 737 readMem(ctx, currentPtr, &bytecodePc); 738 return bytecodePc; 739 } 740 case FrameType::BASELINE_BUILTIN_FRAME: { 741 currentPtr -= BaselineBuiltinFrame::GetTypeOffset(); 742 currentPtr += BaselineBuiltinFrame::GetReturnAddrOffset(); 743 readMem(ctx, currentPtr, &bytecodePc); 744 return bytecodePc; 745 } 746 case FrameType::ASM_BRIDGE_FRAME: { 747 currentPtr -= AsmBridgeFrame::GetTypeOffset(); 748 currentPtr += AsmBridgeFrame::GetReturnAddrOffset(); 749 readMem(ctx, currentPtr, &bytecodePc); 750 return bytecodePc; 751 } 752 case FrameType::LEAVE_FRAME: { 753 currentPtr -= OptimizedLeaveFrame::GetTypeOffset(); 754 currentPtr += OptimizedLeaveFrame::GetReturnAddrOffset(); 755 readMem(ctx, currentPtr, &bytecodePc); 756 return bytecodePc; 757 } 758 case FrameType::LEAVE_FRAME_WITH_ARGV: { 759 currentPtr -= OptimizedWithArgvLeaveFrame::GetTypeOffset(); 760 currentPtr += OptimizedWithArgvLeaveFrame::GetReturnAddrOffset(); 761 readMem(ctx, currentPtr, &bytecodePc); 762 return bytecodePc; 763 } 764 case FrameType::BUILTIN_CALL_LEAVE_FRAME: { 765 currentPtr -= OptimizedBuiltinLeaveFrame::GetTypeOffset(); 766 currentPtr += OptimizedBuiltinLeaveFrame::GetReturnAddrOffset(); 767 readMem(ctx, currentPtr, &bytecodePc); 768 return bytecodePc; 769 } 770 case FrameType::OPTIMIZED_FRAME: { 771 currentPtr -= OptimizedFrame::GetTypeOffset(); 772 currentPtr += OptimizedFrame::GetReturnAddrOffset(); 773 readMem(ctx, currentPtr, &bytecodePc); 774 return bytecodePc; 775 } 776 case FrameType::ASM_INTERPRETER_BRIDGE_FRAME: { 777 currentPtr -= AsmInterpretedBridgeFrame::GetTypeOffset(); 778 currentPtr += AsmInterpretedBridgeFrame::GetReturnAddrOffset(false); 779 readMem(ctx, currentPtr, &bytecodePc); 780 return bytecodePc; 781 } 782 case FrameType::OPTIMIZED_JS_FUNCTION_UNFOLD_ARGV_FRAME: { 783 currentPtr -= OptimizedJSFunctionUnfoldArgVFrame::GetTypeOffset(); 784 currentPtr += OptimizedJSFunctionUnfoldArgVFrame::GetReturnAddrOffset(); 785 readMem(ctx, currentPtr, &bytecodePc); 786 return bytecodePc; 787 } 788 default: { 789 break; 790 } 791 } 792 return 0; 793} 794 795uintptr_t ArkGetFunction(void *ctx, ReadMemFunc readMem, uintptr_t currentPtr, uintptr_t frameType) 796{ 797 FrameType type = static_cast<FrameType>(frameType); 798 uintptr_t funcAddr = currentPtr; 799 switch (type) { 800 case FrameType::OPTIMIZED_JS_FAST_CALL_FUNCTION_FRAME: 801 case FrameType::OPTIMIZED_JS_FUNCTION_FRAME: { 802 funcAddr -= OptimizedJSFunctionFrame::GetTypeOffset(); 803 funcAddr += OptimizedJSFunctionFrame::GetFunctionOffset(); 804 break; 805 } 806 case FrameType::ASM_INTERPRETER_FRAME: 807 case FrameType::INTERPRETER_CONSTRUCTOR_FRAME: { 808 funcAddr -= AsmInterpretedFrame::GetTypeOffset(); 809 funcAddr += AsmInterpretedFrame::GetFunctionOffset(false); 810 break; 811 } 812 case FrameType::INTERPRETER_FRAME: 813 case FrameType::INTERPRETER_FAST_NEW_FRAME: { 814 funcAddr -= InterpretedFrame::GetTypeOffset(); 815 funcAddr += InterpretedFrame::GetFunctionOffset(); 816 break; 817 } 818 case FrameType::FASTJIT_FUNCTION_FRAME: 819 case FrameType::FASTJIT_FAST_CALL_FUNCTION_FRAME: { 820 funcAddr -= FASTJITFunctionFrame::GetTypeOffset(); 821 funcAddr += FASTJITFunctionFrame::GetFunctionOffset(); 822 break; 823 } 824 default: { 825 return 0; 826 } 827 } 828 uintptr_t function = 0; 829 if (!readMem(ctx, funcAddr, &function)) { 830 return 0; 831 } 832 return function; 833} 834 835bool ArkCheckIsJSFunctionBaseOrJSProxy(void *ctx, ReadMemFunc readMem, uintptr_t objAddr, bool &isJSFunctionBase) 836{ 837 bool isHeapObj = ((objAddr & JSTaggedValue::TAG_HEAPOBJECT_MASK) == 0U); 838 bool isInvalidValue = (objAddr <= JSTaggedValue::INVALID_VALUE_LIMIT); 839 if (isHeapObj && !isInvalidValue) { 840 ASSERT_PRINT(((objAddr & JSTaggedValue::TAG_WEAK) == 0U), 841 "can not convert JSTaggedValue to HeapObject :" << std::hex << objAddr); 842 uintptr_t hclassAddr = objAddr + TaggedObject::HCLASS_OFFSET; 843 uintptr_t hclass = 0; 844 if (!readMem(ctx, hclassAddr, &hclass)) { 845 return false; 846 } 847 if (hclass != 0) { 848 uintptr_t bitsAddr = reinterpret_cast<uintptr_t>(hclass + JSHClass::BIT_FIELD_OFFSET); 849 uintptr_t bits = 0; 850 if (!readMem(ctx, bitsAddr, &bits)) { 851 return false; 852 } 853 JSType jsType = JSHClass::ObjectTypeBits::Decode(bits); 854 isJSFunctionBase = (jsType >= JSType::JS_FUNCTION_BASE && jsType <= JSType::JS_BOUND_FUNCTION); 855 bool isJSProxy = (jsType == JSType::JS_PROXY); 856 return isJSFunctionBase || isJSProxy; 857 } 858 } 859 return false; 860} 861 862uintptr_t ArkCheckAndGetMethod(void *ctx, ReadMemFunc readMem, uintptr_t value) 863{ 864 bool isJSFunctionBase = 0; 865 if (ArkCheckIsJSFunctionBaseOrJSProxy(ctx, readMem, value, isJSFunctionBase)) { 866 if (isJSFunctionBase) { 867 value += JSFunctionBase::METHOD_OFFSET; 868 } else { 869 value += JSProxy::METHOD_OFFSET; 870 } 871 uintptr_t method = 0; 872 if (!readMem(ctx, value, &method)) { 873 return 0; 874 } 875 return method; 876 } 877 return 0; 878} 879 880bool ArkGetMethodIdFromMethod(void *ctx, ReadMemFunc readMem, uintptr_t method, uintptr_t &methodId) 881{ 882 uintptr_t methodLiteralAddr = method + Method::LITERAL_INFO_OFFSET; 883 uintptr_t methodLiteral = 0; 884 if (!readMem(ctx, methodLiteralAddr, &methodLiteral)) { 885 return false; 886 } 887 methodId = MethodLiteral::MethodIdBits::Decode(methodLiteral); 888 return true; 889} 890 891bool ArkGetMethodId(void *ctx, ReadMemFunc readMem, uintptr_t frameType, uintptr_t currentPtr, uintptr_t &methodId) 892{ 893 uintptr_t function = ArkGetFunction(ctx, readMem, currentPtr, frameType); 894 if (!function) { 895 LOG_ECMA(DEBUG) << "Failed to get function"; 896 return false; 897 } 898 899 uintptr_t method = ArkCheckAndGetMethod(ctx, readMem, function); 900 if (!method) { 901 LOG_ECMA(DEBUG) << std::hex << "Failed to get method: " << function; 902 return false; 903 } 904 905 if (!ArkGetMethodIdFromMethod(ctx, readMem, method, methodId)) { 906 LOG_ECMA(DEBUG) << std::hex << "ArkGetJsFrameDebugInfo failed, method: " << method; 907 return false; 908 } 909 return true; 910} 911 912bool ArkGetNextFrame(void *ctx, ReadMemFunc readMem, uintptr_t ¤tPtr, 913 uintptr_t &frameType, uintptr_t &pc, uintptr_t *methodId) 914{ 915 currentPtr -= sizeof(FrameType); 916 if (!readMem(ctx, currentPtr, &frameType)) { 917 return false; 918 } 919 if (ArkFrameCheck(frameType)) { 920 return true; 921 } 922 bool ret = false; 923 if (IsJsFunctionFrame(frameType)) { 924 pc = GetBytecodeOffset(ctx, readMem, frameType, currentPtr); 925 ret = true; 926 if (methodId != nullptr) { 927 ret = ArkGetMethodId(ctx, readMem, frameType, currentPtr, *methodId); 928 } 929 } else if (IsNativeFunctionFrame(frameType)) { 930 pc = GetBytecodeOffset(ctx, readMem, frameType, currentPtr); 931 ret = true; 932 } 933 934 uintptr_t typeOffset = 0; 935 uintptr_t prevOffset = 0; 936 if (!GetTypeOffsetAndPrevOffsetFromFrameType(frameType, typeOffset, prevOffset)) { 937 return false; 938 } 939 currentPtr -= typeOffset; 940 currentPtr += prevOffset; 941 if (!readMem(ctx, currentPtr, ¤tPtr)) { 942 return false; 943 } 944 945 if (ret) { 946 return true; 947 } 948 return ArkGetNextFrame(ctx, readMem, currentPtr, frameType, pc, methodId); 949} 950 951bool ArkGetMethodIdWithJit(ArkUnwindParam *arkUnwindParam, uintptr_t frameType, uintptr_t currentPtr) 952{ 953 uintptr_t function = ArkGetFunction(arkUnwindParam->ctx, arkUnwindParam->readMem, currentPtr, frameType); 954 if (!function) { 955 LOG_ECMA(DEBUG) << "Failed to get function"; 956 return false; 957 } 958 959 uintptr_t method = ArkCheckAndGetMethod(arkUnwindParam->ctx, arkUnwindParam->readMem, function); 960 if (!method) { 961 LOG_ECMA(DEBUG) << std::hex << "Failed to get method: " << function; 962 return false; 963 } 964 965 if (!ArkGetMethodIdFromMethod(arkUnwindParam->ctx, arkUnwindParam->readMem, method, *arkUnwindParam->methodId)) { 966 LOG_ECMA(DEBUG) << std::hex << "ArkGetJsFrameDebugInfo failed, method: " << method; 967 return false; 968 } 969 970 if (IsFastJitFunctionFrame(frameType)) { 971 uintptr_t machineCode = 0; 972 uintptr_t functionAddr = function + JSFunction::MACHINECODE_OFFSET; 973 arkUnwindParam->readMem(arkUnwindParam->ctx, functionAddr, &machineCode); 974 uintptr_t size = 0; 975 uintptr_t funcAddr = 0; 976 if (machineCode) { 977 arkUnwindParam->readMem(arkUnwindParam->ctx, machineCode + MachineCode::INSTRSIZ_OFFSET, &size); 978 arkUnwindParam->readMem(arkUnwindParam->ctx, machineCode + MachineCode::FUNCADDR_OFFSET, &funcAddr); 979 } 980 if (size && funcAddr) { 981 // take the lower four bytes 982 size &= 0xFFFFFFFF; 983 std::vector<uint8> codeVec; 984 for (size_t l = 0; l < size; l++) { 985 uintptr_t tmp = 0; 986 arkUnwindParam->readMem(arkUnwindParam->ctx, funcAddr + l, &tmp); 987 codeVec.push_back(tmp); 988 } 989 arkUnwindParam->jitCache.push_back(*arkUnwindParam->methodId); 990 JsStackInfo::machineCodeMap[EntityId(*arkUnwindParam->methodId)] = codeVec; 991 } 992 } 993 return true; 994} 995 996bool ArkGetNextFrameWithJit(ArkUnwindParam *arkUnwindParam, uintptr_t ¤tPtr, uintptr_t &frameType) 997{ 998 currentPtr -= sizeof(FrameType); 999 if (!arkUnwindParam->readMem(arkUnwindParam->ctx, currentPtr, &frameType)) { 1000 return false; 1001 } 1002 if (ArkFrameCheck(frameType)) { 1003 return true; 1004 } 1005 bool ret = false; 1006 if (IsJsFunctionFrame(frameType) || 1007 IsFastJitFunctionFrame(frameType)) { 1008 *arkUnwindParam->pc = GetBytecodeOffset(arkUnwindParam->ctx, arkUnwindParam->readMem, frameType, currentPtr); 1009 ret = true; 1010 if (arkUnwindParam->methodId != nullptr) { 1011 ret = ArkGetMethodIdWithJit(arkUnwindParam, frameType, currentPtr); 1012 } 1013 } else if (IsNativeFunctionFrame(frameType)) { 1014 *arkUnwindParam->pc = GetBytecodeOffset(arkUnwindParam->ctx, arkUnwindParam->readMem, frameType, currentPtr); 1015 ret = true; 1016 } 1017 1018 uintptr_t typeOffset = 0; 1019 uintptr_t prevOffset = 0; 1020 if (!GetTypeOffsetAndPrevOffsetFromFrameType(frameType, typeOffset, prevOffset)) { 1021 return false; 1022 } 1023 currentPtr -= typeOffset; 1024 currentPtr += prevOffset; 1025 if (!arkUnwindParam->readMem(arkUnwindParam->ctx, currentPtr, ¤tPtr)) { 1026 return false; 1027 } 1028 1029 if (ret) { 1030 return true; 1031 } 1032 return ArkGetNextFrameWithJit(arkUnwindParam, currentPtr, frameType); 1033} 1034 1035bool ArkWriteJitCode([[maybe_unused]] void *ctx, [[maybe_unused]] ReadMemFunc readMem, 1036 int fd, const uintptr_t *const jitCodeArray, const size_t jitSize) 1037{ 1038 JsJitDumpElf jitDumpElf; 1039 jitDumpElf.Init(); 1040 std::set<uintptr_t> memos; 1041 int64 idx = 0; 1042 size_t offset = 0; 1043 for (size_t i = 0; i < jitSize; i++) { 1044 uintptr_t methodId = jitCodeArray[i]; 1045 auto res = memos.insert(methodId); 1046 if (res.second) { 1047 std::vector<uint8> codeVec = JsStackInfo::machineCodeMap[EntityId(methodId)]; 1048 std::string name = JsStackInfo::nameMap[EntityId(methodId)]; 1049 size_t len = codeVec.size(); 1050 jitDumpElf.AppendData(codeVec); 1051 jitDumpElf.AppendSymbolToSymTab(idx++, offset, len, name); 1052 offset += len; 1053 } 1054 } 1055 jitDumpElf.WriteJitElfFile(fd); 1056 JsStackInfo::nameMap.clear(); 1057 JsStackInfo::machineCodeMap.clear(); 1058 return true; 1059} 1060 1061bool StepArkWithRecordJit(ArkUnwindParam *arkUnwindParam) 1062{ 1063 constexpr size_t FP_SIZE = sizeof(uintptr_t); 1064 uintptr_t currentPtr = *arkUnwindParam->fp; 1065 if (currentPtr == 0) { 1066 LOG_ECMA(ERROR) << "fp is nullptr in StepArkWithRecordJit()!"; 1067 return false; 1068 } 1069 1070 uintptr_t frameType = 0; 1071 if (ArkGetNextFrameWithJit(arkUnwindParam, currentPtr, frameType)) { 1072 if (ArkFrameCheck(frameType)) { 1073 currentPtr += sizeof(FrameType); 1074 *arkUnwindParam->sp = currentPtr; 1075 bool ret = arkUnwindParam->readMem(arkUnwindParam->ctx, currentPtr, arkUnwindParam->fp); 1076 currentPtr += FP_SIZE; 1077 ret &= arkUnwindParam->readMem(arkUnwindParam->ctx, currentPtr, arkUnwindParam->pc); 1078 *arkUnwindParam->isJsFrame = false; 1079 return ret; 1080 } else { 1081 *arkUnwindParam->fp = currentPtr; 1082 *arkUnwindParam->sp = currentPtr; 1083 // js && jit -> true, native -> false 1084 *arkUnwindParam->isJsFrame = IsJsFunctionFrame(frameType) || 1085 IsFastJitFunctionFrame(frameType); 1086 } 1087 } else { 1088 LOG_ECMA(ERROR) << "ArkGetNextFrame failed, currentPtr: " << currentPtr << ", frameType: " << frameType; 1089 return false; 1090 } 1091 return true; 1092} 1093 1094bool StepArk(void *ctx, ReadMemFunc readMem, uintptr_t *fp, uintptr_t *sp, 1095 uintptr_t *pc, uintptr_t *methodId, bool *isJsFrame) 1096{ 1097 constexpr size_t FP_SIZE = sizeof(uintptr_t); 1098 uintptr_t currentPtr = *fp; 1099 if (currentPtr == 0) { 1100 LOG_ECMA(ERROR) << "fp is nullptr in StepArk()!"; 1101 return false; 1102 } 1103 1104 uintptr_t frameType = 0; 1105 if (ArkGetNextFrame(ctx, readMem, currentPtr, frameType, *pc, methodId)) { 1106 if (ArkFrameCheck(frameType)) { 1107 currentPtr += sizeof(FrameType); 1108 *sp = currentPtr; 1109 bool ret = readMem(ctx, currentPtr, fp); 1110 currentPtr += FP_SIZE; 1111 ret &= readMem(ctx, currentPtr, pc); 1112 *isJsFrame = false; 1113 return ret; 1114 } else { 1115 *fp = currentPtr; 1116 *sp = currentPtr; 1117 // js -> true, native -> false 1118 *isJsFrame = IsJsFunctionFrame(frameType); 1119 } 1120 } else { 1121 LOG_ECMA(ERROR) << std::hex << "ArkGetNextFrame failed, addr: " << currentPtr; 1122 return false; 1123 } 1124 1125 return true; 1126} 1127 1128uintptr_t ArkGetFunction(int pid, uintptr_t currentPtr, uintptr_t frameType) 1129{ 1130 FrameType type = static_cast<FrameType>(frameType); 1131 uintptr_t funcAddr = currentPtr; 1132 switch (type) { 1133 case FrameType::OPTIMIZED_JS_FAST_CALL_FUNCTION_FRAME: 1134 case FrameType::OPTIMIZED_JS_FUNCTION_FRAME: { 1135 funcAddr -= OptimizedJSFunctionFrame::GetTypeOffset(); 1136 funcAddr += OptimizedJSFunctionFrame::GetFunctionOffset(); 1137 break; 1138 } 1139 case FrameType::ASM_INTERPRETER_FRAME: 1140 case FrameType::INTERPRETER_CONSTRUCTOR_FRAME: { 1141 funcAddr -= AsmInterpretedFrame::GetTypeOffset(); 1142 funcAddr += AsmInterpretedFrame::GetFunctionOffset(false); 1143 break; 1144 } 1145 case FrameType::INTERPRETER_FRAME: 1146 case FrameType::INTERPRETER_FAST_NEW_FRAME: { 1147 funcAddr -= InterpretedFrame::GetTypeOffset(); 1148 funcAddr += InterpretedFrame::GetFunctionOffset(); 1149 break; 1150 } 1151 case FrameType::INTERPRETER_BUILTIN_FRAME: { 1152 funcAddr -= InterpretedBuiltinFrame::GetTypeOffset(); 1153 funcAddr += InterpretedBuiltinFrame::GetFunctionOffset(); 1154 break; 1155 } 1156 case FrameType::BUILTIN_FRAME_WITH_ARGV: { 1157 funcAddr += sizeof(FrameType); 1158 auto topAddress = funcAddr + 1159 (static_cast<int>(BuiltinWithArgvFrame::Index::StackArgsTopIndex) * sizeof(uintptr_t)); 1160 uintptr_t argcAddress = static_cast<uintptr_t>(funcAddr + (static_cast<int> 1161 (BuiltinWithArgvFrame::Index::NumArgsIndex) * sizeof(uintptr_t))); 1162 if (!ReadUintptrFromAddr(pid, argcAddress, argcAddress, g_needCheck)) { 1163 return 0; 1164 } 1165 auto numberArgs = argcAddress + NUM_MANDATORY_JSFUNC_ARGS; 1166 funcAddr = topAddress - static_cast<uint32_t>(numberArgs) * sizeof(uintptr_t); 1167 break; 1168 } 1169 case FrameType::BUILTIN_ENTRY_FRAME: 1170 case FrameType::BUILTIN_FRAME: { 1171 funcAddr -= BuiltinFrame::GetTypeOffset(); 1172 funcAddr += BuiltinFrame::GetStackArgsOffset(); 1173 break; 1174 } 1175 case FrameType::BUILTIN_CALL_LEAVE_FRAME: { 1176 funcAddr -= OptimizedBuiltinLeaveFrame::GetTypeOffset(); 1177 funcAddr += OptimizedBuiltinLeaveFrame::GetFunctionOffset(); 1178 break; 1179 } 1180 case FrameType::FASTJIT_FUNCTION_FRAME: 1181 case FrameType::FASTJIT_FAST_CALL_FUNCTION_FRAME: { 1182 funcAddr -= FASTJITFunctionFrame::GetTypeOffset(); 1183 funcAddr += FASTJITFunctionFrame::GetFunctionOffset(); 1184 break; 1185 } 1186 case FrameType::BUILTIN_FRAME_WITH_ARGV_STACK_OVER_FLOW_FRAME : 1187 case FrameType::OPTIMIZED_FRAME: 1188 case FrameType::OPTIMIZED_ENTRY_FRAME: 1189 case FrameType::ASM_BRIDGE_FRAME: 1190 case FrameType::LEAVE_FRAME: 1191 case FrameType::LEAVE_FRAME_WITH_ARGV: 1192 case FrameType::INTERPRETER_ENTRY_FRAME: 1193 case FrameType::ASM_INTERPRETER_ENTRY_FRAME: 1194 case FrameType::ASM_INTERPRETER_BRIDGE_FRAME: 1195 case FrameType::OPTIMIZED_JS_FUNCTION_ARGS_CONFIG_FRAME: 1196 case FrameType::OPTIMIZED_JS_FUNCTION_UNFOLD_ARGV_FRAME: { 1197 return 0; 1198 } 1199 default: { 1200 LOG_FULL(FATAL) << "Unknown frame type: " << static_cast<uintptr_t>(type); 1201 UNREACHABLE(); 1202 } 1203 } 1204 uintptr_t function = 0; 1205 if (!ReadUintptrFromAddr(pid, funcAddr, function, g_needCheck)) { 1206 return 0; 1207 } 1208 return function; 1209} 1210 1211bool ArkCheckIsJSFunctionBaseOrJSProxy(int pid, uintptr_t objAddr, bool &isJSFunctionBase) 1212{ 1213 bool isHeapObj = ((objAddr & JSTaggedValue::TAG_HEAPOBJECT_MASK) == 0U); 1214 bool isInvalidValue = (objAddr <= JSTaggedValue::INVALID_VALUE_LIMIT); 1215 if (isHeapObj && !isInvalidValue) { 1216 ASSERT_PRINT(((objAddr & JSTaggedValue::TAG_WEAK) == 0U), 1217 "can not convert JSTaggedValue to HeapObject :" << std::hex << objAddr); 1218 uintptr_t hclassAddr = objAddr + TaggedObject::HCLASS_OFFSET; 1219 uintptr_t hclass = 0; 1220 if (!ReadUintptrFromAddr(pid, hclassAddr, hclass, g_needCheck)) { 1221 return false; 1222 } 1223 if (hclass != 0) { 1224 uintptr_t bitsAddr = reinterpret_cast<uintptr_t>(hclass + JSHClass::BIT_FIELD_OFFSET); 1225 uintptr_t bits = 0; 1226 if (!ReadUintptrFromAddr(pid, bitsAddr, bits, g_needCheck)) { 1227 return false; 1228 } 1229 JSType jsType = JSHClass::ObjectTypeBits::Decode(bits); 1230 isJSFunctionBase = (jsType >= JSType::JS_FUNCTION_BASE && jsType <= JSType::JS_BOUND_FUNCTION); 1231 bool isJSProxy = (jsType == JSType::JS_PROXY); 1232 return isJSFunctionBase || isJSProxy; 1233 } 1234 } 1235 return false; 1236} 1237 1238uintptr_t ArkCheckAndGetMethod(int pid, uintptr_t value) 1239{ 1240 bool isJSFunctionBase = 0; 1241 if (ArkCheckIsJSFunctionBaseOrJSProxy(pid, value, isJSFunctionBase)) { 1242 if (isJSFunctionBase) { 1243 value += JSFunctionBase::METHOD_OFFSET; 1244 } else { 1245 value += JSProxy::METHOD_OFFSET; 1246 } 1247 uintptr_t method = 0; 1248 if (!ReadUintptrFromAddr(pid, value, method, g_needCheck)) { 1249 return 0; 1250 } 1251 return method; 1252 } 1253 return 0; 1254} 1255 1256bool ArkGetMethodIdandJSPandaFileAddr(int pid, uintptr_t method, uintptr_t &methodId, uintptr_t &jsPandaFileAddr) 1257{ 1258 uintptr_t methodLiteralAddr = method + Method::LITERAL_INFO_OFFSET; 1259 uintptr_t methodLiteral = 0; 1260 if (!ReadUintptrFromAddr(pid, methodLiteralAddr, methodLiteral, g_needCheck)) { 1261 return false; 1262 } 1263 methodId = MethodLiteral::MethodIdBits::Decode(methodLiteral); 1264 uintptr_t constantpoolAddr = method + Method::CONSTANT_POOL_OFFSET; 1265 uintptr_t constantpool = 0; 1266 if (!ReadUintptrFromAddr(pid, constantpoolAddr, constantpool, g_needCheck)) { 1267 return false; 1268 } 1269 if (constantpool == JSTaggedValue::VALUE_UNDEFINED) { 1270 return false; 1271 } 1272 uintptr_t lengthAddr = constantpool + TaggedArray::LENGTH_OFFSET; 1273 uintptr_t length = 0; 1274 if (!ReadUintptrFromAddr(pid, lengthAddr, length, g_needCheck)) { 1275 return false; 1276 } 1277 jsPandaFileAddr = constantpool + TaggedArray::DATA_OFFSET + 1278 JSTaggedValue::TaggedTypeSize() * (length - ConstantPool::JS_PANDA_FILE_INDEX); 1279 if (!ReadUintptrFromAddr(pid, jsPandaFileAddr, jsPandaFileAddr, g_needCheck)) { 1280 return false; 1281 } 1282 return true; 1283} 1284 1285uint32_t ArkGetOffsetFromMethod(int pid, uintptr_t currentPtr, uintptr_t method) 1286{ 1287 uintptr_t pc = 0; 1288 if (!ReadUintptrFromAddr(pid, currentPtr, pc, g_needCheck)) { 1289 return 0; 1290 } 1291 uintptr_t byteCodeArrayAddr = method + Method::NATIVE_POINTER_OR_BYTECODE_ARRAY_OFFSET; 1292 uintptr_t byteCodeArray = 0; 1293 if (!ReadUintptrFromAddr(pid, byteCodeArrayAddr, byteCodeArray, g_needCheck)) { 1294 return 0; 1295 } 1296 uintptr_t offset = pc - byteCodeArray; 1297 return static_cast<uint32_t>(offset); 1298} 1299 1300uint32_t ArkGetBytecodeOffset(int pid, uintptr_t method, uintptr_t frameType, uintptr_t currentPtr) 1301{ 1302 FrameType type = static_cast<FrameType>(frameType); 1303 switch (type) { 1304 case FrameType::ASM_INTERPRETER_FRAME: 1305 case FrameType::INTERPRETER_CONSTRUCTOR_FRAME: { 1306 currentPtr -= AsmInterpretedFrame::GetTypeOffset(); 1307 currentPtr += AsmInterpretedFrame::GetPcOffset(false); 1308 return ArkGetOffsetFromMethod(pid, currentPtr, method); 1309 } 1310 case FrameType::INTERPRETER_FRAME: 1311 case FrameType::INTERPRETER_FAST_NEW_FRAME: { 1312 currentPtr -= InterpretedFrame::GetTypeOffset(); 1313 currentPtr += InterpretedFrame::GetPcOffset(false); 1314 return ArkGetOffsetFromMethod(pid, currentPtr, method); 1315 } 1316 // aot need stackmaps 1317 case FrameType::OPTIMIZED_JS_FAST_CALL_FUNCTION_FRAME: 1318 case FrameType::OPTIMIZED_JS_FUNCTION_FRAME: 1319 case FrameType::FASTJIT_FUNCTION_FRAME: 1320 case FrameType::FASTJIT_FAST_CALL_FUNCTION_FRAME: { 1321 break; 1322 } 1323 default: { 1324 break; 1325 } 1326 } 1327 return 0; 1328} 1329 1330std::string ArkGetFilePath(std::string &fileName) 1331{ 1332 auto lastSlash = fileName.rfind("/"); 1333 if (lastSlash == std::string::npos) { 1334 LOG_ECMA(ERROR) << "ArkGetFilePath can't find fisrt /: " << fileName; 1335 return ""; 1336 } 1337 if (lastSlash == 0) { 1338 LOG_ECMA(ERROR) << "ArkGetFilePath can't find second /: " << fileName; 1339 return ""; 1340 } 1341 1342 auto secondLastSlash = fileName.rfind("/", lastSlash - 1); 1343 if (secondLastSlash == std::string::npos) { 1344 LOG_ECMA(ERROR) << "ArkGetFilePath can't find second /: " << fileName; 1345 return ""; 1346 } 1347 1348 std::string mapPath = fileName.substr(secondLastSlash + 1); 1349 return mapPath; 1350} 1351 1352bool ArkIsNativeWithCallField(int pid, uintptr_t method) 1353{ 1354 uintptr_t callFieldAddr = method + Method::CALL_FIELD_OFFSET; 1355 uintptr_t callField = 0; 1356 if (!ReadUintptrFromAddr(pid, callFieldAddr, callField, g_needCheck)) { 1357 return true; 1358 } 1359 return Method::IsNativeBit::Decode(callField); 1360} 1361 1362std::string ArkReadCStringFromAddr(int pid, uintptr_t descAddr) 1363{ 1364 std::string name; 1365 bool key = true; 1366 while (key) { 1367 uintptr_t desc = 0; 1368 if (!ReadUintptrFromAddr(pid, descAddr, desc, g_needCheck)) { 1369 LOG_ECMA(ERROR) << "ArkReadCStringFromAddr failed, descAddr: " << descAddr; 1370 return name; 1371 } 1372 size_t shiftAmount = 8; 1373 for (size_t i = 0; i < sizeof(long); i++) { 1374 char bottomEightBits = static_cast<char>(desc); 1375 desc = desc >> shiftAmount; 1376 if (!bottomEightBits) { 1377 key = false; 1378 break; 1379 } 1380 name += bottomEightBits; 1381 } 1382 if (!key) { 1383 break; 1384 } 1385 descAddr += sizeof(long); 1386 } 1387 return name; 1388} 1389 1390std::string ArkGetFileName(int pid, uintptr_t jsPandaFileAddr, std::string &hapPath) 1391{ 1392 size_t size = sizeof(JSPandaFile) / sizeof(long); 1393 uintptr_t *jsPandaFilePart = new uintptr_t[size](); 1394 if (jsPandaFilePart == nullptr) { 1395 LOG_ECMA(FATAL) << "ArkGetFileName:jsPandaFilePart is nullptr"; 1396 } 1397 for (size_t i = 0; i < size; i++) { 1398 if (!ReadUintptrFromAddr(pid, jsPandaFileAddr, jsPandaFilePart[i], g_needCheck)) { 1399 LOG_ECMA(ERROR) << "ArkGetFilePath failed, jsPandaFileAddr: " << jsPandaFileAddr; 1400 delete []jsPandaFilePart; 1401 return ""; 1402 } 1403 jsPandaFileAddr += sizeof(long); 1404 } 1405 JSPandaFile *jsPandaFile = reinterpret_cast<JSPandaFile *>(jsPandaFilePart); 1406 1407 uintptr_t hapPathAddr = reinterpret_cast<uintptr_t>( 1408 const_cast<char *>(jsPandaFile->GetJSPandaFileHapPath().c_str())); 1409 hapPath = ArkReadCStringFromAddr(pid, hapPathAddr); 1410 1411 uintptr_t descAddr = reinterpret_cast<uintptr_t>( 1412 const_cast<char *>(jsPandaFile->GetJSPandaFileDesc().c_str())); 1413 delete []jsPandaFilePart; 1414 return ArkReadCStringFromAddr(pid, descAddr); 1415} 1416 1417std::unique_ptr<uint8_t[]> ArkReadData([[maybe_unused]] const std::string &hapPath, 1418 [[maybe_unused]] const std::string &fileName, 1419 [[maybe_unused]] size_t &dataSize) 1420{ 1421 std::unique_ptr<uint8_t[]> dataPtr = nullptr; 1422#if defined(PANDA_TARGET_OHOS) 1423 bool newCreate = false; 1424 std::shared_ptr<Extractor> extractor = ExtractorUtil::GetExtractor( 1425 ExtractorUtil::GetLoadFilePath(hapPath), newCreate); 1426 if (extractor == nullptr) { 1427 LOG_ECMA(ERROR) << "Ark read data failed, hapPath: " << hapPath; 1428 return dataPtr; 1429 } 1430 if (!extractor->ExtractToBufByName(fileName, dataPtr, dataSize)) { 1431 LOG_ECMA(ERROR) << "Ark read data failed, hap/hsp path: " << hapPath << ", file name: " << fileName; 1432 return dataPtr; 1433 } 1434#endif 1435 return dataPtr; 1436} 1437 1438std::shared_ptr<JSPandaFile> OpenJSPandaFileByReadData(const std::string &hapPath, const std::string &fileName) 1439{ 1440 size_t dataSize = 0; 1441 auto data = ArkReadData(hapPath, fileName, dataSize); 1442 if (data == nullptr) { 1443 return nullptr; 1444 } 1445 auto pf = panda_file::OpenPandaFileFromMemory(data.get(), dataSize); 1446 if (pf == nullptr) { 1447 return nullptr; 1448 } 1449 return std::make_shared<JSPandaFile>(pf.release(), fileName.c_str()); 1450} 1451 1452void ArkParseJsFrameDebugInfos([[maybe_unused]] const std::vector<JsFrameDebugInfo> &JsFrameDebugInfos, 1453 [[maybe_unused]] size_t size, [[maybe_unused]] JsFrame *jsFrame, 1454 [[maybe_unused]] size_t &jsFrameIndex) 1455{ 1456#if defined(PANDA_TARGET_OHOS) 1457 jsFrameIndex = 0; 1458 size = JsFrameDebugInfos.size() > size ? size : JsFrameDebugInfos.size(); 1459 std::unordered_map<std::string, std::shared_ptr<JSPandaFile>> jsPandaFileTable; 1460 for (size_t i = 0; i < size; ++i) { 1461 auto fileIter = jsPandaFileTable.find(JsFrameDebugInfos[i].hapPath); 1462 if (fileIter == jsPandaFileTable.end()) { 1463 auto jsPandaFile = OpenJSPandaFileByReadData(JsFrameDebugInfos[i].hapPath, JsFrameDebugInfos[i].filePath); 1464 if (jsPandaFile != nullptr) { 1465 jsPandaFileTable.emplace(JsFrameDebugInfos[i].hapPath, jsPandaFile); 1466 auto debugExtractor = std::make_unique<DebugInfoExtractor>(jsPandaFile.get()); 1467 ParseJsFrameInfo(jsPandaFile.get(), debugExtractor.get(), JsFrameDebugInfos[i].methodId, 1468 JsFrameDebugInfos[i].offset, jsFrame[jsFrameIndex]); 1469 jsFrameIndex++; 1470 } 1471 } else { 1472 auto jsPandaFile = fileIter->second; 1473 auto debugExtractor = std::make_unique<DebugInfoExtractor>(jsPandaFile.get()); 1474 ParseJsFrameInfo(jsPandaFile.get(), debugExtractor.get(), JsFrameDebugInfos[i].methodId, 1475 JsFrameDebugInfos[i].offset, jsFrame[jsFrameIndex]); 1476 jsFrameIndex++; 1477 } 1478 } 1479#endif 1480} 1481 1482bool ArkGetJsFrameDebugInfo(int pid, uintptr_t currentPtr, uintptr_t frameType, 1483 std::vector<JsFrameDebugInfo> &JsFrameDebugInfos) 1484{ 1485 uintptr_t function = ArkGetFunction(pid, currentPtr, frameType); 1486 if (!function) { 1487 return false; 1488 } 1489 1490 uintptr_t method = ArkCheckAndGetMethod(pid, function); 1491 if (!method || ArkIsNativeWithCallField(pid, method)) { 1492 return false; 1493 } 1494 uintptr_t jsPandaFileAddr = 0; 1495 uintptr_t methodId = 0; 1496 if (!ArkGetMethodIdandJSPandaFileAddr(pid, method, methodId, jsPandaFileAddr)) { 1497 LOG_ECMA(ERROR) << "ArkGetJsFrameDebugInfo failed, method: " << method; 1498 return false; 1499 } 1500 uintptr_t offset = ArkGetBytecodeOffset(pid, method, frameType, currentPtr); 1501 std::string hapPath; 1502 std::string fileName = ArkGetFileName(pid, jsPandaFileAddr, hapPath); 1503 if (fileName.empty() || hapPath.empty()) { 1504 LOG_ECMA(DEBUG) << "ArkGetJsFrameDebugInfo get filename or hapPath failed, fileName: " 1505 << fileName << ", hapPath: "<< hapPath; 1506 return false; 1507 } 1508 std::string filePath = ArkGetFilePath(fileName); 1509 if (filePath.empty()) { 1510 return false; 1511 } 1512 JsFrameDebugInfo JsFrameDebugInfo(EntityId(methodId), offset, hapPath, filePath); 1513 JsFrameDebugInfos.push_back(std::move(JsFrameDebugInfo)); 1514 return true; 1515} 1516 1517bool ArkGetNextFrame(int pid, uintptr_t frameType, uintptr_t ¤tPtr) 1518{ 1519 uintptr_t typeOffset = 0; 1520 uintptr_t prevOffset = 0; 1521 if (!GetTypeOffsetAndPrevOffsetFromFrameType(frameType, typeOffset, prevOffset)) { 1522 LOG_ECMA(ERROR) << "FrameType ERROR, addr: " << currentPtr << ", frameType: " << frameType; 1523 return false; 1524 } 1525 currentPtr -= typeOffset; 1526 currentPtr += prevOffset; 1527 if (!ReadUintptrFromAddr(pid, currentPtr, currentPtr, g_needCheck)) { 1528 return false; 1529 } 1530 if (currentPtr == 0) { 1531 LOG_ECMA(ERROR) << "currentPtr is nullptr in GetArkNativeFrameInfo()!"; 1532 return false; 1533 } 1534 return true; 1535} 1536 1537bool GetArkNativeFrameInfo([[maybe_unused]] int pid, [[maybe_unused]] uintptr_t *pc, 1538 [[maybe_unused]] uintptr_t *fp, [[maybe_unused]] uintptr_t *sp, 1539 [[maybe_unused]] JsFrame *jsFrame, [[maybe_unused]] size_t &size) 1540{ 1541#if defined(PANDA_TARGET_OHOS) 1542 constexpr size_t FP_SIZE = sizeof(uintptr_t); 1543 uintptr_t currentPtr = *fp; 1544 if (pid == getpid()) { 1545 g_needCheck = false; 1546 } 1547 if (currentPtr == 0) { 1548 LOG_ECMA(ERROR) << "fp is nullptr in GetArkNativeFrameInfo()!"; 1549 return false; 1550 } 1551 1552 if (pid == getpid() && JsStackInfo::loader != nullptr && 1553 !JsStackInfo::loader->InsideStub(*pc) && !JsStackInfo::loader->InsideAOT(*pc)) { 1554 LOG_ECMA(ERROR) << "invalid pc in StepArkManagedNativeFrame()!"; 1555 return false; 1556 } 1557 1558 std::vector<JsFrameDebugInfo> JsFrameDebugInfos; 1559 bool ret = true; 1560 while (true) { 1561 currentPtr -= sizeof(FrameType); 1562 uintptr_t frameType = 0; 1563 if (!ReadUintptrFromAddr(pid, currentPtr, frameType, g_needCheck)) { 1564 return false; 1565 } 1566 if (g_needCheck && (IsJsFunctionFrame(frameType) || IsAotFunctionFrame(frameType))) { 1567 ArkGetJsFrameDebugInfo(pid, currentPtr, frameType, JsFrameDebugInfos); 1568 } else if (ArkFrameCheck(frameType)) { 1569 currentPtr += sizeof(FrameType); 1570 *sp = currentPtr; 1571 ret &= ReadUintptrFromAddr(pid, currentPtr, *fp, g_needCheck); 1572 currentPtr += FP_SIZE; 1573 ret &= ReadUintptrFromAddr(pid, currentPtr, *pc, g_needCheck); 1574 break; 1575 } 1576 1577 if (!ArkGetNextFrame(pid, frameType, currentPtr)) { 1578 return false; 1579 } 1580 } 1581 if (g_needCheck && !JsFrameDebugInfos.empty()) { 1582 ArkParseJsFrameDebugInfos(JsFrameDebugInfos, size, jsFrame, size); 1583 } else { 1584 size = 0; 1585 } 1586 return ret; 1587#else 1588 return false; 1589#endif 1590} 1591 1592uint8_t* JSSymbolExtractor::GetData() 1593{ 1594 return data_; 1595} 1596 1597uintptr_t JSSymbolExtractor::GetLoadOffset() 1598{ 1599 return loadOffset_; 1600} 1601 1602uintptr_t JSSymbolExtractor::GetDataSize() 1603{ 1604 return dataSize_; 1605} 1606 1607bool JSSymbolExtractor::ParseHapFileData([[maybe_unused]] std::string& hapName) 1608{ 1609 bool ret = false; 1610#if defined(PANDA_TARGET_OHOS) 1611 if (hapName.empty()) { 1612 LOG_ECMA(ERROR) << "Get file data failed, path empty."; 1613 return false; 1614 } 1615 bool newCreate = false; 1616 std::shared_ptr<Extractor> extractor = ExtractorUtil::GetExtractor(hapName, newCreate); 1617 if (extractor == nullptr) { 1618 LOG_ECMA(ERROR) << "GetExtractor failed, hap path: " << hapName; 1619 return false; 1620 } 1621 1622 std::string pandaFilePath = "ets/modules.abc"; 1623 auto data = extractor->GetSafeData(pandaFilePath); 1624 if (!data) { 1625 LOG_ECMA(ERROR) << "GetSafeData failed, hap path: " << hapName; 1626 return false; 1627 } 1628 1629 data_ = data->GetDataPtr(); 1630 dataSize_ = data->GetDataLen(); 1631 loadOffset_ = static_cast<uintptr_t>(data->GetOffset()); 1632 ret = true; 1633 auto zipFile = std::make_unique<ZipFile>(hapName); 1634 if (zipFile == nullptr || !zipFile->Open()) { 1635 return false; 1636 } 1637 auto &entrys = zipFile->GetAllEntries(); 1638 if (ret) { 1639 std::string filePath = "ets/sourceMaps.map"; 1640 if (entrys.find(filePath) == entrys.end()) { 1641 LOG_ECMA(INFO) << "Can't find sourceMaps.map in hap/hsp"; 1642 return ret; 1643 } 1644 CreateSourceMap(hapName); 1645 } 1646#endif 1647 return ret; 1648} 1649 1650bool ArkParseJSFileInfo([[maybe_unused]] uintptr_t byteCodePc, [[maybe_unused]] uintptr_t methodId, 1651 [[maybe_unused]] uintptr_t mapBase, [[maybe_unused]] const char* filePath, 1652 [[maybe_unused]] uintptr_t extractorptr, [[maybe_unused]] JsFunction *jsFunction) 1653{ 1654 bool ret = false; 1655#if defined(PANDA_TARGET_OHOS) 1656 if (filePath == nullptr) { 1657 LOG_ECMA(ERROR) << "FilePath from dfx is nullptr."; 1658 return false; 1659 } 1660 auto extractor = reinterpret_cast<JSSymbolExtractor*>(extractorptr); 1661 if (extractor == nullptr) { 1662 LOG_ECMA(ERROR) << "Parse JSframe info failed, extractor is nullptr."; 1663 return false; 1664 } 1665 if (extractor->GetJSPandaFile() == nullptr) { 1666 std::string hapName = std::string(filePath); 1667 extractor->ParseHapFileData(hapName); 1668 extractor->CreateJSPandaFile(); 1669 } 1670 ret = ArkParseJsFrameInfo(byteCodePc, methodId, mapBase, extractor->GetLoadOffset(), 1671 extractor->GetData(), extractor->GetDataSize(), extractorptr, jsFunction); 1672#endif 1673 return ret; 1674} 1675 1676JSSymbolExtractor::~JSSymbolExtractor() 1677{ 1678 if (sourceMap_ != nullptr) { 1679 sourceMap_.reset(); 1680 } 1681 if (debugExtractor_ != nullptr) { 1682 debugExtractor_.reset(); 1683 } 1684 if (jsPandaFile_ != nullptr) { 1685 jsPandaFile_.reset(); 1686 } 1687 methodInfo_.clear(); 1688} 1689 1690JSSymbolExtractor* JSSymbolExtractor::Create() 1691{ 1692 auto extractor = new JSSymbolExtractor(); 1693 return extractor; 1694} 1695 1696bool JSSymbolExtractor::Destory(JSSymbolExtractor *extractor) 1697{ 1698 if (extractor == nullptr) { 1699 LOG_ECMA(ERROR) << "Destory ark symbol extractor failed, extractor is nullptr."; 1700 return false; 1701 } 1702 delete extractor; 1703 extractor = nullptr; 1704 return true; 1705} 1706 1707CVector<MethodInfo> JSSymbolExtractor::GetMethodInfos() 1708{ 1709 if (methodInfo_.empty()) { 1710 methodInfo_ = JSStackTrace::ReadAllMethodInfos(jsPandaFile_); 1711 } 1712 1713 return methodInfo_; 1714} 1715 1716JSPandaFile* JSSymbolExtractor::GetJSPandaFile(uint8_t *data, size_t dataSize) 1717{ 1718 if (jsPandaFile_ == nullptr && data != nullptr) { 1719 CreateJSPandaFile(data, dataSize); 1720 } 1721 return jsPandaFile_.get(); 1722} 1723 1724void JSSymbolExtractor::CreateJSPandaFile() 1725{ 1726 auto pf = panda_file::OpenPandaFileFromSecureMemory(data_, dataSize_); 1727 if (pf == nullptr) { 1728 LOG_ECMA(ERROR) << "Failed to open panda file."; 1729 return; 1730 } 1731 jsPandaFile_ = std::make_shared<JSPandaFile>(pf.release(), ""); 1732} 1733 1734void JSSymbolExtractor::CreateJSPandaFile(uint8_t *data, size_t dataSize) 1735{ 1736 auto pf = panda_file::OpenPandaFileFromSecureMemory(data, dataSize); 1737 if (pf == nullptr) { 1738 LOG_ECMA(ERROR) << "Failed to open panda file."; 1739 return; 1740 } 1741 jsPandaFile_ = std::make_shared<JSPandaFile>(pf.release(), ""); 1742} 1743 1744SourceMap* JSSymbolExtractor::GetSourceMap(uint8_t *data, size_t dataSize) 1745{ 1746 if (sourceMap_ == nullptr && data != nullptr) { 1747 JSSymbolExtractor::CreateSourceMap(data, dataSize); 1748 } 1749 return sourceMap_.get(); 1750} 1751 1752void JSSymbolExtractor::CreateSourceMap([[maybe_unused]] const std::string &hapPath) 1753{ 1754#if defined(PANDA_TARGET_OHOS) 1755 if (sourceMap_ == nullptr) { 1756 sourceMap_ = std::make_shared<SourceMap>(); 1757 sourceMap_->Init(hapPath); 1758 } 1759#endif 1760} 1761 1762void JSSymbolExtractor::CreateSourceMap(uint8_t *data, size_t dataSize) 1763{ 1764 sourceMap_ = std::make_shared<SourceMap>(); 1765 sourceMap_->Init(data, dataSize); 1766} 1767 1768DebugInfoExtractor* JSSymbolExtractor::GetDebugExtractor() 1769{ 1770 if (debugExtractor_ == nullptr) { 1771 JSSymbolExtractor::CreateDebugExtractor(); 1772 } 1773 return debugExtractor_.get(); 1774} 1775 1776void JSSymbolExtractor::CreateDebugExtractor() 1777{ 1778 debugExtractor_ = std::make_unique<DebugInfoExtractor>(jsPandaFile_.get()); 1779} 1780 1781uintptr_t ArkCreateJSSymbolExtractor() 1782{ 1783 auto extractor = JSSymbolExtractor::Create(); 1784 auto extractorptr = reinterpret_cast<uintptr_t>(extractor); 1785 return extractorptr; 1786} 1787 1788bool ArkDestoryJSSymbolExtractor(uintptr_t extractorptr) 1789{ 1790 auto extractor = reinterpret_cast<JSSymbolExtractor*>(extractorptr); 1791 return JSSymbolExtractor::Destory(extractor); 1792} 1793 1794JSStackTrace *JSStackTrace::GetInstance() 1795{ 1796 if (trace_ == nullptr) { 1797 std::unique_lock<std::mutex> lock(mutex_); 1798 if (trace_ == nullptr) { 1799 trace_ = new JSStackTrace(); 1800 } 1801 } 1802 1803 return trace_; 1804} 1805 1806JSStackTrace::~JSStackTrace() 1807{ 1808 methodInfo_.clear(); 1809 methodInfos_.clear(); 1810 jsPandaFiles_.clear(); 1811} 1812 1813bool JSStackTrace::AddMethodInfos(uintptr_t mapBase) 1814{ 1815 auto pandaFile = 1816 JSPandaFileManager::GetInstance()->FindJSPandaFileByMapBase(mapBase); 1817 jsPandaFiles_[mapBase] = pandaFile; 1818 auto methodInfos = JSStackTrace::ReadAllMethodInfos(pandaFile); 1819 methodInfos_[mapBase] = std::move(methodInfos); 1820 if (pandaFile == nullptr) { 1821 LOG_ECMA(ERROR) << "Can't find JSPandaFile by mapBase: " << mapBase; 1822 } 1823 return true; 1824} 1825 1826bool JSStackTrace::GetJsFrameInfo(uintptr_t byteCodePc, uintptr_t methodId, uintptr_t mapBase, 1827 uintptr_t loadOffset, JsFunction *jsFunction) 1828{ 1829 bool ret = true; 1830 auto iter = methodInfos_.find(mapBase); 1831 if (iter == methodInfos_.end()) { 1832 ret = AddMethodInfos(mapBase); 1833 } 1834 loadOffset = loadOffset % PageSize(); 1835 byteCodePc = byteCodePc - loadOffset; 1836 auto codeInfo = TranslateByteCodePc(byteCodePc, methodInfos_[mapBase]); 1837 if (!codeInfo) { 1838 LOG_ECMA(ERROR) << std::hex << "Failed to get methodId, pc: " << byteCodePc; 1839 return false; 1840 } 1841 if (!methodId) { 1842 methodId = codeInfo->methodId; 1843 } 1844 auto offset = codeInfo->offset; 1845 auto debugInfoExtractor = 1846 JSPandaFileManager::GetInstance()->GetJSPtExtractor(jsPandaFiles_[mapBase].get()); 1847 ParseJsFrameInfo(jsPandaFiles_[mapBase].get(), debugInfoExtractor, EntityId(methodId), offset, *jsFunction); 1848 jsFunction->codeBegin = byteCodePc - offset; 1849 jsFunction->codeSize = codeInfo->codeSize; 1850 return ret; 1851} 1852 1853void JSStackTrace::Destory() 1854{ 1855 std::unique_lock<std::mutex> lock(mutex_); 1856 if (trace_ != nullptr) { 1857 delete trace_; 1858 trace_ = nullptr; 1859 } 1860} 1861 1862bool ArkParseJsFrameInfoLocal(uintptr_t byteCodePc, uintptr_t methodId, uintptr_t mapBase, 1863 uintptr_t loadOffset, JsFunction *jsFunction) 1864{ 1865 auto trace = JSStackTrace::GetInstance(); 1866 if (trace == nullptr) { 1867 LOG_ECMA(ERROR) << "JSStackTrace GetInstance failed."; 1868 return false; 1869 } 1870 return trace->GetJsFrameInfo(byteCodePc, methodId, mapBase, loadOffset, jsFunction); 1871} 1872 1873void ArkDestoryLocal() 1874{ 1875 JSStackTrace::Destory(); 1876} 1877 1878} // namespace panda::ecmascript 1879 1880__attribute__((visibility("default"))) int ark_create_js_symbol_extractor(uintptr_t *extractorptr) 1881{ 1882 *extractorptr = panda::ecmascript::ArkCreateJSSymbolExtractor(); 1883 return 1; 1884} 1885 1886__attribute__((visibility("default"))) int ark_destory_js_symbol_extractor(uintptr_t extractorptr) 1887{ 1888 if (panda::ecmascript::ArkDestoryJSSymbolExtractor(extractorptr)) { 1889 return 1; 1890 } 1891 return -1; 1892} 1893 1894__attribute__((visibility("default"))) int ark_destory_local() 1895{ 1896 panda::ecmascript::ArkDestoryLocal(); 1897 return 1; 1898} 1899 1900__attribute__((visibility("default"))) int step_ark_with_record_jit(panda::ecmascript::ArkUnwindParam *arkUnwindParam) 1901{ 1902 if (panda::ecmascript::StepArkWithRecordJit(arkUnwindParam)) { 1903 return 1; 1904 } 1905 return -1; 1906} 1907 1908__attribute__((visibility("default"))) int ark_write_jit_code( 1909 void *ctx, panda::ecmascript::ReadMemFunc readMem, int fd, const uintptr_t *const jitCodeArray, 1910 const size_t jitSize) 1911{ 1912 if (panda::ecmascript::ArkWriteJitCode(ctx, readMem, fd, jitCodeArray, jitSize)) { 1913 return 1; 1914 } 1915 return -1; 1916} 1917 1918__attribute__((visibility("default"))) int step_ark( 1919 void *ctx, panda::ecmascript::ReadMemFunc readMem, uintptr_t *fp, uintptr_t *sp, 1920 uintptr_t *pc, uintptr_t *methodId, bool *isJsFrame) 1921{ 1922 if (panda::ecmascript::StepArk(ctx, readMem, fp, sp, pc, methodId, isJsFrame)) { 1923 return 1; 1924 } 1925 return -1; 1926} 1927 1928__attribute__((visibility("default"))) int ark_parse_js_frame_info( 1929 uintptr_t byteCodePc, uintptr_t methodId, uintptr_t mapBase, uintptr_t loadOffset, uint8_t *data, 1930 uint64_t dataSize, uintptr_t extractorptr, panda::ecmascript::JsFunction *jsFunction) 1931{ 1932 if (panda::ecmascript::ArkParseJsFrameInfo(byteCodePc, methodId, mapBase, loadOffset, data, 1933 dataSize, extractorptr, jsFunction)) { 1934 return 1; 1935 } 1936 return -1; 1937} 1938 1939__attribute__((visibility("default"))) int ark_parse_js_file_info( 1940 uintptr_t byteCodePc, uintptr_t methodId, uintptr_t mapBase, const char* filePath, uintptr_t extractorptr, 1941 panda::ecmascript::JsFunction *jsFunction) 1942{ 1943 if (panda::ecmascript::ArkParseJSFileInfo(byteCodePc, methodId, mapBase, filePath, extractorptr, jsFunction)) { 1944 return 1; 1945 } 1946 return -1; 1947} 1948 1949__attribute__((visibility("default"))) int ark_translate_js_frame_info( 1950 uint8_t *data, size_t dataSize, panda::ecmascript::JsFunction *jsFunction) 1951{ 1952 if (panda::ecmascript::ArkTranslateJsFrameInfo(data, dataSize, jsFunction)) { 1953 return 1; 1954 } 1955 return -1; 1956} 1957 1958__attribute__((visibility("default"))) int get_ark_native_frame_info( 1959 int pid, uintptr_t *pc, uintptr_t *fp, uintptr_t *sp, 1960 panda::ecmascript::JsFrame *jsFrame, size_t &size) 1961{ 1962 if (panda::ecmascript::GetArkNativeFrameInfo(pid, pc, fp, sp, jsFrame, size)) { 1963 return 1; 1964 } 1965 return -1; 1966} 1967 1968__attribute__((visibility("default"))) int ark_parse_js_frame_info_local( 1969 uintptr_t byteCodePc, uintptr_t methodId, uintptr_t mapBase, uintptr_t loadOffset, 1970 panda::ecmascript::JsFunction *jsFunction) 1971{ 1972 if (panda::ecmascript::ArkParseJsFrameInfoLocal(byteCodePc, methodId, mapBase, loadOffset, jsFunction)) { 1973 return 1; 1974 } 1975 return -1; 1976}