jit dump code

Signed-off-by: wangyue <guowanlong@huawei.com>
Change-Id: I8bec0484fa473ec2fe39752276d8d18056300b6c
This commit is contained in:
wangyue 2024-05-08 13:09:22 +04:00
parent 068f004cc6
commit 5b26cb6ca8
5 changed files with 690 additions and 0 deletions

View File

@ -649,6 +649,7 @@ ecma_source = [
"ecmascript/debugger/js_debugger_manager.cpp",
"ecmascript/deoptimizer/calleeReg.cpp",
"ecmascript/deoptimizer/deoptimizer.cpp",
"ecmascript/dfx/dump_code/jit_dump_elf.cpp",
"ecmascript/dfx/stackinfo/js_stackinfo.cpp",
"ecmascript/dfx/vmstat/caller_stat.cpp",
"ecmascript/dfx/vmstat/function_call_timer.cpp",

View File

@ -0,0 +1,198 @@
/*
* Copyright (c) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ecmascript/dfx/dump_code/jit_dump_elf.h"
namespace panda::ecmascript {
void JsJitDumpElf::Initx86ElfHeader()
{
header.e_ident[EI_MAG0] = ELFMAG0;
header.e_ident[EI_MAG1] = ELFMAG1;
header.e_ident[EI_MAG2] = ELFMAG2;
header.e_ident[EI_MAG3] = ELFMAG3;
header.e_ident[EI_CLASS] = ELFCLASS64;
header.e_ident[EI_DATA] = ELFDATA2LSB;
header.e_ident[EI_VERSION] = EV_CURRENT;
header.e_ident[EI_OSABI] = ELFOSABI_NONE; /* ELFOSABI_NONE represents UNIX System V */
header.e_ident[EI_ABIVERSION] = 0;
(void)std::fill_n(&header.e_ident[EI_PAD], EI_NIDENT - EI_PAD, 0);
header.e_type = ET_REL;
header.e_machine = EM_X86_64;
header.e_version = EV_CURRENT;
header.e_entry = 0;
header.e_phoff = 0;
header.e_shoff = 0; /* later get */
header.e_flags = 0; /* The Intel architecture defines no flags; so this member contains zero. */
header.e_ehsize = sizeof(maplebe::FileHeader);
header.e_phentsize = 0;
header.e_phnum = 0;
header.e_shentsize = sizeof(maplebe::SectionHeader);
header.e_shnum = static_cast<uint16>(sections.size());
header.e_shstrndx = strTabSection->GetIndex();
}
void JsJitDumpElf::InitArmElfHeader()
{
header.e_ident[EI_MAG0] = ELFMAG0;
header.e_ident[EI_MAG1] = ELFMAG1;
header.e_ident[EI_MAG2] = ELFMAG2;
header.e_ident[EI_MAG3] = ELFMAG3;
header.e_ident[EI_CLASS] = ELFCLASS64;
header.e_ident[EI_DATA] = ELFDATA2LSB;
header.e_ident[EI_VERSION] = EV_CURRENT;
header.e_ident[EI_OSABI] = ELFOSABI_LINUX;
header.e_ident[EI_ABIVERSION] = 0;
std::fill_n(&header.e_ident[EI_PAD], EI_NIDENT - EI_PAD, 0);
header.e_type = ET_REL;
header.e_version = 1;
header.e_machine = EM_AARCH64;
header.e_flags = 0;
header.e_entry = 0;
header.e_ehsize = sizeof(maplebe::FileHeader);
header.e_phentsize = sizeof(maplebe::SegmentHeader);
header.e_shentsize = sizeof(maplebe::SectionHeader);
header.e_shstrndx = strTabSection->GetIndex();
header.e_shoff = 0;
header.e_phoff = 0;
header.e_shnum = sections.size();
header.e_phnum = 0;
}
void JsJitDumpElf::UpdateSectionOffset(Section &section)
{
if (section.GetType() != SHT_NOBITS) {
section.SetOffset(globalOffset);
} else {
section.SetOffset(0);
}
}
void JsJitDumpElf::UpdateGlobalOffset(Section &section)
{
if (section.GetType() != SHT_NOBITS) {
globalOffset += section.GetSectionSize();
}
}
void JsJitDumpElf::LayoutSections()
{
globalOffset = sizeof(maplebe::FileHeader);
globalOffset = Alignment::Align<maplebe::Offset>(globalOffset, k8Bits);
for (auto *section : sections) {
section->SetSectionHeaderNameIndex(static_cast<maplebe::Word>(strTabSection->AddString(section->GetName())));
}
for (auto *section : sections) {
globalOffset = Alignment::Align<maplebe::Offset>(globalOffset, section->GetAlign());
/* lay out section */
UpdateSectionOffset(*section);
if (section->GetType() != SHT_NOBITS) {
section->GenerateData();
}
UpdateGlobalOffset(*section);
}
globalOffset = Alignment::Align<maplebe::Offset>(globalOffset, 16U);
header.e_shoff = globalOffset;
header.e_shnum = static_cast<uint16>(sections.size());
}
void JsJitDumpElf::RegisterSection(Section &section)
{
sections.push_back(&section);
section.SetIndex(static_cast<maplebe::SectionIndex>(sections.size() - 1));
}
void JsJitDumpElf::AppendData(std::vector<uint8> &codeBuff)
{
if (textSection == nullptr) {
DataSection *nullDataSection = new DataSection(" ", SHT_NULL, 0, 0);
RegisterSection(*nullDataSection);
strTabSection = new StringSection(".strtab", SHT_STRTAB, 0, 1);
RegisterSection(*strTabSection);
textSection = new DataSection(".text", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR, k8Bits);
RegisterSection(*textSection);
symbolTabSection = new SymbolSection(".symtab", SHT_SYMTAB, 0, k8Bits, *strTabSection);
RegisterSection(*symbolTabSection);
}
textSection->AppendData(codeBuff.data(), codeBuff.size());
}
void JsJitDumpElf::AddSymToSymTab(const maplebe::Symbol &symbol, int64 symIdx)
{
localSymTab.push_back(std::make_pair(symbol, symIdx));
}
void JsJitDumpElf::AppendGlobalSymsToSymTabSec()
{
for (auto elem : localSymTab) {
const maplebe::Symbol &symbol = elem.first;
int64 symIdx = elem.second;
symbolTabSection->AppendSymbol(symbol);
symbolTabSection->AppendIdxInSymbols(symIdx);
}
}
void JsJitDumpElf::AppendSymbolToSymTab(int64 symIdx, uint64 funcSymValue, uint64 funcSymSize,
const std::string &symbolName)
{
uint8 funcSymType = STB_GLOBAL;
auto nameIndex = strTabSection->AddString(symbolName);
AddSymToSymTab({static_cast<maplebe::Word>(nameIndex),
static_cast<uint8>((funcSymType << kLeftShift4Bits) + (STT_FUNC & 0xf)), 0, textSection->GetIndex(),
funcSymValue, funcSymSize}, symIdx);
}
void JsJitDumpElf::SetFileOffset(int fd, uint64 offset)
{
lseek(fd, offset, SEEK_SET);
}
void JsJitDumpElf::WriteJitElfFile(int fd)
{
AppendGlobalSymsToSymTabSec();
/* Init elf file header */
InitArmElfHeader();
LayoutSections();
/* write header */
(void)write(fd, reinterpret_cast<const char *>(&header), sizeof(header));
/* write sections */
for (auto *section : sections) {
if (section->GetType() == SHT_NOBITS) {
continue;
}
SetFileOffset(fd, section->GetOffset());
section->WriteSection(fd);
}
SetFileOffset(fd, header.e_shoff);
/* write section table */
for (auto *section : sections) {
(void)write(fd, &section->GetSectionHeader(), sizeof(section->GetSectionHeader()));
}
}
void JsJitDumpElf::ClearData()
{
localSymTab.clear();
globalOffset = 0;
textSection->ClearData();
symbolTabSection->ClearData();
strTabSection->ClearData();
sections.clear();
}
} // namespace panda::ecmascript

