diff --git a/ecmascript/dfx/stackinfo/js_stackinfo.cpp b/ecmascript/dfx/stackinfo/js_stackinfo.cpp index 1ac53a1a84..9391db8042 100644 --- a/ecmascript/dfx/stackinfo/js_stackinfo.cpp +++ b/ecmascript/dfx/stackinfo/js_stackinfo.cpp @@ -463,7 +463,7 @@ bool IsFunctionFrame(uintptr_t frameType) static_cast(frameType) == FrameType::OPTIMIZED_JS_FAST_CALL_FUNCTION_FRAME; } -std::optional ReadMethodInfo(panda_file::MethodDataAccessor &mda) +std::optional JSStackTrace::ReadMethodInfo(panda_file::MethodDataAccessor &mda) { uintptr_t methodId = mda.GetMethodId().GetOffset(); auto codeId = mda.GetCodeId(); @@ -476,9 +476,13 @@ std::optional ReadMethodInfo(panda_file::MethodDataAccessor &mda) return std::make_optional(methodId, codeBegin, codeSize); } -std::vector ReadAllMethodInfos(std::shared_ptr jsPandaFile) +CVector JSStackTrace::ReadAllMethodInfos(std::shared_ptr jsPandaFile) { - std::vector result; + CVector result; + if (jsPandaFile == nullptr) { + LOG_ECMA(DEBUG) << "Read all methods info in file failed, file is nullptr."; + return result; + } const panda_file::File *pf = jsPandaFile->GetPandaFile(); Span classIndexes = jsPandaFile->GetClasses(); for (const uint32_t index : classIndexes) { @@ -488,7 +492,7 @@ std::vector ReadAllMethodInfos(std::shared_ptr jsPandaF } panda_file::ClassDataAccessor cda(*pf, classId); cda.EnumerateMethods([&result, jsPandaFile](panda_file::MethodDataAccessor &mda) { - auto info = ReadMethodInfo(mda); + auto info = JSStackTrace::ReadMethodInfo(mda); if (!info) { return; } @@ -500,7 +504,7 @@ std::vector ReadAllMethodInfos(std::shared_ptr jsPandaF return result; } -std::optional TranslateByteCodePc(uintptr_t realPc, const std::vector &vec) +std::optional JSStackTrace::TranslateByteCodePc(uintptr_t realPc, const CVector &vec) { int32_t left = 0; int32_t right = vec.size() - 1; @@ -565,7 +569,7 @@ void ParseJsFrameInfo(JSPandaFile *jsPandaFile, DebugInfoExtractor *debugExtract jsFrame.column = columnNumber; } -bool ArkParseJsFrameInfo(uintptr_t byteCodePc, uintptr_t mapBase, uintptr_t loadOffset, +bool ArkParseJsFrameInfo(uintptr_t byteCodePc, uintptr_t methodId, uintptr_t mapBase, uintptr_t loadOffset, uint8_t *data, uint64_t dataSize, uintptr_t extractorptr, JsFunction *jsFunction) { if (data == nullptr) { @@ -579,21 +583,28 @@ bool ArkParseJsFrameInfo(uintptr_t byteCodePc, uintptr_t mapBase, uintptr_t load return false; } auto jsPandaFile = extractor->GetJSPandaFile(data, dataSize); + if (jsPandaFile == nullptr) { + LOG_ECMA(ERROR) << "Parse JSframe info failed, panda file is nullptr."; + return false; + } auto debugExtractor = extractor->GetDebugExtractor(); - auto methodInfos = extractor->GetmethodInfos(); + auto methodInfos = extractor->GetMethodInfos(); if (methodInfos.empty()) { LOG_ECMA(ERROR) << "Read all method info from JSPandaFile failed, methodInfos is empty."; return false; } uintptr_t realOffset = byteCodePc - mapBase - loadOffset; uintptr_t pfBasePtr = reinterpret_cast(jsPandaFile->GetBase()); - auto codeInfo = TranslateByteCodePc(realOffset + pfBasePtr, methodInfos); + auto codeInfo = JSStackTrace::TranslateByteCodePc(realOffset + pfBasePtr, methodInfos); if (!codeInfo) { + LOG_ECMA(ERROR) << std::hex << "Failed to get methodId, pc: " << byteCodePc; return false; } - auto methodId = EntityId(codeInfo->methodId); + if (!methodId) { + methodId = codeInfo->methodId; + } auto offset = codeInfo->offset; - ParseJsFrameInfo(jsPandaFile, debugExtractor, methodId, offset, *jsFunction); + ParseJsFrameInfo(jsPandaFile, debugExtractor, EntityId(methodId), offset, *jsFunction); jsFunction->codeBegin = byteCodePc - offset; jsFunction->codeSize = codeInfo->codeSize; @@ -649,7 +660,119 @@ uintptr_t GetBytecodeOffset(void *ctx, ReadMemFunc readMem, uintptr_t frameType, return 0; } -bool ArkGetNextFrame(void *ctx, ReadMemFunc readMem, uintptr_t ¤tPtr, uintptr_t &frameType, uintptr_t &pc) +uintptr_t ArkGetFunction(void *ctx, ReadMemFunc readMem, uintptr_t currentPtr, uintptr_t frameType) +{ + FrameType type = static_cast(frameType); + uintptr_t funcAddr = currentPtr; + switch (type) { + case FrameType::OPTIMIZED_JS_FAST_CALL_FUNCTION_FRAME: + case FrameType::OPTIMIZED_JS_FUNCTION_FRAME: { + funcAddr -= OptimizedJSFunctionFrame::GetTypeOffset(); + funcAddr += OptimizedJSFunctionFrame::GetFunctionOffset(); + break; + } + case FrameType::ASM_INTERPRETER_FRAME: + case FrameType::INTERPRETER_CONSTRUCTOR_FRAME: { + funcAddr -= AsmInterpretedFrame::GetTypeOffset(); + funcAddr += AsmInterpretedFrame::GetFunctionOffset(false); + break; + } + case FrameType::INTERPRETER_FRAME: + case FrameType::INTERPRETER_FAST_NEW_FRAME: { + funcAddr -= InterpretedFrame::GetTypeOffset(); + funcAddr += InterpretedFrame::GetFunctionOffset(); + break; + } + default: { + return 0; + } + } + uintptr_t function = 0; + if (!readMem(ctx, funcAddr, &function)) { + return 0; + } + return function; +} + +bool ArkCheckIsJSFunctionBaseOrJSProxy(void *ctx, ReadMemFunc readMem, uintptr_t objAddr, bool &isJSFunctionBase) +{ + bool isHeapObj = ((objAddr & JSTaggedValue::TAG_HEAPOBJECT_MASK) == 0U); + bool isInvalidValue = (objAddr <= JSTaggedValue::INVALID_VALUE_LIMIT); + if (isHeapObj && !isInvalidValue) { + ASSERT_PRINT(((objAddr & JSTaggedValue::TAG_WEAK) == 0U), + "can not convert JSTaggedValue to HeapObject :" << std::hex << objAddr); + uintptr_t hclassAddr = objAddr + TaggedObject::HCLASS_OFFSET; + uintptr_t hclass = 0; + if (!readMem(ctx, hclassAddr, &hclass)) { + return false; + } + if (hclass != 0) { + uintptr_t bitsAddr = reinterpret_cast(hclass + JSHClass::BIT_FIELD_OFFSET); + uintptr_t bits = 0; + if (!readMem(ctx, bitsAddr, &bits)) { + return false; + } + JSType jsType = JSHClass::ObjectTypeBits::Decode(bits); + isJSFunctionBase = (jsType >= JSType::JS_FUNCTION_BASE && jsType <= JSType::JS_BOUND_FUNCTION); + bool isJSProxy = (jsType == JSType::JS_PROXY); + return isJSFunctionBase || isJSProxy; + } + } + return false; +} + +uintptr_t ArkCheckAndGetMethod(void *ctx, ReadMemFunc readMem, uintptr_t value) +{ + bool isJSFunctionBase = 0; + if (ArkCheckIsJSFunctionBaseOrJSProxy(ctx, readMem, value, isJSFunctionBase)) { + if (isJSFunctionBase) { + value += JSFunctionBase::METHOD_OFFSET; + } else { + value += JSProxy::METHOD_OFFSET; + } + uintptr_t method = 0; + if (!readMem(ctx, value, &method)) { + return 0; + } + return method; + } + return 0; +} + +bool ArkGetMethodIdandJSPandaFileAddr(void *ctx, ReadMemFunc readMem, uintptr_t method, uintptr_t &methodId) +{ + uintptr_t methodLiteralAddr = method + Method::LITERAL_INFO_OFFSET; + uintptr_t methodLiteral = 0; + if (!readMem(ctx, methodLiteralAddr, &methodLiteral)) { + return false; + } + methodId = MethodLiteral::MethodIdBits::Decode(methodLiteral); + return true; +} + +bool ArkGetMethodId(void *ctx, ReadMemFunc readMem, uintptr_t frameType, uintptr_t currentPtr, uintptr_t &methodId) +{ + uintptr_t function = ArkGetFunction(ctx, readMem, currentPtr, frameType); + if (!function) { + LOG_ECMA(DEBUG) << "Failed to get function"; + return false; + } + + uintptr_t method = ArkCheckAndGetMethod(ctx, readMem, function); + if (!method) { + LOG_ECMA(DEBUG) << std::hex << "Failed to get method: " << function; + return false; + } + + if (!ArkGetMethodIdandJSPandaFileAddr(ctx, readMem, method, methodId)) { + LOG_ECMA(DEBUG) << std::hex << "ArkGetJsFrameDebugInfo failed, method: " << method; + return false; + } + return true; +} + +bool ArkGetNextFrame(void *ctx, ReadMemFunc readMem, uintptr_t ¤tPtr, + uintptr_t &frameType, uintptr_t &pc, uintptr_t *methodId) { currentPtr -= sizeof(FrameType); if (!readMem(ctx, currentPtr, &frameType)) { @@ -662,6 +785,9 @@ bool ArkGetNextFrame(void *ctx, ReadMemFunc readMem, uintptr_t ¤tPtr, uint if (IsFunctionFrame(frameType)) { pc = GetBytecodeOffset(ctx, readMem, frameType, currentPtr); ret = true; + if (methodId != nullptr) { + ret = ArkGetMethodId(ctx, readMem, frameType, currentPtr, *methodId); + } } uintptr_t typeOffset = 0; @@ -678,10 +804,11 @@ bool ArkGetNextFrame(void *ctx, ReadMemFunc readMem, uintptr_t ¤tPtr, uint if (ret) { return true; } - return ArkGetNextFrame(ctx, readMem, currentPtr, frameType, pc); + return ArkGetNextFrame(ctx, readMem, currentPtr, frameType, pc, methodId); } -bool StepArk(void *ctx, ReadMemFunc readMem, uintptr_t *fp, uintptr_t *sp, uintptr_t *pc, bool *isJsFrame) +bool StepArk(void *ctx, ReadMemFunc readMem, uintptr_t *fp, uintptr_t *sp, + uintptr_t *pc, uintptr_t *methodId, bool *isJsFrame) { constexpr size_t FP_SIZE = sizeof(uintptr_t); uintptr_t currentPtr = *fp; @@ -691,7 +818,7 @@ bool StepArk(void *ctx, ReadMemFunc readMem, uintptr_t *fp, uintptr_t *sp, uintp } uintptr_t frameType = 0; - if (ArkGetNextFrame(ctx, readMem, currentPtr, frameType, *pc)) { + if (ArkGetNextFrame(ctx, readMem, currentPtr, frameType, *pc, methodId)) { if (ArkFrameCheck(frameType)) { currentPtr += sizeof(FrameType); *sp = currentPtr; @@ -706,14 +833,13 @@ bool StepArk(void *ctx, ReadMemFunc readMem, uintptr_t *fp, uintptr_t *sp, uintp *isJsFrame = true; } } else { - LOG_ECMA(ERROR) << "ArkGetNextFrame failed, currentPtr: " << currentPtr << ", frameType: " << frameType; + LOG_ECMA(ERROR) << std::hex << "ArkGetNextFrame failed, addr: " << currentPtr; return false; } return true; } -#if defined(PANDA_TARGET_OHOS) uintptr_t ArkGetFunction(int pid, uintptr_t currentPtr, uintptr_t frameType) { FrameType type = static_cast(frameType); @@ -908,33 +1034,6 @@ uint32_t ArkGetBytecodeOffset(int pid, uintptr_t method, uintptr_t frameType, ui return 0; } -bool ArkReadData(const std::string &hapPath, const std::string &sourceMapPath, char **data, size_t &dataSize) -{ - // Source map relative path, FA: "/assets/js", Stage: "/ets" - if (hapPath.empty()) { - LOG_ECMA(ERROR) << "hapPath is empty"; - return false; - } - bool newCreate = false; - std::shared_ptr extractor = ExtractorUtil::GetExtractor( - ExtractorUtil::GetLoadFilePath(hapPath), newCreate); - if (extractor == nullptr) { - LOG_ECMA(ERROR) << "hap's path: " << hapPath; - return false; - } - std::unique_ptr dataPtr = nullptr; - if (!extractor->ExtractToBufByName(sourceMapPath, dataPtr, dataSize)) { - LOG_ECMA(DEBUG) << "can't find source map, and switch to stage model."; - return false; - } - *data = (char*)malloc(sizeof(char)*dataSize); - if (memcpy_s(*data, dataSize, dataPtr.get(), dataSize) != EOK) { - LOG_ECMA(FATAL) << "memcpy_s failed"; - UNREACHABLE(); - } - return true; -} - std::string ArkGetFilePath(std::string &fileName) { auto lastSlash = fileName.rfind("/"); @@ -966,19 +1065,19 @@ bool ArkIsNativeWithCallField(int pid, uintptr_t method) std::string ArkReadCStringFromAddr(int pid, uintptr_t descAddr) { std::string name; - while (true) { + bool key = true; + while (key) { uintptr_t desc = 0; if (!ReadUintptrFromAddr(pid, descAddr, desc, g_needCheck)) { LOG_ECMA(ERROR) << "ArkReadCStringFromAddr failed, descAddr: " << descAddr; return name; } - bool key = 1; size_t shiftAmount = 8; for (size_t i = 0; i < sizeof(long); i++) { char bottomEightBits = desc; desc = desc >> shiftAmount; if (!bottomEightBits) { - key = 0; + key = false; break; } name += bottomEightBits; @@ -1014,9 +1113,12 @@ std::string ArkGetFileName(int pid, uintptr_t jsPandaFileAddr, std::string &hapP return ArkReadCStringFromAddr(pid, descAddr); } -std::unique_ptr ArkReadData(const std::string &hapPath, const std::string &fileName, size_t &dataSize) +std::unique_ptr ArkReadData([[maybe_unused]] const std::string &hapPath, + [[maybe_unused]] const std::string &fileName, + [[maybe_unused]] size_t &dataSize) { std::unique_ptr dataPtr = nullptr; +#if defined(PANDA_TARGET_OHOS) bool newCreate = false; std::shared_ptr extractor = ExtractorUtil::GetExtractor( ExtractorUtil::GetLoadFilePath(hapPath), newCreate); @@ -1028,6 +1130,7 @@ std::unique_ptr ArkReadData(const std::string &hapPath, const std::st LOG_ECMA(ERROR) << "Ark read data failed, hap/hsp path: " << hapPath << ", file name: " << fileName; return dataPtr; } +#endif return dataPtr; } @@ -1045,9 +1148,11 @@ std::shared_ptr OpenJSPandaFileByReadData(const std::string &hapPat return std::make_shared(pf.release(), fileName.c_str()); } -void ArkParseJsFrameDebugInfos(const std::vector &JsFrameDebugInfos, - size_t size, JsFrame *jsFrame, size_t &jsFrameIndex) +void ArkParseJsFrameDebugInfos([[maybe_unused]] const std::vector &JsFrameDebugInfos, + [[maybe_unused]] size_t size, [[maybe_unused]] JsFrame *jsFrame, + [[maybe_unused]] size_t &jsFrameIndex) { +#if defined(PANDA_TARGET_OHOS) jsFrameIndex = 0; size = JsFrameDebugInfos.size() > size ? size : JsFrameDebugInfos.size(); std::unordered_map> jsPandaFileTable; @@ -1076,6 +1181,7 @@ void ArkParseJsFrameDebugInfos(const std::vector &JsFrameDebug jsFrameIndex++; } } +#endif } bool ArkGetJsFrameDebugInfo(int pid, uintptr_t currentPtr, uintptr_t frameType, @@ -1133,9 +1239,11 @@ bool ArkGetNextFrame(int pid, uintptr_t frameType, uintptr_t ¤tPtr) return true; } -bool GetArkNativeFrameInfo(int pid, uintptr_t *pc, uintptr_t *fp, uintptr_t *sp, - panda::ecmascript::JsFrame *jsFrame, size_t &size) +bool GetArkNativeFrameInfo([[maybe_unused]] int pid, [[maybe_unused]] uintptr_t *pc, + [[maybe_unused]] uintptr_t *fp, [[maybe_unused]] uintptr_t *sp, + [[maybe_unused]] JsFrame *jsFrame, [[maybe_unused]] size_t &size) { +#if defined(PANDA_TARGET_OHOS) constexpr size_t FP_SIZE = sizeof(uintptr_t); uintptr_t currentPtr = *fp; if (pid == getpid()) { @@ -1160,7 +1268,7 @@ bool GetArkNativeFrameInfo(int pid, uintptr_t *pc, uintptr_t *fp, uintptr_t *sp, if (!ReadUintptrFromAddr(pid, currentPtr, frameType, g_needCheck)) { return false; } - if (IsFunctionFrame(frameType)) { + if (g_needCheck && IsFunctionFrame(frameType)) { ArkGetJsFrameDebugInfo(pid, currentPtr, frameType, JsFrameDebugInfos); } else if (ArkFrameCheck(frameType)) { currentPtr += sizeof(FrameType); @@ -1181,8 +1289,84 @@ bool GetArkNativeFrameInfo(int pid, uintptr_t *pc, uintptr_t *fp, uintptr_t *sp, size = 0; } return ret; -} +#else + return false; #endif +} + +uint8_t* JSSymbolExtractor::GetData() +{ + return data_.get(); +} + +uintptr_t JSSymbolExtractor::GetLoadOffset() +{ + return loadOffset_; +} + +uintptr_t JSSymbolExtractor::GetDataSize() +{ + return dataSize_; +} + +bool JSSymbolExtractor::ParseHapFileData([[maybe_unused]] std::string& hapName) +{ + bool ret = false; +#if defined(PANDA_TARGET_OHOS) + if (hapName.empty()) { + return false; + } + auto zipFile = std::make_unique(hapName); + if (zipFile == nullptr && !zipFile->Open()) { + return false; + } + auto &entrys = zipFile->GetAllEntries(); + for (const auto &entry : entrys) { + std::string fileName = entry.first; + if (hapName.rfind(".abc") == std::string::npos) { + continue; + } + + ZipPos offset = 0; + uint32_t length = 0; + if (!zipFile->GetDataOffsetRelative(fileName, offset, length)) { + break; + } + + loadOffset_ = static_cast(offset); + if (zipFile->ExtractToBufByName(fileName, data_, dataSize_)) { + ret = true; + break; + } + } +#endif + return ret; +} + +bool ArkParseJSFileInfo([[maybe_unused]] uintptr_t byteCodePc, [[maybe_unused]] uintptr_t methodId, + [[maybe_unused]] uintptr_t mapBase, [[maybe_unused]] const char* filePath, + [[maybe_unused]] uintptr_t extractorptr, [[maybe_unused]] JsFunction *jsFunction) +{ + bool ret = false; +#if defined(PANDA_TARGET_OHOS) + if (filePath == nullptr) { + LOG_ECMA(ERROR) << "FilePath from dfx is nullptr."; + return false; + } + auto extractor = reinterpret_cast(extractorptr); + if (extractor == nullptr) { + LOG_ECMA(ERROR) << "Parse JSframe info failed, extractor is nullptr."; + return false; + } + if (extractor->GetJSPandaFile() == nullptr) { + std::string hapName = std::string(filePath); + extractor->ParseHapFileData(hapName); + } + ret = ArkParseJsFrameInfo(byteCodePc, methodId, mapBase, extractor->GetLoadOffset(), + extractor->GetData(), extractor->GetDataSize(), extractorptr, jsFunction); +#endif + return ret; +} bool StepArkManagedNativeFrame(int pid, uintptr_t *pc, uintptr_t *fp, uintptr_t *sp, [[maybe_unused]] char *buf, [[maybe_unused]] size_t buf_sz) @@ -1369,10 +1553,10 @@ bool JSSymbolExtractor::Destory(JSSymbolExtractor *extractor) return true; } -std::vector JSSymbolExtractor::GetmethodInfos() +CVector JSSymbolExtractor::GetMethodInfos() { if (methodInfo_.empty()) { - methodInfo_ = ReadAllMethodInfos(jsPandaFile_); + methodInfo_ = JSStackTrace::ReadAllMethodInfos(jsPandaFile_); } return methodInfo_; @@ -1380,15 +1564,29 @@ std::vector JSSymbolExtractor::GetmethodInfos() JSPandaFile* JSSymbolExtractor::GetJSPandaFile(uint8_t *data, size_t dataSize) { - if (jsPandaFile_ == nullptr) { - JSSymbolExtractor::CreateJSPandaFile(data, dataSize); + if (jsPandaFile_ == nullptr && data != nullptr) { + CreateJSPandaFile(data, dataSize); } return jsPandaFile_.get(); } +void JSSymbolExtractor::CreateJSPandaFile() +{ + auto pf = panda_file::OpenPandaFileFromSecureMemory(data_.get(), dataSize_); + if (pf == nullptr) { + LOG_ECMA(ERROR) << "Failed to open panda file."; + return; + } + jsPandaFile_ = std::make_shared(pf.release(), ""); +} + void JSSymbolExtractor::CreateJSPandaFile(uint8_t *data, size_t dataSize) { auto pf = panda_file::OpenPandaFileFromSecureMemory(data, dataSize); + if (pf == nullptr) { + LOG_ECMA(ERROR) << "Failed to open panda file."; + return; + } jsPandaFile_ = std::make_shared(pf.release(), ""); } @@ -1432,6 +1630,79 @@ bool ArkDestoryJSSymbolExtractor(uintptr_t extractorptr) auto extractor = reinterpret_cast(extractorptr); return JSSymbolExtractor::Destory(extractor); } + +JSStackTrace *JSStackTrace::GetInstance() +{ + static JSStackTrace *jsStackTrace = new JSStackTrace(); + return jsStackTrace; +} + +JSStackTrace::~JSStackTrace() +{ + methodInfo_.clear(); + methodInfos_.clear(); + jsPandaFiles_.clear(); +} + +bool JSStackTrace::AddMethodInfos(uintptr_t mapBase) +{ + auto pandaFile = + JSPandaFileManager::GetInstance()->FindJSPandaFileByMapBase(mapBase); + jsPandaFiles_[mapBase] = pandaFile; + auto methodInfos = JSStackTrace::ReadAllMethodInfos(pandaFile); + methodInfos_[mapBase] = std::move(methodInfos); + if (pandaFile == nullptr) { + LOG_ECMA(ERROR) << "Can't find JSPandaFile by mapBase: " << mapBase; + } + return true; +} + +bool JSStackTrace::GetJsFrameInfo(uintptr_t byteCodePc, uintptr_t mapBase, uintptr_t loadOffset, JsFunction *jsFunction) +{ + bool ret = true; + auto iter = methodInfos_.find(mapBase); + if (iter == methodInfos_.end()) { + ret = AddMethodInfos(mapBase); + } + loadOffset = loadOffset % PageSize(); + byteCodePc = byteCodePc - loadOffset; + auto codeInfo = TranslateByteCodePc(byteCodePc, methodInfos_[mapBase]); + if (!codeInfo) { + LOG_ECMA(ERROR) << std::hex << "Failed to get methodId, pc: " << byteCodePc; + return false; + } + auto methodId = EntityId(codeInfo->methodId); + auto offset = codeInfo->offset; + auto debugInfoExtractor = + JSPandaFileManager::GetInstance()->GetJSPtExtractor(jsPandaFiles_[mapBase].get()); + ParseJsFrameInfo(jsPandaFiles_[mapBase].get(), debugInfoExtractor, methodId, offset, *jsFunction); + jsFunction->codeBegin = byteCodePc - offset; + jsFunction->codeSize = codeInfo->codeSize; + return ret; +} + +void JSStackTrace::Destory(JSStackTrace* trace) +{ + if (trace == nullptr) { + return; + } + delete trace; + trace = nullptr; +} + +bool ArkParseJsFrameInfoLocal(uintptr_t byteCodePc, uintptr_t mapBase, uintptr_t loadOffset, JsFunction *jsFunction) +{ + bool ret = + JSStackTrace::GetInstance()->GetJsFrameInfo(byteCodePc, mapBase, loadOffset, jsFunction); + return ret; +} + +void ArkDestoryLocal() +{ + auto trace = JSStackTrace::GetInstance(); + return JSStackTrace::Destory(trace); +} + } // namespace panda::ecmascript __attribute__((visibility("default"))) int ark_create_js_symbol_extractor(uintptr_t *extractorptr) @@ -1448,26 +1719,43 @@ __attribute__((visibility("default"))) int ark_destory_js_symbol_extractor(uintp return -1; } -__attribute__((visibility("default"))) int step_ark( - void *ctx, panda::ecmascript::ReadMemFunc readMem, uintptr_t *fp, uintptr_t *sp, uintptr_t *pc, bool *isJsFrame) +__attribute__((visibility("default"))) int ark_destory_local() { - if (panda::ecmascript::StepArk(ctx, readMem, fp, sp, pc, isJsFrame)) { + panda::ecmascript::ArkDestoryLocal(); + return 1; +} + +__attribute__((visibility("default"))) int step_ark( + void *ctx, panda::ecmascript::ReadMemFunc readMem, uintptr_t *fp, uintptr_t *sp, + uintptr_t *pc, uintptr_t *methodId, bool *isJsFrame) +{ + if (panda::ecmascript::StepArk(ctx, readMem, fp, sp, pc, methodId, isJsFrame)) { return 1; } return -1; } __attribute__((visibility("default"))) int ark_parse_js_frame_info( - uintptr_t byteCodePc, uintptr_t mapBase, uintptr_t loadOffset, uint8_t *data, + uintptr_t byteCodePc, uintptr_t methodId, uintptr_t mapBase, uintptr_t loadOffset, uint8_t *data, uint64_t dataSize, uintptr_t extractorptr, panda::ecmascript::JsFunction *jsFunction) { - if (panda::ecmascript::ArkParseJsFrameInfo(byteCodePc, mapBase, loadOffset, data, + if (panda::ecmascript::ArkParseJsFrameInfo(byteCodePc, methodId, mapBase, loadOffset, data, dataSize, extractorptr, jsFunction)) { return 1; } return -1; } +__attribute__((visibility("default"))) int ark_parse_js_file_info( + uintptr_t byteCodePc, uintptr_t methodId, uintptr_t mapBase, const char* filePath, uintptr_t extractorptr, + panda::ecmascript::JsFunction *jsFunction) +{ + if (panda::ecmascript::ArkParseJSFileInfo(byteCodePc, methodId, mapBase, filePath, extractorptr, jsFunction)) { + return 1; + } + return -1; +} + __attribute__((visibility("default"))) int ark_translate_js_frame_info( uint8_t *data, size_t dataSize, panda::ecmascript::JsFunction *jsFunction) { @@ -1495,13 +1783,22 @@ __attribute__((visibility("default"))) int get_ark_js_heap_crash_info( return -1; } -#if defined(PANDA_TARGET_OHOS) -__attribute__((visibility("default"))) int get_ark_native_frame_info(int pid, uintptr_t *pc, - uintptr_t *fp, uintptr_t *sp, panda::ecmascript::JsFrame *jsFrame, size_t &size) +__attribute__((visibility("default"))) int get_ark_native_frame_info( + int pid, uintptr_t *pc, uintptr_t *fp, uintptr_t *sp, + panda::ecmascript::JsFrame *jsFrame, size_t &size) { - if (GetArkNativeFrameInfo(pid, pc, fp, sp, jsFrame, size)) { + if (panda::ecmascript::GetArkNativeFrameInfo(pid, pc, fp, sp, jsFrame, size)) { return 1; } return -1; } -#endif \ No newline at end of file + +__attribute__((visibility("default"))) int ark_parse_js_frame_info_local( + uintptr_t byteCodePc, uintptr_t mapBase, uintptr_t loadOffset, + panda::ecmascript::JsFunction *jsFunction) +{ + if (panda::ecmascript::ArkParseJsFrameInfoLocal(byteCodePc, mapBase, loadOffset, jsFunction)) { + return 1; + } + return -1; +} \ No newline at end of file diff --git a/ecmascript/dfx/stackinfo/js_stackinfo.h b/ecmascript/dfx/stackinfo/js_stackinfo.h index 010e1bf786..5ab997f326 100644 --- a/ecmascript/dfx/stackinfo/js_stackinfo.h +++ b/ecmascript/dfx/stackinfo/js_stackinfo.h @@ -22,6 +22,9 @@ #include "ecmascript/ohos/aot_crash_info.h" #include "ecmascript/js_thread.h" #include "ecmascript/jspandafile/js_pandafile_manager.h" +#if defined(PANDA_TARGET_OHOS) +#include "ecmascript/extractortool/src/zip_file.h" +#endif namespace panda::ecmascript { typedef bool (*ReadMemFunc)(void *ctx, uintptr_t addr, uintptr_t *val); @@ -81,23 +84,53 @@ struct JsFrame { int32_t column; }; +class JSStackTrace { +public: + JSStackTrace() = default; + ~JSStackTrace(); + + static JSStackTrace *GetInstance(); + static std::optional ReadMethodInfo(panda_file::MethodDataAccessor &mda); + static CVector ReadAllMethodInfos(std::shared_ptr jsPandaFile); + static std::optional TranslateByteCodePc(uintptr_t realPc, const CVector &vec); + bool GetJsFrameInfo(uintptr_t byteCodePc, uintptr_t mapBase, uintptr_t loadOffset, JsFunction *jsFunction); + static void Destory(JSStackTrace* trace); +private: + bool AddMethodInfos(uintptr_t mapBase); + + CVector methodInfo_; + std::unordered_map> jsPandaFiles_; + std::unordered_map> methodInfos_; +}; + class JSSymbolExtractor { public: JSSymbolExtractor() = default; ~JSSymbolExtractor(); + static JSSymbolExtractor* Create(); static bool Destory(JSSymbolExtractor* extractor); + + void CreateJSPandaFile(); void CreateJSPandaFile(uint8_t *data, size_t dataSize); void CreateSourceMap(uint8_t *data, size_t dataSize); void CreateDebugExtractor(); + bool ParseHapFileData(std::string& hapName); + + uint8_t* GetData(); + uintptr_t GetLoadOffset(); + uintptr_t GetDataSize(); JSPandaFile* GetJSPandaFile(uint8_t *data = nullptr, size_t dataSize = 0); DebugInfoExtractor* GetDebugExtractor(); SourceMap* GetSourceMap(uint8_t *data = nullptr, size_t dataSize = 0); - std::vector GetmethodInfos(); + CVector GetMethodInfos(); - std::vector methodInfo_; private: + CVector methodInfo_; + uintptr_t loadOffset_ {0}; + uintptr_t dataSize_ {0}; + std::unique_ptr data_ {nullptr}; std::shared_ptr jsPandaFile_ {nullptr}; std::unique_ptr debugExtractor_ {nullptr}; std::shared_ptr sourceMap_ {nullptr}; @@ -122,18 +155,23 @@ extern "C" int step_ark_managed_native_frame( extern "C" int get_ark_js_heap_crash_info( int pid, uintptr_t *x20, uintptr_t *fp, int out_js_info, char *buf, size_t buf_sz); extern "C" int ark_parse_js_frame_info( - uintptr_t byteCodePc, uintptr_t mapBase, uintptr_t loadOffset, uint8_t *data, uint64_t dataSize, - uintptr_t extractorptr, panda::ecmascript::JsFunction *jsFunction); + uintptr_t byteCodePc, uintptr_t methodId, uintptr_t mapBase, uintptr_t loadOffset, uint8_t *data, + uint64_t dataSize, uintptr_t extractorptr, panda::ecmascript::JsFunction *jsFunction); extern "C" int ark_translate_js_frame_info( uint8_t *data, size_t dataSize, panda::ecmascript::JsFunction *jsFunction); extern "C" int step_ark( - void *ctx, panda::ecmascript::ReadMemFunc readMem, uintptr_t *fp, uintptr_t *sp, uintptr_t *pc, bool *isJsFrame); + void *ctx, panda::ecmascript::ReadMemFunc readMem, uintptr_t *fp, uintptr_t *sp, + uintptr_t *pc, uintptr_t *methodId, bool *isJsFrame); extern "C" int ark_create_js_symbol_extractor(uintptr_t *extractorptr); extern "C" int ark_destory_js_symbol_extractor(uintptr_t extractorptr); -#if defined(PANDA_TARGET_OHOS) +extern "C" int ark_parse_js_file_info( + uintptr_t byteCodePc, uintptr_t methodId, uintptr_t mapBase, const char* filePath, uintptr_t extractorptr, + panda::ecmascript::JsFunction *jsFunction); extern "C" int get_ark_native_frame_info( int pid, uintptr_t *pc, uintptr_t *fp, uintptr_t *sp, panda::ecmascript::JsFrame *jsFrame, size_t &size); -#endif +extern "C" int ark_parse_js_frame_info_local(uintptr_t byteCodePc, uintptr_t mapBase, + uintptr_t loadOffset, panda::ecmascript::JsFunction *jsFunction); +extern "C" int ark_destory_local(); // define in dfx_signal_handler.h typedef void(*ThreadInfoCallback)(char *buf, size_t len, void *ucontext); extern "C" void SetThreadInfoCallback(ThreadInfoCallback func) __attribute__((weak)); \ No newline at end of file diff --git a/ecmascript/jspandafile/js_pandafile_manager.cpp b/ecmascript/jspandafile/js_pandafile_manager.cpp index 5a965f9b96..3b429f1a03 100644 --- a/ecmascript/jspandafile/js_pandafile_manager.cpp +++ b/ecmascript/jspandafile/js_pandafile_manager.cpp @@ -273,6 +273,19 @@ std::shared_ptr JSPandaFileManager::FindJSPandaFileByNormalizedName return result; } +std::shared_ptr JSPandaFileManager::FindJSPandaFileByMapBase(uintptr_t mapBase) +{ + std::shared_ptr result; + EnumerateJSPandaFiles([&](const std::shared_ptr &file) -> bool { + if (reinterpret_cast(file->GetHeader()) == mapBase) { + result = file; + return false; + } + return true; + }); + return result; +} + std::shared_ptr JSPandaFileManager::FindJSPandaFile(const CString &filename) { LockHolder lock(jsPandaFileLock_); diff --git a/ecmascript/jspandafile/js_pandafile_manager.h b/ecmascript/jspandafile/js_pandafile_manager.h index bb5d400b97..ef0956d0fc 100644 --- a/ecmascript/jspandafile/js_pandafile_manager.h +++ b/ecmascript/jspandafile/js_pandafile_manager.h @@ -93,6 +93,7 @@ public: } } std::shared_ptr FindJSPandaFileByNormalizedName(const CString &normalizedName); + std::shared_ptr FindJSPandaFileByMapBase(uintptr_t mapBase); std::shared_ptr FindJSPandaFile(const CString &filename); std::shared_ptr FindMergedJSPandaFile(); void AddJSPandaFile(const std::shared_ptr &jsPandaFile); diff --git a/libark_jsruntime.map b/libark_jsruntime.map index 8bf5f21a93..120a77564e 100644 --- a/libark_jsruntime.map +++ b/libark_jsruntime.map @@ -330,6 +330,9 @@ step_ark; ark_create_js_symbol_extractor; ark_destory_js_symbol_extractor; + ark_destory_local; + ark_parse_js_file_info; + ark_parse_js_frame_info_local; }; local: *;