!3051 Enhance Return Stack for DFX

Merge pull request !3051 from 李晨帅/master
This commit is contained in:
openharmony_ci 2022-12-12 12:59:57 +00:00 committed by Gitee
commit b0343f5d9d
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
5 changed files with 188 additions and 3 deletions

View File

@ -22,6 +22,7 @@
namespace panda::ecmascript::kungfu {
#define IGNORE_BC_STUB(...)
#define ASM_UNUSED_BC_STUB_LIST(T) \
T(HandleOverflowD6) \
T(HandleOverflowD7) \
T(HandleOverflowD8) \
T(HandleOverflowD9) \
@ -58,8 +59,7 @@ namespace panda::ecmascript::kungfu {
T(HandleOverflowF8) \
T(HandleOverflowF9) \
T(HandleOverflowFA) \
T(HandleOverflowFB) \
T(HandleOverflowFC)
T(HandleOverflowFB)
// V: Not Enabled, T: Enabled, D: Always Disable SingleStepDebugging

View File

@ -16,9 +16,11 @@
#include "ecmascript/frames.h"
#include "ecmascript/aot_file_manager.h"
#include "ecmascript/dfx/stackinfo/js_stackinfo.h"
#include "ecmascript/ecma_vm.h"
#include "ecmascript/interpreter/frame_handler.h"
#include "ecmascript/js_thread.h"
#include "ecmascript/message_string.h"
#include "ecmascript/platform/os.h"
#include "ecmascript/stackmap/ark_stackmap_parser.h"
#include "ecmascript/stackmap/llvm_stackmap_parser.h"
@ -769,7 +771,7 @@ bool StepArkManagedNativeFrame(int pid, uintptr_t *pc, uintptr_t *fp, uintptr_t
LOG_ECMA(ERROR) << "FrameType ERROR, addr: " << currentPtr << ", frameType: " << frameType;
return false;
}
if (frameType == (uintptr_t)(FrameType::ASM_INTERPRETER_ENTRY_FRAME)) {
if (static_cast<FrameType>(frameType) == FrameType::ASM_INTERPRETER_ENTRY_FRAME) {
break;
}
currentPtr -= typeOffset;
@ -788,6 +790,99 @@ bool StepArkManagedNativeFrame(int pid, uintptr_t *pc, uintptr_t *fp, uintptr_t
*sp = currentPtr;
return true;
}
void CopyBytecodeInfoToBuffer(const char *prefix, uintptr_t fullBytecode, size_t &strIdx, char *outStr, size_t strLen)
{
// note: big endian
for (size_t i = 0; prefix[i] != '\0' && strIdx < strLen - 1; i++) { // 1: last '\0'
outStr[strIdx++] = prefix[i];
}
size_t start = GET_MESSAGE_STRING_ID(HandleLdundefined);
size_t bytecode = fullBytecode & 0xff; // 0xff: last byte
const char *bytecodeName = MessageString::GetMessageString(start + bytecode).c_str();
for (size_t i = 0; bytecodeName[i] != '\0' && strIdx < strLen - 1; i++) { // 1: last '\0'
outStr[strIdx++] = bytecodeName[i];
}
if (start + bytecode == GET_MESSAGE_STRING_ID(HandleDeprecated) ||
start + bytecode == GET_MESSAGE_STRING_ID(HandleWide) ||
start + bytecode == GET_MESSAGE_STRING_ID(HandleThrow)) {
size_t startSecond = start;
if (start + bytecode == GET_MESSAGE_STRING_ID(HandleDeprecated)) {
startSecond = GET_MESSAGE_STRING_ID(HandleDeprecatedLdlexenvPrefNone);
} else if (start + bytecode == GET_MESSAGE_STRING_ID(HandleWide)) {
startSecond = GET_MESSAGE_STRING_ID(HandleWideCreateobjectwithexcludedkeysPrefImm16V8V8);
} else if (start + bytecode == GET_MESSAGE_STRING_ID(HandleThrow)) {
startSecond = GET_MESSAGE_STRING_ID(HandleThrowPrefNone);
}
size_t bytecodeSecond = (fullBytecode >> 8) & 0xff; // 8, 0xff: second last byte
const char *bytecodeNameSecond = MessageString::GetMessageString(startSecond + bytecodeSecond).c_str();
if (strIdx < strLen - 1) { // 1: last '\0'
outStr[strIdx++] = '/';
}
for (size_t i = 0; bytecodeNameSecond[i] != '\0' && strIdx < strLen - 1; i++) { // 1: last '\0'
outStr[strIdx++] = bytecodeNameSecond[i];
}
}
outStr[strIdx] = '\0';
}
bool GetArkJSHeapCrashInfo(int pid, uintptr_t *bytecodePc, uintptr_t *fp, bool outJSInfo, char *outStr, size_t strLen)
{
// bytecodePc: X20 in ARM
// fp: X29 in ARM
// outJSInfo: not async-safe, more info
uintptr_t currentPtr = *fp;
currentPtr -= sizeof(FrameType);
uintptr_t frameType = 0;
if (!ReadUintptrFromAddr(pid, currentPtr, frameType)) {
return false;
}
if (static_cast<FrameType>(frameType) != FrameType::ASM_INTERPRETER_FRAME) {
return false;
}
size_t strIndex = 0;
uintptr_t registerBytecode = 0;
if (!ReadUintptrFromAddr(pid, *bytecodePc, registerBytecode)) {
return false;
}
CopyBytecodeInfoToBuffer("RegisterBytecode:", registerBytecode, strIndex, outStr, strLen);
uintptr_t typeOffset = MEMBER_OFFSET(AsmInterpretedFrame, base) + MEMBER_OFFSET(InterpretedFrameBase, type);
uintptr_t pcOffset = MEMBER_OFFSET(AsmInterpretedFrame, pc);
currentPtr -= typeOffset;
currentPtr += pcOffset;
uintptr_t framePc = 0;
uintptr_t frameBytecode = 0;
if (!ReadUintptrFromAddr(pid, currentPtr, framePc)) {
return false;
}
if (!ReadUintptrFromAddr(pid, framePc, frameBytecode)) {
return false;
}
CopyBytecodeInfoToBuffer(" FrameBytecode:", frameBytecode, strIndex, outStr, strLen);
if (outJSInfo) {
uintptr_t functionOffset = MEMBER_OFFSET(AsmInterpretedFrame, function);
currentPtr -= pcOffset;
currentPtr += functionOffset;
uintptr_t functionAddress = 0;
if (!ReadUintptrFromAddr(pid, currentPtr, functionAddress)) {
return false;
}
JSTaggedValue functionValue(static_cast<JSTaggedType>(functionAddress));
Method *method = ECMAObject::Cast(functionValue.GetTaggedObject())->GetCallTarget();
auto bytecodeOffset = static_cast<uint32_t>(reinterpret_cast<uint8_t *>(*bytecodePc) -
method->GetBytecodeArray());
std::string info = JsStackInfo::BuildMethodTrace(method, bytecodeOffset);
const char *infoChar = info.c_str();
if (strIndex < strLen - 1) { // 1: last '\0'
outStr[strIndex++] = ' ';
}
for (size_t i = 0; infoChar[i] != '\0' && strIndex < strLen - 1; i++) { // 1: last '\0'
outStr[strIndex++] = infoChar[i];
}
outStr[strIndex] = '\0';
}
return true;
}
} // namespace panda::ecmascript
__attribute__((visibility("default"))) int step_ark_managed_native_frame(
@ -798,3 +893,12 @@ __attribute__((visibility("default"))) int step_ark_managed_native_frame(
}
return -1;
}
__attribute__((visibility("default"))) 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)
{
if (panda::ecmascript::GetArkJSHeapCrashInfo(pid, x20, fp, out_js_info != 0, buf, buf_sz)) {
return 1;
}
return -1;
}

View File

@ -1428,4 +1428,6 @@ private:
} // namespace panda::ecmascript
extern "C" int step_ark_managed_native_frame(
int pid, uintptr_t *pc, uintptr_t *fp, uintptr_t *sp, char *buf, size_t buf_sz);
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);
#endif // ECMASCRIPT_FRAMES_H

