1 /*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <cstdio>
17
18 #include "ecmascript/dfx/stackinfo/js_stackinfo.h"
19 #include "ecmascript/tests/test_helper.h"
20
21 using namespace panda::ecmascript;
22
23 namespace panda::test {
24 class JsStackInfoTest : public testing::Test {
25 public:
SetUpTestCase()26 static void SetUpTestCase()
27 {
28 GTEST_LOG_(INFO) << "SetUpTestCase";
29 }
30
TearDownTestCase()31 static void TearDownTestCase()
32 {
33 GTEST_LOG_(INFO) << "TearDownCase";
34 }
35
SetUp()36 void SetUp() override
37 {
38 TestHelper::CreateEcmaVMWithScope(instance, thread, scope);
39 instance->SetEnableForceGC(false);
40 }
41
TearDown()42 void TearDown() override
43 {
44 TestHelper::DestroyEcmaVMWithScope(instance, scope);
45 }
46
47 EcmaVM *instance {nullptr};
48 EcmaHandleScope *scope {nullptr};
49 JSThread *thread {nullptr};
50 };
51
HWTEST_F_L0(JsStackInfoTest,FrameCheckTest)52 HWTEST_F_L0(JsStackInfoTest, FrameCheckTest)
53 {
54 uintptr_t frame[22];
55 frame[0] = reinterpret_cast<uintptr_t>(FrameType::OPTIMIZED_FRAME);
56 frame[1] = reinterpret_cast<uintptr_t>(FrameType::OPTIMIZED_ENTRY_FRAME);
57 frame[2] = reinterpret_cast<uintptr_t>(FrameType::OPTIMIZED_JS_FUNCTION_FRAME);
58 frame[3] = reinterpret_cast<uintptr_t>(FrameType::OPTIMIZED_JS_FAST_CALL_FUNCTION_FRAME);
59 frame[4] = reinterpret_cast<uintptr_t>(FrameType::ASM_BRIDGE_FRAME);
60 frame[5] = reinterpret_cast<uintptr_t>(FrameType::LEAVE_FRAME);
61 frame[6] = reinterpret_cast<uintptr_t>(FrameType::LEAVE_FRAME_WITH_ARGV);
62 frame[7] = reinterpret_cast<uintptr_t>(FrameType::BUILTIN_CALL_LEAVE_FRAME);
63 frame[8] = reinterpret_cast<uintptr_t>(FrameType::INTERPRETER_FRAME);
64 frame[9] = reinterpret_cast<uintptr_t>(FrameType::ASM_INTERPRETER_FRAME);
65 frame[10] = reinterpret_cast<uintptr_t>(FrameType::INTERPRETER_CONSTRUCTOR_FRAME);
66 frame[11] = reinterpret_cast<uintptr_t>(FrameType::BUILTIN_FRAME);
67 frame[12] = reinterpret_cast<uintptr_t>(FrameType::BUILTIN_FRAME_WITH_ARGV);
68 frame[13] = reinterpret_cast<uintptr_t>(FrameType::BUILTIN_ENTRY_FRAME);
69 frame[14] = reinterpret_cast<uintptr_t>(FrameType::INTERPRETER_BUILTIN_FRAME);
70 frame[15] = reinterpret_cast<uintptr_t>(FrameType::INTERPRETER_FAST_NEW_FRAME);
71 frame[16] = reinterpret_cast<uintptr_t>(FrameType::INTERPRETER_ENTRY_FRAME);
72 frame[17] = reinterpret_cast<uintptr_t>(FrameType::ASM_INTERPRETER_ENTRY_FRAME);
73 frame[18] = reinterpret_cast<uintptr_t>(FrameType::ASM_INTERPRETER_BRIDGE_FRAME);
74 frame[19] = reinterpret_cast<uintptr_t>(FrameType::OPTIMIZED_JS_FUNCTION_ARGS_CONFIG_FRAME);
75 frame[20] = reinterpret_cast<uintptr_t>(FrameType::OPTIMIZED_JS_FUNCTION_UNFOLD_ARGV_FRAME);
76 frame[21] = reinterpret_cast<uintptr_t>(FrameType::BUILTIN_FRAME_WITH_ARGV_STACK_OVER_FLOW_FRAME);
77
78 for (int i = 0; i < 22; i++) {
79 bool ret1 = ArkFrameCheck(frame[i]);
80 if (i == 1 || i == 17) {
81 EXPECT_TRUE(ret1 == true);
82 } else {
83 EXPECT_TRUE(ret1 == false);
84 }
85 bool ret2 = IsFunctionFrame(frame[i]);
86 if (i == 2 || i == 3 || i == 8 || i == 9 || i == 10 || i == 15) {
87 EXPECT_TRUE(ret2 == true);
88 } else {
89 EXPECT_TRUE(ret2 == false);
90 }
91 }
92 }
93
HWTEST_F_L0(JsStackInfoTest,TranslateByteCodePc)94 HWTEST_F_L0(JsStackInfoTest, TranslateByteCodePc)
95 {
96 std::vector<MethodInfo> vec = {
97 {0, 0, 24},
98 {1, 24, 30},
99 {2, 54, 56},
100 {3, 120, 60}
101 };
102 uintptr_t realPc = 115;
103
104 auto ret = TranslateByteCodePc(realPc, vec);
105 EXPECT_TRUE(ret != std::nullopt);
106
107 vec.clear();
108 ret = TranslateByteCodePc(realPc, vec);
109 EXPECT_TRUE(ret == std::nullopt);
110
111 vec.push_back({2, 54, 56});
112 ret = TranslateByteCodePc(realPc, vec);
113 EXPECT_TRUE(ret != std::nullopt);
114 }
115
HWTEST_F_L0(JsStackInfoTest,GetArkNativeFrameInfo)116 HWTEST_F_L0(JsStackInfoTest, GetArkNativeFrameInfo)
117 {
118 if (sizeof(uintptr_t) == sizeof(uint32_t)) { // 32 bit
119 // The frame structure is different between 32 bit and 64 bit.
120 // Skip 32 bit because there is no ArkJS Heap.
121 return;
122 }
123
124 uintptr_t pc = 0;
125 uintptr_t fp = 0;
126 uintptr_t sp = 0;
127 size_t size = 22;
128 JsFrame jsFrame[22];
129 bool ret = GetArkNativeFrameInfo(getpid(), &pc, &fp, &sp, &jsFrame, &size);
130 EXPECT_FALSE(ret);
131 EXPECT_TRUE(size == 22);
132
133 pc = 1234;
134 fp = 62480;
135 sp = 62496;
136 bool ret = GetArkNativeFrameInfo(getpid(), &pc, &fp, &sp, &jsFrame, &size);
137 EXPECT_FALSE(ret);
138 EXPECT_TRUE(size == 22);
139
140 JSTaggedType frame1[3]; // 3: size of ASM_INTERPRETER_ENTRY_FRAME
141 frame1[0] = pc; // 0: pc
142 frame1[1] = 62480; // 1: base.prev
143 frame1[2] = static_cast<JSTaggedType>(FrameType::ASM_INTERPRETER_ENTRY_FRAME); // 2: base.type
144 uintptr_t fp_frame1 = reinterpret_cast<uintptr_t>(&frame3[3]); // 3: bottom of frame
145
146 JSTaggedType frame2[9]; // 9: size of AsmInterpretedFrame
147 frame2[0] = JSTaggedValue::Hole().GetRawData(); // 0: function
148 frame2[1] = JSTaggedValue::Hole().GetRawData(); // 1: thisObj
149 frame2[2] = JSTaggedValue::Hole().GetRawData(); // 2: acc
150 frame2[3] = JSTaggedValue::Hole().GetRawData(); // 3: env
151 frame2[4] = static_cast<JSTaggedType>(0); // 4: callSize
152 frame2[5] = static_cast<JSTaggedType>(0); // 5: fp
153 frame2[6] = reinterpret_cast<JSTaggedType>(&bytecode[2]); // 6: pc
154 frame2[7] = fp_frame1; // 7: base.prev
155 frame2[8] = static_cast<JSTaggedType>(FrameType::ASM_INTERPRETER_FRAME); // 8: base.type
156 uintptr_t fp_frame2 = reinterpret_cast<uintptr_t>(&frame[9]); // 9: bottom of frame
157
158 JSTaggedType frame3[6]; // 6: size of BUILTIN_FRAME
159 frame3[0] = JSTaggedValue::Hole().GetRawData(); // 0: stackArgs
160 frame3[1] = JSTaggedValue::Hole().GetRawData(); // 1:numArgs
161 frame3[2] = JSTaggedValue::Hole().GetRawData(); // 2: thread
162 frame3[3] = JSTaggedValue::Hole().GetRawData(); // 3: returnAddr
163 frame3[4] = fp_frame2; // 4: prevFp
164 frame3[5] = static_cast<JSTaggedType>(FrameType::BUILTIN_FRAME); // 5: type
165 uintptr_t fp_frame3 = reinterpret_cast<uintptr_t>(&frame1[6]); // 6: bottom of frame
166 fp = fp_frame3;
167 bool ret = GetArkNativeFrameInfo(getpid(), &pc, &fp, &sp, &jsFrame, &size);
168 EXPECT_TRUE(ret);
169 EXPECT_TRUE(sp = &fp_frame1);
170 EXPECT_TRUE(pc = 1234);
171 EXPECT_TRUE(fp = 62480);
172 }
173
HWTEST_F_L0(JsStackInfoTest,BuildJsStackInfo)174 HWTEST_F_L0(JsStackInfoTest, BuildJsStackInfo)
175 {
176 auto jsFrame = JsStackInfo::BuildJsStackInfo(thread);
177 EXPECT_TRUE(jsFrame.empty());
178 }
179 } // namespace panda::test
180