mirror of
https://gitee.com/openharmony/arkcompiler_ets_runtime
synced 2024-11-27 12:10:47 +00:00
jit dump code
Signed-off-by: wangyue <guowanlong@huawei.com> Change-Id: I8bec0484fa473ec2fe39752276d8d18056300b6c
This commit is contained in:
parent
068f004cc6
commit
5b26cb6ca8
1
BUILD.gn
1
BUILD.gn
@ -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",
|
||||
|
198
ecmascript/dfx/dump_code/jit_dump_elf.cpp
Normal file
198
ecmascript/dfx/dump_code/jit_dump_elf.cpp
Normal 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 §ion)
|
||||
{
|
||||
if (section.GetType() != SHT_NOBITS) {
|
||||
section.SetOffset(globalOffset);
|
||||
} else {
|
||||
section.SetOffset(0);
|
||||
}
|
||||
}
|
||||
|
||||
void JsJitDumpElf::UpdateGlobalOffset(Section §ion)
|
||||
{
|
||||
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 §ion)
|
||||
{
|
||||
sections.push_back(§ion);
|
||||
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, §ion->GetSectionHeader(), sizeof(section->GetSectionHeader()));
|
||||
}
|
||||
}
|
||||
|
||||
void JsJitDumpElf::ClearData()
|
||||
{
|
||||
localSymTab.clear();
|
||||
globalOffset = 0;
|
||||
textSection->ClearData();
|
||||
symbolTabSection->ClearData();
|
||||
strTabSection->ClearData();
|
||||
sections.clear();
|
||||
}
|
||||
|
||||
} // namespace panda::ecmascript
|
357
ecmascript/dfx/dump_code/jit_dump_elf.h
Normal file
357
ecmascript/dfx/dump_code/jit_dump_elf.h
Normal 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 §ion)
|
||||
{
|
||||
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 §ion);
|
||||
void UpdateGlobalOffset(Section §ion);
|
||||
void RegisterSection(Section §ion);
|
||||
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
|
@ -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 ¤tPtr,
|
||||
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)
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user