wasm-micro-runtime/core/iwasm/libraries/debug-engine/handler.c

617 lines
17 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Copyright (C) 2021 Ant Group. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include <bh_log.h>
#include <handler.h>
#include <limits.h>
#include <string.h>
#include <unistd.h>
#include "debug_engine.h"
#include "packets.h"
#include "utils.h"
#include "wasm_runtime.h"
#define MAX_PACKET_SIZE (0x20000)
static char tmpbuf[MAX_PACKET_SIZE];
void
handle_generay_set(WASMGDBServer *server, char *payload)
{
const char *name;
char *args;
args = strchr(payload, ':');
if (args)
*args++ = '\0';
name = payload;
LOG_VERBOSE("%s:%s\n", __FUNCTION__, payload);
if (!strcmp(name, "StartNoAckMode")) {
server->noack = true;
write_packet(server, "OK");
}
if (!strcmp(name, "ThreadSuffixSupported")) {
write_packet(server, "");
}
if (!strcmp(name, "ListThreadsInStopReply")) {
write_packet(server, "");
}
if (!strcmp(name, "EnableErrorStrings")) {
write_packet(server, "OK");
}
}
static void
process_xfer(WASMGDBServer *server, const char *name, char *args)
{
const char *mode = args;
args = strchr(args, ':');
if (args)
*args++ = '\0';
if (!strcmp(name, "libraries") && !strcmp(mode, "read")) {
// TODO: how to get current wasm file name?
uint64_t addr = wasm_debug_instance_get_load_addr(
(WASMDebugInstance *)server->thread->debug_instance);
#if WASM_ENABLE_LIBC_WASI != 0
char objname[128];
wasm_debug_instance_get_current_object_name(
(WASMDebugInstance *)server->thread->debug_instance, objname, 128);
sprintf(tmpbuf,
"l<library-list><library name=\"%s\"><section "
"address=\"0x%lx\"/></library></library-list>",
objname, addr);
#else
sprintf(tmpbuf,
"l<library-list><library name=\"%s\"><section "
"address=\"0x%lx\"/></library></library-list>",
"nobody.wasm", addr);
#endif
write_packet(server, tmpbuf);
}
}
void
porcess_wasm_local(WASMGDBServer *server, char *args)
{
int frame_index;
int local_index;
char buf[16];
int size = 16;
bool ret;
sprintf(tmpbuf, "E01");
if (sscanf(args, "%d;%d", &frame_index, &local_index) == 2) {
ret = wasm_debug_instance_get_local(
(WASMDebugInstance *)server->thread->debug_instance, frame_index,
local_index, buf, &size);
if (ret && size > 0) {
mem2hex(buf, tmpbuf, size);
}
}
write_packet(server, tmpbuf);
}
void
porcess_wasm_global(WASMGDBServer *server, char *args)
{
int frame_index;
int global_index;
char buf[16];
int size = 16;
bool ret;
sprintf(tmpbuf, "E01");
if (sscanf(args, "%d;%d", &frame_index, &global_index) == 2) {
ret = wasm_debug_instance_get_global(
(WASMDebugInstance *)server->thread->debug_instance, frame_index,
global_index, buf, &size);
if (ret && size > 0) {
mem2hex(buf, tmpbuf, size);
}
}
write_packet(server, tmpbuf);
}
void
handle_generay_query(WASMGDBServer *server, char *payload)
{
const char *name;
char *args;
args = strchr(payload, ':');
if (args)
*args++ = '\0';
name = payload;
LOG_VERBOSE("%s:%s\n", __FUNCTION__, payload);
if (!strcmp(name, "C")) {
uint64_t pid, tid;
pid = wasm_debug_instance_get_pid(
(WASMDebugInstance *)server->thread->debug_instance);
tid = wasm_debug_instance_get_tid(
(WASMDebugInstance *)server->thread->debug_instance);
snprintf(tmpbuf, sizeof(tmpbuf), "QCp%lx.%lx", pid, tid);
write_packet(server, tmpbuf);
}
if (!strcmp(name, "Supported")) {
sprintf(tmpbuf, "qXfer:libraries:read+;PacketSize=%x;",
MAX_PACKET_SIZE);
write_packet(server, tmpbuf);
}
if (!strcmp(name, "Xfer")) {
name = args;
if (!args) {
LOG_ERROR("payload parse error during handle_generay_query");
return;
}
args = strchr(args, ':');
if (args) {
*args++ = '\0';
process_xfer(server, name, args);
}
}
if (!strcmp(name, "HostInfo")) {
// Todo: change vendor to Intel for outside tree
char triple[256];
mem2hex("wasm32-Ant-wasi-wasm", triple, strlen("wasm32-Ant-wasi-wasm"));
sprintf(tmpbuf,
"vendor:Ant;ostype:wasi;arch:wasm32;"
"triple:%s;endian:little;ptrsize:4;",
triple);
write_packet(server, tmpbuf);
}
if (!strcmp(name, "ModuleInfo")) {
write_packet(server, "");
}
if (!strcmp(name, "GetWorkingDir")) {
if (getcwd(tmpbuf, PATH_MAX))
write_packet(server, tmpbuf);
}
if (!strcmp(name, "QueryGDBServer")) {
write_packet(server, "");
}
if (!strcmp(name, "VAttachOrWaitSupported")) {
write_packet(server, "");
}
if (!strcmp(name, "ProcessInfo")) {
// Todo: process id parent-pid
uint64_t pid;
pid = wasm_debug_instance_get_pid(
(WASMDebugInstance *)server->thread->debug_instance);
char triple[256];
// arch-vendor-os-env(format)
mem2hex("wasm32-Ant-wasi-wasm", triple, strlen("wasm32-Ant-wasi-wasm"));
sprintf(tmpbuf,
"pid:%lx;parent-pid:%lx;vendor:Ant;ostype:wasi;arch:wasm32;"
"triple:%s;endian:little;ptrsize:4;",
pid, pid, triple);
write_packet(server, tmpbuf);
}
if (!strcmp(name, "RegisterInfo0")) {
sprintf(
tmpbuf,
"name:pc;alt-name:pc;bitsize:64;offset:0;encoding:uint;format:hex;"
"set:General Purpose Registers;gcc:16;dwarf:16;generic:pc;");
write_packet(server, tmpbuf);
}
else if (!strncmp(name, "RegisterInfo", strlen("RegisterInfo"))) {
write_packet(server, "E45");
}
if (!strcmp(name, "StructuredDataPlugins")) {
write_packet(server, "");
}
if (args && (!strcmp(name, "MemoryRegionInfo"))) {
uint64_t addr = strtol(args, NULL, 16);
WASMDebugMemoryInfo *mem_info = wasm_debug_instance_get_memregion(
(WASMDebugInstance *)server->thread->debug_instance, addr);
if (mem_info) {
char name[256];
mem2hex(mem_info->name, name, strlen(mem_info->name));
sprintf(tmpbuf, "start:%lx;size:%lx;permissions:%s;name:%s;",
(uint64)mem_info->start, mem_info->size,
mem_info->permisson, name);
write_packet(server, tmpbuf);
wasm_debug_instance_destroy_memregion(
(WASMDebugInstance *)server->thread->debug_instance, mem_info);
}
}
if (!strcmp(name, "WasmData")) {
}
if (!strcmp(name, "WasmMem")) {
}
if (!strcmp(name, "Symbol")) {
write_packet(server, "");
}
if (args && (!strcmp(name, "WasmCallStack"))) {
uint64_t tid = strtol(args, NULL, 16);
uint64_t buf[1024 / sizeof(uint64_t)];
uint64_t count = wasm_debug_instance_get_call_stack_pcs(
(WASMDebugInstance *)server->thread->debug_instance, tid, buf,
1024 / sizeof(uint64_t));
if (count > 0) {
mem2hex((char *)buf, tmpbuf, count * sizeof(uint64_t));
write_packet(server, tmpbuf);
}
else
write_packet(server, "");
}
if (args && (!strcmp(name, "WasmLocal"))) {
porcess_wasm_local(server, args);
}
if (args && (!strcmp(name, "WasmGlobal"))) {
porcess_wasm_global(server, args);
}
}
static void
send_thread_stop_status(WASMGDBServer *server, uint32_t status, uint64_t tid)
{
int tids_number, len = 0, i = 0;
uint64_t tids[20];
char pc_string[17];
uint32_t gdb_status = status;
if (status == 0) {
sprintf(tmpbuf, "W%02x", status);
write_packet(server, tmpbuf);
return;
}
tids_number = wasm_debug_instance_get_tids(
(WASMDebugInstance *)server->thread->debug_instance, tids, 20);
uint64_t pc = wasm_debug_instance_get_pc(
(WASMDebugInstance *)server->thread->debug_instance);
if (status == WAMR_SIG_SINGSTEP) {
gdb_status = WAMR_SIG_TRAP;
}
// TODO: how name a wasm thread?
len +=
sprintf(tmpbuf, "T%02xthread:%lx;name:%s;", gdb_status, tid, "nobody");
if (tids_number > 0) {
len += sprintf(tmpbuf + len, "threads:");
while (i < tids_number) {
if (i == tids_number - 1)
len += sprintf(tmpbuf + len, "%lx;", tids[i]);
else
len += sprintf(tmpbuf + len, "%lx,", tids[i]);
i++;
}
}
mem2hex((void *)&pc, pc_string, 8);
pc_string[8 * 2] = '\0';
if (status == WAMR_SIG_TRAP) {
len += sprintf(tmpbuf + len, "thread-pcs:%lx;00:%s,reason:%s;", pc,
pc_string, "breakpoint");
}
else if (status == WAMR_SIG_SINGSTEP) {
len += sprintf(tmpbuf + len, "thread-pcs:%lx;00:%s,reason:%s;", pc,
pc_string, "trace");
}
else if (status > 0) {
len += sprintf(tmpbuf + len, "thread-pcs:%lx;00:%s,reason:%s;", pc,
pc_string, "signal");
}
write_packet(server, tmpbuf);
}
void
handle_v_packet(WASMGDBServer *server, char *payload)
{
const char *name;
char *args;
uint32_t status;
args = strchr(payload, ';');
if (args)
*args++ = '\0';
name = payload;
LOG_VERBOSE("%s:%s\n", __FUNCTION__, payload);
if (!strcmp("Cont?", name))
write_packet(server, "vCont;c;C;s;S;");
if (!strcmp("Cont", name)) {
if (args && args[0] == 's') {
char *numstring = strchr(args, ':');
if (numstring) {
*numstring++ = '\0';
uint64_t tid = strtol(numstring, NULL, 16);
wasm_debug_instance_set_cur_thread(
(WASMDebugInstance *)server->thread->debug_instance, tid);
wasm_debug_instance_singlestep(
(WASMDebugInstance *)server->thread->debug_instance, tid);
tid = wasm_debug_instance_wait_thread(
(WASMDebugInstance *)server->thread->debug_instance, tid,
&status);
send_thread_stop_status(server, status, tid);
}
}
}
}
void
handle_threadstop_request(WASMGDBServer *server, char *payload)
{
uint64_t tid = wasm_debug_instance_get_tid(
(WASMDebugInstance *)server->thread->debug_instance);
uint32_t status;
tid = wasm_debug_instance_wait_thread(
(WASMDebugInstance *)server->thread->debug_instance, tid, &status);
send_thread_stop_status(server, status, tid);
}
void
handle_set_current_thread(WASMGDBServer *server, char *payload)
{
LOG_VERBOSE("%s:%s\n", __FUNCTION__, payload, payload);
if ('g' == *payload++) {
uint64_t tid;
tid = strtol(payload, NULL, 16);
if (tid > 0)
wasm_debug_instance_set_cur_thread(
(WASMDebugInstance *)server->thread->debug_instance, tid);
}
write_packet(server, "OK");
}
void
handle_get_register(WASMGDBServer *server, char *payload)
{
int i = strtol(payload, NULL, 16);
if (i != 0) {
write_packet(server, "E01");
return;
}
uint64_t regdata = wasm_debug_instance_get_pc(
(WASMDebugInstance *)server->thread->debug_instance);
mem2hex((void *)&regdata, tmpbuf, 8);
tmpbuf[8 * 2] = '\0';
write_packet(server, tmpbuf);
}
void
handle_get_json_request(WASMGDBServer *server, char *payload)
{
char *args;
args = strchr(payload, ':');
if (args)
*args++ = '\0';
write_packet(server, "");
}
void
handle_get_read_binary_memory(WASMGDBServer *server, char *payload)
{
write_packet(server, "");
}
void
handle_get_read_memory(WASMGDBServer *server, char *payload)
{
size_t maddr, mlen;
bool ret;
sprintf(tmpbuf, "%s", "");
if (sscanf(payload, "%zx,%zx", &maddr, &mlen) == 2) {
if (mlen * 2 > MAX_PACKET_SIZE) {
LOG_ERROR("Buffer overflow!");
mlen = MAX_PACKET_SIZE / 2;
}
char *buff = wasm_runtime_malloc(mlen);
if (buff) {
ret = wasm_debug_instance_get_mem(
(WASMDebugInstance *)server->thread->debug_instance, maddr,
buff, &mlen);
if (ret) {
mem2hex(buff, tmpbuf, mlen);
}
wasm_runtime_free(buff);
}
}
write_packet(server, tmpbuf);
}
void
handle_get_write_memory(WASMGDBServer *server, char *payload)
{
size_t maddr, mlen, hex_len;
int offset, act_len;
char *buff;
bool ret;
sprintf(tmpbuf, "%s", "");
if (sscanf(payload, "%zx,%zx:%n", &maddr, &mlen, &offset) == 2) {
payload += offset;
hex_len = strlen(payload);
act_len = hex_len / 2 < mlen ? hex_len / 2 : mlen;
buff = wasm_runtime_malloc(act_len);
if (buff) {
hex2mem(payload, buff, act_len);
ret = wasm_debug_instance_set_mem(
(WASMDebugInstance *)server->thread->debug_instance, maddr,
buff, &mlen);
if (ret) {
sprintf(tmpbuf, "%s", "OK");
}
wasm_runtime_free(buff);
}
}
write_packet(server, tmpbuf);
}
void
handle_add_break(WASMGDBServer *server, char *payload)
{
size_t type, addr, length;
if (sscanf(payload, "%zx,%zx,%zx", &type, &addr, &length) == 3) {
if (type == eBreakpointSoftware) {
bool ret = wasm_debug_instance_add_breakpoint(
(WASMDebugInstance *)server->thread->debug_instance, addr,
length);
if (ret)
write_packet(server, "OK");
else
write_packet(server, "E01");
return;
}
}
write_packet(server, "");
}
void
handle_remove_break(WASMGDBServer *server, char *payload)
{
size_t type, addr, length;
if (sscanf(payload, "%zx,%zx,%zx", &type, &addr, &length) == 3) {
if (type == eBreakpointSoftware) {
bool ret = wasm_debug_instance_remove_breakpoint(
(WASMDebugInstance *)server->thread->debug_instance, addr,
length);
if (ret)
write_packet(server, "OK");
else
write_packet(server, "E01");
return;
}
}
write_packet(server, "");
}
void
handle_continue_request(WASMGDBServer *server, char *payload)
{
uint64_t tid;
uint32_t status;
wasm_debug_instance_continue(
(WASMDebugInstance *)server->thread->debug_instance);
tid = wasm_debug_instance_get_tid(
(WASMDebugInstance *)server->thread->debug_instance);
tid = wasm_debug_instance_wait_thread(
(WASMDebugInstance *)server->thread->debug_instance, tid, &status);
send_thread_stop_status(server, status, tid);
}
void
handle_kill_request(WASMGDBServer *server, char *payload)
{
uint64_t tid;
uint32_t status;
wasm_debug_instance_kill(
(WASMDebugInstance *)server->thread->debug_instance);
tid = wasm_debug_instance_get_tid(
(WASMDebugInstance *)server->thread->debug_instance);
tid = wasm_debug_instance_wait_thread(
(WASMDebugInstance *)server->thread->debug_instance, tid, &status);
send_thread_stop_status(server, status, tid);
}
static void
handle_malloc(WASMGDBServer *server, char *payload)
{
char *args;
uint64_t size;
int map_port = MMAP_PROT_NONE;
uint64_t addr;
sprintf(tmpbuf, "%s", "E03");
args = strstr(payload, ",");
if (args) {
*args++ = '\0';
}
else {
LOG_ERROR("Payload parse error during handle malloc");
return;
}
size = strtol(payload, NULL, 16);
if (size > 0) {
while (*args) {
if (*args == 'r') {
map_port |= MMAP_PROT_READ;
}
if (*args == 'w') {
map_port |= MMAP_PROT_WRITE;
}
if (*args == 'x') {
map_port |= MMAP_PROT_EXEC;
}
args++;
}
addr = wasm_debug_instance_mmap(
(WASMDebugInstance *)server->thread->debug_instance, size,
map_port);
if (addr) {
sprintf(tmpbuf, "%lx", addr);
}
}
write_packet(server, tmpbuf);
}
static void
handle_free(WASMGDBServer *server, char *payload)
{
uint64_t addr;
bool ret;
sprintf(tmpbuf, "%s", "E03");
addr = strtol(payload, NULL, 16);
ret = wasm_debug_instance_ummap(
(WASMDebugInstance *)server->thread->debug_instance, addr);
if (ret) {
sprintf(tmpbuf, "%s", "OK");
}
write_packet(server, tmpbuf);
}
void
handle____request(WASMGDBServer *server, char *payload)
{
char *args;
if (payload[0] == 'M') {
args = payload + 1;
handle_malloc(server, args);
}
if (payload[0] == 'm') {
args = payload + 1;
handle_free(server, args);
}
}