1 /*
2 * Copyright (c) 2021 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 <gtest/gtest.h>
17
18 #include <vector>
19
20 #include "runtime/entrypoints/entrypoints.h"
21 #include "runtime/include/method.h"
22 #include "runtime/tooling/debugger.h"
23
24 #include "assembly-emitter.h"
25 #include "assembly-parser.h"
26
27 namespace panda::debugger::test {
28
29 class DebuggerTest : public testing::Test {
30 public:
DebuggerTest()31 DebuggerTest()
32 {
33 RuntimeOptions options;
34 options.SetShouldLoadBootPandaFiles(false);
35 options.SetShouldInitializeIntrinsics(false);
36 Runtime::Create(options);
37 thread_ = panda::MTManagedThread::GetCurrent();
38 thread_->ManagedCodeBegin();
39 }
40
~DebuggerTest()41 ~DebuggerTest()
42 {
43 thread_->ManagedCodeEnd();
44 Runtime::Destroy();
45 }
46
47 protected:
48 panda::MTManagedThread *thread_ {nullptr};
49 };
50
ToPtr(uint64_t v)51 static ObjectHeader *ToPtr(uint64_t v)
52 {
53 return reinterpret_cast<ObjectHeader *>(static_cast<object_pointer_type>(v));
54 }
55
FromPtr(ObjectHeader * ptr)56 static uint64_t FromPtr(ObjectHeader *ptr)
57 {
58 return static_cast<object_pointer_type>(reinterpret_cast<uint64_t>(ptr));
59 }
60
CreateFrame(size_t nregs,Method * method,Frame * prev)61 static Frame *CreateFrame(size_t nregs, Method *method, Frame *prev)
62 {
63 panda::Frame *mem = static_cast<Frame *>(aligned_alloc(8U, panda::Frame::GetSize(nregs)));
64 return (new (mem) panda::Frame(method, prev, nregs));
65 }
66
FreeFrame(Frame * frame)67 static void FreeFrame(Frame *frame)
68 {
69 std::free(frame);
70 }
71
TEST_F(DebuggerTest,Frame)72 TEST_F(DebuggerTest, Frame)
73 {
74 pandasm::Parser p;
75
76 auto source = R"(
77 .function void foo(i32 a0, i32 a1) {
78 movi v0, 1
79 movi v1, 2
80 return.void
81 }
82 )";
83
84 std::string src_filename = "src.pa";
85 auto res = p.Parse(source, src_filename);
86 ASSERT(p.ShowError().err == pandasm::Error::ErrorType::ERR_NONE);
87
88 auto file_ptr = pandasm::AsmEmitter::Emit(res.Value());
89 ASSERT(file_ptr != nullptr);
90
91 PandaString descriptor;
92 auto class_id = file_ptr->GetClassId(ClassHelper::GetDescriptor(utf::CStringAsMutf8("_GLOBAL"), &descriptor));
93 ASSERT_TRUE(class_id.IsValid());
94
95 panda_file::ClassDataAccessor cda(*file_ptr, class_id);
96 panda_file::File::EntityId method_id;
97 panda_file::File::EntityId code_id;
98
99 cda.EnumerateMethods([&](panda_file::MethodDataAccessor &mda) {
100 method_id = mda.GetMethodId();
101 ASSERT_TRUE(mda.GetCodeId());
102 code_id = mda.GetCodeId().value();
103 });
104
105 panda_file::CodeDataAccessor code_data_accessor(*file_ptr, code_id);
106 auto nargs = code_data_accessor.GetNumArgs();
107 auto nregs = code_data_accessor.GetNumVregs();
108
109 constexpr size_t BYTECODE_OFFSET = 0xeeff;
110
111 Method method(nullptr, file_ptr.get(), method_id, code_id, 0, nargs, nullptr);
112 panda::Frame *frame = test::CreateFrame(nregs + nargs, &method, nullptr);
113 frame->SetBytecodeOffset(BYTECODE_OFFSET);
114
115 struct VRegValue {
116 uint64_t value;
117 bool is_ref;
118 };
119
120 std::vector<VRegValue> regs {{0x1111111122222222, false},
121 {FromPtr(ToPtr(0x33333333)), true},
122 {0x3333333344444444, false},
123 {FromPtr(ToPtr(0x55555555)), true}};
124
125 for (size_t i = 0; i < regs.size(); i++) {
126 if (regs[i].is_ref) {
127 frame->GetVReg(i).SetReference(ToPtr(regs[i].value));
128 } else {
129 frame->GetVReg(i).SetPrimitive(static_cast<int64_t>(regs[i].value));
130 }
131 }
132
133 {
134 VRegValue acc {0xaaaaaaaabbbbbbbb, false};
135 frame->GetAcc().SetPrimitive(static_cast<int64_t>(acc.value));
136 tooling::PtDebugFrame debug_frame(frame->GetMethod(), frame);
137
138 EXPECT_EQ(debug_frame.GetVRegNum(), nregs);
139 EXPECT_EQ(debug_frame.GetArgumentNum(), nargs);
140 EXPECT_EQ(debug_frame.GetMethodId(), method_id);
141 EXPECT_EQ(debug_frame.GetBytecodeOffset(), BYTECODE_OFFSET);
142 EXPECT_EQ(debug_frame.GetAccumulator(), acc.value);
143
144 for (size_t i = 0; i < debug_frame.GetVRegNum(); i++) {
145 EXPECT_EQ(debug_frame.GetVReg(i), regs[i].value);
146 }
147
148 for (size_t i = 0; i < debug_frame.GetArgumentNum(); i++) {
149 EXPECT_EQ(debug_frame.GetArgument(i), regs[i + nregs].value);
150 }
151 }
152
153 {
154 VRegValue acc {FromPtr(ToPtr(0xbbbbbbbb)), true};
155 frame->GetAcc().SetReference(ToPtr(acc.value));
156 tooling::PtDebugFrame debug_frame(frame->GetMethod(), frame);
157
158 EXPECT_EQ(debug_frame.GetVRegNum(), nregs);
159 EXPECT_EQ(debug_frame.GetArgumentNum(), nargs);
160 EXPECT_EQ(debug_frame.GetMethodId(), method_id);
161 EXPECT_EQ(debug_frame.GetBytecodeOffset(), BYTECODE_OFFSET);
162 EXPECT_EQ(debug_frame.GetAccumulator(), acc.value);
163
164 for (size_t i = 0; i < debug_frame.GetVRegNum(); i++) {
165 EXPECT_EQ(debug_frame.GetVReg(i), regs[i].value);
166 }
167
168 for (size_t i = 0; i < debug_frame.GetArgumentNum(); i++) {
169 EXPECT_EQ(debug_frame.GetArgument(i), regs[i + nregs].value);
170 }
171 }
172
173 test::FreeFrame(frame);
174 }
175
176 } // namespace panda::debugger::test
177