!368 支持toolchain_cli工具

Merge pull request !368 from caolili123/c_toolchain_client_dev
This commit is contained in:
openharmony_ci 2023-10-08 05:52:44 +00:00 committed by Gitee
commit 5e2a93f734
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
28 changed files with 3689 additions and 1 deletions

View File

@ -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",
]
}
}

View File

@ -280,6 +280,36 @@ std::unique_ptr<PtJson> GetHeapUsageReturns::ToJson() const
return result;
}
std::unique_ptr<GetHeapUsageReturns> GetHeapUsageReturns::Create(const PtJson &params)
{
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();

View File

@ -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 &params);
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
View 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"
}

View 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"
}

View 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

View 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

View 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);
}

View 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", &params);
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

View 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

View 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", &params);
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

View 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

View 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

View 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

View 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

View 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

View 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_;
}
}

View 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

View 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));
}
}
}

View 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

View 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;
}
}
}

View 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

View 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();
}
}

View 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

View 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

View 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

View 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

View 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