mirror of
https://gitee.com/openharmony/arkcompiler_toolchain
synced 2024-11-27 09:40:40 +00:00
!368 支持toolchain_cli工具
Merge pull request !368 from caolili123/c_toolchain_client_dev
This commit is contained in:
commit
5e2a93f734
2
BUILD.gn
2
BUILD.gn
@ -133,6 +133,8 @@ group("ark_toolchain_packages") {
|
||||
"$toolchain_root/inspector:ark_debugger",
|
||||
"$toolchain_root/inspector:connectserver_debugger",
|
||||
"$toolchain_root/tooling:libark_ecma_debugger",
|
||||
"$toolchain_root/tooling/client:libark_client",
|
||||
"$toolchain_root/tooling/client/ark_cli:arkdb",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -280,6 +280,36 @@ std::unique_ptr<PtJson> GetHeapUsageReturns::ToJson() const
|
||||
return result;
|
||||
}
|
||||
|
||||
std::unique_ptr<GetHeapUsageReturns> GetHeapUsageReturns::Create(const PtJson ¶ms)
|
||||
{
|
||||
auto heapUsageReturns = std::make_unique<GetHeapUsageReturns>();
|
||||
std::string error;
|
||||
Result ret;
|
||||
|
||||
double usedSize;
|
||||
ret = params.GetDouble("usedSize", &usedSize);
|
||||
if (ret == Result::SUCCESS) {
|
||||
heapUsageReturns->usedSize_ = usedSize;
|
||||
} else {
|
||||
error += "Unknown 'usedSize';";
|
||||
}
|
||||
|
||||
double totalSize;
|
||||
ret = params.GetDouble("totalSize", &totalSize);
|
||||
if (ret == Result::SUCCESS) {
|
||||
heapUsageReturns->totalSize_ = totalSize;
|
||||
} else {
|
||||
error += "Unknown 'totalSize';";
|
||||
}
|
||||
|
||||
if (!error.empty()) {
|
||||
LOG_DEBUGGER(ERROR) << "HeapUsageReturns::Create " << error;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return heapUsageReturns;
|
||||
}
|
||||
|
||||
std::unique_ptr<PtJson> GetBestEffortCoverageReturns::ToJson() const
|
||||
{
|
||||
std::unique_ptr<PtJson> result = PtJson::CreateObject();
|
||||
|
@ -331,13 +331,35 @@ private:
|
||||
|
||||
class GetHeapUsageReturns : public PtBaseReturns {
|
||||
public:
|
||||
GetHeapUsageReturns() = default;
|
||||
explicit GetHeapUsageReturns(double usedSize, double totalSize)
|
||||
: usedSize_(usedSize), totalSize_(totalSize) {}
|
||||
~GetHeapUsageReturns() override = default;
|
||||
std::unique_ptr<PtJson> ToJson() const override;
|
||||
|
||||
static std::unique_ptr<GetHeapUsageReturns> Create(const PtJson ¶ms);
|
||||
|
||||
void SetUsedSize(const double &usedSize)
|
||||
{
|
||||
usedSize_ = usedSize;
|
||||
}
|
||||
|
||||
double GetUsedSize() const
|
||||
{
|
||||
return usedSize_;
|
||||
}
|
||||
|
||||
void SetTotalSize(const double &totalSize)
|
||||
{
|
||||
totalSize_ = totalSize;
|
||||
}
|
||||
|
||||
double GetTotalSize() const
|
||||
{
|
||||
return totalSize_;
|
||||
}
|
||||
|
||||
private:
|
||||
GetHeapUsageReturns() = default;
|
||||
NO_COPY_SEMANTIC(GetHeapUsageReturns);
|
||||
NO_MOVE_SEMANTIC(GetHeapUsageReturns);
|
||||
|
||||
|
93
tooling/client/BUILD.gn
Normal file
93
tooling/client/BUILD.gn
Normal file
@ -0,0 +1,93 @@
|
||||
# Copyright (c) 2023 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("//arkcompiler/toolchain/toolchain.gni")
|
||||
|
||||
config("hiviewdfx_config") {
|
||||
defines = []
|
||||
if (enable_dump_in_faultlog) {
|
||||
defines += [ "ENABLE_DUMP_IN_FAULTLOG" ]
|
||||
}
|
||||
if (enable_bytrace) {
|
||||
defines += [ "ENABLE_BYTRACE" ]
|
||||
cflags_cc = [ "-Wno-gnu-zero-variadic-macro-arguments" ]
|
||||
}
|
||||
if (enable_hitrace) {
|
||||
defines += [ "ENABLE_HITRACE" ]
|
||||
}
|
||||
if (enable_hilog) {
|
||||
defines += [ "ENABLE_HILOG" ]
|
||||
}
|
||||
|
||||
include_dirs = [ "$hilog_root/include" ]
|
||||
}
|
||||
|
||||
ohos_source_set("libark_client_set") {
|
||||
stack_protector_ret = false
|
||||
defines = []
|
||||
deps = []
|
||||
configs = [ sdk_libc_secshared_config ]
|
||||
|
||||
# hiviewdfx libraries
|
||||
external_deps = hiviewdfx_ext_deps
|
||||
deps += hiviewdfx_deps
|
||||
|
||||
include_dirs = [
|
||||
"./",
|
||||
"../base",
|
||||
"../../inspector",
|
||||
"../../websocket",
|
||||
"//third_party/cJSON",
|
||||
]
|
||||
|
||||
sources = [
|
||||
"domain/debugger_client.cpp",
|
||||
"domain/heapprofiler_client.cpp",
|
||||
"domain/profiler_client.cpp",
|
||||
"domain/runtime_client.cpp",
|
||||
"manager/breakpoint_manager.cpp",
|
||||
"manager/domain_manager.cpp",
|
||||
"manager/stack_manager.cpp",
|
||||
"manager/variable_manager.cpp",
|
||||
"utils/utils.cpp",
|
||||
"websocket/websocket_client.cpp",
|
||||
]
|
||||
|
||||
deps += [
|
||||
"$ark_third_party_root/openssl:libcrypto_shared",
|
||||
"../:libark_ecma_debugger_set",
|
||||
"//third_party/libuv:uv",
|
||||
sdk_libc_secshared_dep,
|
||||
]
|
||||
|
||||
external_deps += [ "ets_runtime:libark_jsruntime" ]
|
||||
|
||||
configs += [ ":hiviewdfx_config" ]
|
||||
|
||||
cflags_cc = [ "-Wno-error=vla-extension" ]
|
||||
|
||||
subsystem_name = "arkcompiler"
|
||||
part_name = "toolchain"
|
||||
}
|
||||
|
||||
ohos_shared_library("libark_client") {
|
||||
stack_protector_ret = false
|
||||
deps = [ ":libark_client_set" ]
|
||||
|
||||
if (!is_mingw && !is_mac) {
|
||||
output_extension = "so"
|
||||
}
|
||||
|
||||
subsystem_name = "arkcompiler"
|
||||
part_name = "toolchain"
|
||||
}
|
110
tooling/client/ark_cli/BUILD.gn
Normal file
110
tooling/client/ark_cli/BUILD.gn
Normal file
@ -0,0 +1,110 @@
|
||||
# Copyright (c) 2023 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("//arkcompiler/toolchain/toolchain.gni")
|
||||
|
||||
config("hiviewdfx_config") {
|
||||
defines = []
|
||||
if (enable_dump_in_faultlog) {
|
||||
defines += [ "ENABLE_DUMP_IN_FAULTLOG" ]
|
||||
}
|
||||
if (enable_bytrace) {
|
||||
defines += [ "ENABLE_BYTRACE" ]
|
||||
cflags_cc = [ "-Wno-gnu-zero-variadic-macro-arguments" ]
|
||||
}
|
||||
if (enable_hitrace) {
|
||||
defines += [ "ENABLE_HITRACE" ]
|
||||
}
|
||||
if (enable_hilog) {
|
||||
defines += [ "ENABLE_HILOG" ]
|
||||
}
|
||||
|
||||
include_dirs = [ "$hilog_root/include" ]
|
||||
|
||||
if (is_linux) {
|
||||
defines += [
|
||||
"PANDA_TARGET_UNIX",
|
||||
"PANDA_TARGET_LINUX",
|
||||
"PANDA_USE_FUTEX",
|
||||
]
|
||||
} else if (is_mingw) {
|
||||
cflags_cc += [
|
||||
"-std=c++17",
|
||||
"-Wno-ignored-attributes",
|
||||
]
|
||||
defines += [
|
||||
"PANDA_TARGET_WINDOWS",
|
||||
"_CRTBLD",
|
||||
"__LIBMSVCRT__",
|
||||
]
|
||||
} else if (is_mac) {
|
||||
defines += [
|
||||
"PANDA_TARGET_UNIX",
|
||||
"PANDA_TARGET_MACOS",
|
||||
]
|
||||
} else if (target_os == "android") {
|
||||
defines += [
|
||||
"PANDA_TARGET_ANDROID",
|
||||
"PANDA_TARGET_UNIX",
|
||||
"PANDA_USE_FUTEX",
|
||||
]
|
||||
if (!ark_standalone_build) {
|
||||
defines += [ "ENABLE_ANLOG" ]
|
||||
}
|
||||
} else if (target_os == "ios") {
|
||||
defines += [
|
||||
"PANDA_TARGET_UNIX",
|
||||
"PANDA_TARGET_IOS",
|
||||
]
|
||||
} else {
|
||||
defines += [
|
||||
"PANDA_TARGET_UNIX",
|
||||
"PANDA_USE_FUTEX",
|
||||
]
|
||||
if (!is_standard_system && (current_cpu != "arm" || is_wearable_product)) {
|
||||
defines += [ "PANDA_TARGET_MOBILE" ]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ohos_executable("arkdb") {
|
||||
sources = [
|
||||
"cli_command.cpp",
|
||||
"main.cpp",
|
||||
]
|
||||
|
||||
include_dirs = [
|
||||
"./",
|
||||
"../",
|
||||
"../../base",
|
||||
"../../../inspector",
|
||||
"../../../tooling",
|
||||
"../../../websocket",
|
||||
"//third_party/cJSON",
|
||||
"//third_party/libuv/include",
|
||||
]
|
||||
|
||||
deps = [ "../:libark_client_set" ]
|
||||
|
||||
external_deps = [
|
||||
"ets_runtime:libark_jsruntime",
|
||||
"hitrace:hitrace_meter",
|
||||
]
|
||||
|
||||
configs = [ ":hiviewdfx_config" ]
|
||||
|
||||
install_enable = false
|
||||
|
||||
part_name = "toolchain"
|
||||
subsystem_name = "arkcompiler"
|
||||
}
|
363
tooling/client/ark_cli/cli_command.cpp
Normal file
363
tooling/client/ark_cli/cli_command.cpp
Normal file
@ -0,0 +1,363 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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 "cli_command.h"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <mutex>
|
||||
|
||||
#include "domain/debugger_client.h"
|
||||
#include "domain/runtime_client.h"
|
||||
#include "log_wrapper.h"
|
||||
#include "manager/breakpoint_manager.h"
|
||||
#include "manager/domain_manager.h"
|
||||
#include "manager/stack_manager.h"
|
||||
#include "manager/variable_manager.h"
|
||||
|
||||
namespace OHOS::ArkCompiler::Toolchain {
|
||||
DomainManager g_domainManager;
|
||||
WebsocketClient g_cliSocket;
|
||||
const std::string HELP_MSG = "usage: <command> <options>\n"
|
||||
" These are common commands list:\n"
|
||||
" allocationtrack(at) allocation-track-start with options\n"
|
||||
" allocationtrack-stop(at-stop) allocation-track-stop\n"
|
||||
" heapdump(hd) heapdump with options\n"
|
||||
" heapprofiler-enable(hp-enable) heapdump enable\n"
|
||||
" heapprofiler-disable(hp-disable) heapdump disable\n"
|
||||
" sampling(sampling) heapprofiler sampling\n"
|
||||
" sampling-stop(sampling-stop) heapprofiler sampling stop\n"
|
||||
" collectgarbage(gc) heapprofiler collectgarbage\n"
|
||||
" cpuprofile(cp) cpuprofile start\n"
|
||||
" cpuprofile-stop(cp-stop) cpuprofile stop\n"
|
||||
" cpuprofile-enable(cp-enable) cpuprofile enable\n"
|
||||
" cpuprofile-disable(cp-disable) cpuprofile disable\n"
|
||||
" cpuprofile-show(cp-show) cpuprofile show\n"
|
||||
" cpuprofile-setSamplingInterval(cp-ssi) cpuprofile setSamplingInterval\n"
|
||||
" runtime-enable(rt-enable) runtime enable\n"
|
||||
" heapusage(hu) runtime getHeapUsage\n"
|
||||
" break(b) break with options\n"
|
||||
" backtrack(bt) backtrace\n"
|
||||
" continue(c) continue\n"
|
||||
" delete(d) delete with options\n"
|
||||
" disable disable\n"
|
||||
" display display\n"
|
||||
" enable debugger enable\n"
|
||||
" finish(fin) finish\n"
|
||||
" frame(f) frame\n"
|
||||
" help(h) list available commands\n"
|
||||
" ignore(ig) ignore\n"
|
||||
" infobreakpoints(infob) info-breakpoints\n"
|
||||
" infosource(infos) info-source\n"
|
||||
" jump(j) jump\n"
|
||||
" list(l) list\n"
|
||||
" next(n) next\n"
|
||||
" print(p) print with options\n"
|
||||
" ptype ptype\n"
|
||||
" quit(q) quit\n"
|
||||
" run(r) run\n"
|
||||
" setvar(sv) set value with options\n"
|
||||
" step(s) step\n"
|
||||
" undisplay undisplay\n"
|
||||
" watch(wa) watch\n"
|
||||
" resume resume\n"
|
||||
" showstack(ss) showstack\n"
|
||||
" step-into(si) step-into\n"
|
||||
" step-out(so) step-out\n"
|
||||
" step-over(sov) step-over\n"
|
||||
" runtime-disable rt-disable\n";
|
||||
|
||||
const std::vector<std::string> cmdList = {
|
||||
"allocationtrack",
|
||||
"allocationtrack-stop",
|
||||
"heapdump",
|
||||
"heapprofiler-enable",
|
||||
"heapprofiler-disable",
|
||||
"sampling",
|
||||
"sampling-stop",
|
||||
"collectgarbage",
|
||||
"cpuprofile",
|
||||
"cpuprofile-stop",
|
||||
"cpuprofile-enable",
|
||||
"cpuprofile-disable",
|
||||
"cpuprofile-show",
|
||||
"cpuprofile-setSamplingInterval",
|
||||
"runtime-enable",
|
||||
"heapusage",
|
||||
"break",
|
||||
"backtrack",
|
||||
"continue",
|
||||
"delete",
|
||||
"disable",
|
||||
"display",
|
||||
"enable",
|
||||
"finish",
|
||||
"frame",
|
||||
"help",
|
||||
"ignore",
|
||||
"infobreakpoints",
|
||||
"infosource",
|
||||
"jump",
|
||||
"list",
|
||||
"next",
|
||||
"print",
|
||||
"ptype",
|
||||
"run",
|
||||
"setvar",
|
||||
"step",
|
||||
"undisplay",
|
||||
"watch",
|
||||
"resume",
|
||||
"step-into",
|
||||
"step-out",
|
||||
"step-over",
|
||||
"runtime-disable"
|
||||
};
|
||||
ErrCode CliCommand::ExecCommand()
|
||||
{
|
||||
CreateCommandMap();
|
||||
|
||||
ErrCode result = OnCommand();
|
||||
return result;
|
||||
}
|
||||
|
||||
void CliCommand::CreateCommandMap()
|
||||
{
|
||||
commandMap_ = {
|
||||
{std::make_pair("allocationtrack", "at"), std::bind(&CliCommand::HeapProfilerCommand, this, "allocationtrack")},
|
||||
{std::make_pair("allocationtrack-stop", "at-stop"),
|
||||
std::bind(&CliCommand::HeapProfilerCommand, this, "allocationtrack-stop")},
|
||||
{std::make_pair("heapdump", "hd"), std::bind(&CliCommand::HeapProfilerCommand, this, "heapdump")},
|
||||
{std::make_pair("heapprofiler-enable", "hp-enable"),
|
||||
std::bind(&CliCommand::HeapProfilerCommand, this, "heapprofiler-enable")},
|
||||
{std::make_pair("heapprofiler-disable", "hp-disable"),
|
||||
std::bind(&CliCommand::HeapProfilerCommand, this, "heapprofiler-disable")},
|
||||
{std::make_pair("sampling", "sampling"), std::bind(&CliCommand::HeapProfilerCommand, this, "sampling")},
|
||||
{std::make_pair("sampling-stop", "sampling-stop"),
|
||||
std::bind(&CliCommand::HeapProfilerCommand, this, "sampling-stop")},
|
||||
{std::make_pair("collectgarbage", "gc"), std::bind(&CliCommand::HeapProfilerCommand, this, "collectgarbage")},
|
||||
{std::make_pair("cpuprofile", "cp"), std::bind(&CliCommand::CpuProfileCommand, this, "cpuprofile")},
|
||||
{std::make_pair("cpuprofile-stop", "cp-stop"),
|
||||
std::bind(&CliCommand::CpuProfileCommand, this, "cpuprofile-stop")},
|
||||
{std::make_pair("cpuprofile-enable", "cp-enable"),
|
||||
std::bind(&CliCommand::CpuProfileCommand, this, "cpuprofile-enable")},
|
||||
{std::make_pair("cpuprofile-disable", "cp-disable"),
|
||||
std::bind(&CliCommand::CpuProfileCommand, this, "cpuprofile-disable")},
|
||||
{std::make_pair("cpuprofile-show", "cp-show"),
|
||||
std::bind(&CliCommand::CpuProfileCommand, this, "cpuprofile-show")},
|
||||
{std::make_pair("cpuprofile-setSamplingInterval", "cp-ssi"),
|
||||
std::bind(&CliCommand::CpuProfileCommand, this, "cpuprofile-setSamplingInterval")},
|
||||
{std::make_pair("runtime-enable", "rt-enable"), std::bind(&CliCommand::RuntimeCommand, this, "runtime-enable")},
|
||||
{std::make_pair("heapusage", "hu"), std::bind(&CliCommand::RuntimeCommand, this, "heapusage")},
|
||||
{std::make_pair("break", "b"), std::bind(&CliCommand::DebuggerCommand, this, "break")},
|
||||
{std::make_pair("backtrack", "bt"), std::bind(&CliCommand::DebuggerCommand, this, "backtrack")},
|
||||
{std::make_pair("continue", "c"), std::bind(&CliCommand::DebuggerCommand, this, "continue")},
|
||||
{std::make_pair("delete", "d"), std::bind(&CliCommand::DebuggerCommand, this, "delete")},
|
||||
{std::make_pair("disable", "disable"), std::bind(&CliCommand::DebuggerCommand, this, "disable")},
|
||||
{std::make_pair("display", "display"), std::bind(&CliCommand::DebuggerCommand, this, "display")},
|
||||
{std::make_pair("enable", "enable"), std::bind(&CliCommand::DebuggerCommand, this, "enable")},
|
||||
{std::make_pair("finish", "fin"), std::bind(&CliCommand::DebuggerCommand, this, "finish")},
|
||||
{std::make_pair("frame", "f"), std::bind(&CliCommand::DebuggerCommand, this, "frame")},
|
||||
{std::make_pair("help", "h"), std::bind(&CliCommand::ExecHelpCommand, this)},
|
||||
{std::make_pair("ignore", "ig"), std::bind(&CliCommand::DebuggerCommand, this, "ignore")},
|
||||
{std::make_pair("infobreakpoints", "infob"), std::bind(&CliCommand::DebuggerCommand, this, "infobreakpoints")},
|
||||
{std::make_pair("infosource", "infos"), std::bind(&CliCommand::DebuggerCommand, this, "infosource")},
|
||||
{std::make_pair("jump", "j"), std::bind(&CliCommand::DebuggerCommand, this, "jump")},
|
||||
{std::make_pair("list", "l"), std::bind(&CliCommand::DebuggerCommand, this, "list")},
|
||||
{std::make_pair("next", "n"), std::bind(&CliCommand::DebuggerCommand, this, "next")},
|
||||
{std::make_pair("print", "p"), std::bind(&CliCommand::RuntimeCommand, this, "print")},
|
||||
{std::make_pair("print2", "p2"), std::bind(&CliCommand::RuntimeCommand, this, "print2")},
|
||||
{std::make_pair("ptype", "ptype"), std::bind(&CliCommand::DebuggerCommand, this, "ptype")},
|
||||
{std::make_pair("run", "r"), std::bind(&CliCommand::RuntimeCommand, this, "run")},
|
||||
{std::make_pair("setvar", "sv"), std::bind(&CliCommand::DebuggerCommand, this, "setvar")},
|
||||
{std::make_pair("step", "s"), std::bind(&CliCommand::DebuggerCommand, this, "step")},
|
||||
{std::make_pair("undisplay", "undisplay"), std::bind(&CliCommand::DebuggerCommand, this, "undisplay")},
|
||||
{std::make_pair("watch", "wa"), std::bind(&CliCommand::DebuggerCommand, this, "watch")},
|
||||
{std::make_pair("resume", "resume"), std::bind(&CliCommand::DebuggerCommand, this, "resume")},
|
||||
{std::make_pair("showstack", "ss"), std::bind(&CliCommand::DebuggerCommand, this, "showstack")},
|
||||
{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("runtime-disable", "rt-disable"),
|
||||
std::bind(&CliCommand::RuntimeCommand, this, "runtime-disable")}
|
||||
};
|
||||
}
|
||||
|
||||
ErrCode CliCommand::HeapProfilerCommand(const std::string &cmd)
|
||||
{
|
||||
std::cout << "exe success, cmd is " << cmd << std::endl;
|
||||
std::string request;
|
||||
bool result = false;
|
||||
HeapProfilerClient* heapProfilerClient = g_domainManager.GetHeapProfilerClient();
|
||||
VecStr argList = GetArgList();
|
||||
if (argList.empty()) {
|
||||
argList.push_back("/data/");
|
||||
}
|
||||
result = heapProfilerClient->DispatcherCmd(id_, cmd, argList[0], &request);
|
||||
if (result) {
|
||||
g_cliSocket.ClientSendReq(request);
|
||||
if (g_domainManager.GetDomainById(id_).empty()) {
|
||||
g_domainManager.SetDomainById(id_, "HeapProfiler");
|
||||
}
|
||||
} else {
|
||||
return ErrCode::ERR_FAIL;
|
||||
}
|
||||
return ErrCode::ERR_OK;
|
||||
}
|
||||
|
||||
ErrCode CliCommand::CpuProfileCommand(const std::string &cmd)
|
||||
{
|
||||
std::cout << "exe success, cmd is " << cmd << std::endl;
|
||||
std::string request;
|
||||
bool result = false;
|
||||
ProfilerClient* profilerClient = g_domainManager.GetProfilerClient();
|
||||
ProfilerSingleton& pro = ProfilerSingleton::GetInstance();
|
||||
if (cmd == "cpuprofile-show") {
|
||||
pro.ShowCpuFile();
|
||||
return ErrCode::ERR_OK;
|
||||
}
|
||||
if (cmd == "cpuprofile-setSamplingInterval") {
|
||||
profilerClient->SetSamplingInterval(std::atoi(GetArgList()[0].c_str()));
|
||||
}
|
||||
if (cmd == "cpuprofile-stop" && GetArgList().size() == 1) {
|
||||
pro.SetAddress(GetArgList()[0]);
|
||||
}
|
||||
result = profilerClient->DispatcherCmd(id_, cmd, &request);
|
||||
if (result) {
|
||||
g_cliSocket.ClientSendReq(request);
|
||||
if (g_domainManager.GetDomainById(id_).empty()) {
|
||||
g_domainManager.SetDomainById(id_, "Profiler");
|
||||
}
|
||||
} else {
|
||||
return ErrCode::ERR_FAIL;
|
||||
}
|
||||
return ErrCode::ERR_OK;
|
||||
}
|
||||
|
||||
ErrCode CliCommand::DebuggerCommand(const std::string &cmd)
|
||||
{
|
||||
std::cout << "exe success, cmd is " << cmd << std::endl;
|
||||
std::string request;
|
||||
bool result = false;
|
||||
DebuggerClient debuggerCli;
|
||||
BreakPointManager &breakpoint = BreakPointManager::GetInstance();
|
||||
if (cmd == "display") {
|
||||
breakpoint.Show();
|
||||
return ErrCode::ERR_OK;
|
||||
}
|
||||
|
||||
if (cmd == "delete") {
|
||||
std::string bnumber = GetArgList()[0];
|
||||
unsigned int num = std::stoi(bnumber);
|
||||
if (breakpoint.Getbreaklist().size() >= num && num > 0) {
|
||||
debuggerCli.AddBreakPointInfo(breakpoint.Getbreaklist()[num - 1].breakpointId, 0); // 1: breakpoinId
|
||||
breakpoint.Deletebreaklist(num);
|
||||
} else {
|
||||
return ErrCode::ERR_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
if (cmd == "step-into" || cmd == "step-out" || cmd == "step-over") {
|
||||
RuntimeClient &runtimeClient = RuntimeClient::GetInstance();
|
||||
runtimeClient.SetIsInitializeTree(true);
|
||||
}
|
||||
|
||||
if (cmd == "showstack") {
|
||||
StackManager &stackManager = StackManager::GetInstance();
|
||||
stackManager.ShowCallFrames();
|
||||
}
|
||||
|
||||
if (cmd == "break" && GetArgList().size() == 2) { // 2: two parameters
|
||||
debuggerCli.AddBreakPointInfo(GetArgList()[0], std::stoi(GetArgList()[1]));
|
||||
}
|
||||
|
||||
result = debuggerCli.DispatcherCmd(id_, cmd, &request);
|
||||
if (result) {
|
||||
g_cliSocket.ClientSendReq(request);
|
||||
if (g_domainManager.GetDomainById(id_).empty()) {
|
||||
g_domainManager.SetDomainById(id_, "Debugger");
|
||||
}
|
||||
} else {
|
||||
return ErrCode::ERR_FAIL;
|
||||
}
|
||||
return ErrCode::ERR_OK;
|
||||
}
|
||||
|
||||
ErrCode CliCommand::RuntimeCommand(const std::string &cmd)
|
||||
{
|
||||
std::cout << "exe success, cmd is " << cmd << std::endl;
|
||||
std::string request;
|
||||
bool result = false;
|
||||
RuntimeClient &runtimeClient = RuntimeClient::GetInstance();
|
||||
|
||||
if (cmd == "print" && GetArgList().size() == 1) {
|
||||
runtimeClient.SetIsInitializeTree(false);
|
||||
VariableManager &variableManager = VariableManager::GetInstance();
|
||||
int32_t objectId = variableManager.FindObjectIdWithIndex(std::stoi(GetArgList()[0]));
|
||||
runtimeClient.SetObjectId(std::to_string(objectId));
|
||||
}
|
||||
|
||||
result = runtimeClient.DispatcherCmd(id_, cmd, &request);
|
||||
if (result) {
|
||||
g_cliSocket.ClientSendReq(request);
|
||||
runtimeClient.SetObjectId("0");
|
||||
if (g_domainManager.GetDomainById(id_).empty()) {
|
||||
g_domainManager.SetDomainById(id_, "Runtime");
|
||||
}
|
||||
} else {
|
||||
return ErrCode::ERR_FAIL;
|
||||
}
|
||||
return ErrCode::ERR_OK;
|
||||
}
|
||||
|
||||
ErrCode CliCommand::ExecHelpCommand()
|
||||
{
|
||||
std::cout << HELP_MSG;
|
||||
return ErrCode::ERR_OK;
|
||||
}
|
||||
|
||||
ErrCode CliCommand::OnCommand()
|
||||
{
|
||||
std::map<StrPair, std::function<ErrCode()>>::iterator it;
|
||||
StrPair cmdPair;
|
||||
bool haveCmdFlag = false;
|
||||
|
||||
for (it = commandMap_.begin(); it != commandMap_.end(); it++) {
|
||||
cmdPair = it->first;
|
||||
if (!strcmp(cmdPair.first.c_str(), cmd_.c_str())
|
||||
||!strcmp(cmdPair.second.c_str(), cmd_.c_str())) {
|
||||
auto respond = it->second;
|
||||
return respond();
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < cmdList.size(); i++) {
|
||||
if (!strncmp(cmdList[i].c_str(), cmd_.c_str(), std::strlen(cmd_.c_str()))) {
|
||||
haveCmdFlag = true;
|
||||
std::cout << cmdList[i] << " ";
|
||||
}
|
||||
}
|
||||
|
||||
if (haveCmdFlag) {
|
||||
std::cout << std::endl;
|
||||
} else {
|
||||
ExecHelpCommand();
|
||||
}
|
||||
|
||||
return ErrCode::ERR_FAIL;
|
||||
}
|
||||
} // namespace OHOS::ArkCompiler::Toolchain
|
82
tooling/client/ark_cli/cli_command.h
Normal file
82
tooling/client/ark_cli/cli_command.h
Normal file
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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.
|
||||
*/
|
||||
|
||||
#ifndef ECMASCRIPT_TOOLING_CLIENT_ARK_CLI_CLI_COMMAND_H
|
||||
#define ECMASCRIPT_TOOLING_CLIENT_ARK_CLI_CLI_COMMAND_H
|
||||
|
||||
#include <cstdlib>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include "domain/heapprofiler_client.h"
|
||||
#include "domain/profiler_client.h"
|
||||
#include "log_wrapper.h"
|
||||
#include "manager/domain_manager.h"
|
||||
#include "websocket/websocket_client.h"
|
||||
|
||||
namespace OHOS::ArkCompiler::Toolchain {
|
||||
using StrPair = std::pair<std::string, std::string>;
|
||||
using VecStr = std::vector<std::string>;
|
||||
extern DomainManager g_domainManager;
|
||||
extern WebsocketClient g_cliSocket;
|
||||
|
||||
enum class ErrCode : uint8_t {
|
||||
ERR_OK = 0,
|
||||
ERR_FAIL = 1
|
||||
};
|
||||
|
||||
class CliCommand {
|
||||
public:
|
||||
CliCommand(std::vector<std::string> cliCmdStr, int cmdId)
|
||||
{
|
||||
id_ = cmdId;
|
||||
cmd_ = cliCmdStr[0];
|
||||
for (unsigned int i = 1; i < cliCmdStr.size(); i++) {
|
||||
argList_.push_back(cliCmdStr[i]);
|
||||
}
|
||||
}
|
||||
|
||||
~CliCommand() = default;
|
||||
|
||||
ErrCode OnCommand();
|
||||
ErrCode ExecCommand();
|
||||
void CreateCommandMap();
|
||||
ErrCode HeapProfilerCommand(const std::string &cmd);
|
||||
ErrCode DebuggerCommand(const std::string &cmd);
|
||||
ErrCode CpuProfileCommand(const std::string &cmd);
|
||||
ErrCode RuntimeCommand(const std::string &cmd);
|
||||
ErrCode ExecHelpCommand();
|
||||
|
||||
uint32_t GetId() const
|
||||
{
|
||||
return id_;
|
||||
}
|
||||
|
||||
VecStr GetArgList()
|
||||
{
|
||||
return argList_;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string cmd_ ;
|
||||
VecStr argList_ {};
|
||||
std::map<StrPair, std::function<ErrCode()>> commandMap_;
|
||||
std::string resultReceiver_ = "";
|
||||
uint32_t id_ = 0;
|
||||
};
|
||||
} // namespace OHOS::ArkCompiler::Toolchain
|
||||
|
||||
#endif // ECMASCRIPT_TOOLING_CLIENT_ARK_CLI_CLI_COMMAND_H
|
238
tooling/client/ark_cli/main.cpp
Normal file
238
tooling/client/ark_cli/main.cpp
Normal file
@ -0,0 +1,238 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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 <cstring>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <pthread.h>
|
||||
#include <thread>
|
||||
#include <uv.h>
|
||||
#include <securec.h>
|
||||
|
||||
#include "cli_command.h"
|
||||
|
||||
namespace OHOS::ArkCompiler::Toolchain {
|
||||
uint32_t g_messageId = 0;
|
||||
uv_async_t* g_socketSignal;
|
||||
uv_async_t* g_inputSignal;
|
||||
uv_async_t* g_releaseHandle;
|
||||
uv_loop_t* g_loop;
|
||||
|
||||
|
||||
bool StrToUInt(const char *content, uint32_t *result)
|
||||
{
|
||||
const int dec = 10;
|
||||
char *endPtr = nullptr;
|
||||
*result = std::strtoul(content, &endPtr, dec);
|
||||
if (endPtr == content || *endPtr != '\0') {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<std::string> SplitString(const std::string &str, const std::string &delimiter)
|
||||
{
|
||||
std::size_t strIndex = 0;
|
||||
std::vector<std::string> value;
|
||||
std::size_t pos = str.find_first_of(delimiter, strIndex);
|
||||
while ((pos < str.size()) && (pos > strIndex)) {
|
||||
std::string subStr = str.substr(strIndex, pos - strIndex);
|
||||
value.push_back(std::move(subStr));
|
||||
strIndex = pos;
|
||||
strIndex = str.find_first_not_of(delimiter, strIndex);
|
||||
pos = str.find_first_of(delimiter, strIndex);
|
||||
}
|
||||
if (pos > strIndex) {
|
||||
std::string subStr = str.substr(strIndex, pos - strIndex);
|
||||
if (!subStr.empty()) {
|
||||
value.push_back(std::move(subStr));
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
void ReleaseHandle(uv_async_t *handle)
|
||||
{
|
||||
uv_close(reinterpret_cast<uv_handle_t*>(g_inputSignal), [](uv_handle_t* handle) {
|
||||
if (handle != nullptr) {
|
||||
delete reinterpret_cast<uv_async_t*>(handle);
|
||||
handle = nullptr;
|
||||
}
|
||||
});
|
||||
|
||||
uv_close(reinterpret_cast<uv_handle_t*>(g_socketSignal), [](uv_handle_t* handle) {
|
||||
if (handle != nullptr) {
|
||||
delete reinterpret_cast<uv_async_t*>(handle);
|
||||
handle = nullptr;
|
||||
}
|
||||
});
|
||||
|
||||
uv_close(reinterpret_cast<uv_handle_t*>(g_releaseHandle), [](uv_handle_t* handle) {
|
||||
if (handle != nullptr) {
|
||||
delete reinterpret_cast<uv_async_t*>(handle);
|
||||
handle = nullptr;
|
||||
}
|
||||
});
|
||||
|
||||
if (g_loop != nullptr) {
|
||||
uv_stop(g_loop);
|
||||
}
|
||||
}
|
||||
|
||||
void InputOnMessage(uv_async_t *handle)
|
||||
{
|
||||
char* msg = static_cast<char*>(handle->data);
|
||||
std::string inputStr = std::string(msg);
|
||||
std::vector<std::string> cliCmdStr = SplitString(inputStr, " ");
|
||||
g_messageId += 1;
|
||||
CliCommand cmd(cliCmdStr, g_messageId);
|
||||
if (cmd.ExecCommand() == ErrCode::ERR_FAIL) {
|
||||
g_messageId -= 1;
|
||||
}
|
||||
std::cout << ">>> ";
|
||||
fflush(stdout);
|
||||
if (msg != nullptr) {
|
||||
free(msg);
|
||||
}
|
||||
}
|
||||
|
||||
void GetInputCommand(void *arg)
|
||||
{
|
||||
std::cout << ">>> ";
|
||||
std::string inputStr;
|
||||
while (getline(std::cin, inputStr)) {
|
||||
if (inputStr.empty()) {
|
||||
std::cout << ">>> ";
|
||||
continue;
|
||||
}
|
||||
if ((!strcmp(inputStr.c_str(), "quit")) || (!strcmp(inputStr.c_str(), "q"))) {
|
||||
LOGE("arkdb: quit");
|
||||
g_cliSocket.Close();
|
||||
if (uv_is_active(reinterpret_cast<uv_handle_t*>(g_releaseHandle))) {
|
||||
uv_async_send(g_releaseHandle);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (uv_is_active(reinterpret_cast<uv_handle_t*>(g_inputSignal))) {
|
||||
uint32_t len = inputStr.length();
|
||||
char* msg = (char*)malloc(len + 1);
|
||||
if ((msg != nullptr) && uv_is_active(reinterpret_cast<uv_handle_t*>(g_inputSignal))) {
|
||||
if (strncpy_s(msg, len + 1, inputStr.c_str(), len) != 0) {
|
||||
g_cliSocket.Close();
|
||||
if (uv_is_active(reinterpret_cast<uv_handle_t*>(g_releaseHandle))) {
|
||||
uv_async_send(g_releaseHandle);
|
||||
}
|
||||
break;
|
||||
}
|
||||
g_inputSignal->data = std::move(msg);
|
||||
uv_async_send(g_inputSignal);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SocketOnMessage(uv_async_t *handle)
|
||||
{
|
||||
char* msg = static_cast<char*>(handle->data);
|
||||
g_domainManager.DispatcherReply(msg);
|
||||
if (msg != nullptr) {
|
||||
free(msg);
|
||||
}
|
||||
}
|
||||
|
||||
void GetSocketMessage(void *arg)
|
||||
{
|
||||
while (g_cliSocket.IsConnected()) {
|
||||
std::string decMessage = g_cliSocket.Decode();
|
||||
uint32_t len = decMessage.length();
|
||||
if (len == 0) {
|
||||
continue;
|
||||
}
|
||||
char* msg = (char*)malloc(len + 1);
|
||||
if ((msg != nullptr) && uv_is_active(reinterpret_cast<uv_handle_t*>(g_socketSignal))) {
|
||||
if (strncpy_s(msg, len + 1, decMessage.c_str(), len) != 0) {
|
||||
g_cliSocket.Close();
|
||||
if (uv_is_active(reinterpret_cast<uv_handle_t*>(g_releaseHandle))) {
|
||||
uv_async_send(g_releaseHandle);
|
||||
}
|
||||
break;
|
||||
}
|
||||
g_socketSignal->data = std::move(msg);
|
||||
uv_async_send(g_socketSignal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int Main(const int argc, const char** argv)
|
||||
{
|
||||
uint32_t port = 0;
|
||||
|
||||
if (argc < 2) { // 2: two parameters
|
||||
LOGE("arkdb is missing a parameter");
|
||||
return -1;
|
||||
}
|
||||
if (strstr(argv[0], "arkdb") != nullptr) {
|
||||
if (StrToUInt(argv[1], &port)) {
|
||||
if ((port <= 0) || (port >= 65535)) { // 65535: max port
|
||||
LOGE("arkdb:InitToolchainWebSocketForPort the port = %{public}d is wrong.", port);
|
||||
return -1;
|
||||
}
|
||||
if (!g_cliSocket.InitToolchainWebSocketForPort(port, 5)) { // 5: five times
|
||||
LOGE("arkdb:InitToolchainWebSocketForPort failed");
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
if (!g_cliSocket.InitToolchainWebSocketForSockName(argv[1])) {
|
||||
LOGE("arkdb:InitToolchainWebSocketForSockName failed");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!g_cliSocket.ClientSendWSUpgradeReq()) {
|
||||
LOGE("arkdb:ClientSendWSUpgradeReq failed");
|
||||
return -1;
|
||||
}
|
||||
if (!g_cliSocket.ClientRecvWSUpgradeRsp()) {
|
||||
LOGE("arkdb:ClientRecvWSUpgradeRsp failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
g_loop = uv_default_loop();
|
||||
|
||||
g_inputSignal = new uv_async_t;
|
||||
uv_async_init(g_loop, g_inputSignal, reinterpret_cast<uv_async_cb>(InputOnMessage));
|
||||
|
||||
g_socketSignal = new uv_async_t;
|
||||
uv_async_init(g_loop, g_socketSignal, reinterpret_cast<uv_async_cb>(SocketOnMessage));
|
||||
|
||||
g_releaseHandle = new uv_async_t;
|
||||
uv_async_init(g_loop, g_releaseHandle, reinterpret_cast<uv_async_cb>(ReleaseHandle));
|
||||
|
||||
uv_thread_t inputTid;
|
||||
uv_thread_create(&inputTid, GetInputCommand, nullptr);
|
||||
|
||||
uv_thread_t socketTid;
|
||||
uv_thread_create(&socketTid, GetSocketMessage, nullptr);
|
||||
|
||||
uv_run(g_loop, UV_RUN_DEFAULT);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
} // OHOS::ArkCompiler::Toolchain
|
||||
|
||||
int main(int argc, const char **argv)
|
||||
{
|
||||
return OHOS::ArkCompiler::Toolchain::Main(argc, argv);
|
||||
}
|
340
tooling/client/domain/debugger_client.cpp
Normal file
340
tooling/client/domain/debugger_client.cpp
Normal file
@ -0,0 +1,340 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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 "domain/debugger_client.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "log_wrapper.h"
|
||||
#include "manager/breakpoint_manager.h"
|
||||
#include "manager/stack_manager.h"
|
||||
#include "pt_json.h"
|
||||
|
||||
using PtJson = panda::ecmascript::tooling::PtJson;
|
||||
namespace OHOS::ArkCompiler::Toolchain {
|
||||
bool DebuggerClient::DispatcherCmd(int id, const std::string &cmd, std::string* reqStr)
|
||||
{
|
||||
std::map<std::string, std::function<std::string()>> dispatcherTable {
|
||||
{ "break", std::bind(&DebuggerClient::BreakCommand, this, id)},
|
||||
{ "backtrack", std::bind(&DebuggerClient::BacktrackCommand, this, id)},
|
||||
{ "continue", std::bind(&DebuggerClient::ContinueCommand, this, id)},
|
||||
{ "delete", std::bind(&DebuggerClient::DeleteCommand, this, id)},
|
||||
{ "jump", std::bind(&DebuggerClient::JumpCommand, this, id)},
|
||||
{ "disable", std::bind(&DebuggerClient::DisableCommand, this, id)},
|
||||
{ "display", std::bind(&DebuggerClient::DisplayCommand, this, id)},
|
||||
{ "enable", std::bind(&DebuggerClient::EnableCommand, this, id)},
|
||||
{ "finish", std::bind(&DebuggerClient::FinishCommand, this, id)},
|
||||
{ "frame", std::bind(&DebuggerClient::FrameCommand, this, id)},
|
||||
{ "ignore", std::bind(&DebuggerClient::IgnoreCommand, this, id)},
|
||||
{ "infobreakpoints", std::bind(&DebuggerClient::InfobreakpointsCommand, this, id)},
|
||||
{ "infosource", std::bind(&DebuggerClient::InfosourceCommand, this, id)},
|
||||
{ "list", std::bind(&DebuggerClient::ListCommand, this, id)},
|
||||
{ "next", std::bind(&DebuggerClient::NextCommand, this, id)},
|
||||
{ "ptype", std::bind(&DebuggerClient::PtypeCommand, this, id)},
|
||||
{ "run", std::bind(&DebuggerClient::RunCommand, this, id)},
|
||||
{ "setvar", std::bind(&DebuggerClient::SetvarCommand, this, id)},
|
||||
{ "step", std::bind(&DebuggerClient::StepCommand, this, id)},
|
||||
{ "undisplay", std::bind(&DebuggerClient::UndisplayCommand, this, id)},
|
||||
{ "watch", std::bind(&DebuggerClient::WatchCommand, this, id)},
|
||||
{ "resume", std::bind(&DebuggerClient::ResumeCommand, this, id)},
|
||||
{ "step-into", std::bind(&DebuggerClient::StepIntoCommand, this, id)},
|
||||
{ "step-out", std::bind(&DebuggerClient::StepOutCommand, this, id)},
|
||||
{ "step-over", std::bind(&DebuggerClient::StepOverCommand, this, id)},
|
||||
};
|
||||
|
||||
auto entry = dispatcherTable.find(cmd);
|
||||
if (entry != dispatcherTable.end()) {
|
||||
*reqStr = entry->second();
|
||||
LOGE("DebuggerClient DispatcherCmd reqStr1: %{public}s", reqStr->c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
*reqStr = "Unknown commond: " + cmd;
|
||||
LOGE("DebuggerClient DispatcherCmd reqStr2: %{public}s", reqStr->c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string DebuggerClient::BreakCommand(int id)
|
||||
{
|
||||
std::unique_ptr<PtJson> request = PtJson::CreateObject();
|
||||
request->Add("id", id);
|
||||
request->Add("method", "Debugger.setBreakpointByUrl");
|
||||
|
||||
std::unique_ptr<PtJson> params = PtJson::CreateObject();
|
||||
params->Add("columnNumber", breakPointInfoList_.back().columnNumber);
|
||||
params->Add("lineNumber", breakPointInfoList_.back().lineNumber);
|
||||
params->Add("url", breakPointInfoList_.back().url.c_str());
|
||||
request->Add("params", params);
|
||||
return request->Stringify();
|
||||
}
|
||||
|
||||
std::string DebuggerClient::BacktrackCommand([[maybe_unused]] int id)
|
||||
{
|
||||
return "backtrack";
|
||||
}
|
||||
|
||||
std::string DebuggerClient::ContinueCommand([[maybe_unused]] int id)
|
||||
{
|
||||
return "continue";
|
||||
}
|
||||
|
||||
std::string DebuggerClient::DeleteCommand(int id)
|
||||
{
|
||||
std::unique_ptr<PtJson> request = PtJson::CreateObject();
|
||||
request->Add("id", id);
|
||||
request->Add("method", "Debugger.removeBreakpoint");
|
||||
|
||||
std::unique_ptr<PtJson> params = PtJson::CreateObject();
|
||||
std::string breakpointId = breakPointInfoList_.back().url;
|
||||
params->Add("breakpointId", breakpointId.c_str());
|
||||
request->Add("params", params);
|
||||
return request->Stringify();
|
||||
}
|
||||
|
||||
std::string DebuggerClient::DisableCommand(int id)
|
||||
{
|
||||
std::unique_ptr<PtJson> request = PtJson::CreateObject();
|
||||
request->Add("id", id);
|
||||
request->Add("method", "Debugger.disable");
|
||||
|
||||
std::unique_ptr<PtJson> params = PtJson::CreateObject();
|
||||
request->Add("params", params);
|
||||
return request->Stringify();
|
||||
}
|
||||
|
||||
std::string DebuggerClient::DisplayCommand([[maybe_unused]] int id)
|
||||
{
|
||||
return "display";
|
||||
}
|
||||
|
||||
std::string DebuggerClient::EnableCommand(int id)
|
||||
{
|
||||
std::unique_ptr<PtJson> request = PtJson::CreateObject();
|
||||
request->Add("id", id);
|
||||
request->Add("method", "Debugger.enable");
|
||||
|
||||
std::unique_ptr<PtJson> params = PtJson::CreateObject();
|
||||
request->Add("params", params);
|
||||
return request->Stringify();
|
||||
}
|
||||
|
||||
std::string DebuggerClient::FinishCommand([[maybe_unused]] int id)
|
||||
{
|
||||
return "finish";
|
||||
}
|
||||
|
||||
std::string DebuggerClient::FrameCommand([[maybe_unused]] int id)
|
||||
{
|
||||
return "frame";
|
||||
}
|
||||
|
||||
std::string DebuggerClient::IgnoreCommand([[maybe_unused]] int id)
|
||||
{
|
||||
return "ignore";
|
||||
}
|
||||
|
||||
std::string DebuggerClient::InfobreakpointsCommand([[maybe_unused]] int id)
|
||||
{
|
||||
return "infobreakpoint";
|
||||
}
|
||||
|
||||
std::string DebuggerClient::InfosourceCommand([[maybe_unused]] int id)
|
||||
{
|
||||
return "infosource";
|
||||
}
|
||||
|
||||
std::string DebuggerClient::JumpCommand([[maybe_unused]] int id)
|
||||
{
|
||||
return "jump";
|
||||
}
|
||||
|
||||
std::string DebuggerClient::NextCommand([[maybe_unused]] int id)
|
||||
{
|
||||
return "next";
|
||||
}
|
||||
|
||||
std::string DebuggerClient::ListCommand([[maybe_unused]] int id)
|
||||
{
|
||||
return "list";
|
||||
}
|
||||
|
||||
std::string DebuggerClient::PtypeCommand([[maybe_unused]] int id)
|
||||
{
|
||||
return "ptype";
|
||||
}
|
||||
|
||||
std::string DebuggerClient::RunCommand([[maybe_unused]] int id)
|
||||
{
|
||||
return "run";
|
||||
}
|
||||
|
||||
std::string DebuggerClient::SetvarCommand([[maybe_unused]] int id)
|
||||
{
|
||||
return "Debugger.setVariableValue";
|
||||
}
|
||||
|
||||
std::string DebuggerClient::StepCommand([[maybe_unused]] int id)
|
||||
{
|
||||
return "step";
|
||||
}
|
||||
|
||||
std::string DebuggerClient::UndisplayCommand([[maybe_unused]] int id)
|
||||
{
|
||||
return "undisplay";
|
||||
}
|
||||
|
||||
std::string DebuggerClient::WatchCommand([[maybe_unused]] int id)
|
||||
{
|
||||
return "Debugger.evaluateOnCallFrame";
|
||||
}
|
||||
|
||||
std::string DebuggerClient::ResumeCommand(int id)
|
||||
{
|
||||
std::unique_ptr<PtJson> request = PtJson::CreateObject();
|
||||
request->Add("id", id);
|
||||
request->Add("method", "Debugger.resume");
|
||||
|
||||
std::unique_ptr<PtJson> params = PtJson::CreateObject();
|
||||
request->Add("params", params);
|
||||
return request->Stringify();
|
||||
}
|
||||
|
||||
std::string DebuggerClient::StepIntoCommand(int id)
|
||||
{
|
||||
std::unique_ptr<PtJson> request = PtJson::CreateObject();
|
||||
request->Add("id", id);
|
||||
request->Add("method", "Debugger.stepInto");
|
||||
|
||||
std::unique_ptr<PtJson> params = PtJson::CreateObject();
|
||||
request->Add("params", params);
|
||||
return request->Stringify();
|
||||
}
|
||||
|
||||
std::string DebuggerClient::StepOutCommand(int id)
|
||||
{
|
||||
std::unique_ptr<PtJson> request = PtJson::CreateObject();
|
||||
request->Add("id", id);
|
||||
request->Add("method", "Debugger.stepOut");
|
||||
|
||||
std::unique_ptr<PtJson> params = PtJson::CreateObject();
|
||||
request->Add("params", params);
|
||||
return request->Stringify();
|
||||
}
|
||||
|
||||
std::string DebuggerClient::StepOverCommand(int id)
|
||||
{
|
||||
std::unique_ptr<PtJson> request = PtJson::CreateObject();
|
||||
request->Add("id", id);
|
||||
request->Add("method", "Debugger.stepOver");
|
||||
|
||||
std::unique_ptr<PtJson> params = PtJson::CreateObject();
|
||||
request->Add("params", params);
|
||||
return request->Stringify();
|
||||
}
|
||||
|
||||
void DebuggerClient::AddBreakPointInfo(const std::string& url, const int& lineNumber, const int& columnNumber)
|
||||
{
|
||||
BreakPointInfo breakPointInfo;
|
||||
breakPointInfo.url = url;
|
||||
breakPointInfo.lineNumber = lineNumber;
|
||||
breakPointInfo.columnNumber = columnNumber;
|
||||
breakPointInfoList_.emplace_back(breakPointInfo);
|
||||
}
|
||||
|
||||
void DebuggerClient::RecvReply(std::unique_ptr<PtJson> json)
|
||||
{
|
||||
if (json == nullptr) {
|
||||
LOGE("arkdb: json parse error");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!json->IsObject()) {
|
||||
LOGE("arkdb: json parse format error");
|
||||
json->ReleaseRoot();
|
||||
return;
|
||||
}
|
||||
|
||||
Result ret;
|
||||
std::string wholeMethod;
|
||||
std::string method;
|
||||
ret = json->GetString("method", &wholeMethod);
|
||||
if (ret != Result::SUCCESS) {
|
||||
LOGE("arkdb: find method error");
|
||||
}
|
||||
|
||||
std::string::size_type length = wholeMethod.length();
|
||||
std::string::size_type indexPoint = 0;
|
||||
indexPoint = wholeMethod.find_first_of('.', 0);
|
||||
method = wholeMethod.substr(indexPoint + 1, length);
|
||||
if (method == "paused") {
|
||||
PausedReply(std::move(json));
|
||||
return;
|
||||
} else {
|
||||
LOGI("arkdb: Debugger reply is: %{public}s", json->Stringify().c_str());
|
||||
}
|
||||
|
||||
std::unique_ptr<PtJson> result;
|
||||
ret = json->GetObject("result", &result);
|
||||
if (ret != Result::SUCCESS) {
|
||||
LOGE("arkdb: find result error");
|
||||
return;
|
||||
}
|
||||
|
||||
std::string breakpointId;
|
||||
ret = result->GetString("breakpointId", &breakpointId);
|
||||
if (ret == Result::SUCCESS) {
|
||||
BreakPointManager &breakpoint = BreakPointManager::GetInstance();
|
||||
breakpoint.Createbreaklocation(std::move(json));
|
||||
}
|
||||
}
|
||||
|
||||
void DebuggerClient::PausedReply(const std::unique_ptr<PtJson> json)
|
||||
{
|
||||
if (json == nullptr) {
|
||||
LOGE("arkdb: json parse error");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!json->IsObject()) {
|
||||
LOGE("arkdb: json parse format error");
|
||||
json->ReleaseRoot();
|
||||
return;
|
||||
}
|
||||
|
||||
std::unique_ptr<PtJson> params;
|
||||
Result ret = json->GetObject("params", ¶ms);
|
||||
if (ret != Result::SUCCESS) {
|
||||
LOGE("arkdb: find params error");
|
||||
return;
|
||||
}
|
||||
|
||||
std::unique_ptr<PtJson> callFrames;
|
||||
ret = params->GetArray("callFrames", &callFrames);
|
||||
if (ret != Result::SUCCESS) {
|
||||
LOGE("arkdb: find callFrames error");
|
||||
return;
|
||||
}
|
||||
|
||||
std::map<int32_t, std::unique_ptr<CallFrame>> data;
|
||||
for (int32_t i = 0; i < callFrames->GetSize(); i++) {
|
||||
std::unique_ptr<CallFrame> callFrameInfo = CallFrame::Create(*(callFrames->Get(i)));
|
||||
data.emplace(i + 1, std::move(callFrameInfo));
|
||||
}
|
||||
|
||||
StackManager &stackManager = StackManager::GetInstance();
|
||||
stackManager.ClearCallFrame();
|
||||
stackManager.SetCallFrames(std::move(data));
|
||||
}
|
||||
} // OHOS::ArkCompiler::Toolchain
|
72
tooling/client/domain/debugger_client.h
Normal file
72
tooling/client/domain/debugger_client.h
Normal file
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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.
|
||||
*/
|
||||
|
||||
#ifndef ECMASCRIPT_TOOLING_CLIENT_DOMAIN_DEBUGGER_CLIENT_H
|
||||
#define ECMASCRIPT_TOOLING_CLIENT_DOMAIN_DEBUGGER_CLIENT_H
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
#include "pt_json.h"
|
||||
|
||||
using PtJson = panda::ecmascript::tooling::PtJson;
|
||||
using Result = panda::ecmascript::tooling::Result;
|
||||
namespace OHOS::ArkCompiler::Toolchain {
|
||||
struct BreakPointInfo {
|
||||
int lineNumber;
|
||||
int columnNumber;
|
||||
std::string url;
|
||||
};
|
||||
class DebuggerClient final {
|
||||
public:
|
||||
DebuggerClient() = default;
|
||||
~DebuggerClient() = default;
|
||||
|
||||
bool DispatcherCmd(int id, const std::string &cmd, std::string* reqStr);
|
||||
std::string BreakCommand(int id);
|
||||
std::string BacktrackCommand(int id);
|
||||
std::string ContinueCommand(int id);
|
||||
std::string DeleteCommand(int id);
|
||||
std::string DisableCommand(int id);
|
||||
std::string DisplayCommand(int id);
|
||||
std::string EnableCommand(int id);
|
||||
std::string FinishCommand(int id);
|
||||
std::string FrameCommand(int id);
|
||||
std::string IgnoreCommand(int id);
|
||||
std::string InfobreakpointsCommand(int id);
|
||||
std::string InfosourceCommand(int id);
|
||||
std::string JumpCommand(int id);
|
||||
std::string NextCommand(int id);
|
||||
std::string ListCommand(int id);
|
||||
std::string PtypeCommand(int id);
|
||||
std::string RunCommand(int id);
|
||||
std::string SetvarCommand(int id);
|
||||
std::string StepCommand(int id);
|
||||
std::string UndisplayCommand(int id);
|
||||
std::string WatchCommand(int id);
|
||||
std::string ResumeCommand(int id);
|
||||
std::string StepIntoCommand(int id);
|
||||
std::string StepOutCommand(int id);
|
||||
std::string StepOverCommand(int id);
|
||||
|
||||
void AddBreakPointInfo(const std::string& url, const int& lineNumber, const int& columnNumber = 0);
|
||||
void RecvReply(std::unique_ptr<PtJson> json);
|
||||
void PausedReply(const std::unique_ptr<PtJson> json);
|
||||
|
||||
private:
|
||||
std::vector<BreakPointInfo> breakPointInfoList_ {};
|
||||
};
|
||||
} // OHOS::ArkCompiler::Toolchain
|
||||
#endif
|
249
tooling/client/domain/heapprofiler_client.cpp
Normal file
249
tooling/client/domain/heapprofiler_client.cpp
Normal file
@ -0,0 +1,249 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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 "domain/heapprofiler_client.h"
|
||||
#include "log_wrapper.h"
|
||||
#include "utils/utils.h"
|
||||
|
||||
#include <map>
|
||||
#include <functional>
|
||||
#include <cstring>
|
||||
|
||||
using Result = panda::ecmascript::tooling::Result;
|
||||
namespace OHOS::ArkCompiler::Toolchain {
|
||||
static constexpr int32_t SAMPLING_INTERVAL = 16384;
|
||||
bool HeapProfilerClient::DispatcherCmd(int id, const std::string &cmd, const std::string &arg, std::string* reqStr)
|
||||
{
|
||||
if (reqStr == nullptr) {
|
||||
return false;
|
||||
}
|
||||
path_ = arg;
|
||||
|
||||
std::map<std::string, std::function<std::string()>> dispatcherTable {
|
||||
{ "allocationtrack", std::bind(&HeapProfilerClient::AllocationTrackCommand, this, id)},
|
||||
{ "allocationtrack-stop", std::bind(&HeapProfilerClient::AllocationTrackStopCommand, this, id)},
|
||||
{ "heapdump", std::bind(&HeapProfilerClient::HeapDumpCommand, this, id)},
|
||||
{ "heapprofiler-enable", std::bind(&HeapProfilerClient::Enable, this, id)},
|
||||
{ "heapprofiler-disable", std::bind(&HeapProfilerClient::Disable, this, id)},
|
||||
{ "sampling", std::bind(&HeapProfilerClient::Samping, this, id)},
|
||||
{ "sampling-stop", std::bind(&HeapProfilerClient::SampingStop, this, id)},
|
||||
{ "collectgarbage", std::bind(&HeapProfilerClient::CollectGarbage, this, id)}
|
||||
};
|
||||
|
||||
auto entry = dispatcherTable.find(cmd);
|
||||
if (entry != dispatcherTable.end() && entry->second != nullptr) {
|
||||
*reqStr = entry->second();
|
||||
LOGE("DispatcherCmd reqStr1: %{public}s", reqStr->c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
*reqStr = "Unknown commond: " + cmd;
|
||||
LOGE("DispatcherCmd reqStr2: %{public}s", reqStr->c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string HeapProfilerClient::HeapDumpCommand(int id)
|
||||
{
|
||||
idEventMap_.emplace(id, HEAPDUMP);
|
||||
std::unique_ptr<PtJson> request = PtJson::CreateObject();
|
||||
request->Add("id", id);
|
||||
request->Add("method", "HeapProfiler.takeHeapSnapshot");
|
||||
|
||||
std::unique_ptr<PtJson> params = PtJson::CreateObject();
|
||||
params->Add("reportProgress", true);
|
||||
params->Add("captureNumericValue", true);
|
||||
params->Add("exposeInternals", false);
|
||||
request->Add("params", params);
|
||||
return request->Stringify();
|
||||
}
|
||||
|
||||
std::string HeapProfilerClient::AllocationTrackCommand(int id)
|
||||
{
|
||||
idEventMap_.emplace(id, ALLOCATION);
|
||||
std::unique_ptr<PtJson> request = PtJson::CreateObject();
|
||||
request->Add("id", id);
|
||||
request->Add("method", "HeapProfiler.startTrackingHeapObjects");
|
||||
|
||||
std::unique_ptr<PtJson> params = PtJson::CreateObject();
|
||||
params->Add("trackAllocations", true);
|
||||
request->Add("params", params);
|
||||
return request->Stringify();
|
||||
}
|
||||
|
||||
std::string HeapProfilerClient::AllocationTrackStopCommand(int id)
|
||||
{
|
||||
idEventMap_.emplace(id, ALLOCATION_STOP);
|
||||
std::unique_ptr<PtJson> request = PtJson::CreateObject();
|
||||
request->Add("id", id);
|
||||
request->Add("method", "HeapProfiler.stopTrackingHeapObjects");
|
||||
|
||||
std::unique_ptr<PtJson> params = PtJson::CreateObject();
|
||||
params->Add("reportProgress", true);
|
||||
request->Add("params", params);
|
||||
return request->Stringify();
|
||||
}
|
||||
|
||||
std::string HeapProfilerClient::Enable(int id)
|
||||
{
|
||||
idEventMap_.emplace(id, ENABLE);
|
||||
std::unique_ptr<PtJson> request = PtJson::CreateObject();
|
||||
request->Add("id", id);
|
||||
request->Add("method", "HeapProfiler.enable");
|
||||
|
||||
std::unique_ptr<PtJson> params = PtJson::CreateObject();
|
||||
request->Add("params", params);
|
||||
return request->Stringify();
|
||||
}
|
||||
|
||||
std::string HeapProfilerClient::Disable(int id)
|
||||
{
|
||||
idEventMap_.emplace(id, DISABLE);
|
||||
std::unique_ptr<PtJson> request = PtJson::CreateObject();
|
||||
request->Add("id", id);
|
||||
request->Add("method", "HeapProfiler.disable");
|
||||
|
||||
std::unique_ptr<PtJson> params = PtJson::CreateObject();
|
||||
request->Add("params", params);
|
||||
return request->Stringify();
|
||||
}
|
||||
|
||||
std::string HeapProfilerClient::Samping(int id)
|
||||
{
|
||||
idEventMap_.emplace(id, SAMPLING);
|
||||
std::unique_ptr<PtJson> request = PtJson::CreateObject();
|
||||
request->Add("id", id);
|
||||
request->Add("method", "HeapProfiler.startSampling");
|
||||
|
||||
std::unique_ptr<PtJson> params = PtJson::CreateObject();
|
||||
params->Add("samplingInterval", SAMPLING_INTERVAL);
|
||||
request->Add("params", params);
|
||||
return request->Stringify();
|
||||
}
|
||||
|
||||
std::string HeapProfilerClient::SampingStop(int id)
|
||||
{
|
||||
idEventMap_.emplace(id, SAMPLING_STOP);
|
||||
std::unique_ptr<PtJson> request = PtJson::CreateObject();
|
||||
request->Add("id", id);
|
||||
request->Add("method", "HeapProfiler.stopSampling");
|
||||
|
||||
std::unique_ptr<PtJson> params = PtJson::CreateObject();
|
||||
request->Add("params", params);
|
||||
return request->Stringify();
|
||||
}
|
||||
|
||||
std::string HeapProfilerClient::CollectGarbage(int id)
|
||||
{
|
||||
idEventMap_.emplace(id, COLLECT_GARBAGE);
|
||||
std::unique_ptr<PtJson> request = PtJson::CreateObject();
|
||||
request->Add("id", id);
|
||||
request->Add("method", "HeapProfiler.collectGarbage");
|
||||
|
||||
std::unique_ptr<PtJson> params = PtJson::CreateObject();
|
||||
request->Add("params", params);
|
||||
return request->Stringify();
|
||||
}
|
||||
|
||||
void HeapProfilerClient::RecvReply(std::unique_ptr<PtJson> json)
|
||||
{
|
||||
if (json == nullptr) {
|
||||
LOGE("json parse error");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!json->IsObject()) {
|
||||
LOGE("json parse format error");
|
||||
json->ReleaseRoot();
|
||||
return;
|
||||
}
|
||||
|
||||
Result ret;
|
||||
std::string wholeMethod;
|
||||
std::string method;
|
||||
ret = json->GetString("method", &wholeMethod);
|
||||
if (ret != Result::SUCCESS) {
|
||||
LOGE("find method error");
|
||||
return;
|
||||
}
|
||||
|
||||
std::string::size_type length = wholeMethod.length();
|
||||
std::string::size_type indexPoint = 0;
|
||||
indexPoint = wholeMethod.find_first_of('.', 0);
|
||||
if (indexPoint == std::string::npos || indexPoint == 0 || indexPoint == length - 1) {
|
||||
return;
|
||||
}
|
||||
method = wholeMethod.substr(indexPoint + 1, length);
|
||||
if (method == "lastSeenObjectId") {
|
||||
isAllocationMsg_ = true;
|
||||
}
|
||||
|
||||
std::unique_ptr<PtJson> params;
|
||||
ret = json->GetObject("params", ¶ms);
|
||||
if (ret != Result::SUCCESS) {
|
||||
LOGE("find params error");
|
||||
return;
|
||||
}
|
||||
|
||||
std::string chunk;
|
||||
ret = params->GetString("chunk", &chunk);
|
||||
if (ret != Result::SUCCESS) {
|
||||
LOGE("find chunk error");
|
||||
return;
|
||||
}
|
||||
|
||||
std::string head = "{\"snapshot\":\n";
|
||||
if (!strncmp(chunk.c_str(), head.c_str(), head.length())) {
|
||||
char date[16];
|
||||
char time[16];
|
||||
bool res = Utils::GetCurrentTime(date, time, sizeof(date));
|
||||
if (!res) {
|
||||
LOGE("arkdb: get time failed");
|
||||
return;
|
||||
}
|
||||
if (isAllocationMsg_) {
|
||||
fileName_ = "Heap-" + std::string(date) + "T" + std::string(time) + ".heaptimeline";
|
||||
std::cout << "heaptimeline file name is " << fileName_ << std::endl;
|
||||
} else {
|
||||
fileName_ = "Heap-" + std::string(date) + "T" + std::string(time) + ".heapsnapshot";
|
||||
std::cout << "heapsnapshot file name is " << fileName_ << std::endl;
|
||||
}
|
||||
std::cout << ">>> ";
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
std::string tail = "]\n}\n";
|
||||
std::string subStr = chunk.substr(chunk.length() - tail.length(), chunk.length());
|
||||
if (!strncmp(subStr.c_str(), tail.c_str(), tail.length())) {
|
||||
isAllocationMsg_ = false;
|
||||
}
|
||||
WriteHeapProfilerForFile(fileName_, chunk);
|
||||
}
|
||||
|
||||
bool HeapProfilerClient::WriteHeapProfilerForFile(const std::string &fileName, const std::string &data)
|
||||
{
|
||||
std::ofstream ofs;
|
||||
std::string pathname = path_ + fileName;
|
||||
ofs.open(pathname.c_str(), std::ios::app);
|
||||
if (!ofs.is_open()) {
|
||||
LOGE("arkdb: file open error!");
|
||||
return false;
|
||||
}
|
||||
int strSize = data.size();
|
||||
ofs.write(data.c_str(), strSize);
|
||||
ofs.close();
|
||||
ofs.clear();
|
||||
return true;
|
||||
}
|
||||
} // OHOS::ArkCompiler::Toolchain
|
63
tooling/client/domain/heapprofiler_client.h
Normal file
63
tooling/client/domain/heapprofiler_client.h
Normal file
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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.
|
||||
*/
|
||||
|
||||
#ifndef ECMASCRIPT_TOOLING_CLIENT_DOMAIN_HEAPPROFILER_CLIENT_H
|
||||
#define ECMASCRIPT_TOOLING_CLIENT_DOMAIN_HEAPPROFILER_CLIENT_H
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <map>
|
||||
|
||||
#include "pt_json.h"
|
||||
|
||||
using PtJson = panda::ecmascript::tooling::PtJson;
|
||||
|
||||
namespace OHOS::ArkCompiler::Toolchain {
|
||||
enum HeapProfilerEvent {
|
||||
DAFAULT_VALUE = 0,
|
||||
ALLOCATION = 1,
|
||||
ALLOCATION_STOP,
|
||||
HEAPDUMP,
|
||||
ENABLE,
|
||||
DISABLE,
|
||||
SAMPLING,
|
||||
SAMPLING_STOP,
|
||||
COLLECT_GARBAGE
|
||||
};
|
||||
class HeapProfilerClient final {
|
||||
public:
|
||||
HeapProfilerClient() = default;
|
||||
~HeapProfilerClient() = default;
|
||||
|
||||
bool DispatcherCmd(int id, const std::string &cmd, const std::string &arg, std::string* reqStr);
|
||||
std::string HeapDumpCommand(int id);
|
||||
std::string AllocationTrackCommand(int id);
|
||||
std::string AllocationTrackStopCommand(int id);
|
||||
std::string Enable(int id);
|
||||
std::string Disable(int id);
|
||||
std::string Samping(int id);
|
||||
std::string SampingStop(int id);
|
||||
std::string CollectGarbage(int id);
|
||||
void RecvReply(std::unique_ptr<PtJson> json);
|
||||
bool WriteHeapProfilerForFile(const std::string &fileName, const std::string &data);
|
||||
|
||||
private:
|
||||
std::string fileName_;
|
||||
std::map<uint32_t, HeapProfilerEvent> idEventMap_;
|
||||
std::string path_;
|
||||
bool isAllocationMsg_ {false};
|
||||
};
|
||||
} // OHOS::ArkCompiler::Toolchain
|
||||
#endif
|
183
tooling/client/domain/profiler_client.cpp
Normal file
183
tooling/client/domain/profiler_client.cpp
Normal file
@ -0,0 +1,183 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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 "domain/profiler_client.h"
|
||||
#include "pt_types.h"
|
||||
#include "log_wrapper.h"
|
||||
#include "utils/utils.h"
|
||||
|
||||
#include <map>
|
||||
#include <functional>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
|
||||
using Result = panda::ecmascript::tooling::Result;
|
||||
using Profile = panda::ecmascript::tooling::Profile;
|
||||
namespace OHOS::ArkCompiler::Toolchain {
|
||||
ProfilerSingleton ProfilerSingleton::instance_;
|
||||
bool ProfilerClient::DispatcherCmd(int id, const std::string &cmd, std::string* reqStr)
|
||||
{
|
||||
std::map<std::string, std::function<std::string()>> dispatcherTable {
|
||||
{ "cpuprofile", std::bind(&ProfilerClient::CpuprofileCommand, this, id)},
|
||||
{ "cpuprofile-stop", std::bind(&ProfilerClient::CpuprofileStopCommand, this, id)},
|
||||
{ "cpuprofile-setSamplingInterval", std::bind(&ProfilerClient::SetSamplingIntervalCommand, this, id)},
|
||||
{ "cpuprofile-enable", std::bind(&ProfilerClient::CpuprofileEnableCommand, this, id)},
|
||||
{ "cpuprofile-disable", std::bind(&ProfilerClient::CpuprofileDisableCommand, this, id)},
|
||||
};
|
||||
|
||||
auto entry = dispatcherTable.find(cmd);
|
||||
if (entry == dispatcherTable.end()) {
|
||||
*reqStr = "Unknown commond: " + cmd;
|
||||
LOGE("DispatcherCmd reqStr2: %{public}s", reqStr->c_str());
|
||||
return false;
|
||||
}
|
||||
*reqStr = entry->second();
|
||||
LOGE("DispatcherCmd reqStr1: %{public}s", reqStr->c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string ProfilerClient::CpuprofileEnableCommand(int id)
|
||||
{
|
||||
idEventMap_.emplace(id, "cpuprofileenable");
|
||||
std::unique_ptr<PtJson> request = PtJson::CreateObject();
|
||||
request->Add("id", id);
|
||||
request->Add("method", "Profiler.enable");
|
||||
|
||||
std::unique_ptr<PtJson> params = PtJson::CreateObject();
|
||||
request->Add("params", params);
|
||||
return request->Stringify();
|
||||
}
|
||||
|
||||
std::string ProfilerClient::CpuprofileDisableCommand(int id)
|
||||
{
|
||||
idEventMap_.emplace(id, "cpuprofiledisable");
|
||||
std::unique_ptr<PtJson> request = PtJson::CreateObject();
|
||||
request->Add("id", id);
|
||||
request->Add("method", "Profiler.disable");
|
||||
|
||||
std::unique_ptr<PtJson> params = PtJson::CreateObject();
|
||||
request->Add("params", params);
|
||||
return request->Stringify();
|
||||
}
|
||||
|
||||
std::string ProfilerClient::CpuprofileCommand(int id)
|
||||
{
|
||||
idEventMap_.emplace(id, "cpuprofile");
|
||||
std::unique_ptr<PtJson> request = PtJson::CreateObject();
|
||||
request->Add("id", id);
|
||||
request->Add("method", "Profiler.start");
|
||||
|
||||
std::unique_ptr<PtJson> params = PtJson::CreateObject();
|
||||
request->Add("params", params);
|
||||
return request->Stringify();
|
||||
}
|
||||
|
||||
std::string ProfilerClient::CpuprofileStopCommand(int id)
|
||||
{
|
||||
idEventMap_.emplace(id, "cpuprofilestop");
|
||||
std::unique_ptr<PtJson> request = PtJson::CreateObject();
|
||||
request->Add("id", id);
|
||||
request->Add("method", "Profiler.stop");
|
||||
|
||||
std::unique_ptr<PtJson> params = PtJson::CreateObject();
|
||||
request->Add("params", params);
|
||||
return request->Stringify();
|
||||
}
|
||||
|
||||
std::string ProfilerClient::SetSamplingIntervalCommand(int id)
|
||||
{
|
||||
idEventMap_.emplace(id, "setsamplinginterval");
|
||||
std::unique_ptr<PtJson> request = PtJson::CreateObject();
|
||||
request->Add("id", id);
|
||||
request->Add("method", "Profiler.setSamplingInterval");
|
||||
|
||||
std::unique_ptr<PtJson> params = PtJson::CreateObject();
|
||||
params->Add("interval", interval_);
|
||||
request->Add("params", params);
|
||||
return request->Stringify();
|
||||
}
|
||||
|
||||
ProfilerSingleton& ProfilerSingleton::GetInstance()
|
||||
{
|
||||
return instance_;
|
||||
}
|
||||
|
||||
void ProfilerClient::RecvProfilerResult(std::unique_ptr<PtJson> json)
|
||||
{
|
||||
if (json == nullptr) {
|
||||
LOGE("arkdb: json parse error");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!json->IsObject()) {
|
||||
LOGE("arkdb: json parse format error");
|
||||
json->ReleaseRoot();
|
||||
return;
|
||||
}
|
||||
|
||||
std::unique_ptr<PtJson> result;
|
||||
Result ret = json->GetObject("result", &result);
|
||||
if (ret != Result::SUCCESS) {
|
||||
LOGE("arkdb: find result error");
|
||||
return;
|
||||
}
|
||||
|
||||
std::unique_ptr<PtJson> profile;
|
||||
ret = result->GetObject("profile", &profile);
|
||||
if (ret != Result::SUCCESS) {
|
||||
LOGE("arkdb: the cmd is not cp-stop!");
|
||||
return;
|
||||
}
|
||||
|
||||
char date[16];
|
||||
char time[16];
|
||||
bool res = Utils::GetCurrentTime(date, time, sizeof(date));
|
||||
if (!res) {
|
||||
LOGE("arkdb: get time failed");
|
||||
return;
|
||||
}
|
||||
|
||||
ProfilerSingleton& pro = ProfilerSingleton::GetInstance();
|
||||
std::string fileName = "CPU-" + std::string(date) + "T" + std::string(time) + ".cpuprofile";
|
||||
std::string cpufile = pro.GetAddress() + fileName;
|
||||
std::cout << "cpuprofile file name is " << cpufile << std::endl;
|
||||
std::cout << ">>> ";
|
||||
fflush(stdout);
|
||||
WriteCpuProfileForFile(cpufile, profile->Stringify());
|
||||
pro.AddCpuName(fileName);
|
||||
}
|
||||
|
||||
bool ProfilerClient::WriteCpuProfileForFile(const std::string &fileName, const std::string &data)
|
||||
{
|
||||
std::ofstream ofs;
|
||||
ofs.open(fileName.c_str(), std::ios::out);
|
||||
if (!ofs.is_open()) {
|
||||
LOGE("arkdb: file open error!");
|
||||
return false;
|
||||
}
|
||||
int strSize = data.size();
|
||||
ofs.write(data.c_str(), strSize);
|
||||
ofs.close();
|
||||
ofs.clear();
|
||||
ProfilerSingleton& pro = ProfilerSingleton::GetInstance();
|
||||
pro.SetAddress("");
|
||||
return true;
|
||||
}
|
||||
|
||||
void ProfilerClient::SetSamplingInterval(int interval)
|
||||
{
|
||||
this->interval_ = interval;
|
||||
}
|
||||
} // OHOS::ArkCompiler::Toolchain
|
84
tooling/client/domain/profiler_client.h
Normal file
84
tooling/client/domain/profiler_client.h
Normal file
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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.
|
||||
*/
|
||||
|
||||
#ifndef ECMASCRIPT_TOOLING_CLIENT_DOMAIN_PROFILER_CLIENT_H
|
||||
#define ECMASCRIPT_TOOLING_CLIENT_DOMAIN_PROFILER_CLIENT_H
|
||||
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "pt_json.h"
|
||||
|
||||
namespace OHOS::ArkCompiler::Toolchain {
|
||||
using PtJson = panda::ecmascript::tooling::PtJson;
|
||||
class ProfilerSingleton {
|
||||
public:
|
||||
static ProfilerSingleton& GetInstance();
|
||||
|
||||
void AddCpuName(const std::string &data)
|
||||
{
|
||||
cpulist_.emplace_back(data);
|
||||
}
|
||||
|
||||
void ShowCpuFile()
|
||||
{
|
||||
size_t size = cpulist_.size();
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
std::cout << cpulist_[i] << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void SetAddress(std::string address)
|
||||
{
|
||||
address_ = address;
|
||||
}
|
||||
|
||||
const std::string& GetAddress() const
|
||||
{
|
||||
return address_;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<std::string> cpulist_;
|
||||
std::string address_ = "";
|
||||
static ProfilerSingleton instance_;
|
||||
ProfilerSingleton() = default;
|
||||
ProfilerSingleton(const ProfilerSingleton&) = delete;
|
||||
ProfilerSingleton& operator=(const ProfilerSingleton&) = delete;
|
||||
};
|
||||
|
||||
class ProfilerClient final {
|
||||
public:
|
||||
ProfilerClient() = default;
|
||||
~ProfilerClient() = default;
|
||||
|
||||
bool DispatcherCmd(int id, const std::string &cmd, std::string* reqStr);
|
||||
std::string CpuprofileCommand(int id);
|
||||
std::string CpuprofileStopCommand(int id);
|
||||
std::string SetSamplingIntervalCommand(int id);
|
||||
std::string CpuprofileEnableCommand(int id);
|
||||
std::string CpuprofileDisableCommand(int id);
|
||||
bool WriteCpuProfileForFile(const std::string &fileName, const std::string &data);
|
||||
void RecvProfilerResult(std::unique_ptr<PtJson> json);
|
||||
void SetSamplingInterval(int interval);
|
||||
|
||||
private:
|
||||
int32_t interval_ = 0;
|
||||
std::map<uint32_t, std::string> idEventMap_ {};
|
||||
};
|
||||
} // OHOS::ArkCompiler::Toolchain
|
||||
#endif
|
255
tooling/client/domain/runtime_client.cpp
Normal file
255
tooling/client/domain/runtime_client.cpp
Normal file
@ -0,0 +1,255 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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 "domain/runtime_client.h"
|
||||
|
||||
#include "log_wrapper.h"
|
||||
#include "manager/variable_manager.h"
|
||||
#include "pt_json.h"
|
||||
|
||||
using PtJson = panda::ecmascript::tooling::PtJson;
|
||||
namespace OHOS::ArkCompiler::Toolchain {
|
||||
RuntimeClient RuntimeClient::instance_;
|
||||
RuntimeClient& RuntimeClient::GetInstance()
|
||||
{
|
||||
return instance_;
|
||||
}
|
||||
bool RuntimeClient::DispatcherCmd(int id, const std::string &cmd, std::string* reqStr)
|
||||
{
|
||||
std::map<std::string, std::function<std::string()>> dispatcherTable {
|
||||
{ "heapusage", std::bind(&RuntimeClient::HeapusageCommand, this, id)},
|
||||
{ "runtime-enable", std::bind(&RuntimeClient::RuntimeEnableCommand, this, id)},
|
||||
{ "runtime-disable", std::bind(&RuntimeClient::RuntimeDisableCommand, this, id)},
|
||||
{ "print", std::bind(&RuntimeClient::GetPropertiesCommand, this, id)},
|
||||
{ "print2", std::bind(&RuntimeClient::GetPropertiesCommand2, this, id)},
|
||||
{ "run", std::bind(&RuntimeClient::RunIfWaitingForDebuggerCommand, this, id)},
|
||||
};
|
||||
|
||||
auto entry = dispatcherTable.find(cmd);
|
||||
if (entry != dispatcherTable.end()) {
|
||||
*reqStr = entry->second();
|
||||
LOGE("RuntimeClient DispatcherCmd reqStr1: %{public}s", reqStr->c_str());
|
||||
return true;
|
||||
} else {
|
||||
*reqStr = "Unknown commond: " + cmd;
|
||||
LOGE("RuntimeClient DispatcherCmd reqStr2: %{public}s", reqStr->c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
std::string RuntimeClient::HeapusageCommand(int id)
|
||||
{
|
||||
idMethodMap_[id] = std::make_tuple("getHeapUsage", "");
|
||||
std::unique_ptr<PtJson> request = PtJson::CreateObject();
|
||||
request->Add("id", id);
|
||||
request->Add("method", "Runtime.getHeapUsage");
|
||||
|
||||
std::unique_ptr<PtJson> params = PtJson::CreateObject();
|
||||
request->Add("params", params);
|
||||
return request->Stringify();
|
||||
}
|
||||
|
||||
std::string RuntimeClient::RuntimeEnableCommand(int id)
|
||||
{
|
||||
idMethodMap_[id] = std::make_tuple("enable", "");
|
||||
std::unique_ptr<PtJson> request = PtJson::CreateObject();
|
||||
request->Add("id", id);
|
||||
request->Add("method", "Runtime.enable");
|
||||
|
||||
std::unique_ptr<PtJson> params = PtJson::CreateObject();
|
||||
request->Add("params", params);
|
||||
return request->Stringify();
|
||||
}
|
||||
|
||||
std::string RuntimeClient::RuntimeDisableCommand(int id)
|
||||
{
|
||||
idMethodMap_[id] = std::make_tuple("disable", "");
|
||||
std::unique_ptr<PtJson> request = PtJson::CreateObject();
|
||||
request->Add("id", id);
|
||||
request->Add("method", "Runtime.disable");
|
||||
|
||||
std::unique_ptr<PtJson> params = PtJson::CreateObject();
|
||||
request->Add("params", params);
|
||||
return request->Stringify();
|
||||
}
|
||||
|
||||
std::string RuntimeClient::RunIfWaitingForDebuggerCommand(int id)
|
||||
{
|
||||
idMethodMap_[id] = std::make_tuple("runIfWaitingForDebugger", "");
|
||||
std::unique_ptr<PtJson> request = PtJson::CreateObject();
|
||||
request->Add("id", id);
|
||||
request->Add("method", "Runtime.runIfWaitingForDebugger");
|
||||
|
||||
std::unique_ptr<PtJson> params = PtJson::CreateObject();
|
||||
request->Add("params", params);
|
||||
return request->Stringify();
|
||||
}
|
||||
|
||||
std::string RuntimeClient::GetPropertiesCommand(int id)
|
||||
{
|
||||
idMethodMap_[id] = std::make_tuple("getProperties", objectId_);
|
||||
std::unique_ptr<PtJson> request = PtJson::CreateObject();
|
||||
request->Add("id", id);
|
||||
request->Add("method", "Runtime.getProperties");
|
||||
|
||||
std::unique_ptr<PtJson> params = PtJson::CreateObject();
|
||||
params->Add("accessorPropertiesOnly", false);
|
||||
params->Add("generatePreview", true);
|
||||
params->Add("objectId", objectId_.c_str());
|
||||
params->Add("ownProperties", true);
|
||||
request->Add("params", params);
|
||||
return request->Stringify();
|
||||
}
|
||||
|
||||
std::string RuntimeClient::GetPropertiesCommand2(int id)
|
||||
{
|
||||
idMethodMap_[id] = std::make_tuple("getProperties", objectId_);
|
||||
std::unique_ptr<PtJson> request = PtJson::CreateObject();
|
||||
request->Add("id", id);
|
||||
request->Add("method", "Runtime.getProperties");
|
||||
|
||||
std::unique_ptr<PtJson> params = PtJson::CreateObject();
|
||||
params->Add("accessorPropertiesOnly", true);
|
||||
params->Add("generatePreview", true);
|
||||
params->Add("objectId", "0");
|
||||
params->Add("ownProperties", false);
|
||||
request->Add("params", params);
|
||||
return request->Stringify();
|
||||
}
|
||||
|
||||
void RuntimeClient::RecvReply(std::unique_ptr<PtJson> json)
|
||||
{
|
||||
if (json == nullptr) {
|
||||
LOGE("arkdb: json parse error");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!json->IsObject()) {
|
||||
LOGE("arkdb: json parse format error");
|
||||
json->ReleaseRoot();
|
||||
return;
|
||||
}
|
||||
|
||||
int replyId;
|
||||
Result ret = json->GetInt("id", &replyId);
|
||||
if (ret != Result::SUCCESS) {
|
||||
LOGE("arkdb: find id error");
|
||||
return;
|
||||
}
|
||||
|
||||
if (GetMethodById(replyId) == "getHeapUsage") {
|
||||
HandleHeapUsage(std::move(json));
|
||||
} else if (GetMethodById(replyId) == "getProperties") {
|
||||
HandleGetProperties(std::move(json), replyId);
|
||||
} else {
|
||||
LOGI("arkdb: Runtime replay message is %{public}s", json->Stringify().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
std::string RuntimeClient::GetMethodById(const int &id)
|
||||
{
|
||||
auto it = idMethodMap_.find(id);
|
||||
if (it != idMethodMap_.end()) {
|
||||
return std::get<0>(it->second);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string RuntimeClient::GetRequestObjectIdById(const int &id)
|
||||
{
|
||||
auto it = idMethodMap_.find(id);
|
||||
if (it != idMethodMap_.end()) {
|
||||
return std::get<1>(it->second);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
void RuntimeClient::HandleGetProperties(std::unique_ptr<PtJson> json, const int &id)
|
||||
{
|
||||
if (json == nullptr) {
|
||||
LOGE("arkdb: json parse error");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!json->IsObject()) {
|
||||
LOGE("arkdb: json parse format error");
|
||||
json->ReleaseRoot();
|
||||
return;
|
||||
}
|
||||
|
||||
std::unique_ptr<PtJson> result;
|
||||
Result ret = json->GetObject("result", &result);
|
||||
if (ret != Result::SUCCESS) {
|
||||
LOGE("arkdb: find result error");
|
||||
return;
|
||||
}
|
||||
|
||||
std::unique_ptr<PtJson> innerResult;
|
||||
ret = result->GetArray("result", &innerResult);
|
||||
if (ret != Result::SUCCESS) {
|
||||
LOGE("arkdb: find innerResult error");
|
||||
return;
|
||||
}
|
||||
|
||||
StackManager &stackManager = StackManager::GetInstance();
|
||||
VariableManager &variableManager = VariableManager::GetInstance();
|
||||
std::map<int32_t, std::map<int32_t, std::string>> treeInfo = stackManager.GetScopeChainInfo();
|
||||
if (isInitializeTree_) {
|
||||
variableManager.ClearVariableInfo();
|
||||
variableManager.InitializeTree(treeInfo);
|
||||
}
|
||||
std::string requestObjectId = GetRequestObjectIdById(id);
|
||||
TreeNode *node = nullptr;
|
||||
if (!isInitializeTree_) {
|
||||
node = variableManager.FindNodeWithObjectId(std::stoi(requestObjectId));
|
||||
} else {
|
||||
node = variableManager.FindNodeObjectZero();
|
||||
}
|
||||
|
||||
for (int32_t i = 0; i < innerResult->GetSize(); i++) {
|
||||
std::unique_ptr<PropertyDescriptor> variableInfo = PropertyDescriptor::Create(*(innerResult->Get(i)));
|
||||
variableManager.AddVariableInfo(node, std::move(variableInfo));
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
variableManager.PrintVariableInfo();
|
||||
}
|
||||
|
||||
void RuntimeClient::HandleHeapUsage(std::unique_ptr<PtJson> json)
|
||||
{
|
||||
if (json == nullptr) {
|
||||
LOGE("arkdb: json parse error");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!json->IsObject()) {
|
||||
LOGE("arkdb: json parse format error");
|
||||
json->ReleaseRoot();
|
||||
return;
|
||||
}
|
||||
|
||||
std::unique_ptr<PtJson> result;
|
||||
Result ret = json->GetObject("result", &result);
|
||||
if (ret != Result::SUCCESS) {
|
||||
LOGE("arkdb: find result error");
|
||||
return;
|
||||
}
|
||||
|
||||
VariableManager &variableManager = VariableManager::GetInstance();
|
||||
std::unique_ptr<GetHeapUsageReturns> heapUsageReturns = GetHeapUsageReturns::Create(*result);
|
||||
variableManager.SetHeapUsageInfo(std::move(heapUsageReturns));
|
||||
variableManager.ShowHeapUsageInfo();
|
||||
}
|
||||
} // OHOS::ArkCompiler::Toolchain
|
69
tooling/client/domain/runtime_client.h
Normal file
69
tooling/client/domain/runtime_client.h
Normal file
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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.
|
||||
*/
|
||||
|
||||
#ifndef ECMASCRIPT_TOOLING_CLIENT_DOMAIN_RUNTIME_CLIENT_H
|
||||
#define ECMASCRIPT_TOOLING_CLIENT_DOMAIN_RUNTIME_CLIENT_H
|
||||
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
|
||||
#include "pt_types.h"
|
||||
|
||||
using PtJson = panda::ecmascript::tooling::PtJson;
|
||||
using Result = panda::ecmascript::tooling::Result;
|
||||
namespace OHOS::ArkCompiler::Toolchain {
|
||||
class RuntimeClient final {
|
||||
public:
|
||||
static RuntimeClient& GetInstance();
|
||||
|
||||
bool DispatcherCmd(int id, const std::string &cmd, std::string *reqStr);
|
||||
std::string HeapusageCommand(int id);
|
||||
std::string RuntimeEnableCommand(int id);
|
||||
std::string RuntimeDisableCommand(int id);
|
||||
std::string RunIfWaitingForDebuggerCommand(int id);
|
||||
std::string GetPropertiesCommand(int id);
|
||||
std::string GetPropertiesCommand2(int id);
|
||||
std::string GetMethodById(const int &id);
|
||||
std::string GetRequestObjectIdById(const int &id);
|
||||
void RecvReply(std::unique_ptr<PtJson> json);
|
||||
void HandleHeapUsage(std::unique_ptr<PtJson> json);
|
||||
void HandleGetProperties(std::unique_ptr<PtJson> json, const int &id);
|
||||
|
||||
void SetObjectId(const std::string &objectId)
|
||||
{
|
||||
objectId_ = objectId;
|
||||
}
|
||||
|
||||
void SetIsInitializeTree(const bool &isInitializeTree)
|
||||
{
|
||||
isInitializeTree_ = isInitializeTree;
|
||||
}
|
||||
|
||||
bool GetIsInitializeTree() const
|
||||
{
|
||||
return isInitializeTree_;
|
||||
}
|
||||
|
||||
private:
|
||||
RuntimeClient() = default;
|
||||
static RuntimeClient instance_;
|
||||
std::map<int, std::tuple<std::string, std::string>> idMethodMap_ {};
|
||||
std::string objectId_ {"0"};
|
||||
bool isInitializeTree_ {true};
|
||||
RuntimeClient(const RuntimeClient&) = delete;
|
||||
RuntimeClient& operator=(const RuntimeClient&) = delete;
|
||||
};
|
||||
} // OHOS::ArkCompiler::Toolchain
|
||||
#endif
|
102
tooling/client/manager/breakpoint_manager.cpp
Normal file
102
tooling/client/manager/breakpoint_manager.cpp
Normal file
@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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 "manager/breakpoint_manager.h"
|
||||
#include "ark_cli/cli_command.h"
|
||||
#include "log_wrapper.h"
|
||||
|
||||
using PtJson = panda::ecmascript::tooling::PtJson;
|
||||
using Result = panda::ecmascript::tooling::Result;
|
||||
namespace OHOS::ArkCompiler::Toolchain {
|
||||
BreakPointManager BreakPointManager::instance_;
|
||||
BreakPointManager& BreakPointManager::GetInstance()
|
||||
{
|
||||
return instance_;
|
||||
}
|
||||
|
||||
void BreakPointManager::Createbreaklocation(const std::unique_ptr<PtJson> json)
|
||||
{
|
||||
if (json == nullptr) {
|
||||
LOGE("arkdb: json parse error");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!json->IsObject()) {
|
||||
LOGE("arkdb: json parse format error");
|
||||
json->ReleaseRoot();
|
||||
return;
|
||||
}
|
||||
Result ret;
|
||||
std::unique_ptr<PtJson> result;
|
||||
ret = json->GetObject("result", &result);
|
||||
if (ret != Result::SUCCESS) {
|
||||
LOGE("arkdb: find result error");
|
||||
return;
|
||||
}
|
||||
std::string breakpointId;
|
||||
ret = result->GetString("breakpointId", &breakpointId);
|
||||
if (ret == Result::SUCCESS) {
|
||||
Breaklocation breaklocation;
|
||||
breaklocation.breakpointId = breakpointId;
|
||||
std::vector<std::string> breaksplitstring;
|
||||
breaksplitstring = SplitString(breakpointId, ':');
|
||||
breaklocation.lineNumber = breaksplitstring[1]; // 1: linenumber
|
||||
breaklocation.columnNumber = breaksplitstring[2]; // 2: columnnumber
|
||||
breaklocation.url = breaksplitstring[3]; // 3: url
|
||||
breaklist_.push_back(breaklocation);
|
||||
} else {
|
||||
LOGE("arkdb: find breakpointId error");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> BreakPointManager::SplitString(std::string &str, const char delimiter)
|
||||
{
|
||||
int size = str.size();
|
||||
std::vector<std::string> value;
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (str[i] == delimiter) {
|
||||
str[i] = ' ';
|
||||
}
|
||||
}
|
||||
std::istringstream out(str);
|
||||
std::string sstr;
|
||||
while (out >> sstr) {
|
||||
value.push_back(sstr);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
void BreakPointManager::Show()
|
||||
{
|
||||
int size = breaklist_.size();
|
||||
for (int i = 0; i < size; i++) {
|
||||
std::cout << (i + 1) << ':' << " url:" << breaklist_[i].url;
|
||||
std::cout << " lineNumber:" << breaklist_[i].lineNumber
|
||||
<< " columnNumber:" << breaklist_[i].columnNumber << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void BreakPointManager::Deletebreaklist(unsigned int num)
|
||||
{
|
||||
std::vector<Breaklocation>::iterator it = breaklist_.begin() + num - 1;
|
||||
breaklist_.erase(it);
|
||||
}
|
||||
|
||||
std::vector<Breaklocation> BreakPointManager::Getbreaklist() const
|
||||
{
|
||||
return breaklist_;
|
||||
}
|
||||
}
|
55
tooling/client/manager/breakpoint_manager.h
Normal file
55
tooling/client/manager/breakpoint_manager.h
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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.
|
||||
*/
|
||||
#ifndef ECMASCRIPT_TOOLING_CLIENT_MANAGER_BREAKPOINT_MANAGER_H
|
||||
#define ECMASCRIPT_TOOLING_CLIENT_MANAGER_BREAKPOINT_MANAGER_H
|
||||
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "pt_json.h"
|
||||
#include "pt_types.h"
|
||||
|
||||
namespace OHOS::ArkCompiler::Toolchain {
|
||||
using PtJson = panda::ecmascript::tooling::PtJson;
|
||||
using Result = panda::ecmascript::tooling::Result;
|
||||
struct Breaklocation {
|
||||
std::string breakpointId;
|
||||
std::string url;
|
||||
std::string lineNumber;
|
||||
std::string columnNumber;
|
||||
};
|
||||
class BreakPointManager {
|
||||
public:
|
||||
static BreakPointManager& GetInstance();
|
||||
|
||||
std::vector<std::string> SplitString(std::string &str, const char delimiter);
|
||||
void Createbreaklocation(const std::unique_ptr<PtJson> json);
|
||||
void Show();
|
||||
void Deletebreaklist(unsigned int num);
|
||||
std::vector<Breaklocation> Getbreaklist() const;
|
||||
|
||||
private:
|
||||
static BreakPointManager instance_;
|
||||
std::vector<Breaklocation> breaklist_ {};
|
||||
BreakPointManager() = default;
|
||||
BreakPointManager(const BreakPointManager&) = delete;
|
||||
BreakPointManager& operator=(const BreakPointManager&) = delete;
|
||||
};
|
||||
}
|
||||
#endif
|
71
tooling/client/manager/domain_manager.cpp
Normal file
71
tooling/client/manager/domain_manager.cpp
Normal file
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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 "domain_manager.h"
|
||||
|
||||
#include "log_wrapper.h"
|
||||
#include "manager/breakpoint_manager.h"
|
||||
#include "pt_json.h"
|
||||
|
||||
using PtJson = panda::ecmascript::tooling::PtJson;
|
||||
using Result = panda::ecmascript::tooling::Result;
|
||||
namespace OHOS::ArkCompiler::Toolchain {
|
||||
void DomainManager::DispatcherReply(char* msg)
|
||||
{
|
||||
std::string decMessage = std::string(msg);
|
||||
std::unique_ptr<PtJson> json = PtJson::Parse(decMessage);
|
||||
if (json == nullptr) {
|
||||
LOGE("json parse error");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!json->IsObject()) {
|
||||
LOGE("json parse format error");
|
||||
json->ReleaseRoot();
|
||||
return;
|
||||
}
|
||||
|
||||
std::string domain;
|
||||
Result ret;
|
||||
int32_t id;
|
||||
ret = json->GetInt("id", &id);
|
||||
if (ret == Result::SUCCESS) {
|
||||
domain = GetDomainById(id);
|
||||
RemoveDomainById(id);
|
||||
}
|
||||
|
||||
std::string wholeMethod;
|
||||
ret = json->GetString("method", &wholeMethod);
|
||||
if (ret == Result::SUCCESS) {
|
||||
std::string::size_type length = wholeMethod.length();
|
||||
std::string::size_type indexPoint = 0;
|
||||
indexPoint = wholeMethod.find_first_of('.', 0);
|
||||
if (indexPoint == std::string::npos || indexPoint == 0 || indexPoint == length - 1) {
|
||||
return;
|
||||
}
|
||||
domain = wholeMethod.substr(0, indexPoint);
|
||||
}
|
||||
|
||||
if (domain == "HeapProfiler") {
|
||||
heapProfilerClient_.RecvReply(std::move(json));
|
||||
} else if (domain == "Profiler") {
|
||||
profilerClient_.RecvProfilerResult(std::move(json));
|
||||
} else if (domain == "Runtime") {
|
||||
runtimeClient_.RecvReply(std::move(json));
|
||||
} else if (domain == "Debugger") {
|
||||
debuggerClient_.RecvReply(std::move(json));
|
||||
}
|
||||
}
|
||||
}
|
74
tooling/client/manager/domain_manager.h
Normal file
74
tooling/client/manager/domain_manager.h
Normal file
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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.
|
||||
*/
|
||||
|
||||
#ifndef ECMASCRIPT_TOOLING_CLIENT_MANAGER_DOMAIN_MANAGER_H
|
||||
#define ECMASCRIPT_TOOLING_CLIENT_MANAGER_DOMAIN_MANAGER_H
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "domain/debugger_client.h"
|
||||
#include "domain/heapprofiler_client.h"
|
||||
#include "domain/profiler_client.h"
|
||||
#include "domain/runtime_client.h"
|
||||
|
||||
namespace OHOS::ArkCompiler::Toolchain {
|
||||
class DomainManager {
|
||||
public:
|
||||
DomainManager() = default;
|
||||
~DomainManager() = default;
|
||||
|
||||
void DispatcherReply(char* msg);
|
||||
|
||||
std::string GetDomainById(uint32_t id)
|
||||
{
|
||||
auto iter = idDomainMap_.find(id);
|
||||
if (iter == idDomainMap_.end()) {
|
||||
return "";
|
||||
}
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
void SetDomainById(uint32_t id, std::string domain)
|
||||
{
|
||||
idDomainMap_.emplace(id, domain);
|
||||
}
|
||||
|
||||
void RemoveDomainById(uint32_t id)
|
||||
{
|
||||
auto it = idDomainMap_.find(id);
|
||||
if (it != idDomainMap_.end()) {
|
||||
idDomainMap_.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
HeapProfilerClient* GetHeapProfilerClient()
|
||||
{
|
||||
return &heapProfilerClient_;
|
||||
}
|
||||
|
||||
ProfilerClient* GetProfilerClient()
|
||||
{
|
||||
return &profilerClient_;
|
||||
}
|
||||
|
||||
private:
|
||||
HeapProfilerClient heapProfilerClient_ {};
|
||||
ProfilerClient profilerClient_ {};
|
||||
DebuggerClient debuggerClient_ {};
|
||||
RuntimeClient &runtimeClient_ = RuntimeClient::GetInstance();
|
||||
std::map<uint32_t, std::string> idDomainMap_ {};
|
||||
};
|
||||
} // OHOS::ArkCompiler::Toolchain
|
||||
#endif
|
72
tooling/client/manager/stack_manager.cpp
Normal file
72
tooling/client/manager/stack_manager.cpp
Normal file
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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 "manager/stack_manager.h"
|
||||
#include "log_wrapper.h"
|
||||
|
||||
namespace OHOS::ArkCompiler::Toolchain {
|
||||
StackManager StackManager::instance_;
|
||||
StackManager& StackManager::GetInstance()
|
||||
{
|
||||
return instance_;
|
||||
}
|
||||
|
||||
void StackManager::SetCallFrames(std::map<int32_t, std::unique_ptr<CallFrame>> callFrames)
|
||||
{
|
||||
for (auto &callFrame : callFrames) {
|
||||
callFrames_[callFrame.first] = std::move(callFrame.second);
|
||||
}
|
||||
}
|
||||
|
||||
void StackManager::ShowCallFrames()
|
||||
{
|
||||
std::cout << std::endl;
|
||||
for (const auto &callFrame : callFrames_) {
|
||||
if (callFrame.second->GetFunctionName().empty()) {
|
||||
callFrame.second->SetFunctionName("<anonymous function>");
|
||||
}
|
||||
std::cout << callFrame.first << ". " << callFrame.second->GetFunctionName() << "(), "
|
||||
<< callFrame.second->GetUrl() << ": " << callFrame.second->GetLocation()->GetLine() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
std::map<int32_t, std::map<int32_t, std::string>> StackManager::GetScopeChainInfo()
|
||||
{
|
||||
std::map<int32_t, std::map<int32_t, std::string>> scopeInfos;
|
||||
for (const auto &callFram : callFrames_) {
|
||||
int32_t callFramId = callFram.second->GetCallFrameId();
|
||||
for (const auto &scope : *(callFram.second->GetScopeChain())) {
|
||||
scopeInfos[callFramId][scope->GetObject()->GetObjectId()] = scope->GetType();
|
||||
}
|
||||
}
|
||||
return scopeInfos;
|
||||
}
|
||||
|
||||
void StackManager::ClearCallFrame()
|
||||
{
|
||||
callFrames_.clear();
|
||||
}
|
||||
|
||||
void StackManager::PrintScopeChainInfo(const std::map<int32_t, std::map<int32_t, std::string>>& scopeInfos)
|
||||
{
|
||||
for (const auto& [callFrameId, scopes] : scopeInfos) {
|
||||
std::cout << "CallFrame ID: " << callFrameId << std::endl;
|
||||
for (const auto& [objectId, type] : scopes) {
|
||||
std::cout << " Object ID: " << objectId << ", Type: " << type << std::endl;
|
||||
}
|
||||
std::cout << "-----------------------" << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
49
tooling/client/manager/stack_manager.h
Normal file
49
tooling/client/manager/stack_manager.h
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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.
|
||||
*/
|
||||
|
||||
#ifndef ECMASCRIPT_TOOLING_CLIENT_MANAGER_STACK_MANAGER_H
|
||||
#define ECMASCRIPT_TOOLING_CLIENT_MANAGER_STACK_MANAGER_H
|
||||
|
||||
#include <map>
|
||||
#include <variant>
|
||||
|
||||
#include "log_wrapper.h"
|
||||
#include "pt_json.h"
|
||||
#include "pt_types.h"
|
||||
|
||||
using PtJson = panda::ecmascript::tooling::PtJson;
|
||||
using Result = panda::ecmascript::tooling::Result;
|
||||
using CallFrame = panda::ecmascript::tooling::CallFrame;
|
||||
using Scope = panda::ecmascript::tooling::Scope;
|
||||
namespace OHOS::ArkCompiler::Toolchain {
|
||||
class StackManager final {
|
||||
public:
|
||||
static StackManager& GetInstance();
|
||||
|
||||
std::map<int32_t, std::map<int32_t, std::string>> GetScopeChainInfo();
|
||||
void SetCallFrames(std::map<int32_t, std::unique_ptr<CallFrame>> callFrames);
|
||||
void ClearCallFrame();
|
||||
void ShowCallFrames();
|
||||
void PrintScopeChainInfo(const std::map<int32_t, std::map<int32_t, std::string>>& scopeInfos);
|
||||
|
||||
private:
|
||||
static StackManager instance_;
|
||||
std::map<int32_t, std::unique_ptr<CallFrame>> callFrames_ {};
|
||||
StackManager() = default;
|
||||
StackManager(const StackManager&) = delete;
|
||||
StackManager& operator=(const StackManager&) = delete;
|
||||
};
|
||||
} // OHOS::ArkCompiler::Toolchain
|
||||
#endif
|
319
tooling/client/manager/variable_manager.cpp
Normal file
319
tooling/client/manager/variable_manager.cpp
Normal file
@ -0,0 +1,319 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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 "manager/variable_manager.h"
|
||||
|
||||
#include "log_wrapper.h"
|
||||
|
||||
using PtJson = panda::ecmascript::tooling::PtJson;
|
||||
namespace OHOS::ArkCompiler::Toolchain {
|
||||
VariableManager VariableManager::instance_;
|
||||
void TreeNode::AddChild(std::unique_ptr<PropertyDescriptor> descriptor)
|
||||
{
|
||||
children.push_back(std::make_unique<TreeNode>(std::move(descriptor)));
|
||||
}
|
||||
|
||||
void TreeNode::AddChild(DescriptorMap descriptorMap)
|
||||
{
|
||||
children.push_back(std::make_unique<TreeNode>(std::move(descriptorMap)));
|
||||
}
|
||||
|
||||
void TreeNode::AddChild(std::unique_ptr<TreeNode> child)
|
||||
{
|
||||
children.push_back(std::move(child));
|
||||
}
|
||||
|
||||
void TreeNode::Print(int depth) const
|
||||
{
|
||||
int actualIndent = 0;
|
||||
if (depth > 1) {
|
||||
actualIndent = (depth - 1) * 4; // 4: four spaces
|
||||
}
|
||||
std::string indent(actualIndent, ' ');
|
||||
|
||||
if (std::holds_alternative<int32_t>(data)) {
|
||||
std::cout << indent << "CallFrameId: " << std::get<int32_t>(data) << std::endl;
|
||||
} else if (std::holds_alternative<std::map<int32_t, std::map<int32_t, std::string>>>(data)) {
|
||||
const auto& outerMap = std::get<std::map<int32_t, std::map<int32_t, std::string>>>(data);
|
||||
for (const auto& [key, innerMap] : outerMap) {
|
||||
for (const auto& [innerKey, value] : innerMap) {
|
||||
std::cout << key << ". " << value << std::endl;
|
||||
}
|
||||
}
|
||||
} else if (std::holds_alternative<std::unique_ptr<PropertyDescriptor>>(data)) {
|
||||
const auto &descriptor = std::get<std::unique_ptr<PropertyDescriptor>>(data);
|
||||
if (descriptor) {
|
||||
if (descriptor->GetValue()->HasDescription()) {
|
||||
std::cout << indent << " " << descriptor->GetName() << " = "
|
||||
<< descriptor->GetValue()->GetDescription() << std::endl;
|
||||
} else {
|
||||
std::cout << indent << " " << descriptor->GetName() << " = "
|
||||
<< descriptor->GetValue()->GetType() << std::endl;
|
||||
}
|
||||
}
|
||||
} else if (std::holds_alternative<DescriptorMap>(data)) {
|
||||
const auto &descriptorMap = std::get<DescriptorMap>(data);
|
||||
for (const auto& [key, descriptor] : descriptorMap) {
|
||||
std::cout << indent << key << ". ";
|
||||
if (descriptor) {
|
||||
std::cout << descriptor->GetName() << " = " << descriptor->GetValue()->GetDescription() << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto &child : children) {
|
||||
child->Print(depth + 1);
|
||||
}
|
||||
}
|
||||
|
||||
Tree::Tree(const std::map<int32_t, std::map<int32_t, std::string>>& dataMap, int32_t index)
|
||||
{
|
||||
root_ = std::make_unique<TreeNode>(index);
|
||||
|
||||
auto it = dataMap.find(index);
|
||||
if (it != dataMap.end()) {
|
||||
for (const auto& [key, value] : it->second) {
|
||||
std::map<int32_t, std::map<int32_t, std::string>> childData;
|
||||
childData[index_] = {{key, value}};
|
||||
root_->children.push_back(std::make_unique<TreeNode>(childData));
|
||||
index_++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Tree::PrintRootAndImmediateChildren() const
|
||||
{
|
||||
if (std::holds_alternative<int32_t>(root_->data)) {
|
||||
std::cout << "CallFrame ID: " << std::get<int32_t>(root_->data) << std::endl;
|
||||
}
|
||||
|
||||
for (const auto& child : root_->children) {
|
||||
if (std::holds_alternative<std::map<int32_t, std::map<int32_t, std::string>>>(child->data)) {
|
||||
const auto& outerMap = std::get<std::map<int32_t, std::map<int32_t, std::string>>>(child->data);
|
||||
for (const auto& [index, innerMap] : outerMap) {
|
||||
std::cout << " Index: " << index << std::endl;
|
||||
for (const auto& [objectId, type] : innerMap) {
|
||||
std::cout << " Object ID: " << objectId << ", Type: " << type << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Tree::Clear()
|
||||
{
|
||||
if (root_ != nullptr) {
|
||||
root_.reset();
|
||||
}
|
||||
}
|
||||
|
||||
void Tree::Print() const
|
||||
{
|
||||
if (root_) {
|
||||
root_->Print();
|
||||
}
|
||||
}
|
||||
|
||||
TreeNode* Tree::FindNodeWithObjectId(int32_t objectId) const
|
||||
{
|
||||
return FindNodeWithObjectIdRecursive(root_.get(), objectId);
|
||||
}
|
||||
|
||||
void Tree::AddVariableNode(TreeNode* parentNode, std::unique_ptr<PropertyDescriptor> descriptor)
|
||||
{
|
||||
if (!parentNode) {
|
||||
return;
|
||||
}
|
||||
parentNode->AddChild(std::move(descriptor));
|
||||
}
|
||||
|
||||
void Tree::AddObjectNode(TreeNode* parentNode, std::unique_ptr<PropertyDescriptor> descriptor)
|
||||
{
|
||||
if (!parentNode) {
|
||||
return;
|
||||
}
|
||||
DescriptorMap descriptorMap;
|
||||
descriptorMap[index_] = std::move(descriptor);
|
||||
parentNode->AddChild(std::move(descriptorMap));
|
||||
index_++;
|
||||
}
|
||||
|
||||
TreeNode* Tree::GetRoot() const
|
||||
{
|
||||
return root_.get();
|
||||
}
|
||||
|
||||
TreeNode* Tree::FindNodeWithObjectIdRecursive(TreeNode* node, int32_t objectId) const
|
||||
{
|
||||
if (!node) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (std::holds_alternative<std::map<int32_t, std::map<int32_t, std::string>>>(node->data)) {
|
||||
const auto& outerMap = std::get<std::map<int32_t, std::map<int32_t, std::string>>>(node->data);
|
||||
for (const auto& [key, innerMap] : outerMap) {
|
||||
if (innerMap.find(objectId) != innerMap.end()) {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
} else if (std::holds_alternative<DescriptorMap>(node->data)) {
|
||||
const auto& descriptorMap = std::get<DescriptorMap>(node->data);
|
||||
for (const auto& [key, descriptor] : descriptorMap) {
|
||||
if (descriptor && descriptor->GetValue()->GetObjectId() == objectId) {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& child : node->children) {
|
||||
TreeNode* foundNode = FindNodeWithObjectIdRecursive(child.get(), objectId);
|
||||
if (foundNode) {
|
||||
return foundNode;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
TreeNode* Tree::FindNodeWithInnerKeyZero(TreeNode* node) const
|
||||
{
|
||||
if (!node) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (std::holds_alternative<std::map<int32_t, std::map<int32_t, std::string>>>(node->data)) {
|
||||
const auto &outerMap = std::get<std::map<int32_t, std::map<int32_t, std::string>>>(node->data);
|
||||
for (const auto &innerMapPair : outerMap) {
|
||||
if (innerMapPair.second.find(0) != innerMapPair.second.end()) {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto &child : node->children) {
|
||||
TreeNode* foundNode = FindNodeWithInnerKeyZero(child.get());
|
||||
if (foundNode) {
|
||||
return foundNode;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
TreeNode* Tree::FindNodeWithCondition() const
|
||||
{
|
||||
return FindNodeWithInnerKeyZero(root_.get());
|
||||
}
|
||||
|
||||
int32_t Tree::FindObjectByIndex(int32_t index) const
|
||||
{
|
||||
return FindObjectByIndexRecursive(root_.get(), index);
|
||||
}
|
||||
|
||||
int32_t Tree::FindObjectByIndexRecursive(const TreeNode* node, int32_t index) const
|
||||
{
|
||||
if (!node) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (std::holds_alternative<std::map<int32_t, std::map<int32_t, std::string>>>(node->data)) {
|
||||
const auto &outerMap = std::get<std::map<int32_t, std::map<int32_t, std::string>>>(node->data);
|
||||
auto it = outerMap.find(index);
|
||||
if (it != outerMap.end() && !it->second.empty()) {
|
||||
return it->second.begin()->first;
|
||||
}
|
||||
} else if (std::holds_alternative<DescriptorMap>(node->data)) {
|
||||
const auto &descriptorMap = std::get<DescriptorMap>(node->data);
|
||||
auto it = descriptorMap.find(index);
|
||||
if (it != descriptorMap.end() && it->second) {
|
||||
return it->second->GetValue()->GetObjectId();
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& child : node->children) {
|
||||
int32_t result = FindObjectByIndexRecursive(child.get(), index);
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
VariableManager& VariableManager::GetInstance()
|
||||
{
|
||||
return instance_;
|
||||
}
|
||||
|
||||
void VariableManager::SetHeapUsageInfo(std::unique_ptr<GetHeapUsageReturns> heapUsageReturns)
|
||||
{
|
||||
heapUsageInfo_.SetUsedSize(heapUsageReturns->GetUsedSize());
|
||||
heapUsageInfo_.SetTotalSize(heapUsageReturns->GetTotalSize());
|
||||
}
|
||||
|
||||
void VariableManager::ShowHeapUsageInfo() const
|
||||
{
|
||||
std::cout << std::endl;
|
||||
std::cout << "UsedSize is: " << heapUsageInfo_.GetUsedSize() << std::endl;
|
||||
std::cout << "TotalSize is: " << std::fixed << std::setprecision(0) << heapUsageInfo_.GetTotalSize() << std::endl;
|
||||
}
|
||||
|
||||
void VariableManager::ShowVariableInfos() const
|
||||
{
|
||||
variableInfo_.Print();
|
||||
}
|
||||
|
||||
void VariableManager::ClearVariableInfo()
|
||||
{
|
||||
variableInfo_.Clear();
|
||||
}
|
||||
void VariableManager::InitializeTree(std::map<int32_t, std::map<int32_t, std::string>> dataMap, int index)
|
||||
{
|
||||
variableInfo_ = Tree(dataMap, index);
|
||||
}
|
||||
|
||||
void VariableManager::PrintVariableInfo()
|
||||
{
|
||||
variableInfo_.Print();
|
||||
}
|
||||
|
||||
TreeNode* VariableManager::FindNodeWithObjectId(int32_t objectId)
|
||||
{
|
||||
return variableInfo_.FindNodeWithObjectId(objectId);
|
||||
}
|
||||
|
||||
void VariableManager::AddVariableInfo(TreeNode *parentNode, std::unique_ptr<PropertyDescriptor> variableInfo)
|
||||
{
|
||||
if (variableInfo->GetValue()->HasObjectId()) {
|
||||
variableInfo_.AddObjectNode(parentNode, std::move(variableInfo));
|
||||
} else {
|
||||
variableInfo_.AddVariableNode(parentNode, std::move(variableInfo));
|
||||
}
|
||||
}
|
||||
|
||||
TreeNode* VariableManager::FindNodeObjectZero()
|
||||
{
|
||||
return variableInfo_.FindNodeWithCondition();
|
||||
}
|
||||
|
||||
int32_t VariableManager::FindObjectIdWithIndex(int index)
|
||||
{
|
||||
return variableInfo_.FindObjectByIndex(index);
|
||||
}
|
||||
|
||||
void VariableManager::Printinfo() const
|
||||
{
|
||||
variableInfo_.PrintRootAndImmediateChildren();
|
||||
}
|
||||
}
|
99
tooling/client/manager/variable_manager.h
Normal file
99
tooling/client/manager/variable_manager.h
Normal file
@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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.
|
||||
*/
|
||||
|
||||
#ifndef ECMASCRIPT_TOOLING_CLIENT_MANAGER_VARIABLE_MANAGER_H
|
||||
#define ECMASCRIPT_TOOLING_CLIENT_MANAGER_VARIABLE_MANAGER_H
|
||||
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
|
||||
#include "manager/stack_manager.h"
|
||||
#include "pt_json.h"
|
||||
#include "pt_returns.h"
|
||||
#include "pt_types.h"
|
||||
|
||||
using PtJson = panda::ecmascript::tooling::PtJson;
|
||||
using Result = panda::ecmascript::tooling::Result;
|
||||
using PropertyDescriptor = panda::ecmascript::tooling::PropertyDescriptor;
|
||||
using GetHeapUsageReturns = panda::ecmascript::tooling::GetHeapUsageReturns;
|
||||
using PropertyDescriptor = panda::ecmascript::tooling::PropertyDescriptor;
|
||||
using DescriptorMap = std::map<int32_t, std::unique_ptr<PropertyDescriptor>>;
|
||||
using NodeData = std::variant<int32_t, std::map<int32_t, std::map<int32_t, std::string>>,
|
||||
std::unique_ptr<PropertyDescriptor>, DescriptorMap>;
|
||||
namespace OHOS::ArkCompiler::Toolchain {
|
||||
class TreeNode {
|
||||
public:
|
||||
NodeData data;
|
||||
std::vector<std::unique_ptr<TreeNode>> children;
|
||||
|
||||
TreeNode(int32_t CallFrameId) : data(CallFrameId) {}
|
||||
TreeNode(const std::map<int32_t, std::map<int32_t, std::string>>& scopeInfo) : data(scopeInfo) {}
|
||||
TreeNode(std::unique_ptr<PropertyDescriptor> descriptor) : data(std::move(descriptor)) {}
|
||||
TreeNode(DescriptorMap&& descriptorMap) : data(std::move(descriptorMap)) {}
|
||||
|
||||
void AddChild(std::unique_ptr<PropertyDescriptor> descriptor);
|
||||
void AddChild(DescriptorMap descriptorMap);
|
||||
void AddChild(std::unique_ptr<TreeNode> child);
|
||||
void Print(int depth = 0) const;
|
||||
};
|
||||
|
||||
class Tree {
|
||||
public:
|
||||
Tree(int32_t rootValue) : root_(std::make_unique<TreeNode>(rootValue)) {}
|
||||
Tree(const std::map<int32_t, std::map<int32_t, std::string>>& dataMap, int32_t index);
|
||||
|
||||
void Clear();
|
||||
void Print() const;
|
||||
TreeNode* GetRoot() const;
|
||||
TreeNode* FindNodeWithObjectId(int32_t objectId) const;
|
||||
void AddVariableNode(TreeNode* parentNode, std::unique_ptr<PropertyDescriptor> descriptor);
|
||||
void AddObjectNode(TreeNode* parentNode, std::unique_ptr<PropertyDescriptor> descriptor);
|
||||
TreeNode* FindNodeWithCondition() const;
|
||||
void PrintRootAndImmediateChildren() const;
|
||||
int32_t FindObjectByIndex(int32_t index) const;
|
||||
|
||||
private:
|
||||
std::unique_ptr<TreeNode> root_ {};
|
||||
int32_t index_ {1};
|
||||
TreeNode* FindNodeWithObjectIdRecursive(TreeNode* node, int32_t objectId) const;
|
||||
TreeNode* FindNodeWithInnerKeyZero(TreeNode* node) const;
|
||||
int32_t FindObjectByIndexRecursive(const TreeNode* node, int32_t index) const;
|
||||
};
|
||||
|
||||
class VariableManager final {
|
||||
public:
|
||||
static VariableManager& GetInstance();
|
||||
void SetHeapUsageInfo(std::unique_ptr<GetHeapUsageReturns> heapUsageReturns);
|
||||
void ShowHeapUsageInfo() const;
|
||||
void ShowVariableInfos() const;
|
||||
void ClearVariableInfo();
|
||||
void InitializeTree(std::map<int32_t, std::map<int32_t, std::string>> dataMap, int index = 0);
|
||||
void PrintVariableInfo();
|
||||
TreeNode* FindNodeWithObjectId(int32_t objectId);
|
||||
int32_t FindObjectIdWithIndex(int index);
|
||||
void AddVariableInfo(TreeNode *parentNode, std::unique_ptr<PropertyDescriptor> variableInfo);
|
||||
TreeNode* FindNodeObjectZero();
|
||||
void Printinfo() const;
|
||||
|
||||
private:
|
||||
VariableManager() = default;
|
||||
static VariableManager instance_;
|
||||
GetHeapUsageReturns heapUsageInfo_ {};
|
||||
Tree variableInfo_ {0};
|
||||
VariableManager(const VariableManager&) = delete;
|
||||
VariableManager& operator=(const VariableManager&) = delete;
|
||||
};
|
||||
} // OHOS::ArkCompiler::Toolchain
|
||||
#endif
|
55
tooling/client/utils/utils.cpp
Normal file
55
tooling/client/utils/utils.cpp
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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 "utils/utils.h"
|
||||
#include "log_wrapper.h"
|
||||
#include <ctime>
|
||||
|
||||
namespace OHOS::ArkCompiler::Toolchain {
|
||||
bool Utils::GetCurrentTime(char *date, char *tim, size_t size)
|
||||
{
|
||||
time_t timep = time(nullptr);
|
||||
if (timep == -1) {
|
||||
LOGE("get timep failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
tm* currentDate = localtime(&timep);
|
||||
if (currentDate == nullptr) {
|
||||
LOGE("get currentDate failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t timeResult = 0;
|
||||
timeResult = strftime(date, size, "%Y%m%d", currentDate);
|
||||
if (timeResult == 0) {
|
||||
LOGE("format date failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
tm* currentTime = localtime(&timep);
|
||||
if (currentTime == nullptr) {
|
||||
LOGE("get currentTime failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
timeResult = strftime(tim, size, "%H%M%S", currentTime);
|
||||
if (timeResult == 0) {
|
||||
LOGE("format time failed");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} // OHOS::ArkCompiler::Toolchain
|
27
tooling/client/utils/utils.h
Normal file
27
tooling/client/utils/utils.h
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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.
|
||||
*/
|
||||
|
||||
#ifndef ECMASCRIPT_TOOLING_CLIENT_UTILS_UTILS_H
|
||||
#define ECMASCRIPT_TOOLING_CLIENT_UTILS_UTILS_H
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
namespace OHOS::ArkCompiler::Toolchain {
|
||||
class Utils {
|
||||
public:
|
||||
static bool GetCurrentTime(char *date, char *tim, size_t size);
|
||||
};
|
||||
} // OHOS::ArkCompiler::Toolchain
|
||||
#endif
|
428
tooling/client/websocket/websocket_client.cpp
Normal file
428
tooling/client/websocket/websocket_client.cpp
Normal file
@ -0,0 +1,428 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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 <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/un.h>
|
||||
#include <unistd.h>
|
||||
#include <securec.h>
|
||||
|
||||
#include "log_wrapper.h"
|
||||
#include "websocket_client.h"
|
||||
|
||||
|
||||
namespace OHOS::ArkCompiler::Toolchain {
|
||||
bool WebsocketClient::InitToolchainWebSocketForPort(int port, uint32_t timeoutLimit)
|
||||
{
|
||||
if (socketState_ != ToolchainSocketState::UNINITED) {
|
||||
LOGE("InitToolchainWebSocketForPort::client has inited.");
|
||||
return true;
|
||||
}
|
||||
|
||||
client_ = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (client_ < SOCKET_SUCCESS) {
|
||||
LOGE("InitToolchainWebSocketForPort::client socket failed, error = %{public}d , desc = %{public}s",
|
||||
errno, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
// set send and recv timeout limit
|
||||
if (!SetWebSocketTimeOut(client_, timeoutLimit)) {
|
||||
LOGE("InitToolchainWebSocketForPort::client SetWebSocketTimeOut failed, error = %{public}d , desc = %{public}s",
|
||||
errno, strerror(errno));
|
||||
close(client_);
|
||||
client_ = -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
sockaddr_in clientAddr;
|
||||
if (memset_s(&clientAddr, sizeof(clientAddr), 0, sizeof(clientAddr)) != EOK) {
|
||||
LOGE("InitToolchainWebSocketForPort::client memset_s clientAddr failed, error = %{public}d, desc = %{public}s",
|
||||
errno, strerror(errno));
|
||||
close(client_);
|
||||
client_ = -1;
|
||||
return false;
|
||||
}
|
||||
clientAddr.sin_family = AF_INET;
|
||||
clientAddr.sin_port = htons(port);
|
||||
if (int ret = inet_pton(AF_INET, "127.0.0.1", &clientAddr.sin_addr) < NET_SUCCESS) {
|
||||
LOGE("InitToolchainWebSocketForPort::client inet_pton failed, error = %{public}d, desc = %{public}s",
|
||||
errno, strerror(errno));
|
||||
close(client_);
|
||||
client_ = -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
int ret = connect(client_, reinterpret_cast<struct sockaddr*>(&clientAddr), sizeof(clientAddr));
|
||||
if (ret != SOCKET_SUCCESS) {
|
||||
LOGE("InitToolchainWebSocketForPort::client connect failed, error = %{public}d, desc = %{public}s",
|
||||
errno, strerror(errno));
|
||||
close(client_);
|
||||
client_ = -1;
|
||||
return false;
|
||||
}
|
||||
socketState_ = ToolchainSocketState::INITED;
|
||||
LOGE("InitToolchainWebSocketForPort::client connect success.");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WebsocketClient::InitToolchainWebSocketForSockName(const std::string &sockName, uint32_t timeoutLimit)
|
||||
{
|
||||
if (socketState_ != ToolchainSocketState::UNINITED) {
|
||||
LOGE("InitToolchainWebSocketForSockName::client has inited.");
|
||||
return true;
|
||||
}
|
||||
|
||||
client_ = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (client_ < SOCKET_SUCCESS) {
|
||||
LOGE("InitToolchainWebSocketForSockName::client socket failed, error = %{public}d , desc = %{public}s",
|
||||
errno, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
// set send and recv timeout limit
|
||||
if (!SetWebSocketTimeOut(client_, timeoutLimit)) {
|
||||
LOGE("InitToolchainWebSocketForSockName::client SetWebSocketTimeOut failed, error = %{public}d ,\
|
||||
desc = %{public}s", errno, strerror(errno));
|
||||
close(client_);
|
||||
client_ = -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
struct sockaddr_un serverAddr;
|
||||
if (memset_s(&serverAddr, sizeof(serverAddr), 0, sizeof(serverAddr)) != EOK) {
|
||||
LOGE("InitToolchainWebSocketForSockName::client memset_s clientAddr failed, error = %{public}d,\
|
||||
desc = %{public}s", errno, strerror(errno));
|
||||
close(client_);
|
||||
client_ = -1;
|
||||
return false;
|
||||
}
|
||||
serverAddr.sun_family = AF_UNIX;
|
||||
if (strcpy_s(serverAddr.sun_path + 1, sizeof(serverAddr.sun_path) - 1, sockName.c_str()) != EOK) {
|
||||
LOGE("InitToolchainWebSocketForSockName::client strcpy_s serverAddr.sun_path failed, error = %{public}d,\
|
||||
desc = %{public}s", errno, strerror(errno));
|
||||
close(client_);
|
||||
client_ = -1;
|
||||
return false;
|
||||
}
|
||||
serverAddr.sun_path[0] = '\0';
|
||||
|
||||
uint32_t len = offsetof(struct sockaddr_un, sun_path) + strlen(sockName.c_str()) + 1;
|
||||
int ret = connect(client_, reinterpret_cast<struct sockaddr*>(&serverAddr), static_cast<int32_t>(len));
|
||||
if (ret != SOCKET_SUCCESS) {
|
||||
LOGE("InitToolchainWebSocketForSockName::client connect failed, error = %{public}d, desc = %{public}s",
|
||||
errno, strerror(errno));
|
||||
close(client_);
|
||||
client_ = -1;
|
||||
return false;
|
||||
}
|
||||
socketState_ = ToolchainSocketState::INITED;
|
||||
LOGE("InitToolchainWebSocketForSockName::client connect success.");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WebsocketClient::ClientSendWSUpgradeReq()
|
||||
{
|
||||
if (socketState_ == ToolchainSocketState::UNINITED) {
|
||||
LOGE("ClientSendWSUpgradeReq::client has not inited.");
|
||||
return false;
|
||||
}
|
||||
if (socketState_ == ToolchainSocketState::CONNECTED) {
|
||||
LOGE("ClientSendWSUpgradeReq::client has connected.");
|
||||
return true;
|
||||
}
|
||||
|
||||
int msgLen = strlen(CLIENT_WEBSOCKET_UPGRADE_REQ);
|
||||
int32_t sendLen = send(client_, CLIENT_WEBSOCKET_UPGRADE_REQ, msgLen, 0);
|
||||
if (sendLen != msgLen) {
|
||||
LOGE("ClientSendWSUpgradeReq::client send wsupgrade req failed, error = %{public}d, desc = %{public}sn",
|
||||
errno, strerror(errno));
|
||||
socketState_ = ToolchainSocketState::UNINITED;
|
||||
close(client_);
|
||||
client_ = -1;
|
||||
return false;
|
||||
}
|
||||
LOGE("ClientSendWSUpgradeReq::client send wsupgrade req success.");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WebsocketClient::ClientRecvWSUpgradeRsp()
|
||||
{
|
||||
if (socketState_ == ToolchainSocketState::UNINITED) {
|
||||
LOGE("ClientRecvWSUpgradeRsp::client has not inited.");
|
||||
return false;
|
||||
}
|
||||
if (socketState_ == ToolchainSocketState::CONNECTED) {
|
||||
LOGE("ClientRecvWSUpgradeRsp::client has connected.");
|
||||
return true;
|
||||
}
|
||||
|
||||
char recvBuf[CLIENT_WEBSOCKET_UPGRADE_RSP_LEN + 1] = {0};
|
||||
int32_t bufLen = recv(client_, recvBuf, CLIENT_WEBSOCKET_UPGRADE_RSP_LEN, 0);
|
||||
if (bufLen != CLIENT_WEBSOCKET_UPGRADE_RSP_LEN) {
|
||||
LOGE("ClientRecvWSUpgradeRsp::client recv wsupgrade rsp failed, error = %{public}d, desc = %{public}sn",
|
||||
errno, strerror(errno));
|
||||
socketState_ = ToolchainSocketState::UNINITED;
|
||||
close(client_);
|
||||
client_ = -1;
|
||||
return false;
|
||||
}
|
||||
socketState_ = ToolchainSocketState::CONNECTED;
|
||||
LOGE("ClientRecvWSUpgradeRsp::client recv wsupgrade rsp success.");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WebsocketClient::ClientSendReq(const std::string &message)
|
||||
{
|
||||
if (socketState_ != ToolchainSocketState::CONNECTED) {
|
||||
LOGE("ClientSendReq::client has not connected.");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t msgLen = message.length();
|
||||
std::unique_ptr<char []> msgBuf = std::make_unique<char []>(msgLen + 15); // 15: the maximum expand length
|
||||
char *sendBuf = msgBuf.get();
|
||||
uint32_t sendMsgLen = 0;
|
||||
sendBuf[0] = 0x81; // 0x81: the text message sent by the server should start with '0x81'.
|
||||
uint32_t mask = 1;
|
||||
// Depending on the length of the messages, client will use shift operation to get the res
|
||||
// and store them in the buffer.
|
||||
if (msgLen <= 125) { // 125: situation 1 when message's length <= 125
|
||||
sendBuf[1] = msgLen | (mask << 7); // 7: mask need shift left by 7 bits
|
||||
sendMsgLen = 2; // 2: the length of header frame is 2;
|
||||
} else if (msgLen < 65536) { // 65536: message's length
|
||||
sendBuf[1] = 126 | (mask << 7); // 126: payloadLen according to the spec; 7: mask shift left by 7 bits
|
||||
sendBuf[2] = ((msgLen >> 8) & 0xff); // 8: shift right by 8 bits => res * (256^1)
|
||||
sendBuf[3] = (msgLen & 0xff); // 3: store len's data => res * (256^0)
|
||||
sendMsgLen = 4; // 4: the length of header frame is 4
|
||||
} else {
|
||||
sendBuf[1] = 127 | (mask << 7); // 127: payloadLen according to the spec; 7: mask shift left by 7 bits
|
||||
for (int32_t i = 2; i <= 5; i++) { // 2 ~ 5: unused bits
|
||||
sendBuf[i] = 0;
|
||||
}
|
||||
sendBuf[6] = ((msgLen & 0xff000000) >> 24); // 6: shift 24 bits => res * (256^3)
|
||||
sendBuf[7] = ((msgLen & 0x00ff0000) >> 16); // 7: shift 16 bits => res * (256^2)
|
||||
sendBuf[8] = ((msgLen & 0x0000ff00) >> 8); // 8: shift 8 bits => res * (256^1)
|
||||
sendBuf[9] = (msgLen & 0x000000ff); // 9: res * (256^0)
|
||||
sendMsgLen = 10; // 10: the length of header frame is 10
|
||||
}
|
||||
|
||||
if (memcpy_s(sendBuf + sendMsgLen, SOCKET_MASK_LEN, MASK_KEY, SOCKET_MASK_LEN) != EOK) {
|
||||
LOGE("ClientSendReq::client memcpy_s MASK_KEY failed, error = %{public}d, desc = %{public}s",
|
||||
errno, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
sendMsgLen += SOCKET_MASK_LEN;
|
||||
|
||||
std::string maskMessage;
|
||||
for (uint64_t i = 0; i < msgLen; i++) {
|
||||
uint64_t j = i % SOCKET_MASK_LEN;
|
||||
maskMessage.push_back(message[i] ^ MASK_KEY[j]);
|
||||
}
|
||||
if (memcpy_s(sendBuf + sendMsgLen, msgLen, maskMessage.c_str(), msgLen) != EOK) {
|
||||
LOGE("ClientSendReq::client memcpy_s maskMessage failed, error = %{public}d, desc = %{public}s",
|
||||
errno, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
msgBuf[sendMsgLen + msgLen] = '\0';
|
||||
|
||||
if (send(client_, sendBuf, sendMsgLen + msgLen, 0) != static_cast<int>(sendMsgLen + msgLen)) {
|
||||
LOGE("ClientSendReq::client send msg req failed, error = %{public}d, desc = %{public}s",
|
||||
errno, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
LOGE("ClientRecvWSUpgradeRsp::client send msg req success.");
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string WebsocketClient::Decode()
|
||||
{
|
||||
if (socketState_ != ToolchainSocketState::CONNECTED) {
|
||||
LOGE("WebsocketClient:Decode failed, websocket not connected!");
|
||||
return "";
|
||||
}
|
||||
char recvbuf[SOCKET_HEADER_LEN + 1];
|
||||
if (!Recv(client_, recvbuf, SOCKET_HEADER_LEN, 0)) {
|
||||
LOGE("WebsocketClient:Decode failed, client websocket disconnect");
|
||||
socketState_ = ToolchainSocketState::INITED;
|
||||
close(client_);
|
||||
client_ = -1;
|
||||
return "";
|
||||
}
|
||||
ToolchainWebSocketFrame wsFrame;
|
||||
int32_t index = 0;
|
||||
wsFrame.fin = static_cast<uint8_t>(recvbuf[index] >> 7); // 7: shift right by 7 bits to get the fin
|
||||
wsFrame.opcode = static_cast<uint8_t>(recvbuf[index] & 0xf);
|
||||
if (wsFrame.opcode == 0x1) { // 0x1: 0x1 means a text frame
|
||||
index++;
|
||||
wsFrame.mask = static_cast<uint8_t>((recvbuf[index] >> 7) & 0x1); // 7: to get the mask
|
||||
wsFrame.payloadLen = recvbuf[index] & 0x7f;
|
||||
if (HandleFrame(wsFrame)) {
|
||||
return wsFrame.payload.get();
|
||||
}
|
||||
return "";
|
||||
} else if (wsFrame.opcode == 0x9) { // 0x9: 0x9 means a ping frame
|
||||
// send pong frame
|
||||
char pongFrame[SOCKET_HEADER_LEN] = {0};
|
||||
pongFrame[0] = 0x8a; // 0x8a: 0x8a means a pong frame
|
||||
pongFrame[1] = 0x0;
|
||||
if (!Send(client_, pongFrame, SOCKET_HEADER_LEN, 0)) {
|
||||
LOGE("WebsocketClient Decode: Send pong frame failed");
|
||||
return "";
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
bool WebsocketClient::HandleFrame(ToolchainWebSocketFrame& wsFrame)
|
||||
{
|
||||
if (wsFrame.payloadLen == 126) { // 126: the payloadLen read from frame
|
||||
char recvbuf[PAYLOAD_LEN + 1] = {0};
|
||||
if (!Recv(client_, recvbuf, PAYLOAD_LEN, 0)) {
|
||||
LOGE("WebsocketClient HandleFrame: Recv payloadLen == 126 failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint16_t msgLen = 0;
|
||||
if (memcpy_s(&msgLen, sizeof(recvbuf), recvbuf, sizeof(recvbuf) - 1) != EOK) {
|
||||
LOGE("WebsocketClient HandleFrame: memcpy_s failed");
|
||||
return false;
|
||||
}
|
||||
wsFrame.payloadLen = ntohs(msgLen);
|
||||
} else if (wsFrame.payloadLen > 126) { // 126: the payloadLen read from frame
|
||||
char recvbuf[EXTEND_PAYLOAD_LEN + 1] = {0};
|
||||
if (!Recv(client_, recvbuf, EXTEND_PAYLOAD_LEN, 0)) {
|
||||
LOGE("WebsocketClient HandleFrame: Recv payloadLen > 127 failed");
|
||||
return false;
|
||||
}
|
||||
wsFrame.payloadLen = NetToHostLongLong(recvbuf, EXTEND_PAYLOAD_LEN);
|
||||
}
|
||||
return DecodeMessage(wsFrame);
|
||||
}
|
||||
|
||||
bool WebsocketClient::DecodeMessage(ToolchainWebSocketFrame& wsFrame)
|
||||
{
|
||||
if (wsFrame.payloadLen == 0 || wsFrame.payloadLen > UINT64_MAX) {
|
||||
LOGE("WebsocketClient:ReadMsg length error, expected greater than zero and less than UINT64_MAX");
|
||||
return false;
|
||||
}
|
||||
uint64_t msgLen = wsFrame.payloadLen;
|
||||
wsFrame.payload = std::make_unique<char []>(msgLen + 1);
|
||||
if (wsFrame.mask == 1) {
|
||||
char buf[msgLen + 1];
|
||||
if (!Recv(client_, wsFrame.maskingkey, SOCKET_MASK_LEN, 0)) {
|
||||
LOGE("WebsocketClient DecodeMessage: Recv maskingkey failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Recv(client_, buf, msgLen, 0)) {
|
||||
LOGE("WebsocketClient DecodeMessage: Recv message with mask failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint64_t i = 0; i < msgLen; i++) {
|
||||
uint64_t j = i % SOCKET_MASK_LEN;
|
||||
wsFrame.payload.get()[i] = buf[i] ^ wsFrame.maskingkey[j];
|
||||
}
|
||||
} else {
|
||||
char buf[msgLen + 1];
|
||||
if (!Recv(client_, buf, msgLen, 0)) {
|
||||
LOGE("WebsocketClient DecodeMessage: Recv message without mask failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (memcpy_s(wsFrame.payload.get(), msgLen, buf, msgLen) != EOK) {
|
||||
LOGE("WebsocketClient DecodeMessage: memcpy_s failed");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
wsFrame.payload.get()[msgLen] = '\0';
|
||||
return true;
|
||||
}
|
||||
|
||||
uint64_t WebsocketClient::NetToHostLongLong(char* buf, uint32_t len)
|
||||
{
|
||||
uint64_t result = 0;
|
||||
for (uint32_t i = 0; i < len; i++) {
|
||||
result |= static_cast<unsigned char>(buf[i]);
|
||||
if ((i + 1) < len) {
|
||||
result <<= 8; // 8: result need shift left 8 bits in order to big endian convert to int
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool WebsocketClient::Send(int32_t fd, const char* buf, size_t totalLen, int32_t flags) const
|
||||
{
|
||||
size_t sendLen = 0;
|
||||
while (sendLen < totalLen) {
|
||||
ssize_t len = send(fd, buf + sendLen, totalLen - sendLen, flags);
|
||||
if (len <= 0) {
|
||||
LOGE("WebsocketClient Send Message in while failed, WebsocketClient disconnect");
|
||||
return false;
|
||||
}
|
||||
sendLen += static_cast<size_t>(len);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WebsocketClient::Recv(int32_t fd, char* buf, size_t totalLen, int32_t flags) const
|
||||
{
|
||||
size_t recvLen = 0;
|
||||
while (recvLen < totalLen) {
|
||||
ssize_t len = recv(fd, buf + recvLen, totalLen - recvLen, flags);
|
||||
if (len <= 0) {
|
||||
LOGE("WebsocketClient Recv payload in while failed, WebsocketClient disconnect");
|
||||
return false;
|
||||
}
|
||||
recvLen += static_cast<size_t>(len);
|
||||
}
|
||||
buf[totalLen] = '\0';
|
||||
return true;
|
||||
}
|
||||
|
||||
void WebsocketClient::Close()
|
||||
{
|
||||
if (socketState_ == ToolchainSocketState::UNINITED) {
|
||||
return;
|
||||
}
|
||||
socketState_ = ToolchainSocketState::UNINITED;
|
||||
close(client_);
|
||||
client_ = -1;
|
||||
}
|
||||
|
||||
bool WebsocketClient::SetWebSocketTimeOut(int32_t fd, uint32_t timeoutLimit)
|
||||
{
|
||||
if (timeoutLimit > 0) {
|
||||
struct timeval timeout = {timeoutLimit, 0};
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO,
|
||||
reinterpret_cast<char *>(&timeout), sizeof(timeout)) != SOCKET_SUCCESS) {
|
||||
LOGE("WebsocketClient:SetWebSocketTimeOut setsockopt SO_SNDTIMEO failed");
|
||||
return false;
|
||||
}
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO,
|
||||
reinterpret_cast<char *>(&timeout), sizeof(timeout)) != SOCKET_SUCCESS) {
|
||||
LOGE("WebsocketClient:SetWebSocketTimeOut setsockopt SO_RCVTIMEO failed");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WebsocketClient::IsConnected()
|
||||
{
|
||||
return socketState_ == ToolchainSocketState::CONNECTED;
|
||||
}
|
||||
} // namespace OHOS::ArkCompiler::Toolchain
|
82
tooling/client/websocket/websocket_client.h
Normal file
82
tooling/client/websocket/websocket_client.h
Normal file
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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.
|
||||
*/
|
||||
|
||||
#ifndef ECMASCRIPT_TOOLING_CLIENT_WEBSOCKET_CLIENT_H
|
||||
#define ECMASCRIPT_TOOLING_CLIENT_WEBSOCKET_CLIENT_H
|
||||
|
||||
#include <atomic>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <map>
|
||||
|
||||
#include "websocket.h"
|
||||
|
||||
namespace OHOS::ArkCompiler::Toolchain {
|
||||
struct ToolchainWebSocketFrame {
|
||||
uint8_t fin = 0;
|
||||
uint8_t opcode = 0;
|
||||
uint8_t mask = 0;
|
||||
uint64_t payloadLen = 0;
|
||||
char maskingkey[5] = {0};
|
||||
std::unique_ptr<char []> payload = nullptr;
|
||||
};
|
||||
class WebsocketClient : public WebSocket {
|
||||
public:
|
||||
enum ToolchainSocketState : uint8_t {
|
||||
UNINITED,
|
||||
INITED,
|
||||
CONNECTED,
|
||||
};
|
||||
WebsocketClient() = default;
|
||||
~WebsocketClient() = default;
|
||||
bool InitToolchainWebSocketForPort(int port, uint32_t timeoutLimit = 5);
|
||||
bool InitToolchainWebSocketForSockName(const std::string &sockName, uint32_t timeoutLimit = 0);
|
||||
bool ClientSendWSUpgradeReq();
|
||||
bool ClientRecvWSUpgradeRsp();
|
||||
bool ClientSendReq(const std::string &message);
|
||||
std::string Decode();
|
||||
bool HandleFrame(ToolchainWebSocketFrame& wsFrame);
|
||||
bool DecodeMessage(ToolchainWebSocketFrame& wsFrame);
|
||||
uint64_t NetToHostLongLong(char* buf, uint32_t len);
|
||||
bool Recv(int32_t fd, char* buf, size_t totalLen, int32_t flags) const;
|
||||
bool Send(int32_t fd, const char* buf, size_t totalLen, int32_t flags) const;
|
||||
void Close();
|
||||
bool SetWebSocketTimeOut(int32_t fd, uint32_t timeoutLimit);
|
||||
bool IsConnected();
|
||||
|
||||
private:
|
||||
int32_t client_ {-1};
|
||||
std::atomic<ToolchainSocketState> socketState_ {ToolchainSocketState::UNINITED};
|
||||
static constexpr int32_t CLIENT_WEBSOCKET_UPGRADE_RSP_LEN = 129;
|
||||
static constexpr char CLIENT_WEBSOCKET_UPGRADE_REQ[] = "GET / HTTP/1.1\r\n"
|
||||
"Connection: Upgrade\r\n"
|
||||
"Pragma: no-cache\r\n"
|
||||
"Cache-Control: no-cache\r\n"
|
||||
"Upgrade: websocket\r\n"
|
||||
"Sec-WebSocket-Version: 13\r\n"
|
||||
"Accept-Encoding: gzip, deflate, br\r\n"
|
||||
"Sec-WebSocket-Key: 64b4B+s5JDlgkdg7NekJ+g==\r\n"
|
||||
"Sec-WebSocket-Extensions: permessage-deflate\r\n";
|
||||
static constexpr int32_t SOCKET_SUCCESS = 0;
|
||||
static constexpr int NET_SUCCESS = 1;
|
||||
static constexpr int32_t SOCKET_MASK_LEN = 4;
|
||||
static constexpr int32_t SOCKET_HEADER_LEN = 2;
|
||||
static constexpr int32_t PAYLOAD_LEN = 2;
|
||||
static constexpr int32_t EXTEND_PAYLOAD_LEN = 8;
|
||||
static constexpr char MASK_KEY[SOCKET_MASK_LEN + 1] = "abcd";
|
||||
};
|
||||
} // namespace OHOS::ArkCompiler::Toolchain
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user