/* * Copyright (C) 2021 Ant Group. All rights reserved. * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception */ #include #include #include #include #include #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
", objname, addr); #else sprintf(tmpbuf, "l
", "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, "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 *)®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'; } 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); } }