diff --git a/BUILD.gn b/BUILD.gn index 97aba4c40cfcffc95489559c0678a49a174f10fb..9e918fb448c8a47f54f7ef7549155b079ba0d5db 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -193,6 +193,7 @@ group("ark_toolchain_packages") { deps = [] if (host_os != "mac") { deps += [ + "./arkdbjs:arkdebugger", "./inspector:ark_debugger", "./inspector:connectserver_debugger", "./tooling:libark_ecma_debugger", diff --git a/arkdbjs/BUILD.gn b/arkdbjs/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..f957b970b0a8a48f1c2a515dfc3328948a80c44e --- /dev/null +++ b/arkdbjs/BUILD.gn @@ -0,0 +1,69 @@ +# Copyright (c) 2021 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("../toolchain.gni") + +import("//arkcompiler/ets_runtime/js_runtime_config.gni") + +ohos_executable("arkdebugger") { + sources = [ "main.cpp" ] + + configs = [ + "//arkcompiler/ets_runtime:ark_jsruntime_common_config", + "//arkcompiler/ets_runtime:ark_jsruntime_public_config", + "//arkcompiler/toolchain:ark_toolchain_common_config", + ] + + external_deps = [ "ets_runtime:libark_jsruntime" ] + + deps = [ + "//arkcompiler/toolchain/inspector:ark_debugger", + "//arkcompiler/toolchain/inspector:connectserver_debugger", + "//third_party/libuv:uv", + ] + + if (ark_standalone_build) { + if (run_with_qemu && (is_ohos || is_linux)) { + deps += [ + ":copy_libcxxso_for_qemu", + "$build_root/third_party_gn/bounds_checking_function:libsec_shared_for_qemu", + ] + + if (use_musl) { + deps += + [ "$build_root/third_party_gn/musl:soft_create_linker_for_qemu" ] + } + } + } + + if (!is_arkui_x) { + external_deps += [ + "runtime_core:arkfile_header_deps", + "runtime_core:libarkbase_static", + ] + } else { + external_deps += [ + "$ark_root/libpandabase:libarkbase_static", + "$ark_root/libpandafile:arkfile_header_deps", + ] + } + + # hiviewdfx libraries + external_deps += hiviewdfx_ext_deps + deps += hiviewdfx_deps + + install_enable = false + + part_name = "toolchain" + subsystem_name = "arkcompiler" +} diff --git a/arkdbjs/main.cpp b/arkdbjs/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..289196c4ad3bc148ed7606a0a8d6eb304cb57b35 --- /dev/null +++ b/arkdbjs/main.cpp @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include // NOLINTNEXTLINE(modernize-deprecated-headers) +#include + +#include "ecmascript/jspandafile/js_pandafile.h" +#include "ecmascript/jspandafile/js_pandafile_manager.h" +#include "ecmascript/base/string_helper.h" +#include "ecmascript/ecma_string.h" +#include "ecmascript/ecma_vm.h" +#include "ecmascript/js_runtime_options.h" +#include "ecmascript/log.h" +#include "ecmascript/mem/mem_controller.h" +#include "ecmascript/mem/clock_scope.h" +#include "ecmascript/napi/include/jsnapi.h" +#include "ecmascript/debugger/js_debugger_manager.h" + +#ifdef OHOS_PLATFORM +#define DEBUGGER_LIBRARY "libark_debugger.z.so" +#else +#define DEBUGGER_LIBRARY "libark_debugger.so" +#endif +using EntityId = panda::panda_file::File::EntityId; + +namespace panda::ecmascript { + +void BlockSignals() +{ +#if defined(PANDA_TARGET_UNIX) + sigset_t set; + if (sigemptyset(&set) == -1) { + LOG_ECMA(ERROR) << "sigemptyset failed"; + return; + } +#endif // PANDA_TARGET_UNIX +} + +std::string GetHelper() +{ + std::string str; + str.append(COMMON_HELP_HEAD_MSG); + str.append(HELP_OPTION_MSG); + return str; +} + +int Main(const int argc, const char **argv) +{ + auto startTime = + std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()) + .count(); + + BlockSignals(); + + if (argc < 2) { // 2: at least have two arguments + std::cerr << GetHelper(); + return -1; + } + + int newArgc = argc; + std::string files = argv[argc - 1]; + + if (!base::StringHelper::EndsWith(files, ".abc")) { + std::cerr << "The last argument must be abc file" << std::endl; + std::cerr << GetHelper(); + return 1; + } + + newArgc--; + JSRuntimeOptions runtimeOptions; + bool retOpt = runtimeOptions.ParseCommand(newArgc, argv); + if (!retOpt) { + std::cerr << GetHelper(); + return 1; + } + + if (runtimeOptions.IsStartupTime()) { + std::cout << "\n" + << "Startup start time: " << startTime << std::endl; + } + bool ret = true; + EcmaVM *vm = JSNApi::CreateEcmaVM(runtimeOptions); + if (vm == nullptr) { + std::cerr << "Cannot Create vm" << std::endl; + return -1; + } + + bool isMergeAbc = runtimeOptions.GetMergeAbc(); + JSNApi::SetBundle(vm, !isMergeAbc); + { + LocalScope scope(vm); + std::string entry = runtimeOptions.GetEntryPoint(); +#if defined(PANDA_TARGET_WINDOWS) + arg_list_t fileNames = base::StringHelper::SplitString(files, ";"); +#else + arg_list_t fileNames = base::StringHelper::SplitString(files, ":"); +#endif + ClockScope execute; + for (const auto &fileName : fileNames) { + JSThread *thread = vm->GetJSThread(); + CString FileName = ""; + FileName += fileName; + std::shared_ptr jsPandaFile = + JSPandaFileManager::GetInstance()->LoadJSPandaFile(thread, FileName, entry.c_str(), false); + JSNApi::DebugOption debugOption = {DEBUGGER_LIBRARY, true}; + JSNApi::StartDebugger(vm, debugOption); + auto res = JSNApi::Execute(vm, fileName, entry); + if (!res) { + std::cerr << "Cannot execute panda file '" << fileName << "' with entry '" << entry << "'" << std::endl; + ret = false; + break; + } + } + auto totalTime = execute.TotalSpentTime(); + if (runtimeOptions.IsEnablePrintExecuteTime()) { + std::cout << "execute pandafile spent time " << totalTime << "ms" << std::endl; + } + } + + JSNApi::DestroyJSVM(vm); + + return ret ? 0 : -1; +} +} // namespace panda::ecmascript + +int main(int argc, const char **argv) +{ + return panda::ecmascript::Main(argc, argv); +} \ No newline at end of file diff --git a/tooling/agent/debugger_impl.cpp b/tooling/agent/debugger_impl.cpp index a87353413855f04011f99867eb21c5071313a3ae..3bd63789b8b656bbc877b5c604ee1c6852827e03 100644 --- a/tooling/agent/debugger_impl.cpp +++ b/tooling/agent/debugger_impl.cpp @@ -72,7 +72,7 @@ bool DebuggerImpl::NotifyScriptParsed(ScriptId scriptId, const std::string &file #if !defined(PANDA_TARGET_WINDOWS) && !defined(PANDA_TARGET_MACOS) \ && !defined(PANDA_TARGET_ANDROID) && !defined(PANDA_TARGET_IOS) \ && !defined(PANDA_TARGET_LINUX) - if (fileName.substr(0, DATA_APP_PATH.length()) != DATA_APP_PATH) { + if (fileName.substr(0, DATA_APP_PATH.length()) != DATA_APP_PATH && !base::StringHelper::EndsWith(fileName, ".abc")) { LOG_DEBUGGER(DEBUG) << "NotifyScriptParsed: unsupport file: " << fileName; return false; } @@ -94,7 +94,7 @@ bool DebuggerImpl::NotifyScriptParsed(ScriptId scriptId, const std::string &file auto mainMethodIndex = panda_file::File::EntityId(jsPandaFile->GetMainMethodIndex(recordName)); const std::string &source = extractor->GetSourceCode(mainMethodIndex); const std::string &url = extractor->GetSourceFile(mainMethodIndex); - if (source.empty()) { + if (source.empty() && !base::StringHelper::EndsWith(fileName, ".abc")) { LOG_DEBUGGER(WARN) << "NotifyScriptParsed: invalid debugger file: " << fileName; return false; } @@ -377,6 +377,7 @@ void DebuggerImpl::DispatcherImpl::Dispatch(const DispatchRequest &request) { "setNativeRange", &DebuggerImpl::DispatcherImpl::SetNativeRange }, { "resetSingleStepper", &DebuggerImpl::DispatcherImpl::ResetSingleStepper }, { "clientDisconnect", &DebuggerImpl::DispatcherImpl::ClientDisconnect }, + { "scriptParsed", &DebuggerImpl::DispatcherImpl::ScriptParsed}, }; const std::string &method = request.GetMethod(); @@ -655,6 +656,13 @@ void DebuggerImpl::DispatcherImpl::DropFrame(const DispatchRequest &request) SendResponse(request, response); } +void DebuggerImpl::DispatcherImpl::ScriptParsed(const DispatchRequest &request) +{ + std::unique_ptr params = ScriptParsedParams::Create(request.GetParams()); + DispatchResponse response = debugger_->ScriptParsed(*params); + SendResponse(request, response); +} + void DebuggerImpl::DispatcherImpl::ClientDisconnect(const DispatchRequest &request) { DispatchResponse response = debugger_->ClientDisconnect(); @@ -1199,6 +1207,15 @@ DispatchResponse DebuggerImpl::DropFrame(const DropFrameParams ¶ms) return DispatchResponse::Ok(); } +DispatchResponse DebuggerImpl::ScriptParsed(const ScriptParsedParams ¶ms) +{ + ScriptId scriptId = params.GetScriptId(); + std::string fileName = params.GetFileName(); + std::string_view entryPoint = params.GetEntryPoint(); + NotifyScriptParsed(scriptId, fileName, entryPoint); + return DispatchResponse::Ok(); +} + DispatchResponse DebuggerImpl::ClientDisconnect() { DeviceDisconnectCallback cb = vm_->GetDeviceDisconnectCallback(); diff --git a/tooling/agent/debugger_impl.h b/tooling/agent/debugger_impl.h index aece3b5adc8a16f2c232166efa2b7ec9dc25af68..dce6dd81e4cab4b73ad5dc3ba1aea3b05c176fa0 100644 --- a/tooling/agent/debugger_impl.h +++ b/tooling/agent/debugger_impl.h @@ -78,6 +78,7 @@ public: DispatchResponse ReplyNativeCalling(const ReplyNativeCallingParams ¶ms); DispatchResponse DropFrame(const DropFrameParams ¶ms); DispatchResponse ClientDisconnect(); + DispatchResponse ScriptParsed(const ScriptParsedParams ¶ms); /** * @brief: match first script and callback @@ -167,6 +168,7 @@ public: void GetPossibleAndSetBreakpointByUrl(const DispatchRequest &request); void DropFrame(const DispatchRequest &request); void ClientDisconnect(const DispatchRequest &request); + void ScriptParsed(const DispatchRequest &request); private: NO_COPY_SEMANTIC(DispatcherImpl); diff --git a/tooling/base/pt_params.cpp b/tooling/base/pt_params.cpp index ebc8f0e81b4feba4dc931719ada7b46bff7ca948..73e9fcf4ba7c4f976991b6bc7daed99038635e40 100644 --- a/tooling/base/pt_params.cpp +++ b/tooling/base/pt_params.cpp @@ -562,6 +562,44 @@ std::unique_ptr DropFrameParams::Create(const PtJson ¶ms) return paramsObject; } +std::unique_ptr ScriptParsedParams::Create(const PtJson ¶ms) +{ + auto paramsObject = std::make_unique(); + std::string error; + Result ret; + + std::string scriptId; + ret = params.GetString("scriptId", &scriptId); + if (ret == Result::SUCCESS) { + paramsObject->scriptId_ = std::stoi(scriptId); + } else if (ret == Result::TYPE_ERROR) { + error += "Wrong type of 'ScriptParsed';"; + } + + std::string fileName; + ret = params.GetString("fileName", &fileName); + if (ret == Result::SUCCESS) { + paramsObject->fileName_ = fileName; + } else if (ret == Result::TYPE_ERROR) { + error += "Wrong type of 'ScriptParsed';"; + } + + std::string entryPoint; + ret = params.GetString("entryPoint", &entryPoint); + if (ret == Result::SUCCESS) { + paramsObject->entryPoint_ = entryPoint; + } else if (ret == Result::TYPE_ERROR) { + error += "Wrong type of 'ScriptParsed';"; + } + + if (!error.empty()) { + LOG_DEBUGGER(ERROR) << "ScriptParsedParams::Create " << error; + return nullptr; + } + + return paramsObject; +} + std::unique_ptr SetNativeRangeParams::Create(const PtJson ¶ms) { auto paramsObject = std::make_unique(); diff --git a/tooling/base/pt_params.h b/tooling/base/pt_params.h index b7af219963a8dc39f2024fb3f48a01a5a59f4168..8f5423a8e0995d6972a8a13f902645c1d1ab8669 100644 --- a/tooling/base/pt_params.h +++ b/tooling/base/pt_params.h @@ -535,7 +535,31 @@ private: std::vector nativeRange_ {}; }; +class ScriptParsedParams { +public: + ScriptParsedParams() = default; + ~ScriptParsedParams() = default; + static std::unique_ptr Create(const PtJson ¶ms); + + ScriptId GetScriptId() const + { + return scriptId_; + } + + std::string GetFileName() const + { + return fileName_; + } + std::string GetEntryPoint() const + { + return entryPoint_; + } +private: + ScriptId scriptId_ {0}; + std::string fileName_ {}; + std::string entryPoint_ {}; +}; class ResetSingleStepperParams : public PtBaseParams { public: ResetSingleStepperParams() = default; diff --git a/tooling/client/domain/debugger_client.cpp b/tooling/client/domain/debugger_client.cpp index 56b73e8f26c84de5ae91c325b7f2c7bf3bf2c513..2187686dfa1856ea722ce03cfb2d031017fb9ce2 100644 --- a/tooling/client/domain/debugger_client.cpp +++ b/tooling/client/domain/debugger_client.cpp @@ -54,6 +54,7 @@ bool DebuggerClient::DispatcherCmd(const std::string &cmd) { "step-into", std::bind(&DebuggerClient::StepIntoCommand, this)}, { "step-out", std::bind(&DebuggerClient::StepOutCommand, this)}, { "step-over", std::bind(&DebuggerClient::StepOverCommand, this)}, + { "parseabc", std::bind(&DebuggerClient::ParseabcCommand, this)}, }; auto entry = dispatcherTable.find(cmd); @@ -67,6 +68,27 @@ bool DebuggerClient::DispatcherCmd(const std::string &cmd) return false; } +int DebuggerClient::ParseabcCommand(){ + Session *session = SessionManager::getInstance().GetSessionById(sessionId_); + uint32_t id = session->GetMessageId(); + + std::unique_ptr request = PtJson::CreateObject(); + request->Add("id", id); + request->Add("method", "Debugger.scriptParsed"); + + std::unique_ptr params = PtJson::CreateObject(); + std::string fileName = breakPointInfoList_.back().url; + params->Add("fileName", fileName.c_str()); + params->Add("entryPoint", "func_main_0"); + request->Add("params", params); + + std::string message = request->Stringify(); + if (session->ClientSendReq(message)) { + session->GetDomainManager().SetDomainById(id, "Debugger"); + } + return 0; +} + int DebuggerClient::BreakCommand() { Session *session = SessionManager::getInstance().GetSessionById(sessionId_); diff --git a/tooling/client/domain/debugger_client.h b/tooling/client/domain/debugger_client.h index ddf03031da7aab696f627ff75318056cd3d8fa4c..9ea4fcbde001d3f2ef4c5e1ed3979d269d3ff3eb 100644 --- a/tooling/client/domain/debugger_client.h +++ b/tooling/client/domain/debugger_client.h @@ -59,6 +59,7 @@ public: int StepIntoCommand(); int StepOutCommand(); int StepOverCommand(); + int ParseabcCommand(); void AddBreakPointInfo(const std::string& url, const int& lineNumber, const int& columnNumber = 0); void RecvReply(std::unique_ptr json); diff --git a/tooling/client/utils/cli_command.cpp b/tooling/client/utils/cli_command.cpp index 41cd28d6ca8907e69e327c2ac7e5f1f6181e240f..d8da7b22bd9dcaf0b7eccf5f519b087c9319f5f0 100644 --- a/tooling/client/utils/cli_command.cpp +++ b/tooling/client/utils/cli_command.cpp @@ -145,6 +145,15 @@ ErrCode CliCommand::ExecCommand() return result; } +bool CliCommand::EndsWith(const std::string &str, const std::string &suffix) +{ + if (str.length() < suffix.length()) { + return false; + } + std::string subStr = str.substr(str.length() - suffix.length(), str.length()); + return subStr == suffix; +} + void CliCommand::CreateCommandMap() { commandMap_ = { @@ -202,6 +211,7 @@ void CliCommand::CreateCommandMap() {std::make_pair("step-into", "si"), std::bind(&CliCommand::DebuggerCommand, this, "step-into")}, {std::make_pair("step-out", "so"), std::bind(&CliCommand::DebuggerCommand, this, "step-out")}, {std::make_pair("step-over", "sov"), std::bind(&CliCommand::DebuggerCommand, this, "step-over")}, + {std::make_pair("parseabc", "pabc"), std::bind(&CliCommand::DebuggerCommand, this, "parseabc")}, {std::make_pair("runtime-disable", "rt-disable"), std::bind(&CliCommand::RuntimeCommand, this, "runtime-disable")}, {std::make_pair("session-new", "session-new"), @@ -318,6 +328,15 @@ ErrCode CliCommand::DebuggerCommand(const std::string &cmd) } } + if(cmd == "parseabc"){ + std::string bnumber = GetArgList()[0]; + if (!EndsWith(bnumber, ".abc")) { + LOGE("ardb: The last argument must be abc file"); + return ErrCode::ERR_FAIL; + } + debuggerCli.AddBreakPointInfo(bnumber,0); + } + if (cmd == "step-into" || cmd == "step-out" || cmd == "step-over") { RuntimeClient &runtimeClient = session->GetDomainManager().GetRuntimeClient(); runtimeClient.SetIsInitializeTree(true); @@ -329,6 +348,14 @@ ErrCode CliCommand::DebuggerCommand(const std::string &cmd) } if (cmd == "break" && GetArgList().size() == 2) { // 2: two parameters + std::vector breaklist_ = breakpoint.Getbreaklist(); + size_t bsize = breaklist_.size(); + for (size_t i = 0; i < bsize; i++) { + if (breaklist_[i].url == GetArgList()[0] && + std::stoi(breaklist_[i].lineNumber) + 1 == std::stoi(GetArgList()[1])) { + return ErrCode::ERR_FAIL; + } + } debuggerCli.AddBreakPointInfo(GetArgList()[0], std::stoi(GetArgList()[1])); } diff --git a/tooling/client/utils/cli_command.h b/tooling/client/utils/cli_command.h index 5410695e356a7a73de5db50fff448a6e1c821220..0330c5e9b272ae3560a4f74d1f19d120ea44e153 100644 --- a/tooling/client/utils/cli_command.h +++ b/tooling/client/utils/cli_command.h @@ -64,6 +64,7 @@ public: ErrCode SessionSwitchCommand(const std::string &cmd); ErrCode TestCommand(const std::string &cmd); ErrCode ExecHelpCommand(); + bool EndsWith(const std::string &str, const std::string &suffix); VecStr GetArgList() {