1 /*
2 * Copyright (c) 2022 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 "backend/js_single_stepper.h"
17
18 #include "ecmascript/debugger/debugger_api.h"
19 #include "ecmascript/jspandafile/debug_info_extractor.h"
20 #include "ecmascript/jspandafile/js_pandafile_manager.h"
21
22 namespace panda::ecmascript::tooling {
GetStackDepth() const23 uint32_t SingleStepper::GetStackDepth() const
24 {
25 return DebuggerApi::GetStackDepth(ecmaVm_);
26 }
27
InStepRange(uint32_t pc) const28 bool SingleStepper::InStepRange(uint32_t pc) const
29 {
30 for (const auto &range : stepRanges_) {
31 if (pc >= range.startBcOffset && pc < range.endBcOffset) {
32 return true;
33 }
34 }
35 return false;
36 }
37
StepComplete(uint32_t bcOffset) const38 bool SingleStepper::StepComplete(uint32_t bcOffset) const
39 {
40 std::unique_ptr<PtMethod> ptMethod = DebuggerApi::GetMethod(ecmaVm_);
41 uint32_t stackDepth = GetStackDepth();
42
43 switch (type_) {
44 case Type::STEP_INTO: {
45 if ((method_->GetMethodId() == ptMethod->GetMethodId()) &&
46 (method_->GetJSPandaFile() == ptMethod->GetJSPandaFile()) &&
47 (InStepRange(bcOffset))) {
48 return false;
49 }
50 break;
51 }
52 case Type::STEP_OVER: {
53 if (stackDepth_ < stackDepth) {
54 return false;
55 }
56 if (stackDepth_ == stackDepth && InStepRange(bcOffset)) {
57 return false;
58 }
59 break;
60 }
61 case Type::STEP_OUT: {
62 if (stackDepth_ <= stackDepth) {
63 return false;
64 }
65 break;
66 }
67 default: {
68 return false;
69 }
70 }
71
72 return true;
73 }
74
GetStepIntoStepper(const EcmaVM * ecmaVm)75 std::unique_ptr<SingleStepper> SingleStepper::GetStepIntoStepper(const EcmaVM *ecmaVm)
76 {
77 return GetStepper(ecmaVm, SingleStepper::Type::STEP_INTO);
78 }
79
GetStepOverStepper(const EcmaVM * ecmaVm)80 std::unique_ptr<SingleStepper> SingleStepper::GetStepOverStepper(const EcmaVM *ecmaVm)
81 {
82 return GetStepper(ecmaVm, SingleStepper::Type::STEP_OVER);
83 }
84
GetStepOutStepper(const EcmaVM * ecmaVm)85 std::unique_ptr<SingleStepper> SingleStepper::GetStepOutStepper(const EcmaVM *ecmaVm)
86 {
87 return GetStepper(ecmaVm, SingleStepper::Type::STEP_OUT);
88 }
89
GetStepRanges(DebugInfoExtractor * extractor,panda_file::File::EntityId methodId,uint32_t offset)90 std::list<JSPtStepRange> SingleStepper::GetStepRanges(DebugInfoExtractor *extractor,
91 panda_file::File::EntityId methodId, uint32_t offset)
92 {
93 std::list<JSPtStepRange> ranges {};
94 const LineNumberTable &table = extractor->GetLineNumberTable(methodId);
95 auto callbackFunc = [table, &ranges](int32_t line) -> bool {
96 for (auto it = table.begin(); it != table.end(); ++it) {
97 auto next = it + 1;
98 if (it->line == line) {
99 JSPtStepRange range {it->offset, next != table.end() ? next->offset : UINT32_MAX};
100 ranges.push_back(range);
101 }
102 }
103 return true;
104 };
105 extractor->MatchLineWithOffset(callbackFunc, methodId, offset);
106 return ranges;
107 }
108
GetStepper(const EcmaVM * ecmaVm,SingleStepper::Type type)109 std::unique_ptr<SingleStepper> SingleStepper::GetStepper(const EcmaVM *ecmaVm,
110 SingleStepper::Type type)
111 {
112 std::unique_ptr<PtMethod> ptMethod = DebuggerApi::GetMethod(ecmaVm);
113 ASSERT(ptMethod != nullptr);
114
115 DebugInfoExtractor *extractor = JSPandaFileManager::GetInstance()->GetJSPtExtractor(
116 ptMethod->GetJSPandaFile());
117 if (extractor == nullptr) {
118 LOG_DEBUGGER(ERROR) << "GetStepper: extractor is null";
119 return nullptr;
120 }
121
122 if (type == SingleStepper::Type::STEP_OUT) {
123 return std::make_unique<SingleStepper>(ecmaVm, std::move(ptMethod), std::list<JSPtStepRange> {}, type);
124 }
125
126 std::list<JSPtStepRange> ranges = GetStepRanges(extractor, ptMethod->GetMethodId(),
127 DebuggerApi::GetBytecodeOffset(ecmaVm));
128 return std::make_unique<SingleStepper>(ecmaVm, std::move(ptMethod), std::move(ranges), type);
129 }
130 } // namespace panda::ecmascript::tooling
131