!7202 Adaptive sampling stack local rollback

Merge pull request !7202 from 邵益江/dfx
This commit is contained in:
openharmony_ci 2024-04-30 08:29:37 +00:00 committed by Gitee
commit 9e07eb0fec
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
5 changed files with 426 additions and 74 deletions

View File

@ -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 &currentPtr, 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 &currentPtr,
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 &currentPtr, 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 &currentPtr, 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 &currentPtr)
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

View File

@ -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));

View File

@ -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_);

View File

@ -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);

View File

@ -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:
*;