// Copyright 2016 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "src/codegen/assembler-inl.h" #include "src/debug/debug-interface.h" #include "src/execution/frames-inl.h" #include "src/objects/property-descriptor.h" #include "src/utils/utils.h" #include "src/wasm/wasm-debug.h" #include "src/wasm/wasm-objects-inl.h" #include "test/cctest/cctest.h" #include "test/cctest/compiler/value-helper.h" #include "test/cctest/wasm/wasm-run-utils.h" #include "test/common/wasm/test-signatures.h" #include "test/common/wasm/wasm-macro-gen.h" namespace v8 { namespace internal { namespace wasm { namespace { debug::Location TranslateLocation(WasmRunnerBase* runner, const debug::Location& loc) { // Convert locations from {func_index, offset_in_func} to // {0, offset_in_module}. int func_index = loc.GetLineNumber(); int func_offset = runner->builder().GetFunctionAt(func_index)->code.offset(); int offset = loc.GetColumnNumber() + func_offset; return {0, offset}; } void CheckLocations( WasmRunnerBase* runner, NativeModule* native_module, debug::Location start, debug::Location end, std::initializer_list expected_locations_init) { std::vector locations; std::vector expected_locations; for (auto loc : expected_locations_init) { expected_locations.push_back(TranslateLocation(runner, loc)); } bool success = WasmScript::GetPossibleBreakpoints( native_module, TranslateLocation(runner, start), TranslateLocation(runner, end), &locations); CHECK(success); printf("got %d locations: ", static_cast(locations.size())); for (size_t i = 0, e = locations.size(); i != e; ++i) { printf("%s<%d,%d>", i == 0 ? "" : ", ", locations[i].GetLineNumber(), locations[i].GetColumnNumber()); } printf("\n"); CHECK_EQ(expected_locations.size(), locations.size()); for (size_t i = 0, e = locations.size(); i != e; ++i) { CHECK_EQ(expected_locations[i].GetLineNumber(), locations[i].GetLineNumber()); CHECK_EQ(expected_locations[i].GetColumnNumber(), locations[i].GetColumnNumber()); } } void CheckLocationsFail(WasmRunnerBase* runner, NativeModule* native_module, debug::Location start, debug::Location end) { std::vector locations; bool success = WasmScript::GetPossibleBreakpoints( native_module, TranslateLocation(runner, start), TranslateLocation(runner, end), &locations); CHECK(!success); } class BreakHandler : public debug::DebugDelegate { public: enum Action { Continue = StepAction::LastStepAction + 1, StepNext = StepAction::StepNext, StepIn = StepAction::StepIn, StepOut = StepAction::StepOut }; struct BreakPoint { int position; Action action; std::function pre_action; BreakPoint(int position, Action action) : position(position), action(action), pre_action([]() {}) {} BreakPoint(int position, Action action, std::function pre_action) : position(position), action(action), pre_action(pre_action) {} }; explicit BreakHandler(Isolate* isolate, std::initializer_list expected_breaks) : isolate_(isolate), expected_breaks_(expected_breaks) { v8::debug::SetDebugDelegate(reinterpret_cast(isolate_), this); } ~BreakHandler() override { // Check that all expected breakpoints have been hit. CHECK_EQ(count_, expected_breaks_.size()); v8::debug::SetDebugDelegate(reinterpret_cast(isolate_), nullptr); } int count() const { return count_; } private: Isolate* isolate_; int count_ = 0; std::vector expected_breaks_; void BreakProgramRequested(v8::Local paused_context, const std::vector&) override { printf("Break #%d\n", count_); CHECK_GT(expected_breaks_.size(), count_); // Check the current position. StackTraceFrameIterator frame_it(isolate_); auto summ = FrameSummary::GetTop(frame_it.frame()).AsWasm(); CHECK_EQ(expected_breaks_[count_].position, summ.byte_offset()); expected_breaks_[count_].pre_action(); Action next_action = expected_breaks_[count_].action; switch (next_action) { case Continue: break; case StepNext: case StepIn: case StepOut: isolate_->debug()->PrepareStep(static_cast(next_action)); break; default: UNREACHABLE(); } ++count_; } }; Handle SetBreakpoint(WasmRunnerBase* runner, int function_index, int byte_offset, int expected_set_byte_offset = -1) { runner->TierDown(); int func_offset = runner->builder().GetFunctionAt(function_index)->code.offset(); int code_offset = func_offset + byte_offset; if (expected_set_byte_offset == -1) expected_set_byte_offset = byte_offset; Handle instance = runner->builder().instance_object(); Handle