mirror of
https://gitee.com/openharmony/arkcompiler_ets_runtime
synced 2024-10-08 08:54:12 +00:00
!7202 Adaptive sampling stack local rollback
Merge pull request !7202 from 邵益江/dfx
This commit is contained in:
commit
9e07eb0fec
@ -463,7 +463,7 @@ bool IsFunctionFrame(uintptr_t frameType)
|
||||
static_cast<FrameType>(frameType) == FrameType::OPTIMIZED_JS_FAST_CALL_FUNCTION_FRAME;
|
||||
}
|
||||
|
||||
std::optional<MethodInfo> ReadMethodInfo(panda_file::MethodDataAccessor &mda)
|
||||
std::optional<MethodInfo> JSStackTrace::ReadMethodInfo(panda_file::MethodDataAccessor &mda)
|
||||
{
|
||||
uintptr_t methodId = mda.GetMethodId().GetOffset();
|
||||
auto codeId = mda.GetCodeId();
|
||||
@ -476,9 +476,13 @@ std::optional<MethodInfo> ReadMethodInfo(panda_file::MethodDataAccessor &mda)
|
||||
return std::make_optional<MethodInfo>(methodId, codeBegin, codeSize);
|
||||
}
|
||||
|
||||
std::vector<MethodInfo> ReadAllMethodInfos(std::shared_ptr<JSPandaFile> jsPandaFile)
|
||||
CVector<MethodInfo> JSStackTrace::ReadAllMethodInfos(std::shared_ptr<JSPandaFile> jsPandaFile)
|
||||
{
|
||||
std::vector<MethodInfo> result;
|
||||
CVector<MethodInfo> 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<const uint32_t> classIndexes = jsPandaFile->GetClasses();
|
||||
for (const uint32_t index : classIndexes) {
|
||||
@ -488,7 +492,7 @@ std::vector<MethodInfo> ReadAllMethodInfos(std::shared_ptr<JSPandaFile> 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<MethodInfo> ReadAllMethodInfos(std::shared_ptr<JSPandaFile> jsPandaF
|
||||
return result;
|
||||
}
|
||||
|
||||
std::optional<CodeInfo> TranslateByteCodePc(uintptr_t realPc, const std::vector<MethodInfo> &vec)
|
||||
std::optional<CodeInfo> JSStackTrace::TranslateByteCodePc(uintptr_t realPc, const CVector<MethodInfo> &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<uintptr_t>(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>(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<uintptr_t>(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>(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> extractor = ExtractorUtil::GetExtractor(
|
||||
ExtractorUtil::GetLoadFilePath(hapPath), newCreate);
|
||||
if (extractor == nullptr) {
|
||||
LOG_ECMA(ERROR) << "hap's path: " << hapPath;
|
||||
return false;
|
||||
}
|
||||
std::unique_ptr<uint8_t[]> 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<uint8_t[]> ArkReadData(const std::string &hapPath, const std::string &fileName, size_t &dataSize)
|
||||
std::unique_ptr<uint8_t[]> ArkReadData([[maybe_unused]] const std::string &hapPath,
|
||||
[[maybe_unused]] const std::string &fileName,
|
||||
[[maybe_unused]] size_t &dataSize)
|
||||
{
|
||||
std::unique_ptr<uint8_t[]> dataPtr = nullptr;
|
||||
#if defined(PANDA_TARGET_OHOS)
|
||||
bool newCreate = false;
|
||||
std::shared_ptr<Extractor> extractor = ExtractorUtil::GetExtractor(
|
||||
ExtractorUtil::GetLoadFilePath(hapPath), newCreate);
|
||||
@ -1028,6 +1130,7 @@ std::unique_ptr<uint8_t[]> 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<JSPandaFile> OpenJSPandaFileByReadData(const std::string &hapPat
|
||||
return std::make_shared<JSPandaFile>(pf.release(), fileName.c_str());
|
||||
}
|
||||
|
||||
void ArkParseJsFrameDebugInfos(const std::vector<JsFrameDebugInfo> &JsFrameDebugInfos,
|
||||
size_t size, JsFrame *jsFrame, size_t &jsFrameIndex)
|
||||
void ArkParseJsFrameDebugInfos([[maybe_unused]] const std::vector<JsFrameDebugInfo> &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<std::string, std::shared_ptr<JSPandaFile>> jsPandaFileTable;
|
||||
@ -1076,6 +1181,7 @@ void ArkParseJsFrameDebugInfos(const std::vector<JsFrameDebugInfo> &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<ZipFile>(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<uintptr_t>(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<JSSymbolExtractor*>(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<MethodInfo> JSSymbolExtractor::GetmethodInfos()
|
||||
CVector<MethodInfo> JSSymbolExtractor::GetMethodInfos()
|
||||
{
|
||||
if (methodInfo_.empty()) {
|
||||
methodInfo_ = ReadAllMethodInfos(jsPandaFile_);
|
||||
methodInfo_ = JSStackTrace::ReadAllMethodInfos(jsPandaFile_);
|
||||
}
|
||||
|
||||
return methodInfo_;
|
||||
@ -1380,15 +1564,29 @@ std::vector<MethodInfo> 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<JSPandaFile>(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<JSPandaFile>(pf.release(), "");
|
||||
}
|
||||
|
||||
@ -1432,6 +1630,79 @@ bool ArkDestoryJSSymbolExtractor(uintptr_t extractorptr)
|
||||
auto extractor = reinterpret_cast<JSSymbolExtractor*>(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;
|
||||
}
|
||||
|
||||
__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;
|
||||
}
|
||||
#endif
|
@ -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<MethodInfo> ReadMethodInfo(panda_file::MethodDataAccessor &mda);
|
||||
static CVector<MethodInfo> ReadAllMethodInfos(std::shared_ptr<JSPandaFile> jsPandaFile);
|
||||
static std::optional<CodeInfo> TranslateByteCodePc(uintptr_t realPc, const CVector<MethodInfo> &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> methodInfo_;
|
||||
std::unordered_map<uintptr_t, std::shared_ptr<JSPandaFile>> jsPandaFiles_;
|
||||
std::unordered_map<uintptr_t, CVector<MethodInfo>> 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<MethodInfo> GetmethodInfos();
|
||||
CVector<MethodInfo> GetMethodInfos();
|
||||
|
||||
std::vector<MethodInfo> methodInfo_;
|
||||
private:
|
||||
CVector<MethodInfo> methodInfo_;
|
||||
uintptr_t loadOffset_ {0};
|
||||
uintptr_t dataSize_ {0};
|
||||
std::unique_ptr<uint8_t[]> data_ {nullptr};
|
||||
std::shared_ptr<JSPandaFile> jsPandaFile_ {nullptr};
|
||||
std::unique_ptr<DebugInfoExtractor> debugExtractor_ {nullptr};
|
||||
std::shared_ptr<SourceMap> 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));
|
@ -273,6 +273,19 @@ std::shared_ptr<JSPandaFile> JSPandaFileManager::FindJSPandaFileByNormalizedName
|
||||
return result;
|
||||
}
|
||||
|
||||
std::shared_ptr<JSPandaFile> JSPandaFileManager::FindJSPandaFileByMapBase(uintptr_t mapBase)
|
||||
{
|
||||
std::shared_ptr<JSPandaFile> result;
|
||||
EnumerateJSPandaFiles([&](const std::shared_ptr<JSPandaFile> &file) -> bool {
|
||||
if (reinterpret_cast<uintptr_t>(file->GetHeader()) == mapBase) {
|
||||
result = file;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
std::shared_ptr<JSPandaFile> JSPandaFileManager::FindJSPandaFile(const CString &filename)
|
||||
{
|
||||
LockHolder lock(jsPandaFileLock_);
|
||||
|
@ -93,6 +93,7 @@ public:
|
||||
}
|
||||
}
|
||||
std::shared_ptr<JSPandaFile> FindJSPandaFileByNormalizedName(const CString &normalizedName);
|
||||
std::shared_ptr<JSPandaFile> FindJSPandaFileByMapBase(uintptr_t mapBase);
|
||||
std::shared_ptr<JSPandaFile> FindJSPandaFile(const CString &filename);
|
||||
std::shared_ptr<JSPandaFile> FindMergedJSPandaFile();
|
||||
void AddJSPandaFile(const std::shared_ptr<JSPandaFile> &jsPandaFile);
|
||||
|
@ -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:
|
||||
*;
|
||||
|
Loading…
Reference in New Issue
Block a user