View File

@ -33,6 +33,7 @@ host_unittest_action("EcmaVm_001_Test") {
"ecma_string_accessor_test.cpp",
"ecma_string_table_test.cpp",
"ecma_vm_test.cpp",
"frame_test.cpp",
"gc_test.cpp",
"global_dictionary_test.cpp",
"glue_regs_test.cpp",

View File

@ -0,0 +1,78 @@
/*
* Copyright (c) 2022 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/frames.h"
#include "ecmascript/tests/test_helper.h"
using namespace panda::ecmascript;
namespace panda::test {
class FrameTest : public testing::Test {
public:
static void SetUpTestCase()
{
GTEST_LOG_(INFO) << "SetUpTestCase";
}
static void TearDownTestCase()
{
GTEST_LOG_(INFO) << "TearDownCase";
}
void SetUp() override
{
}
void TearDown() override
{
}
};
/*
* @tc.name: GetArkJSHeapCrashInfoTest
* @tc.desc: Test API get_ark_js_heap_crash_info
* @tc.type: FUNC
* @tc.require:
*/
HWTEST_F_L0(FrameTest, GetArkJSHeapCrashInfoTest)
{
uint8_t bytecode[] = {
12, // 12: HandleMul2Imm8V8
34, // 34: HandleDecImm8
56, // 56: HandleStobjbyvalueImm8V8V8
78, // 78: HandleJmpImm16
90, // 90: HandleJstrictequndefinedImm8
254, // 254: HandleThrow
8, // 8: HandleThrowIfsupernotcorrectcallPrefImm16
};
JSTaggedType frame[9]; // 9: size of AsmInterpretedFrame
frame[0] = JSTaggedValue::Hole().GetRawData(); // 0: function
frame[1] = JSTaggedValue::Hole().GetRawData(); // 1: thisObj
frame[2] = JSTaggedValue::Hole().GetRawData(); // 2: acc
frame[3] = JSTaggedValue::Hole().GetRawData(); // 3: env
frame[4] = static_cast<JSTaggedType>(0); // 4: callSize
frame[5] = static_cast<JSTaggedType>(0); // 5: fp
frame[6] = reinterpret_cast<JSTaggedType>(&bytecode[2]); // 6: pc
frame[7] = static_cast<JSTaggedType>(0); // 7: base.prev
frame[8] = static_cast<JSTaggedType>(FrameType::ASM_INTERPRETER_FRAME); // 8: base.type
uintptr_t x20 = reinterpret_cast<uintptr_t>(&bytecode[5]); // 5: HandleThrow offset
uintptr_t fp = reinterpret_cast<uintptr_t>(&frame[9]); // 9: bottom of frame
char buf[256]; // 256: buf size
int result = get_ark_js_heap_crash_info(getpid(), &x20, &fp, 0, &buf[0], 256); // 256: buf size
EXPECT_EQ(result, 1);
EXPECT_EQ(std::string(buf), std::string("RegisterBytecode:HandleThrow/HandleThrowIfsupernotcorrectcallPrefImm16") +
std::string(" FrameBytecode:HandleStobjbyvalueImm8V8V8"));
}
} // namespace panda::ecmascript