Implement source debugging for interpreter and AOT (#769)
Implement source debugging feature for classic interpreter and AOT: - use `cmake -DWAMR_BUILD_DEBUG_INTERP=1` to enable interpreter debugging - use `cmake -DWAMR_BUILD_DEBUG_AOT=1` to enable AOT debugging See doc/source_debugging.md for more details.
This commit is contained in:
1011
core/iwasm/libraries/debug-engine/debug_engine.c
Normal file
1011
core/iwasm/libraries/debug-engine/debug_engine.c
Normal file
File diff suppressed because it is too large
Load Diff
12
core/iwasm/libraries/debug-engine/debug_engine.cmake
Normal file
12
core/iwasm/libraries/debug-engine/debug_engine.cmake
Normal file
@ -0,0 +1,12 @@
|
||||
# Copyright (C) 2021 Ant Group. All rights reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
set (DEBUG_ENGINE_DIR ${CMAKE_CURRENT_LIST_DIR})
|
||||
|
||||
add_definitions (-DWASM_ENABLE_DEBUG_INTERP=1)
|
||||
|
||||
include_directories(${DEBUG_ENGINE_DIR})
|
||||
|
||||
file (GLOB source_all ${DEBUG_ENGINE_DIR}/*.c)
|
||||
|
||||
set (DEBUG_ENGINE_SOURCE ${source_all})
|
||||
193
core/iwasm/libraries/debug-engine/debug_engine.h
Normal file
193
core/iwasm/libraries/debug-engine/debug_engine.h
Normal file
@ -0,0 +1,193 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Ant Group. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#ifndef _DEBUG_ENGINE_H
|
||||
#define _DEBUG_ENGINE_H
|
||||
|
||||
#include "bh_list.h"
|
||||
#include "gdbserver.h"
|
||||
#include "thread_manager.h"
|
||||
|
||||
typedef enum WASMDebugControlThreadStatus {
|
||||
RUNNING,
|
||||
STOPPED,
|
||||
} WASMDebugControlThreadStatus;
|
||||
|
||||
struct WASMDebugObject;
|
||||
typedef struct WASMDebugControlThread {
|
||||
WASMGDBServer *server;
|
||||
korp_tid tid;
|
||||
korp_mutex wait_lock;
|
||||
korp_cond wait_cond;
|
||||
char ip_addr[128];
|
||||
int port;
|
||||
WASMDebugControlThreadStatus status;
|
||||
struct WASMDebugObject *debug_engine;
|
||||
struct WASMDebugObject *debug_instance;
|
||||
} WASMDebugControlThread;
|
||||
|
||||
typedef struct WASMDebugObject {
|
||||
struct WASMDebugObject *next;
|
||||
WASMDebugControlThread *control_thread;
|
||||
} WASMDebugObject;
|
||||
|
||||
typedef struct WASMDebugBreakPoint {
|
||||
struct WASMDebugBreakPoint *next;
|
||||
uint64 addr;
|
||||
uint64 orignal_data;
|
||||
} WASMDebugBreakPoint;
|
||||
|
||||
typedef struct WASMDebugInstance {
|
||||
struct WASMDebugInstance *next;
|
||||
WASMDebugControlThread *control_thread;
|
||||
bh_list break_point_list;
|
||||
WASMCluster *cluster;
|
||||
uint32 id;
|
||||
korp_tid current_tid;
|
||||
} WASMDebugInstance;
|
||||
|
||||
typedef enum WASMDebugEventKind {
|
||||
BREAK_POINT_ADD,
|
||||
BREAK_POINT_REMOVE
|
||||
} WASMDebugEventKind;
|
||||
|
||||
typedef struct WASMDebugEvent {
|
||||
WASMDebugEventKind kind;
|
||||
unsigned char metadata[0];
|
||||
} WASMDebugEvent;
|
||||
|
||||
typedef struct WASMDebugMemoryInfo {
|
||||
uint64 start;
|
||||
uint64 size;
|
||||
char name[128];
|
||||
char permisson[4];
|
||||
} WASMDebugMemoryInfo;
|
||||
|
||||
typedef enum WasmAddressType {
|
||||
WasmMemory = 0x00,
|
||||
WasmObj = 0x01,
|
||||
WasmInvalid = 0x03
|
||||
} WasmAddressType;
|
||||
|
||||
#define WASM_ADDR(type, id, offset) \
|
||||
(((uint64)type << 62) | ((uint64)0 << 32) | ((uint64)offset << 0))
|
||||
|
||||
#define WASM_ADDR_TYPE(addr) (((addr)&0xC000000000000000) >> 62)
|
||||
#define WASM_ADDR_OFFSET(addr) (((addr)&0x00000000FFFFFFFF))
|
||||
|
||||
#define INVALIED_ADDR (0xFFFFFFFFFFFFFFFF)
|
||||
|
||||
WASMDebugInstance *
|
||||
wasm_debug_instance_create(WASMCluster *cluster);
|
||||
|
||||
void
|
||||
wasm_debug_instance_destroy(WASMCluster *cluster);
|
||||
|
||||
WASMDebugInstance *
|
||||
wasm_exec_env_get_instance(WASMExecEnv *exec_env);
|
||||
|
||||
bool
|
||||
wasm_debug_engine_init(char *ip_addr, int platform_port, int process_port);
|
||||
|
||||
void
|
||||
wasm_debug_engine_destroy();
|
||||
|
||||
void
|
||||
wasm_debug_set_engine_active(bool active);
|
||||
|
||||
bool
|
||||
wasm_debug_get_engine_active(void);
|
||||
|
||||
|
||||
uint64
|
||||
wasm_debug_instance_get_pid(WASMDebugInstance *instance);
|
||||
|
||||
uint64
|
||||
wasm_debug_instance_get_tid(WASMDebugInstance *instance);
|
||||
|
||||
int
|
||||
wasm_debug_instance_get_tids(WASMDebugInstance *instance,
|
||||
uint64 tids[], int len);
|
||||
|
||||
void
|
||||
wasm_debug_instance_set_cur_thread(WASMDebugInstance *instance, uint64 tid);
|
||||
|
||||
uint64
|
||||
wasm_debug_instance_get_pc(WASMDebugInstance *instance);
|
||||
|
||||
uint64
|
||||
wasm_debug_instance_get_load_addr(WASMDebugInstance *instance);
|
||||
|
||||
WASMDebugMemoryInfo *
|
||||
wasm_debug_instance_get_memregion(WASMDebugInstance *instance, uint64 addr);
|
||||
|
||||
void
|
||||
wasm_debug_instance_destroy_memregion(WASMDebugInstance *instance,
|
||||
WASMDebugMemoryInfo *mem_info);
|
||||
|
||||
bool
|
||||
wasm_debug_instance_get_obj_mem(WASMDebugInstance *instance,
|
||||
uint64 addr, char *buf, uint64 *size);
|
||||
|
||||
bool
|
||||
wasm_debug_instance_get_linear_mem(WASMDebugInstance *instance,
|
||||
uint64 addr, char *buf, uint64 *size);
|
||||
|
||||
bool
|
||||
wasm_debug_instance_get_mem(WASMDebugInstance *instance,
|
||||
uint64 addr, char *buf, uint64 *size);
|
||||
|
||||
bool
|
||||
wasm_debug_instance_set_mem(WASMDebugInstance *instance,
|
||||
uint64 addr, char *buf, uint64 *size);
|
||||
|
||||
int
|
||||
wasm_debug_instance_get_call_stack_pcs(WASMDebugInstance *instance,
|
||||
uint64 tid, uint64 buf[], uint64 size);
|
||||
|
||||
bool
|
||||
wasm_debug_instance_add_breakpoint(WASMDebugInstance *instance,
|
||||
uint64 addr, uint64 length);
|
||||
|
||||
bool
|
||||
wasm_debug_instance_remove_breakpoint(WASMDebugInstance *instance,
|
||||
uint64 addr, uint64 length);
|
||||
|
||||
bool
|
||||
wasm_debug_instance_continue(WASMDebugInstance *instance);
|
||||
|
||||
bool
|
||||
wasm_debug_instance_kill(WASMDebugInstance *instance);
|
||||
|
||||
uint64
|
||||
wasm_debug_instance_wait_thread(WASMDebugInstance *instance,
|
||||
uint64 tid, uint32 *status);
|
||||
|
||||
bool
|
||||
wasm_debug_instance_singlestep(WASMDebugInstance *instance, uint64 tid);
|
||||
|
||||
bool
|
||||
wasm_debug_instance_get_local(WASMDebugInstance *instance,
|
||||
int frame_index, int local_index,
|
||||
char buf[], int *size);
|
||||
|
||||
bool
|
||||
wasm_debug_instance_get_global(WASMDebugInstance *instance,
|
||||
int frame_index, int global_index,
|
||||
char buf[], int *size);
|
||||
|
||||
#if WASM_ENABLE_LIBC_WASI != 0
|
||||
bool
|
||||
wasm_debug_instance_get_current_object_name(WASMDebugInstance *instance,
|
||||
char name_buffer[], int len);
|
||||
#endif
|
||||
|
||||
uint64
|
||||
wasm_debug_instance_mmap(WASMDebugInstance *instance,
|
||||
uint32 size, int map_port);
|
||||
|
||||
bool
|
||||
wasm_debug_instance_ummap(WASMDebugInstance *instance, uint64 addr);
|
||||
#endif
|
||||
177
core/iwasm/libraries/debug-engine/gdbserver.c
Normal file
177
core/iwasm/libraries/debug-engine/gdbserver.c
Normal file
@ -0,0 +1,177 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Ant Group. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#include "gdbserver.h"
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <fcntl.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <signal.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/poll.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "bh_log.h"
|
||||
#include "handler.h"
|
||||
#include "packets.h"
|
||||
#include "utils.h"
|
||||
|
||||
typedef void (*PacketHandler)(WASMGDBServer *server, char *payload);
|
||||
|
||||
struct packet_handler_elem {
|
||||
char request;
|
||||
PacketHandler handler;
|
||||
};
|
||||
|
||||
#define DEL_HANDLER(r, h) [r] = { .request = r, .handler = h }
|
||||
|
||||
static struct packet_handler_elem packet_handler_table[255] = {
|
||||
DEL_HANDLER('Q', handle_generay_set),
|
||||
DEL_HANDLER('q', handle_generay_query),
|
||||
DEL_HANDLER('v', handle_v_packet),
|
||||
DEL_HANDLER('?', handle_threadstop_request),
|
||||
DEL_HANDLER('H', handle_set_current_thread),
|
||||
DEL_HANDLER('p', handle_get_register),
|
||||
DEL_HANDLER('j', handle_get_json_request),
|
||||
DEL_HANDLER('m', handle_get_read_memory),
|
||||
DEL_HANDLER('M', handle_get_write_memory),
|
||||
DEL_HANDLER('x', handle_get_read_binary_memory),
|
||||
DEL_HANDLER('Z', handle_add_break),
|
||||
DEL_HANDLER('z', handle_remove_break),
|
||||
DEL_HANDLER('c', handle_continue_request),
|
||||
DEL_HANDLER('k', handle_kill_request),
|
||||
DEL_HANDLER('_', handle____request),
|
||||
};
|
||||
|
||||
WASMGDBServer *
|
||||
wasm_launch_gdbserver(char *host, int port)
|
||||
{
|
||||
int listen_fd = -1;
|
||||
const int one = 1;
|
||||
struct sockaddr_in addr;
|
||||
int ret;
|
||||
int sockt_fd = 0;
|
||||
|
||||
WASMGDBServer *server;
|
||||
|
||||
if (!(server = wasm_runtime_malloc(sizeof(WASMGDBServer)))) {
|
||||
LOG_ERROR("wasm gdb server error: failed to allocate memory");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
listen_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (listen_fd < 0) {
|
||||
LOG_ERROR("wasm gdb server error: socket() failed");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = fcntl(listen_fd, F_SETFD, FD_CLOEXEC);
|
||||
if(ret < 0) {
|
||||
LOG_ERROR("wasm gdb server error: fcntl() failed on setting FD_CLOEXEC");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
|
||||
if (ret < 0) {
|
||||
LOG_ERROR("wasm gdb server error: setsockopt() failed");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
LOG_VERBOSE("Listening on %s:%d\n", host, port);
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr.s_addr = inet_addr(host);
|
||||
addr.sin_port = htons(port);
|
||||
|
||||
ret = bind(listen_fd, (struct sockaddr *)&addr, sizeof(addr));
|
||||
if (ret < 0) {
|
||||
LOG_ERROR("wasm gdb server error: bind() failed");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = listen(listen_fd, 1);
|
||||
if (ret < 0) {
|
||||
LOG_ERROR("wasm gdb server error: listen() failed");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
server->listen_fd = listen_fd;
|
||||
|
||||
sockt_fd = accept(listen_fd, NULL, NULL);
|
||||
if (sockt_fd < 0) {
|
||||
LOG_ERROR("wasm gdb server error: accept() failed");
|
||||
goto fail;
|
||||
}
|
||||
LOG_VERBOSE("accept gdb client");
|
||||
server->socket_fd = sockt_fd;
|
||||
server->noack = false;
|
||||
return server;
|
||||
|
||||
fail:
|
||||
if (listen_fd > 0) {
|
||||
shutdown(listen_fd, SHUT_RDWR);
|
||||
close(listen_fd);
|
||||
}
|
||||
if (server)
|
||||
wasm_runtime_free(server);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
wasm_close_gdbserver(WASMGDBServer *server)
|
||||
{
|
||||
if (server->socket_fd > 0) {
|
||||
shutdown(server->socket_fd, SHUT_RDWR);
|
||||
close(server->socket_fd);
|
||||
}
|
||||
if (server->listen_fd > 0) {
|
||||
shutdown(server->listen_fd, SHUT_RDWR);
|
||||
close(server->listen_fd);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
handler_packet(WASMGDBServer *server, char request, char *payload)
|
||||
{
|
||||
if (packet_handler_table[(int)request].handler != NULL)
|
||||
packet_handler_table[(int)request].handler(server, payload);
|
||||
}
|
||||
|
||||
static void
|
||||
process_packet(WASMGDBServer *server)
|
||||
{
|
||||
uint8_t *inbuf = server->pkt.buf;
|
||||
int inbuf_size = server->pkt.end;
|
||||
uint8_t *packetend_ptr = (uint8_t *)memchr(inbuf, '#', inbuf_size);
|
||||
int packetend = packetend_ptr - inbuf;
|
||||
bh_assert('$' == inbuf[0]);
|
||||
char request = inbuf[1];
|
||||
char *payload = (char *)&inbuf[2];
|
||||
inbuf[packetend] = '\0';
|
||||
|
||||
uint8_t checksum = 0;
|
||||
for (int i = 1; i < packetend; i++)
|
||||
checksum += inbuf[i];
|
||||
bh_assert(checksum
|
||||
== (hex(inbuf[packetend + 1]) << 4 | hex(inbuf[packetend + 2])));
|
||||
|
||||
LOG_VERBOSE("receive request:%c %s\n", request, payload);
|
||||
handler_packet(server, request, payload);
|
||||
inbuf_erase_head(server, packetend + 3);
|
||||
}
|
||||
|
||||
bool
|
||||
wasm_gdbserver_handle_packet(WASMGDBServer *server)
|
||||
{
|
||||
bool ret;
|
||||
ret = read_packet(server);
|
||||
if (ret)
|
||||
process_packet(server);
|
||||
return ret;
|
||||
}
|
||||
43
core/iwasm/libraries/debug-engine/gdbserver.h
Normal file
43
core/iwasm/libraries/debug-engine/gdbserver.h
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Ant Group. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#ifndef _GDB_SERVER_H
|
||||
#define _GDB_SERVER_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#define PACKET_BUF_SIZE 0x8000
|
||||
|
||||
enum GDBStoppointType {
|
||||
eStoppointInvalid = -1,
|
||||
eBreakpointSoftware = 0,
|
||||
eBreakpointHardware,
|
||||
eWatchpointWrite,
|
||||
eWatchpointRead,
|
||||
eWatchpointReadWrite
|
||||
};
|
||||
typedef struct WasmDebugPacket {
|
||||
unsigned char buf[PACKET_BUF_SIZE];
|
||||
unsigned int end;
|
||||
} WasmDebugPacket;
|
||||
|
||||
struct WASMDebugControlThread;
|
||||
typedef struct WASMGDBServer {
|
||||
int listen_fd;
|
||||
int socket_fd;
|
||||
WasmDebugPacket pkt;
|
||||
bool noack;
|
||||
struct WASMDebugControlThread *thread;
|
||||
} WASMGDBServer;
|
||||
|
||||
WASMGDBServer *
|
||||
wasm_launch_gdbserver(char *addr, int port);
|
||||
|
||||
void
|
||||
wasm_close_gdbserver(WASMGDBServer *server);
|
||||
|
||||
bool
|
||||
wasm_gdbserver_handle_packet(WASMGDBServer *server);
|
||||
#endif
|
||||
598
core/iwasm/libraries/debug-engine/handler.c
Normal file
598
core/iwasm/libraries/debug-engine/handler.c
Normal file
@ -0,0 +1,598 @@
|
||||
/*
|
||||
* 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, ':');
|
||||
*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;
|
||||
args = strchr(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, "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 (!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 (!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 (!strcmp(name, "WasmLocal")) {
|
||||
porcess_wasm_local(server, args);
|
||||
}
|
||||
|
||||
if (!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[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 *)®data, 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';
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
55
core/iwasm/libraries/debug-engine/handler.h
Normal file
55
core/iwasm/libraries/debug-engine/handler.h
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Ant Group. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#ifndef HANDLER_H
|
||||
#define HANDLER_H
|
||||
|
||||
#include "gdbserver.h"
|
||||
|
||||
void
|
||||
handle_generay_set(WASMGDBServer *server, char *payload);
|
||||
|
||||
void
|
||||
handle_generay_query(WASMGDBServer *server, char *payload);
|
||||
|
||||
void
|
||||
handle_v_packet(WASMGDBServer *server, char *payload);
|
||||
|
||||
void
|
||||
handle_threadstop_request(WASMGDBServer *server, char *payload);
|
||||
|
||||
void
|
||||
handle_set_current_thread(WASMGDBServer *server, char *payload);
|
||||
|
||||
void
|
||||
handle_get_register(WASMGDBServer *server, char *payload);
|
||||
|
||||
void
|
||||
handle_get_json_request(WASMGDBServer *server, char *payload);
|
||||
|
||||
void
|
||||
handle_get_read_binary_memory(WASMGDBServer *server, char *payload);
|
||||
|
||||
void
|
||||
handle_get_read_memory(WASMGDBServer *server, char *payload);
|
||||
|
||||
void
|
||||
handle_get_write_memory(WASMGDBServer *server, char *payload);
|
||||
|
||||
void
|
||||
handle_add_break(WASMGDBServer *server, char *payload);
|
||||
|
||||
void
|
||||
handle_remove_break(WASMGDBServer *server, char *payload);
|
||||
|
||||
void
|
||||
handle_continue_request(WASMGDBServer *server, char *payload);
|
||||
|
||||
void
|
||||
handle_kill_request(WASMGDBServer *server, char *payload);
|
||||
|
||||
void
|
||||
handle____request(WASMGDBServer *server, char *payload);
|
||||
#endif
|
||||
173
core/iwasm/libraries/debug-engine/packets.c
Normal file
173
core/iwasm/libraries/debug-engine/packets.c
Normal file
@ -0,0 +1,173 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Ant Group. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#include "packets.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "bh_log.h"
|
||||
#include "gdbserver.h"
|
||||
|
||||
void
|
||||
pktbuf_insert(WASMGDBServer *gdbserver, const uint8_t *buf, ssize_t len)
|
||||
{
|
||||
WasmDebugPacket *pkt = &gdbserver->pkt;
|
||||
|
||||
if ((unsigned long)(pkt->end + len) >= sizeof(pkt->buf)) {
|
||||
LOG_ERROR("Packet buffer overflow");
|
||||
exit(-2);
|
||||
}
|
||||
memcpy(pkt->buf + pkt->end, buf, len);
|
||||
pkt->end += len;
|
||||
}
|
||||
|
||||
void
|
||||
pktbuf_erase_head(WASMGDBServer *gdbserver, ssize_t end)
|
||||
{
|
||||
WasmDebugPacket *pkt = &gdbserver->pkt;
|
||||
memmove(pkt->buf, pkt->buf + end, pkt->end - end);
|
||||
pkt->end -= end;
|
||||
}
|
||||
|
||||
void
|
||||
inbuf_erase_head(WASMGDBServer *gdbserver, ssize_t end)
|
||||
{
|
||||
pktbuf_erase_head(gdbserver, end);
|
||||
}
|
||||
|
||||
void
|
||||
pktbuf_clear(WASMGDBServer *gdbserver)
|
||||
{
|
||||
WasmDebugPacket *pkt = &gdbserver->pkt;
|
||||
pkt->end = 0;
|
||||
}
|
||||
|
||||
int
|
||||
read_data_once(WASMGDBServer *gdbserver)
|
||||
{
|
||||
ssize_t nread;
|
||||
uint8_t buf[4096];
|
||||
|
||||
nread = read(gdbserver->socket_fd, buf, sizeof(buf));
|
||||
if (nread <= 0) {
|
||||
LOG_ERROR("Connection closed");
|
||||
return -1;
|
||||
}
|
||||
pktbuf_insert(gdbserver, buf, nread);
|
||||
return nread;
|
||||
}
|
||||
|
||||
void
|
||||
write_data_raw(WASMGDBServer *gdbserver, const uint8_t *data, ssize_t len)
|
||||
{
|
||||
ssize_t nwritten;
|
||||
|
||||
nwritten = write(gdbserver->socket_fd, data, len);
|
||||
if (nwritten < 0) {
|
||||
LOG_ERROR("Write error\n");
|
||||
exit(-2);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
write_hex(WASMGDBServer *gdbserver, unsigned long hex)
|
||||
{
|
||||
char buf[32];
|
||||
size_t len;
|
||||
|
||||
len = snprintf(buf, sizeof(buf) - 1, "%02lx", hex);
|
||||
write_data_raw(gdbserver, (uint8_t *)buf, len);
|
||||
}
|
||||
|
||||
void
|
||||
write_packet_bytes(WASMGDBServer *gdbserver,
|
||||
const uint8_t *data,
|
||||
size_t num_bytes)
|
||||
{
|
||||
uint8_t checksum;
|
||||
size_t i;
|
||||
|
||||
write_data_raw(gdbserver, (uint8_t *)"$", 1);
|
||||
for (i = 0, checksum = 0; i < num_bytes; ++i)
|
||||
checksum += data[i];
|
||||
write_data_raw(gdbserver, (uint8_t *)data, num_bytes);
|
||||
write_data_raw(gdbserver, (uint8_t *)"#", 1);
|
||||
write_hex(gdbserver, checksum);
|
||||
}
|
||||
|
||||
void
|
||||
write_packet(WASMGDBServer *gdbserver, const char *data)
|
||||
{
|
||||
LOG_VERBOSE("send replay:%s", data);
|
||||
write_packet_bytes(gdbserver, (const uint8_t *)data, strlen(data));
|
||||
}
|
||||
|
||||
void
|
||||
write_binary_packet(WASMGDBServer *gdbserver,
|
||||
const char *pfx,
|
||||
const uint8_t *data,
|
||||
ssize_t num_bytes)
|
||||
{
|
||||
uint8_t *buf;
|
||||
ssize_t pfx_num_chars = strlen(pfx);
|
||||
ssize_t buf_num_bytes = 0;
|
||||
int i;
|
||||
|
||||
buf = malloc(2 * num_bytes + pfx_num_chars);
|
||||
memcpy(buf, pfx, pfx_num_chars);
|
||||
buf_num_bytes += pfx_num_chars;
|
||||
|
||||
for (i = 0; i < num_bytes; ++i) {
|
||||
uint8_t b = data[i];
|
||||
switch (b) {
|
||||
case '#':
|
||||
case '$':
|
||||
case '}':
|
||||
case '*':
|
||||
buf[buf_num_bytes++] = '}';
|
||||
buf[buf_num_bytes++] = b ^ 0x20;
|
||||
break;
|
||||
default:
|
||||
buf[buf_num_bytes++] = b;
|
||||
break;
|
||||
}
|
||||
}
|
||||
write_packet_bytes(gdbserver, buf, buf_num_bytes);
|
||||
free(buf);
|
||||
}
|
||||
|
||||
bool
|
||||
skip_to_packet_start(WASMGDBServer *gdbserver)
|
||||
{
|
||||
ssize_t end = -1;
|
||||
|
||||
for (size_t i = 0; i < gdbserver->pkt.end; ++i)
|
||||
if (gdbserver->pkt.buf[i] == '$') {
|
||||
end = i;
|
||||
break;
|
||||
}
|
||||
|
||||
if (end < 0) {
|
||||
pktbuf_clear(gdbserver);
|
||||
return false;
|
||||
}
|
||||
|
||||
pktbuf_erase_head(gdbserver, end);
|
||||
bh_assert(1 <= gdbserver->pkt.end);
|
||||
bh_assert('$' == gdbserver->pkt.buf[0]);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
read_packet(WASMGDBServer *gdbserver)
|
||||
{
|
||||
while (!skip_to_packet_start(gdbserver)) {
|
||||
if(read_data_once(gdbserver) < 0)
|
||||
return false;
|
||||
}
|
||||
if (!gdbserver->noack)
|
||||
write_data_raw(gdbserver, (uint8_t *)"+", 1);
|
||||
return true;
|
||||
}
|
||||
22
core/iwasm/libraries/debug-engine/packets.h
Normal file
22
core/iwasm/libraries/debug-engine/packets.h
Normal file
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Ant Group. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#ifndef PACKETS_H
|
||||
#define PACKETS_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include "gdbserver.h"
|
||||
|
||||
bool
|
||||
read_packet(WASMGDBServer *gdbserver);
|
||||
|
||||
void
|
||||
write_packet(WASMGDBServer *gdbserver, const char *data);
|
||||
|
||||
void
|
||||
inbuf_erase_head(WASMGDBServer *gdbserver, ssize_t end);
|
||||
|
||||
#endif
|
||||
45
core/iwasm/libraries/debug-engine/utils.c
Normal file
45
core/iwasm/libraries/debug-engine/utils.c
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Ant Group. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
int
|
||||
hex(char ch)
|
||||
{
|
||||
if ((ch >= 'a') && (ch <= 'f'))
|
||||
return (ch - 'a' + 10);
|
||||
if ((ch >= '0') && (ch <= '9'))
|
||||
return (ch - '0');
|
||||
if ((ch >= 'A') && (ch <= 'F'))
|
||||
return (ch - 'A' + 10);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
char *
|
||||
mem2hex(char *mem, char *buf, int count)
|
||||
{
|
||||
unsigned char ch;
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
ch = *(mem++);
|
||||
*buf++ = hexchars[ch >> 4];
|
||||
*buf++ = hexchars[ch % 16];
|
||||
}
|
||||
*buf = 0;
|
||||
return (buf);
|
||||
}
|
||||
|
||||
char *
|
||||
hex2mem(char *buf, char *mem, int count)
|
||||
{
|
||||
unsigned char ch;
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
ch = hex(*buf++) << 4;
|
||||
ch = ch + hex(*buf++);
|
||||
*(mem++) = ch;
|
||||
}
|
||||
return (mem);
|
||||
}
|
||||
23
core/iwasm/libraries/debug-engine/utils.h
Normal file
23
core/iwasm/libraries/debug-engine/utils.h
Normal file
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Ant Group. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#ifndef UTILS_H
|
||||
#define UTILS_H
|
||||
|
||||
static const char hexchars[] = "0123456789abcdef";
|
||||
|
||||
int
|
||||
hex(char ch);
|
||||
|
||||
char *
|
||||
mem2hex(char *mem, char *buf, int count);
|
||||
|
||||
char *
|
||||
hex2mem(char *buf, char *mem, int count);
|
||||
|
||||
int
|
||||
unescape(char *msg, int len);
|
||||
|
||||
#endif /* UTILS_H */
|
||||
Reference in New Issue
Block a user