handler.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646
  1. /*
  2. * Copyright (C) 2021 Ant Group. All rights reserved.
  3. * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. */
  5. #include <bh_log.h>
  6. #include <handler.h>
  7. #include <limits.h>
  8. #include <string.h>
  9. #include <unistd.h>
  10. #include "debug_engine.h"
  11. #include "packets.h"
  12. #include "utils.h"
  13. #include "wasm_runtime.h"
  14. #define MAX_PACKET_SIZE (0x20000)
  15. static char tmpbuf[MAX_PACKET_SIZE];
  16. static void
  17. send_thread_stop_status(WASMGDBServer *server, uint32_t status, uint64_t tid);
  18. void
  19. handle_generay_set(WASMGDBServer *server, char *payload)
  20. {
  21. const char *name;
  22. char *args;
  23. args = strchr(payload, ':');
  24. if (args)
  25. *args++ = '\0';
  26. name = payload;
  27. LOG_VERBOSE("%s:%s\n", __FUNCTION__, payload);
  28. if (!strcmp(name, "StartNoAckMode")) {
  29. server->noack = true;
  30. write_packet(server, "OK");
  31. }
  32. if (!strcmp(name, "ThreadSuffixSupported")) {
  33. write_packet(server, "");
  34. }
  35. if (!strcmp(name, "ListThreadsInStopReply")) {
  36. write_packet(server, "");
  37. }
  38. if (!strcmp(name, "EnableErrorStrings")) {
  39. write_packet(server, "OK");
  40. }
  41. }
  42. static void
  43. process_xfer(WASMGDBServer *server, const char *name, char *args)
  44. {
  45. const char *mode = args;
  46. args = strchr(args, ':');
  47. if (args)
  48. *args++ = '\0';
  49. if (!strcmp(name, "libraries") && !strcmp(mode, "read")) {
  50. // TODO: how to get current wasm file name?
  51. uint64_t addr = wasm_debug_instance_get_load_addr(
  52. (WASMDebugInstance *)server->thread->debug_instance);
  53. #if WASM_ENABLE_LIBC_WASI != 0
  54. char objname[128];
  55. wasm_debug_instance_get_current_object_name(
  56. (WASMDebugInstance *)server->thread->debug_instance, objname, 128);
  57. sprintf(tmpbuf,
  58. "l<library-list><library name=\"%s\"><section "
  59. "address=\"0x%lx\"/></library></library-list>",
  60. objname, addr);
  61. #else
  62. sprintf(tmpbuf,
  63. "l<library-list><library name=\"%s\"><section "
  64. "address=\"0x%lx\"/></library></library-list>",
  65. "nobody.wasm", addr);
  66. #endif
  67. write_packet(server, tmpbuf);
  68. }
  69. }
  70. void
  71. porcess_wasm_local(WASMGDBServer *server, char *args)
  72. {
  73. int frame_index;
  74. int local_index;
  75. char buf[16];
  76. int size = 16;
  77. bool ret;
  78. sprintf(tmpbuf, "E01");
  79. if (sscanf(args, "%d;%d", &frame_index, &local_index) == 2) {
  80. ret = wasm_debug_instance_get_local(
  81. (WASMDebugInstance *)server->thread->debug_instance, frame_index,
  82. local_index, buf, &size);
  83. if (ret && size > 0) {
  84. mem2hex(buf, tmpbuf, size);
  85. }
  86. }
  87. write_packet(server, tmpbuf);
  88. }
  89. void
  90. porcess_wasm_global(WASMGDBServer *server, char *args)
  91. {
  92. int frame_index;
  93. int global_index;
  94. char buf[16];
  95. int size = 16;
  96. bool ret;
  97. sprintf(tmpbuf, "E01");
  98. if (sscanf(args, "%d;%d", &frame_index, &global_index) == 2) {
  99. ret = wasm_debug_instance_get_global(
  100. (WASMDebugInstance *)server->thread->debug_instance, frame_index,
  101. global_index, buf, &size);
  102. if (ret && size > 0) {
  103. mem2hex(buf, tmpbuf, size);
  104. }
  105. }
  106. write_packet(server, tmpbuf);
  107. }
  108. void
  109. handle_generay_query(WASMGDBServer *server, char *payload)
  110. {
  111. const char *name;
  112. char *args;
  113. args = strchr(payload, ':');
  114. if (args)
  115. *args++ = '\0';
  116. name = payload;
  117. LOG_VERBOSE("%s:%s\n", __FUNCTION__, payload);
  118. if (!strcmp(name, "C")) {
  119. uint64_t pid, tid;
  120. pid = wasm_debug_instance_get_pid(
  121. (WASMDebugInstance *)server->thread->debug_instance);
  122. tid = wasm_debug_instance_get_tid(
  123. (WASMDebugInstance *)server->thread->debug_instance);
  124. snprintf(tmpbuf, sizeof(tmpbuf), "QCp%lx.%lx", pid, tid);
  125. write_packet(server, tmpbuf);
  126. }
  127. if (!strcmp(name, "Supported")) {
  128. sprintf(tmpbuf, "qXfer:libraries:read+;PacketSize=%x;",
  129. MAX_PACKET_SIZE);
  130. write_packet(server, tmpbuf);
  131. }
  132. if (!strcmp(name, "Xfer")) {
  133. name = args;
  134. if (!args) {
  135. LOG_ERROR("payload parse error during handle_generay_query");
  136. return;
  137. }
  138. args = strchr(args, ':');
  139. if (args) {
  140. *args++ = '\0';
  141. process_xfer(server, name, args);
  142. }
  143. }
  144. if (!strcmp(name, "HostInfo")) {
  145. // Todo: change vendor to Intel for outside tree?
  146. char triple[256];
  147. mem2hex("wasm32-Ant-wasi-wasm", triple, strlen("wasm32-Ant-wasi-wasm"));
  148. sprintf(tmpbuf,
  149. "vendor:Ant;ostype:wasi;arch:wasm32;"
  150. "triple:%s;endian:little;ptrsize:4;",
  151. triple);
  152. write_packet(server, tmpbuf);
  153. }
  154. if (!strcmp(name, "ModuleInfo")) {
  155. write_packet(server, "");
  156. }
  157. if (!strcmp(name, "GetWorkingDir")) {
  158. if (getcwd(tmpbuf, PATH_MAX))
  159. write_packet(server, tmpbuf);
  160. }
  161. if (!strcmp(name, "QueryGDBServer")) {
  162. write_packet(server, "");
  163. }
  164. if (!strcmp(name, "VAttachOrWaitSupported")) {
  165. write_packet(server, "");
  166. }
  167. if (!strcmp(name, "ProcessInfo")) {
  168. // Todo: process id parent-pid
  169. uint64_t pid;
  170. pid = wasm_debug_instance_get_pid(
  171. (WASMDebugInstance *)server->thread->debug_instance);
  172. char triple[256];
  173. // arch-vendor-os-env(format)
  174. mem2hex("wasm32-Ant-wasi-wasm", triple, strlen("wasm32-Ant-wasi-wasm"));
  175. sprintf(tmpbuf,
  176. "pid:%lx;parent-pid:%lx;vendor:Ant;ostype:wasi;arch:wasm32;"
  177. "triple:%s;endian:little;ptrsize:4;",
  178. pid, pid, triple);
  179. write_packet(server, tmpbuf);
  180. }
  181. if (!strcmp(name, "RegisterInfo0")) {
  182. sprintf(
  183. tmpbuf,
  184. "name:pc;alt-name:pc;bitsize:64;offset:0;encoding:uint;format:hex;"
  185. "set:General Purpose Registers;gcc:16;dwarf:16;generic:pc;");
  186. write_packet(server, tmpbuf);
  187. }
  188. else if (!strncmp(name, "RegisterInfo", strlen("RegisterInfo"))) {
  189. write_packet(server, "E45");
  190. }
  191. if (!strcmp(name, "StructuredDataPlugins")) {
  192. write_packet(server, "");
  193. }
  194. if (args && (!strcmp(name, "MemoryRegionInfo"))) {
  195. uint64_t addr = strtol(args, NULL, 16);
  196. WASMDebugMemoryInfo *mem_info = wasm_debug_instance_get_memregion(
  197. (WASMDebugInstance *)server->thread->debug_instance, addr);
  198. if (mem_info) {
  199. char name_buf[256];
  200. mem2hex(mem_info->name, name_buf, strlen(mem_info->name));
  201. sprintf(tmpbuf, "start:%lx;size:%lx;permissions:%s;name:%s;",
  202. (uint64)mem_info->start, mem_info->size,
  203. mem_info->permisson, name_buf);
  204. write_packet(server, tmpbuf);
  205. wasm_debug_instance_destroy_memregion(
  206. (WASMDebugInstance *)server->thread->debug_instance, mem_info);
  207. }
  208. }
  209. if (!strcmp(name, "WasmData")) {
  210. }
  211. if (!strcmp(name, "WasmMem")) {
  212. }
  213. if (!strcmp(name, "Symbol")) {
  214. write_packet(server, "");
  215. }
  216. if (args && (!strcmp(name, "WasmCallStack"))) {
  217. uint64_t tid = strtol(args, NULL, 16);
  218. uint64_t buf[1024 / sizeof(uint64_t)];
  219. uint64_t count = wasm_debug_instance_get_call_stack_pcs(
  220. (WASMDebugInstance *)server->thread->debug_instance, tid, buf,
  221. 1024 / sizeof(uint64_t));
  222. if (count > 0) {
  223. mem2hex((char *)buf, tmpbuf, count * sizeof(uint64_t));
  224. write_packet(server, tmpbuf);
  225. }
  226. else
  227. write_packet(server, "");
  228. }
  229. if (args && (!strcmp(name, "WasmLocal"))) {
  230. porcess_wasm_local(server, args);
  231. }
  232. if (args && (!strcmp(name, "WasmGlobal"))) {
  233. porcess_wasm_global(server, args);
  234. }
  235. if (!strcmp(name, "Offsets")) {
  236. write_packet(server, "");
  237. }
  238. if (!strncmp(name, "ThreadStopInfo", strlen("ThreadStopInfo"))) {
  239. int32 prefix_len = strlen("ThreadStopInfo");
  240. uint64 tid = strtol(name + prefix_len, NULL, 16);
  241. uint32 status = wasm_debug_instance_get_thread_status(
  242. server->thread->debug_instance, tid);
  243. send_thread_stop_status(server, status, tid);
  244. }
  245. }
  246. static void
  247. send_thread_stop_status(WASMGDBServer *server, uint32_t status, uint64_t tid)
  248. {
  249. int tids_number, len = 0, i = 0;
  250. uint64_t tids[20];
  251. char pc_string[17];
  252. uint32_t gdb_status = status;
  253. if (status == 0) {
  254. sprintf(tmpbuf, "W%02x", status);
  255. write_packet(server, tmpbuf);
  256. return;
  257. }
  258. tids_number = wasm_debug_instance_get_tids(
  259. (WASMDebugInstance *)server->thread->debug_instance, tids, 20);
  260. uint64_t pc = wasm_debug_instance_get_pc(
  261. (WASMDebugInstance *)server->thread->debug_instance);
  262. if (status == WAMR_SIG_SINGSTEP) {
  263. gdb_status = WAMR_SIG_TRAP;
  264. }
  265. // TODO: how name a wasm thread?
  266. len +=
  267. sprintf(tmpbuf, "T%02xthread:%lx;name:%s;", gdb_status, tid, "nobody");
  268. if (tids_number > 0) {
  269. len += sprintf(tmpbuf + len, "threads:");
  270. while (i < tids_number) {
  271. if (i == tids_number - 1)
  272. len += sprintf(tmpbuf + len, "%lx;", tids[i]);
  273. else
  274. len += sprintf(tmpbuf + len, "%lx,", tids[i]);
  275. i++;
  276. }
  277. }
  278. mem2hex((void *)&pc, pc_string, 8);
  279. pc_string[8 * 2] = '\0';
  280. if (status == WAMR_SIG_TRAP) {
  281. len += sprintf(tmpbuf + len, "thread-pcs:%lx;00:%s,reason:%s;", pc,
  282. pc_string, "breakpoint");
  283. }
  284. else if (status == WAMR_SIG_SINGSTEP) {
  285. len += sprintf(tmpbuf + len, "thread-pcs:%lx;00:%s,reason:%s;", pc,
  286. pc_string, "trace");
  287. }
  288. else if (status > 0) {
  289. len += sprintf(tmpbuf + len, "thread-pcs:%lx;00:%s,reason:%s;", pc,
  290. pc_string, "signal");
  291. }
  292. write_packet(server, tmpbuf);
  293. }
  294. void
  295. handle_v_packet(WASMGDBServer *server, char *payload)
  296. {
  297. const char *name;
  298. char *args;
  299. uint32_t status;
  300. args = strchr(payload, ';');
  301. if (args)
  302. *args++ = '\0';
  303. name = payload;
  304. LOG_VERBOSE("%s:%s\n", __FUNCTION__, payload);
  305. if (!strcmp("Cont?", name))
  306. write_packet(server, "vCont;c;C;s;S;");
  307. if (!strcmp("Cont", name)) {
  308. if (args) {
  309. if (args[0] == 's' || args[0] == 'c') {
  310. char *numstring = strchr(args, ':');
  311. if (numstring) {
  312. *numstring++ = '\0';
  313. uint64_t tid = strtol(numstring, NULL, 16);
  314. wasm_debug_instance_set_cur_thread(
  315. (WASMDebugInstance *)server->thread->debug_instance,
  316. tid);
  317. if (args[0] == 's') {
  318. wasm_debug_instance_singlestep(
  319. (WASMDebugInstance *)server->thread->debug_instance,
  320. tid);
  321. }
  322. else {
  323. wasm_debug_instance_continue(
  324. (WASMDebugInstance *)
  325. server->thread->debug_instance);
  326. }
  327. tid = wasm_debug_instance_wait_thread(
  328. (WASMDebugInstance *)server->thread->debug_instance,
  329. tid, &status);
  330. send_thread_stop_status(server, status, tid);
  331. }
  332. }
  333. }
  334. }
  335. }
  336. void
  337. handle_threadstop_request(WASMGDBServer *server, char *payload)
  338. {
  339. uint64_t tid = wasm_debug_instance_get_tid(
  340. (WASMDebugInstance *)server->thread->debug_instance);
  341. uint32_t status;
  342. tid = wasm_debug_instance_wait_thread(
  343. (WASMDebugInstance *)server->thread->debug_instance, tid, &status);
  344. send_thread_stop_status(server, status, tid);
  345. }
  346. void
  347. handle_set_current_thread(WASMGDBServer *server, char *payload)
  348. {
  349. LOG_VERBOSE("%s:%s\n", __FUNCTION__, payload, payload);
  350. if ('g' == *payload++) {
  351. uint64_t tid;
  352. tid = strtol(payload, NULL, 16);
  353. if (tid > 0)
  354. wasm_debug_instance_set_cur_thread(
  355. (WASMDebugInstance *)server->thread->debug_instance, tid);
  356. }
  357. write_packet(server, "OK");
  358. }
  359. void
  360. handle_get_register(WASMGDBServer *server, char *payload)
  361. {
  362. int i = strtol(payload, NULL, 16);
  363. if (i != 0) {
  364. write_packet(server, "E01");
  365. return;
  366. }
  367. uint64_t regdata = wasm_debug_instance_get_pc(
  368. (WASMDebugInstance *)server->thread->debug_instance);
  369. mem2hex((void *)&regdata, tmpbuf, 8);
  370. tmpbuf[8 * 2] = '\0';
  371. write_packet(server, tmpbuf);
  372. }
  373. void
  374. handle_get_json_request(WASMGDBServer *server, char *payload)
  375. {
  376. char *args;
  377. args = strchr(payload, ':');
  378. if (args)
  379. *args++ = '\0';
  380. write_packet(server, "");
  381. }
  382. void
  383. handle_get_read_binary_memory(WASMGDBServer *server, char *payload)
  384. {
  385. write_packet(server, "");
  386. }
  387. void
  388. handle_get_read_memory(WASMGDBServer *server, char *payload)
  389. {
  390. size_t maddr, mlen;
  391. bool ret;
  392. sprintf(tmpbuf, "%s", "");
  393. if (sscanf(payload, "%zx,%zx", &maddr, &mlen) == 2) {
  394. if (mlen * 2 > MAX_PACKET_SIZE) {
  395. LOG_ERROR("Buffer overflow!");
  396. mlen = MAX_PACKET_SIZE / 2;
  397. }
  398. char *buff = wasm_runtime_malloc(mlen);
  399. if (buff) {
  400. ret = wasm_debug_instance_get_mem(
  401. (WASMDebugInstance *)server->thread->debug_instance, maddr,
  402. buff, &mlen);
  403. if (ret) {
  404. mem2hex(buff, tmpbuf, mlen);
  405. }
  406. wasm_runtime_free(buff);
  407. }
  408. }
  409. write_packet(server, tmpbuf);
  410. }
  411. void
  412. handle_get_write_memory(WASMGDBServer *server, char *payload)
  413. {
  414. size_t maddr, mlen, hex_len;
  415. int offset, act_len;
  416. char *buff;
  417. bool ret;
  418. sprintf(tmpbuf, "%s", "");
  419. if (sscanf(payload, "%zx,%zx:%n", &maddr, &mlen, &offset) == 2) {
  420. payload += offset;
  421. hex_len = strlen(payload);
  422. act_len = hex_len / 2 < mlen ? hex_len / 2 : mlen;
  423. buff = wasm_runtime_malloc(act_len);
  424. if (buff) {
  425. hex2mem(payload, buff, act_len);
  426. ret = wasm_debug_instance_set_mem(
  427. (WASMDebugInstance *)server->thread->debug_instance, maddr,
  428. buff, &mlen);
  429. if (ret) {
  430. sprintf(tmpbuf, "%s", "OK");
  431. }
  432. wasm_runtime_free(buff);
  433. }
  434. }
  435. write_packet(server, tmpbuf);
  436. }
  437. void
  438. handle_add_break(WASMGDBServer *server, char *payload)
  439. {
  440. size_t type, addr, length;
  441. if (sscanf(payload, "%zx,%zx,%zx", &type, &addr, &length) == 3) {
  442. if (type == eBreakpointSoftware) {
  443. bool ret = wasm_debug_instance_add_breakpoint(
  444. (WASMDebugInstance *)server->thread->debug_instance, addr,
  445. length);
  446. if (ret)
  447. write_packet(server, "OK");
  448. else
  449. write_packet(server, "E01");
  450. return;
  451. }
  452. }
  453. write_packet(server, "");
  454. }
  455. void
  456. handle_remove_break(WASMGDBServer *server, char *payload)
  457. {
  458. size_t type, addr, length;
  459. if (sscanf(payload, "%zx,%zx,%zx", &type, &addr, &length) == 3) {
  460. if (type == eBreakpointSoftware) {
  461. bool ret = wasm_debug_instance_remove_breakpoint(
  462. (WASMDebugInstance *)server->thread->debug_instance, addr,
  463. length);
  464. if (ret)
  465. write_packet(server, "OK");
  466. else
  467. write_packet(server, "E01");
  468. return;
  469. }
  470. }
  471. write_packet(server, "");
  472. }
  473. void
  474. handle_continue_request(WASMGDBServer *server, char *payload)
  475. {
  476. uint64_t tid;
  477. uint32_t status;
  478. wasm_debug_instance_continue(
  479. (WASMDebugInstance *)server->thread->debug_instance);
  480. tid = wasm_debug_instance_get_tid(
  481. (WASMDebugInstance *)server->thread->debug_instance);
  482. tid = wasm_debug_instance_wait_thread(
  483. (WASMDebugInstance *)server->thread->debug_instance, tid, &status);
  484. send_thread_stop_status(server, status, tid);
  485. }
  486. void
  487. handle_kill_request(WASMGDBServer *server, char *payload)
  488. {
  489. uint64_t tid;
  490. uint32_t status;
  491. wasm_debug_instance_kill(
  492. (WASMDebugInstance *)server->thread->debug_instance);
  493. tid = wasm_debug_instance_get_tid(
  494. (WASMDebugInstance *)server->thread->debug_instance);
  495. tid = wasm_debug_instance_wait_thread(
  496. (WASMDebugInstance *)server->thread->debug_instance, tid, &status);
  497. send_thread_stop_status(server, status, tid);
  498. }
  499. static void
  500. handle_malloc(WASMGDBServer *server, char *payload)
  501. {
  502. char *args;
  503. uint64_t size;
  504. int map_port = MMAP_PROT_NONE;
  505. uint64_t addr;
  506. sprintf(tmpbuf, "%s", "E03");
  507. args = strstr(payload, ",");
  508. if (args) {
  509. *args++ = '\0';
  510. }
  511. else {
  512. LOG_ERROR("Payload parse error during handle malloc");
  513. return;
  514. }
  515. size = strtol(payload, NULL, 16);
  516. if (size > 0) {
  517. while (*args) {
  518. if (*args == 'r') {
  519. map_port |= MMAP_PROT_READ;
  520. }
  521. if (*args == 'w') {
  522. map_port |= MMAP_PROT_WRITE;
  523. }
  524. if (*args == 'x') {
  525. map_port |= MMAP_PROT_EXEC;
  526. }
  527. args++;
  528. }
  529. addr = wasm_debug_instance_mmap(
  530. (WASMDebugInstance *)server->thread->debug_instance, size,
  531. map_port);
  532. if (addr) {
  533. sprintf(tmpbuf, "%lx", addr);
  534. }
  535. }
  536. write_packet(server, tmpbuf);
  537. }
  538. static void
  539. handle_free(WASMGDBServer *server, char *payload)
  540. {
  541. uint64_t addr;
  542. bool ret;
  543. sprintf(tmpbuf, "%s", "E03");
  544. addr = strtol(payload, NULL, 16);
  545. ret = wasm_debug_instance_ummap(
  546. (WASMDebugInstance *)server->thread->debug_instance, addr);
  547. if (ret) {
  548. sprintf(tmpbuf, "%s", "OK");
  549. }
  550. write_packet(server, tmpbuf);
  551. }
  552. void
  553. handle____request(WASMGDBServer *server, char *payload)
  554. {
  555. char *args;
  556. if (payload[0] == 'M') {
  557. args = payload + 1;
  558. handle_malloc(server, args);
  559. }
  560. if (payload[0] == 'm') {
  561. args = payload + 1;
  562. handle_free(server, args);
  563. }
  564. }