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