Mixed debug support stepOut

Issue:#I83IAI

Signed-off-by: yang-19970325 <yangyang585@huawei.com>
Change-Id: I390b6dd75b54b7b9274ddba791296284a7aa7623
This commit is contained in:
yang-19970325 2023-10-30 21:38:57 +08:00
parent 3b2297df11
commit 75e1a26c9c
11 changed files with 304 additions and 11 deletions

View File

@ -51,8 +51,10 @@ DebuggerImpl::DebuggerImpl(const EcmaVM *vm, ProtocolChannel *channel, RuntimeIm
DebuggerExecutor::Initialize(vm_);
updaterFunc_ = std::bind(&DebuggerImpl::UpdateScopeObject, this, _1, _2, _3);
stepperFunc_ = std::bind(&DebuggerImpl::ClearSingleStepper, this);
returnNative_ = std::bind(&DebuggerImpl::NotifyReturnNative, this);
vm_->GetJsDebuggerManager()->SetLocalScopeUpdater(&updaterFunc_);
vm_->GetJsDebuggerManager()->SetStepperFunc(&stepperFunc_);
vm_->GetJsDebuggerManager()->SetJSReturnNativeFunc(&returnNative_);
}
DebuggerImpl::~DebuggerImpl()
@ -109,6 +111,15 @@ bool DebuggerImpl::NotifyScriptParsed(ScriptId scriptId, const std::string &file
return true;
}
bool DebuggerImpl::NotifyNativeOut()
{
if (nativeOutPause_) {
nativeOutPause_ = false;
return true;
}
return false;
}
bool DebuggerImpl::NotifySingleStep(const JSPtLocation &location)
{
if (UNLIKELY(pauseOnNextByteCode_)) {
@ -253,9 +264,10 @@ void DebuggerImpl::NotifyPaused(std::optional<JSPtLocation> location, PauseReaso
paused.SetData(std::move(tmpException));
}
frontend_.Paused(vm_, paused);
if (reason != BREAK_ON_START) {
if (reason != BREAK_ON_START && reason != NATIVE_OUT) {
singleStepper_.reset();
}
nativeOutPause_ = false;
debuggerState_ = DebuggerState::PAUSED;
frontend_.WaitForDebugger(vm_);
DebuggerApi::SetException(vm_, exception);
@ -263,16 +275,14 @@ void DebuggerImpl::NotifyPaused(std::optional<JSPtLocation> location, PauseReaso
void DebuggerImpl::NotifyNativeCalling(const void *nativeAddress)
{
if (mixStackEnabled_) {
tooling::MixedStack mixedStack;
nativePointer_ = DebuggerApi::GetNativePointer(vm_);
mixedStack.SetNativePointers(nativePointer_);
std::vector<std::unique_ptr<CallFrame>> callFrames;
if (GenerateCallFrames(&callFrames)) {
mixedStack.SetCallFrames(std::move(callFrames));
}
frontend_.MixedStack(vm_, mixedStack);
tooling::MixedStack mixedStack;
nativePointer_ = DebuggerApi::GetNativePointer(vm_);
mixedStack.SetNativePointers(nativePointer_);
std::vector<std::unique_ptr<CallFrame>> callFrames;
if (GenerateCallFrames(&callFrames)) {
mixedStack.SetCallFrames(std::move(callFrames));
}
frontend_.MixedStack(vm_, mixedStack);
// native calling only after step into should be reported
if (singleStepper_ != nullptr &&
@ -283,6 +293,43 @@ void DebuggerImpl::NotifyNativeCalling(const void *nativeAddress)
frontend_.NativeCalling(vm_, nativeCalling);
frontend_.WaitForDebugger(vm_);
}
bool isNativeCalling = false;
uint64_t nativeEntry = reinterpret_cast<uint64_t>(nativeAddress);
for (const auto &nativeRange : nativeRanges_) {
if (nativeEntry >= nativeRange.GetStart() && nativeEntry <= nativeRange.GetEnd()) {
isNativeCalling = true;
break;
}
}
if (!isNativeCalling) {
return;
}
checkNeedPause_ = true;
}
void DebuggerImpl::NotifyNativeReturnJS()
{
if (checkNeedPause_) {
nativeOutPause_ = true;
}
}
void DebuggerImpl::NotifyReturnNative()
{
if (vm_->GetJsDebuggerManager()->IsMixedDebugEnabled()) {
tooling::MixedStack mixedStack;
nativePointer_ = DebuggerApi::GetNativePointer(vm_);
mixedStack.SetNativePointers(nativePointer_);
std::vector<std::unique_ptr<CallFrame>> callFrames;
if (GenerateCallFrames(&callFrames)) {
mixedStack.SetCallFrames(std::move(callFrames));
}
if (!nativePointer_.empty()) {
frontend_.MixedStack(vm_, mixedStack);
}
}
}
// only use for test case
@ -321,7 +368,9 @@ void DebuggerImpl::DispatcherImpl::Dispatch(const DispatchRequest &request)
{ "setBlackboxPatterns", &DebuggerImpl::DispatcherImpl::SetBlackboxPatterns },
{ "replyNativeCalling", &DebuggerImpl::DispatcherImpl::ReplyNativeCalling },
{ "getPossibleAndSetBreakpointByUrl", &DebuggerImpl::DispatcherImpl::GetPossibleAndSetBreakpointByUrl },
{ "dropFrame", &DebuggerImpl::DispatcherImpl::DropFrame }
{ "dropFrame", &DebuggerImpl::DispatcherImpl::DropFrame },
{ "setNativeRange", &DebuggerImpl::DispatcherImpl::SetNativeRange },
{ "resetSingleStepper", &DebuggerImpl::DispatcherImpl::ResetSingleStepper },
};
const std::string &method = request.GetMethod();
@ -511,6 +560,28 @@ void DebuggerImpl::DispatcherImpl::SetSkipAllPauses(const DispatchRequest &reque
SendResponse(request, response);
}
void DebuggerImpl::DispatcherImpl::SetNativeRange(const DispatchRequest &request)
{
std::unique_ptr<SetNativeRangeParams> params = SetNativeRangeParams::Create(request.GetParams());
if (params == nullptr) {
SendResponse(request, DispatchResponse::Fail("wrong params"));
return;
}
DispatchResponse response = debugger_->SetNativeRange(*params);
SendResponse(request, response);
}
void DebuggerImpl::DispatcherImpl::ResetSingleStepper(const DispatchRequest &request)
{
std::unique_ptr<ResetSingleStepperParams> params = ResetSingleStepperParams::Create(request.GetParams());
if (params == nullptr) {
SendResponse(request, DispatchResponse::Fail("wrong params"));
return;
}
DispatchResponse response = debugger_->ResetSingleStepper(*params);
SendResponse(request, response);
}
void DebuggerImpl::DispatcherImpl::StepInto(const DispatchRequest &request)
{
std::unique_ptr<StepIntoParams> params = StepIntoParams::Create(request.GetParams());
@ -986,6 +1057,21 @@ bool DebuggerImpl::ProcessSingleBreakpoint(const BreakpointInfo &breakpoint,
return true;
}
DispatchResponse DebuggerImpl::SetNativeRange(const SetNativeRangeParams &params)
{
nativeRanges_ = params.GetNativeRange();
return DispatchResponse::Ok();
}
DispatchResponse DebuggerImpl::ResetSingleStepper(const ResetSingleStepperParams &params)
{
// if JS to C++ and C++ has breakpoint; it need to clear singleStepper_
if (params.GetResetSingleStepper()) {
singleStepper_.reset();
}
return DispatchResponse::Ok();
}
DispatchResponse DebuggerImpl::SetPauseOnExceptions(const SetPauseOnExceptionsParams &params)
{
pauseOnException_ = params.GetState();

View File

@ -42,8 +42,11 @@ public:
std::string_view entryPoint = "func_main_0");
bool NotifySingleStep(const JSPtLocation &location);
void NotifyPaused(std::optional<JSPtLocation> location, PauseReason reason);
bool NotifyNativeOut();
void NotifyHandleProtocolCommand();
void NotifyNativeCalling(const void *nativeAddress);
void NotifyNativeReturnJS();
void NotifyReturnNative();
void SetDebuggerState(DebuggerState debuggerState);
DispatchResponse ContinueToLocation(const ContinueToLocationParams &params);
@ -65,6 +68,8 @@ public:
std::vector<std::unique_ptr<BreakpointReturnInfo>> &outLocations);
DispatchResponse SetPauseOnExceptions(const SetPauseOnExceptionsParams &params);
DispatchResponse SetSkipAllPauses(const SetSkipAllPausesParams &params);
DispatchResponse SetNativeRange(const SetNativeRangeParams &params);
DispatchResponse ResetSingleStepper(const ResetSingleStepperParams &params);
DispatchResponse StepInto(const StepIntoParams &params);
DispatchResponse StepOut();
DispatchResponse StepOver(const StepOverParams &params);
@ -150,6 +155,8 @@ public:
void SetBreakpointsActive(const DispatchRequest &request);
void SetPauseOnExceptions(const DispatchRequest &request);
void SetSkipAllPauses(const DispatchRequest &request);
void SetNativeRange(const DispatchRequest &request);
void ResetSingleStepper(const DispatchRequest &request);
void StepInto(const DispatchRequest &request);
void StepOut(const DispatchRequest &request);
void StepOver(const DispatchRequest &request);
@ -248,12 +255,18 @@ private:
bool mixStackEnabled_ {false};
std::unique_ptr<SingleStepper> singleStepper_ {nullptr};
Location location_ {};
std::unique_ptr<SingleStepper> nativeOut_ {nullptr};
std::vector<void *> nativePointer_;
bool nativeOutPause_ {false};
bool checkNeedPause_ {false};
std::vector<NativeRange> nativeRanges_ {};
std::unordered_map<JSTaggedType *, RemoteObjectId> scopeObjects_ {};
std::vector<std::shared_ptr<FrameHandler>> callFrameHandlers_;
JsDebuggerManager::ObjectUpdaterFunc updaterFunc_ {nullptr};
JsDebuggerManager::SingleStepperFunc stepperFunc_ {nullptr};
JsDebuggerManager::ReturnNativeFunc returnNative_ {nullptr};
friend class JSPtHooks;
friend class test::TestHooks;

View File

@ -66,6 +66,19 @@ bool JSPtHooks::SingleStep(const JSPtLocation &location)
return false;
}
bool JSPtHooks::NativeOut()
{
LOG_DEBUGGER(VERBOSE) << "JSPtHooks: NativeOut";
[[maybe_unused]] LocalScope scope(debugger_->vm_);
if (debugger_->NotifyNativeOut()) {
debugger_->NotifyPaused({}, NATIVE_OUT);
return true;
}
return false;
}
void JSPtHooks::LoadModule(std::string_view pandaFileName, std::string_view entryPoint)
{
LOG_DEBUGGER(VERBOSE) << "JSPtHooks: LoadModule: " << pandaFileName;
@ -86,4 +99,13 @@ void JSPtHooks::NativeCalling(const void *nativeAddress)
debugger_->NotifyNativeCalling(nativeAddress);
}
void JSPtHooks::NativeReturnJS()
{
LOG_DEBUGGER(INFO) << "JSPtHooks: NativeReturnJS";
[[maybe_unused]] LocalScope scope(debugger_->vm_);
debugger_->NotifyNativeReturnJS();
}
} // namespace panda::ecmascript::tooling

View File

@ -35,7 +35,9 @@ public:
void LoadModule(std::string_view pandaFileName, std::string_view entryPoint) override;
void Exception(const JSPtLocation &location) override;
bool SingleStep(const JSPtLocation &location) override;
bool NativeOut() override;
void NativeCalling(const void *nativeAddress) override;
void NativeReturnJS() override;
void VmStart() override {}
void VmDeath() override {}

View File

@ -156,6 +156,9 @@ public:
case STEP: {
return "Step";
}
case NATIVE_OUT: {
return "Native out";
}
default: {
LOG_DEBUGGER(ERROR) << "Unknown paused reason: " << reason;
}

View File

@ -562,6 +562,41 @@ std::unique_ptr<DropFrameParams> DropFrameParams::Create(const PtJson &params)
return paramsObject;
}
std::unique_ptr<SetNativeRangeParams> SetNativeRangeParams::Create(const PtJson &params)
{
auto paramsObject = std::make_unique<SetNativeRangeParams>();
std::string error;
Result ret;
std::unique_ptr<PtJson> nativeRange;
ret = params.GetArray("nativeRange", &nativeRange);
if (ret == Result::SUCCESS) {
int32_t len = nativeRange->GetSize();
std::vector<NativeRange> vectorNativeRange;
for (int32_t i = 0; i < len; ++i) {
std::unique_ptr<NativeRange> obj = NativeRange::Create(*nativeRange->Get(i));
if (obj == nullptr) {
error += "'nativeRange' is invalid;";
break;
} else {
vectorNativeRange.emplace_back(std::move(*obj));
}
}
if (vectorNativeRange.size()) {
paramsObject->nativeRange_ = std::move(vectorNativeRange);
}
} else if (ret == Result::TYPE_ERROR) {
error += "Unknown 'nativeRange';";
}
if (!error.empty()) {
LOG_DEBUGGER(ERROR) << "SetNativeRangeParams::Create " << error;
return nullptr;
}
return paramsObject;
}
std::unique_ptr<SetMixedDebugParams> SetMixedDebugParams::Create(const PtJson &params)
{
auto paramsObject = std::make_unique<SetMixedDebugParams>();
@ -592,6 +627,28 @@ std::unique_ptr<SetMixedDebugParams> SetMixedDebugParams::Create(const PtJson &p
return paramsObject;
}
std::unique_ptr<ResetSingleStepperParams> ResetSingleStepperParams::Create(const PtJson &params)
{
auto paramsObject = std::make_unique<ResetSingleStepperParams>();
std::string error;
Result ret;
bool resetSingleStepper = false;
ret = params.GetBool("resetSingleStepper", &resetSingleStepper);
if (ret == Result::SUCCESS) {
paramsObject->resetSingleStepper_ = resetSingleStepper;
} else if (ret == Result::TYPE_ERROR) {
error += "Wrong type of 'resetSingleStepper';";
}
if (!error.empty()) {
LOG_DEBUGGER(ERROR) << "ResetSingleStepperParams::Create " << error;
return nullptr;
}
return paramsObject;
}
std::unique_ptr<ReplyNativeCallingParams> ReplyNativeCallingParams::Create(const PtJson &params)
{
auto paramsObject = std::make_unique<ReplyNativeCallingParams>();

View File

@ -521,6 +521,38 @@ private:
std::optional<uint32_t> droppedDepth_ {};
};
class SetNativeRangeParams {
public:
SetNativeRangeParams() = default;
~SetNativeRangeParams() = default;
static std::unique_ptr<SetNativeRangeParams> Create(const PtJson &params);
std::vector<NativeRange> GetNativeRange() const
{
return nativeRange_;
}
private:
std::vector<NativeRange> nativeRange_ {};
};
class ResetSingleStepperParams : public PtBaseParams {
public:
ResetSingleStepperParams() = default;
~ResetSingleStepperParams() = default;
static std::unique_ptr<ResetSingleStepperParams> Create(const PtJson &params);
bool GetResetSingleStepper() const
{
return resetSingleStepper_;
}
private:
NO_COPY_SEMANTIC(ResetSingleStepperParams);
NO_MOVE_SEMANTIC(ResetSingleStepperParams);
bool resetSingleStepper_ {false};
};
class SetMixedDebugParams : public PtBaseParams {
public:
SetMixedDebugParams() = default;

View File

@ -1680,6 +1680,36 @@ std::unique_ptr<PtJson> LocationRange::ToJson() const
return result;
}
std::unique_ptr<NativeRange> NativeRange::Create(const PtJson &params)
{
std::string error;
auto nativeRange = std::make_unique<NativeRange>();
Result ret;
uint32_t start;
ret = params.GetUInt("start", &start);
if (ret == Result::SUCCESS) {
nativeRange->start_ = std::move(start);
} else {
error += "Unknown 'start';";
}
uint32_t end;
ret = params.GetUInt("end", &end);
if (ret == Result::SUCCESS) {
nativeRange->end_ = std::move(end);
} else {
error += "Unknown 'end';";
}
if (!error.empty()) {
LOG_DEBUGGER(ERROR) << "NativeRange::Create " << error;
return nullptr;
}
return nativeRange;
}
std::unique_ptr<BreakLocation> BreakLocation::Create(const PtJson &params)
{
std::string error;

View File

@ -1301,6 +1301,41 @@ private:
std::unique_ptr<ScriptPosition> end_ {nullptr};
};
class NativeRange {
public:
NativeRange() = default;
~NativeRange() = default;
static std::unique_ptr<NativeRange> Create(const PtJson &params);
uint32_t GetStart() const
{
return start_;
}
NativeRange &SetStart(uint32_t start)
{
start_ = std::move(start);
return *this;
}
uint32_t GetEnd() const
{
return end_;
}
NativeRange &SetEnd(uint32_t end)
{
end_ = std::move(end);
return *this;
}
private:
uint32_t start_ {0};
uint32_t end_ {0};
};
// Debugger.BreakLocation
class BreakLocation final : public PtBaseTypes {
public:

View File

@ -28,6 +28,7 @@ using BreakpointCallback = std::function<bool(const JSPtLocation &)>;
using LoadModuleCallback = std::function<bool(std::string_view)>;
using ExceptionCallback = std::function<bool(const JSPtLocation &)>;
using SingleStepCallback = std::function<bool(const JSPtLocation &)>;
using NativeOutCallback = std::function<bool()>;
using VmStartCallback = std::function<bool()>;
using VmDeathCallback = std::function<bool()>;
using Scenario = std::function<bool()>;
@ -56,6 +57,7 @@ struct TestEvents {
LoadModuleCallback loadModule;
ExceptionCallback exception;
SingleStepCallback singleStep;
NativeOutCallback nativeOut;
VmStartCallback vmStart;
VmDeathCallback vmDeath;

View File

@ -87,6 +87,15 @@ public:
return false;
}
bool NativeOut() override
{
if (test_->nativeOut) {
return test_->nativeOut();
}
return false;
}
void VmDeath() override
{
if (test_->vmDeath) {
@ -105,6 +114,8 @@ public:
void NativeCalling([[maybe_unused]] const void *nativeAddress) override {}
void NativeReturnJS() override {}
void TerminateTest()
{
debugInterface_->UnregisterHooks();