View File

@ -0,0 +1,357 @@
/*
* Copyright (c) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <vector>
#include <string>
#include <unistd.h>
#include <unordered_map>
#include "ecmascript/compiler/codegen/maple/maple_be/include/cg/elf_types.h"
#include "ecmascript/log_wrapper.h"
#ifndef ECMASCRIPT_JIT_DUMP_ELF_H
#define ECMASCRIPT_JIT_DUMP_ELF_H
namespace panda::ecmascript {
using uint8 = uint8_t;
using uint16 = uint16_t;
using uint32 = uint32_t;
using uint64 = uint64_t;
using int8 = int8_t;
using int16 = int16_t;
using int32 = int32_t;
using int64 = int64_t;
using uintptr = uintptr_t;
const uint8 kLeftShift4Bits = 4;
static const uint8 k8Bits = 8;
class Section {
public:
Section(const std::string &name, maplebe::Word type, maplebe::Xword flags, maplebe::Xword align) : name(name)
{
sectionHeader.sh_type = type;
sectionHeader.sh_flags = flags;
sectionHeader.sh_addralign = align;
}
virtual ~Section() = default;
virtual void GenerateData() = 0;
virtual void WriteSection(int fd) = 0;
virtual void ClearData()
{
return;
}
void SetIndex(maplebe::SectionIndex idx)
{
sectionIndex = idx;
}
maplebe::SectionIndex GetIndex() const
{
return sectionIndex;
}
void SetInfo(maplebe::Word value)
{
sectionHeader.sh_info = value;
}
void SetLink(const Section &section)
{
sectionHeader.sh_link = static_cast<maplebe::Word>(section.GetIndex());
}
void SetEntSize(maplebe::Xword value)
{
sectionHeader.sh_entsize = value;
}
void SetSectionSize(maplebe::Xword size)
{
sectionHeader.sh_size = size;
}
virtual maplebe::Xword GetSectionSize()
{
return sectionHeader.sh_size;
}
void SetAddr(maplebe::Address addr)
{
sectionHeader.sh_addr = addr;
}
maplebe::Address GetAddr() const
{
return sectionHeader.sh_addr;
}
maplebe::Xword GetFlags() const
{
return sectionHeader.sh_flags;
}
void SetOffset(maplebe::Offset value)
{
sectionHeader.sh_offset = value;
}
maplebe::Offset GetOffset() const
{
return sectionHeader.sh_offset;
}
maplebe::Xword GetAlign() const
{
return sectionHeader.sh_addralign;
}
const std::string &GetName() const
{
return name;
}
void SetSectionHeaderNameIndex(maplebe::Word index)
{
sectionHeader.sh_name = index;
}
maplebe::Word GetType() const
{
return sectionHeader.sh_type;
}
const maplebe::SectionHeader &GetSectionHeader() const
{
return sectionHeader;
}
private:
std::string name;
maplebe::SectionIndex sectionIndex {};
maplebe::SectionHeader sectionHeader {};
}; /* class Section */
class RelaSection : public Section {
public:
RelaSection(const std::string &name, maplebe::Word type, maplebe::Xword flags, maplebe::Word info,
maplebe::Xword align, const Section &link) : Section(name, type, flags, align)
{
SetEntSize(sizeof(maplebe::Rela));
SetInfo(info);
SetLink(link);
}
~RelaSection() = default;
void GenerateData() override
{
SetSectionSize(relas.size() * sizeof(maplebe::Rela));
}
void WriteSection(int fd) override
{
(void)write(fd, reinterpret_cast<const char *>(relas.data()), relas.size() * sizeof(maplebe::Rela));
}
void AppendRela(maplebe::Rela rela)
{
relas.push_back(rela);
}
private:
std::vector<maplebe::Rela> relas;
}; /* class RelaSection */
class SymbolSection : public Section {
public:
SymbolSection(const std::string &name, maplebe::Word type, maplebe::Xword flags, maplebe::Xword align,
const Section &link) : Section(name, type, flags, align)
{
SetEntSize(sizeof(maplebe::Symbol));
SetLink(link);
SetInfo(1);
AppendSymbol({0, 0, 0, 0, 0, 0});
}
~SymbolSection() = default;
void GenerateData() override
{
SetSectionSize(symbols.size() * sizeof(maplebe::Symbol));
}
void WriteSection(int fd) override
{
(void)write(fd, reinterpret_cast<const char *>(symbols.data()), symbols.size() * sizeof(maplebe::Symbol));
}
void AppendSymbol(const maplebe::Symbol &symbol)
{
symbols.push_back(symbol);
}
uint32 GetSymbolsSize() const
{
return symbols.size();
}
uint64 GetIdxInSymbols(int64 symIdx) const
{
return symbolIdxMap.at(symIdx);
}
void AppendIdxInSymbols(int64 symIdx)
{
symbolIdxMap[symIdx] = static_cast<uint64>(GetSymbolsSize() - 1);
}
bool ExistSymInSymbols(int64 symIdx)
{
return symbolIdxMap.count(symIdx) != 0;
}
uint32 GetDataSize() const
{
return symbols.size() * sizeof(maplebe::Symbol);
}
const char *GetAddr()
{
return reinterpret_cast<const char*>(symbols.data());
}
void ClearData() override
{
symbols.clear();
symbolIdxMap.clear();
}
private:
std::vector<maplebe::Symbol> symbols;
std::unordered_map<int64, uint64> symbolIdxMap;
}; /* class SymbolSection */
class DataSection : public Section {
public:
DataSection(const std::string &name, maplebe::Word type, maplebe::Xword flags, maplebe::Xword align) :
Section(name, type, flags, align) {}
~DataSection() = default;
virtual void GenerateData() override
{
SetSectionSize(data.size());
}
virtual void WriteSection(int fd) override
{
(void)write(fd, reinterpret_cast<const char *>(data.data()), data.size());
}
void AppendData(const void *value, size_t size)
{
auto pdata = reinterpret_cast<const uint8 *>(value);
data.insert(data.end(), pdata, pdata + size);
}
void AppendData(int64 value, size_t size)
{
for (size_t i = 0; i < size; i++) {
auto pdata = static_cast<uint8>(value >> (i * k8Bits));
data.push_back(pdata);
}
}
void ClearData() override
{
data.clear();
}
uint32 GetDataSize() const
{
return data.size();
}
const std::vector<uint8> &GetData() const
{
return data;
}
protected:
std::vector<uint8> data;
}; /* class DataSection */
class StringSection : public DataSection {
public:
StringSection(const std::string &name, maplebe::Word type, maplebe::Xword flags, maplebe::Xword align) :
DataSection(name, type, flags, align)
{
AddString("\0");
}
~StringSection() = default;
size_t AddString(const std::string &str)
{
size_t pos = data.size();
AppendData(str.c_str(), str.size() + 1);
return pos;
}
}; /* class StringSection */
class Alignment {
public:
template <typename T>
static T Align(T offset, T align)
{
if (align <= 1) {
return offset;
}
return (offset + align - 1) & (~(align - 1));
}
}; /* class Alignment */
class JsJitDumpElf {
public:
void SetFileOffset(int fd, uint64 offset);
void Initx86ElfHeader();
void InitArmElfHeader();
void WriteJitElfFile(int fd);
void LayoutSections();
void UpdateSectionOffset(Section &section);
void UpdateGlobalOffset(Section &section);
void RegisterSection(Section &section);
void AppendData(std::vector<uint8> &codeBuff);
void AddSymToSymTab(const maplebe::Symbol &symbol, int64 symIdx);
void AppendGlobalSymsToSymTabSec();
void AppendSymbolToSymTab(int64 symIdx, uint64 funcSymValue, uint64 funcSymSize, const std::string &symbolName);
void ClearData();
private:
std::vector<std::pair<maplebe::Symbol, int64>> localSymTab;
DataSection *textSection = nullptr;
SymbolSection *symbolTabSection = nullptr;
maplebe::FileHeader header {};
StringSection *strTabSection = nullptr;
std::vector<Section *> sections;
maplebe::Offset globalOffset = 0; /* global offset of the elf file */
};
} // namespace panda::ecmascript
#endif // ECMASCRIPT_JIT_DUMP_ELF_H

View File

@ -35,8 +35,17 @@
namespace panda::ecmascript {
[[maybe_unused]]static bool g_needCheck = true;
std::unordered_map<EntityId, uintptr_t> JsStackInfo::methodMap;
std::unordered_map<uintptr_t, std::string> JsStackInfo::nameMap;
const int USEC_PER_SEC = 1000 * 1000;
const int NSEC_PER_USEC = 1000;
bool IsFastJitFunctionFrame([[maybe_unused]]const FrameType frameType)
{
return true;
}
std::string JsStackInfo::BuildMethodTrace(Method *method, uint32_t pcOffset, bool enableStackSourceFile)
{
std::string data;
@ -534,6 +543,9 @@ void ParseJsFrameInfo(JSPandaFile *jsPandaFile, DebugInfoExtractor *debugExtract
}
std::string name = MethodLiteral::ParseFunctionName(jsPandaFile, methodId);
name = name.empty() ? "anonymous" : name;
if (JsStackInfo::methodMap.find(methodId) != JsStackInfo::methodMap.end()) {
JsStackInfo::nameMap.emplace(JsStackInfo::methodMap[methodId], name);
}
std::string url = debugExtractor->GetSourceFile(methodId);
// line number and column number
@ -807,6 +819,90 @@ bool ArkGetNextFrame(void *ctx, ReadMemFunc readMem, uintptr_t &currentPtr,
return ArkGetNextFrame(ctx, readMem, currentPtr, frameType, pc, methodId);
}
bool ArkWriteJitCode(int fd, std::vector<uintptr_t> *jitCodeVec)
{
JsJitDumpElf jitDumpElf;
int64 idx = 0;
for (size_t i = 0; i < jitCodeVec->size(); i++) {
JSTaggedValue machineCodeValue = JSTaggedValue((*jitCodeVec)[i]);
MachineCode *machineCodeObj = MachineCode::Cast(machineCodeValue.GetTaggedObject());
size_t len = machineCodeObj->GetTextSize();
char *funcAddr = reinterpret_cast<char *>(machineCodeObj->GetFuncAddr());
std::vector<uint8> codeVec;
memmove_s(codeVec.data(), len, funcAddr, len);
jitDumpElf.AppendData(codeVec);
jitDumpElf.AppendSymbolToSymTab(idx++, 0, machineCodeObj->GetTextSize(),
JsStackInfo::nameMap[(*jitCodeVec)[i]]);
}
jitDumpElf.WriteJitElfFile(fd);
JsStackInfo::methodMap.clear();
JsStackInfo::nameMap.clear();
return true;
}
uintptr_t ArkGetJitMachineCode(void *ctx, ReadMemFunc readMem, uintptr_t currentPtr)
{
uintptr_t *function = 0;
uintptr_t *machineCode = 0;
uintptr_t funcAddr = currentPtr;
// funcAddr -= FASTJITFunctionFrame::GetTypeOffset();
// funcAddr += FASTJITFunctionFrame::GetFunctionOffset();
readMem(ctx, funcAddr, function);
*function += JSFunction::MACHINECODE_OFFSET;
readMem(ctx, *function, machineCode);
return *machineCode;
}
void SaveMethodId(EntityId entityId, uintptr_t machineCodeAddr)
{
size_t length = 256; // maximum stack length
if (JsStackInfo::methodMap.size() > length) {
auto it = JsStackInfo::methodMap.begin();
uintptr_t value = it->second;
JsStackInfo::nameMap.erase(value);
JsStackInfo::methodMap.erase(it);
}
JsStackInfo::methodMap.emplace(entityId, machineCodeAddr);
}
bool StepArkWithRecordJit(ArkUnwindParam *arkUnwindParam)
{
constexpr size_t FP_SIZE = sizeof(uintptr_t);
uintptr_t currentPtr = *arkUnwindParam->fp;
if (currentPtr == 0) {
LOG_ECMA(ERROR) << "fp is nullptr in StepArkWithRecordJit()!";
return false;
}
uintptr_t frameType = 0;
if (ArkGetNextFrame(arkUnwindParam->ctx, arkUnwindParam->readMem, currentPtr, frameType, *arkUnwindParam->pc,
arkUnwindParam->methodId)) {
if (ArkFrameCheck(frameType)) {
currentPtr += sizeof(FrameType);
*arkUnwindParam->sp = currentPtr;
bool ret = arkUnwindParam->readMem(arkUnwindParam->ctx, currentPtr, arkUnwindParam->fp);
currentPtr += FP_SIZE;
ret &= arkUnwindParam->readMem(arkUnwindParam->ctx, currentPtr, arkUnwindParam->pc);
*arkUnwindParam->isJsFrame = false;
return ret;
} else {
if (IsFastJitFunctionFrame(static_cast<FrameType>(frameType))) {
uintptr_t machineCode = ArkGetJitMachineCode(arkUnwindParam->ctx, arkUnwindParam->readMem, currentPtr);
*(arkUnwindParam->jitCache + *arkUnwindParam->jitSize) = machineCode;
*arkUnwindParam->jitSize += 1;
SaveMethodId(EntityId(*arkUnwindParam->methodId), machineCode);
}
*arkUnwindParam->fp = currentPtr;
*arkUnwindParam->sp = currentPtr;
*arkUnwindParam->isJsFrame = true;
}
} else {
LOG_ECMA(ERROR) << "ArkGetNextFrame failed, currentPtr: " << currentPtr << ", frameType: " << frameType;
return false;
}
return true;
}
bool StepArk(void *ctx, ReadMemFunc readMem, uintptr_t *fp, uintptr_t *sp,
uintptr_t *pc, uintptr_t *methodId, bool *isJsFrame)
{
@ -1720,6 +1816,23 @@ __attribute__((visibility("default"))) int ark_destory_local()
return 1;
}
__attribute__((visibility("default"))) int step_ark_with_record_jit(panda::ecmascript::ArkUnwindParam *arkUnwindParam)
{
if (panda::ecmascript::StepArkWithRecordJit(arkUnwindParam)) {
return 1;
}
return -1;
}
__attribute__((visibility("default"))) int ark_write_jit_code(
int fd, std::vector<uintptr_t> *jitCodeVec)
{
if (panda::ecmascript::ArkWriteJitCode(fd, jitCodeVec)) {
return 1;
}
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)

View File

@ -22,6 +22,7 @@
#include "ecmascript/ohos/aot_crash_info.h"
#include "ecmascript/js_thread.h"
#include "ecmascript/jspandafile/js_pandafile_manager.h"
#include "ecmascript/dfx/dump_code/jit_dump_elf.h"
#if defined(PANDA_TARGET_OHOS)
#include "ecmascript/extractortool/src/zip_file.h"
#endif
@ -77,6 +78,22 @@ struct JsFrameDebugInfo {
: methodId(methodId), offset(offset), hapPath(hapPath), filePath(filePath) {}
};
struct ArkUnwindParam {
void *ctx;
ReadMemFunc readMem;
uintptr_t *fp;
uintptr_t *sp;
uintptr_t *pc;
uintptr_t *methodId;
bool *isJsFrame;
uintptr_t *jitCache;
size_t *jitSize;
ArkUnwindParam(void *ctx, ReadMemFunc readMem, uintptr_t *fp, uintptr_t *sp, uintptr_t *pc, uintptr_t *methodId,
bool *isJsFrame, uintptr_t *jitCache, size_t *jitSize)
: ctx(ctx), readMem(readMem), fp(fp), sp(sp), pc(pc), methodId(methodId),
isJsFrame(isJsFrame), jitCache(jitCache), jitSize(jitSize) {}
};
struct JsFrame {
char functionName[FUNCTIONNAME_MAX];
char url[URL_MAX];
@ -145,6 +162,8 @@ public:
static AOTFileManager *loader;
static JSRuntimeOptions *options;
static void BuildCrashInfo(bool isJsCrash, uintptr_t pc = 0);
static std::unordered_map<EntityId, uintptr_t> methodMap;
static std::unordered_map<uintptr_t, std::string> nameMap;
};
void CrashCallback(char *buf, size_t len, void *ucontext);
uint64_t GetMicrosecondsTimeStamp();
@ -159,6 +178,8 @@ extern "C" int ark_parse_js_frame_info(
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_with_record_jit(panda::ecmascript::ArkUnwindParam *arkUnwindParam);
extern "C" int ark_write_jit_code(int fd, std::vector<uintptr_t> *jitCodeVec);
extern "C" int step_ark(
void *ctx, panda::ecmascript::ReadMemFunc readMem, uintptr_t *fp, uintptr_t *sp,
uintptr_t *pc, uintptr_t *methodId, bool *isJsFrame);