From 4abf48fdfff98d3c3238419d07ab9390a74e427a Mon Sep 17 00:00:00 2001 From: David Disseldorp Date: Mon, 24 Mar 2025 21:46:30 +1100 Subject: [PATCH 1/2] lkl: hijack: move dbg_handler out of liblkl dbg_handler exposes a very useful debug shell, but it's currently only used (within tools/lkl at least) by hijack and zpoline. Move the functionality into liblkl-hijack, to slightly trim down the liblkl core library. This may break external lkl_register_dbg_handler() callers. Signed-off-by: David Disseldorp --- tools/lkl/include/lkl.h | 12 ------------ tools/lkl/lib/Build | 1 - tools/lkl/lib/hijack/Build | 2 ++ tools/lkl/lib/{ => hijack}/dbg_handler.c | 0 tools/lkl/lib/hijack/init.h | 11 +++++++++++ 5 files changed, 13 insertions(+), 13 deletions(-) rename tools/lkl/lib/{ => hijack}/dbg_handler.c (100%) diff --git a/tools/lkl/include/lkl.h b/tools/lkl/include/lkl.h index cd905556c07f48..5d88ec73b9127f 100644 --- a/tools/lkl/include/lkl.h +++ b/tools/lkl/include/lkl.h @@ -835,18 +835,6 @@ lkl_netdev_wintap_create(const char *ifparams) } #endif - -/* - * lkl_register_dbg_handler- register a signal handler that loads a debug lib. - * - * The signal handler is triggered by Ctrl-Z. It creates a new pthread which - * call dbg_entrance(). - * - * If you run the program from shell script, make sure you ignore SIGTSTP by - * "trap '' TSTP" in the shell script. - */ -void lkl_register_dbg_handler(void); - /** * lkl_add_neighbor - add a permanent arp entry * @ifindex - the ifindex of the interface diff --git a/tools/lkl/lib/Build b/tools/lkl/lib/Build index f1ad8da64f5697..22571a914514f2 100644 --- a/tools/lkl/lib/Build +++ b/tools/lkl/lib/Build @@ -12,7 +12,6 @@ liblkl-y += utils.o liblkl-y += virtio_blk.o liblkl-y += virtio.o liblkl-y += dbg.o -liblkl-y += dbg_handler.o liblkl-$(LKL_HOST_CONFIG_VIRTIO_NET) += virtio_net.o liblkl-$(LKL_HOST_CONFIG_VIRTIO_NET_FD) += virtio_net_fd.o liblkl-$(LKL_HOST_CONFIG_VIRTIO_NET_FD) += virtio_net_tap.o diff --git a/tools/lkl/lib/hijack/Build b/tools/lkl/lib/hijack/Build index 0c807ef2e2b5be..eb9872ae5c29ee 100644 --- a/tools/lkl/lib/hijack/Build +++ b/tools/lkl/lib/hijack/Build @@ -2,8 +2,10 @@ liblkl-hijack-y += preload.o liblkl-hijack-y += hijack.o liblkl-hijack-y += init.o liblkl-hijack-y += xlate.o +liblkl-hijack-y += dbg_handler.o liblkl-zpoline-y += zpoline.o liblkl-zpoline-y += hijack.o liblkl-zpoline-y += init.o liblkl-zpoline-y += xlate.o +liblkl-zpoline-y += dbg_handler.o diff --git a/tools/lkl/lib/dbg_handler.c b/tools/lkl/lib/hijack/dbg_handler.c similarity index 100% rename from tools/lkl/lib/dbg_handler.c rename to tools/lkl/lib/hijack/dbg_handler.c diff --git a/tools/lkl/lib/hijack/init.h b/tools/lkl/lib/hijack/init.h index 2f7a51d3c0a00a..b127b9d7085eeb 100644 --- a/tools/lkl/lib/hijack/init.h +++ b/tools/lkl/lib/hijack/init.h @@ -7,4 +7,15 @@ extern int dual_fds[]; void __hijack_init(void); void __hijack_fini(void); +/* + * lkl_register_dbg_handler- register a signal handler that loads a debug lib. + * + * The signal handler is triggered by Ctrl-Z. It creates a new pthread which + * call dbg_entrance(). + * + * If you run the program from shell script, make sure you ignore SIGTSTP by + * "trap '' TSTP" in the shell script. + */ +void lkl_register_dbg_handler(void); + #endif /*_LKL_HIJACK_INIT_H */ From db1bf05fcb1aab92a29f5c9f99983fa9d220228f Mon Sep 17 00:00:00 2001 From: David Disseldorp Date: Tue, 25 Mar 2025 10:18:34 +1100 Subject: [PATCH 2/2] lkl: hijack: move dbg.c code into dbg_handler.c dbg_entrance() is only called via the SIGTSTP signal handler setup in lkl_register_dbg_handler(). Signed-off-by: David Disseldorp --- tools/lkl/lib/Build | 1 - tools/lkl/lib/dbg.c | 274 ----------------------------- tools/lkl/lib/hijack/dbg_handler.c | 273 +++++++++++++++++++++++++++- 3 files changed, 272 insertions(+), 276 deletions(-) delete mode 100644 tools/lkl/lib/dbg.c diff --git a/tools/lkl/lib/Build b/tools/lkl/lib/Build index 22571a914514f2..b1af186a7f968d 100644 --- a/tools/lkl/lib/Build +++ b/tools/lkl/lib/Build @@ -11,7 +11,6 @@ liblkl-$(LKL_HOST_CONFIG_NT) += nt-host.o liblkl-y += utils.o liblkl-y += virtio_blk.o liblkl-y += virtio.o -liblkl-y += dbg.o liblkl-$(LKL_HOST_CONFIG_VIRTIO_NET) += virtio_net.o liblkl-$(LKL_HOST_CONFIG_VIRTIO_NET_FD) += virtio_net_fd.o liblkl-$(LKL_HOST_CONFIG_VIRTIO_NET_FD) += virtio_net_tap.o diff --git a/tools/lkl/lib/dbg.c b/tools/lkl/lib/dbg.c deleted file mode 100644 index 70dcec7254c908..00000000000000 --- a/tools/lkl/lib/dbg.c +++ /dev/null @@ -1,274 +0,0 @@ -#include -#include -#include -#include -#include -#include - -static const char* PROMOTE = "$"; -#define str(x) #x -#define xstr(s) str(s) -#define MAX_BUF 100 -static char cmd[MAX_BUF]; -static char argv[10][MAX_BUF]; -static int argc = 0; -static char cur_dir[MAX_BUF] = "/"; - -static char* normalize_path(const char * src, size_t src_len) { - char* res; - unsigned int res_len; - const char* ptr = src; - const char* end = &src[src_len]; - const char* next; - - res = malloc((src_len > 0 ? src_len : 1) + 1); - res_len = 0; - - for (ptr = src; ptr < end; ptr=next+1) { - size_t len; - next = memchr(ptr, '/', end-ptr); - if (next == NULL) { - next = end; - } - len = next-ptr; - switch(len) { - case 2: - if (ptr[0] == '.' && ptr[1] == '.') { - const char * slash = strrchr(res, '/'); - if (slash != NULL) { - res_len = slash - res; - } - continue; - } - break; - case 1: - if (ptr[0] == '.') { - continue; - } - break; - case 0: - continue; - } - res[res_len++] = '/'; - memcpy(&res[res_len], ptr, len); - res_len += len; - } - if (res_len == 0) { - res[res_len++] = '/'; - } - res[res_len] = '\0'; - return res; -} - -static void build_path(char* path) { - char* npath; - - strcpy(path, cur_dir); - if (argc >=1) { - if (argv[0][0] == '/') strncpy(path, argv[0], LKL_PATH_MAX); - else { - strncat(path, "/", LKL_PATH_MAX - strlen(path) - 1); - strncat(path, argv[0], LKL_PATH_MAX - strlen(path) - 1); - } - } - npath = normalize_path(path, strlen(path)); - strcpy(path, npath); - free(npath); -} - -static void help() { - const char *msg = - "cat FILE\n" - "\tShow content of FILE\n" - "cd [DIR]\n" - "\tChange directory to DIR\n" - "exit\n" - "\tExit the debug session\n" - "help\n" - "\tShow this message\n" - "ls [DIR]\n" - "\tList files in DIR\n" - "mount FSTYPE\n" - "\tMount FSTYPE as /FSTYPE\n" - "overwrite FILE\n" - "\tOverwrite content of FILE from stdin\n" - "pwd\n" - "\tShow current directory\n" - ; - printf("%s", msg); -} - -static void ls() { - char path[LKL_PATH_MAX]; - struct lkl_dir* dir; - struct lkl_linux_dirent64* de; - int err; - - build_path(path); - dir = lkl_opendir(path, &err); - if (dir) { - do { - de = lkl_readdir(dir); - if (de) { - printf("%s\n", de->d_name); - } else { - err = lkl_errdir(dir); - if (err != 0) { - fprintf(stderr, "%s\n", - lkl_strerror(err)); - } - break; - } - } while(1); - lkl_closedir(dir); - } else { - fprintf(stderr, "%s: %s\n", path, lkl_strerror(err)); - } -} - -static void cd() { - char path[LKL_PATH_MAX]; - struct lkl_dir* dir; - int err; - - build_path(path); - dir = lkl_opendir(path, &err); - if (dir) { - strcpy(cur_dir, path); - lkl_closedir(dir); - } else { - fprintf(stderr, "%s: %s\n", path, lkl_strerror(err)); - } -} - -static void mount() { - char* fstype; - int ret = 0; - - if (argc != 1) { - fprintf(stderr, "%s\n", "One argument is needed."); - return; - } - - fstype = argv[0]; - ret = lkl_mount_fs(fstype); - if (ret == 1) - fprintf(stderr, "%s is already mounted.\n", fstype); -} - -static void cat() { - char path[LKL_PATH_MAX]; - int ret; - char buf[1024]; - int fd; - - if (argc != 1) { - fprintf(stderr, "%s\n", "One argument is needed."); - return; - } - - build_path(path); - fd = lkl_sys_open(path, LKL_O_RDONLY, 0); - - if (fd < 0) { - fprintf(stderr, "lkl_sys_open %s: %s\n", - path, lkl_strerror(fd)); - return; - } - - while ((ret = lkl_sys_read(fd, buf, sizeof(buf) - 1)) > 0) { - buf[ret] = '\0'; - printf("%s", buf); - } - - if (ret) { - fprintf(stderr, "lkl_sys_read %s: %s\n", - path, lkl_strerror(ret)); - } - lkl_sys_close(fd); -} - -static void overwrite() { - char path[LKL_PATH_MAX]; - int ret; - int fd; - char buf[1024]; - - build_path(path); - fd = lkl_sys_open(path, LKL_O_WRONLY | LKL_O_CREAT, 0); - if (fd < 0) { - fprintf(stderr, "lkl_sys_open %s: %s\n", - path, lkl_strerror(fd)); - return; - } - printf("Input the content and stop by hitting Ctrl-D:\n"); - while(fgets(buf, 1023, stdin)) { - ret = lkl_sys_write(fd, buf, strlen(buf)); - if (ret < 0) { - fprintf(stderr, "lkl_sys_write %s: %s\n", - path, lkl_strerror(fd)); - } - } - lkl_sys_close(fd); -} - -static void pwd() { - printf("%s\n", cur_dir); -} - -static int parse_cmd(char* input) { - char* token; - token = strtok(input, " "); - if (token) strcpy(cmd, token); - else return -1; - - argc = 0; - token = strtok(NULL, " "); - while(token) { - if (argc >=10) { - fprintf(stderr, "To many args > 10\n"); - return -1; - } - strcpy(argv[argc++], token); - token = strtok(NULL, " "); - } - return 0; -} - -static void run_cmd() { - if(strcmp(cmd, "cat") == 0) cat(); - else if(strcmp(cmd, "cd") == 0) cd(); - else if(strcmp(cmd, "help") == 0) help(); - else if(strcmp(cmd, "ls") == 0) ls(); - else if(strcmp(cmd, "mount") == 0) mount(); - else if(strcmp(cmd, "overwrite") == 0) overwrite(); - else if(strcmp(cmd, "pwd") == 0) pwd(); - else { - fprintf(stderr, "Unknown command: %s\n", cmd); - } -} - -void dbg_entrance() { - char input[MAX_BUF + 1]; - int ret; - int c; - - printf("Type help to see a list of commands\n"); - do { - printf("%s ", PROMOTE); - ret = scanf("%" xstr(MAX_BUF) "[^\n]s", input); - while ((c = getchar()) != '\n' && c != EOF); - if (ret == 0) continue; - if (ret != 1 && errno != EINTR) { - perror("scanf"); - continue; - } - if (strlen(input) == MAX_BUF) { - fprintf(stderr, "Too long input > %d\n", MAX_BUF - 1); - continue; - } - if (parse_cmd(input)) continue; - if (strcmp(cmd, "exit") == 0) break; - run_cmd(); - } while(1); -} diff --git a/tools/lkl/lib/hijack/dbg_handler.c b/tools/lkl/lib/hijack/dbg_handler.c index a88dd91e377c01..f135944f0c6912 100644 --- a/tools/lkl/lib/hijack/dbg_handler.c +++ b/tools/lkl/lib/hijack/dbg_handler.c @@ -1,8 +1,279 @@ +#include +#include +#include +#include +#include #include #include -extern void dbg_entrance(); static int dbg_running = 0; +static const char* PROMOTE = "$"; +#define str(x) #x +#define xstr(s) str(s) +#define MAX_BUF 100 +static char cmd[MAX_BUF]; +static char argv[10][MAX_BUF]; +static int argc = 0; +static char cur_dir[MAX_BUF] = "/"; + +static char* normalize_path(const char * src, size_t src_len) { + char* res; + unsigned int res_len; + const char* ptr = src; + const char* end = &src[src_len]; + const char* next; + + res = malloc((src_len > 0 ? src_len : 1) + 1); + res_len = 0; + + for (ptr = src; ptr < end; ptr=next+1) { + size_t len; + next = memchr(ptr, '/', end-ptr); + if (next == NULL) { + next = end; + } + len = next-ptr; + switch(len) { + case 2: + if (ptr[0] == '.' && ptr[1] == '.') { + const char * slash = strrchr(res, '/'); + if (slash != NULL) { + res_len = slash - res; + } + continue; + } + break; + case 1: + if (ptr[0] == '.') { + continue; + } + break; + case 0: + continue; + } + res[res_len++] = '/'; + memcpy(&res[res_len], ptr, len); + res_len += len; + } + if (res_len == 0) { + res[res_len++] = '/'; + } + res[res_len] = '\0'; + return res; +} + +static void build_path(char* path) { + char* npath; + + strcpy(path, cur_dir); + if (argc >=1) { + if (argv[0][0] == '/') strncpy(path, argv[0], LKL_PATH_MAX); + else { + strncat(path, "/", LKL_PATH_MAX - strlen(path) - 1); + strncat(path, argv[0], LKL_PATH_MAX - strlen(path) - 1); + } + } + npath = normalize_path(path, strlen(path)); + strcpy(path, npath); + free(npath); +} + +static void help() { + const char *msg = + "cat FILE\n" + "\tShow content of FILE\n" + "cd [DIR]\n" + "\tChange directory to DIR\n" + "exit\n" + "\tExit the debug session\n" + "help\n" + "\tShow this message\n" + "ls [DIR]\n" + "\tList files in DIR\n" + "mount FSTYPE\n" + "\tMount FSTYPE as /FSTYPE\n" + "overwrite FILE\n" + "\tOverwrite content of FILE from stdin\n" + "pwd\n" + "\tShow current directory\n" + ; + printf("%s", msg); +} + +static void ls() { + char path[LKL_PATH_MAX]; + struct lkl_dir* dir; + struct lkl_linux_dirent64* de; + int err; + + build_path(path); + dir = lkl_opendir(path, &err); + if (dir) { + do { + de = lkl_readdir(dir); + if (de) { + printf("%s\n", de->d_name); + } else { + err = lkl_errdir(dir); + if (err != 0) { + fprintf(stderr, "%s\n", + lkl_strerror(err)); + } + break; + } + } while(1); + lkl_closedir(dir); + } else { + fprintf(stderr, "%s: %s\n", path, lkl_strerror(err)); + } +} + +static void cd() { + char path[LKL_PATH_MAX]; + struct lkl_dir* dir; + int err; + + build_path(path); + dir = lkl_opendir(path, &err); + if (dir) { + strcpy(cur_dir, path); + lkl_closedir(dir); + } else { + fprintf(stderr, "%s: %s\n", path, lkl_strerror(err)); + } +} + +static void mount() { + char* fstype; + int ret = 0; + + if (argc != 1) { + fprintf(stderr, "%s\n", "One argument is needed."); + return; + } + + fstype = argv[0]; + ret = lkl_mount_fs(fstype); + if (ret == 1) + fprintf(stderr, "%s is already mounted.\n", fstype); +} + +static void cat() { + char path[LKL_PATH_MAX]; + int ret; + char buf[1024]; + int fd; + + if (argc != 1) { + fprintf(stderr, "%s\n", "One argument is needed."); + return; + } + + build_path(path); + fd = lkl_sys_open(path, LKL_O_RDONLY, 0); + + if (fd < 0) { + fprintf(stderr, "lkl_sys_open %s: %s\n", + path, lkl_strerror(fd)); + return; + } + + while ((ret = lkl_sys_read(fd, buf, sizeof(buf) - 1)) > 0) { + buf[ret] = '\0'; + printf("%s", buf); + } + + if (ret) { + fprintf(stderr, "lkl_sys_read %s: %s\n", + path, lkl_strerror(ret)); + } + lkl_sys_close(fd); +} + +static void overwrite() { + char path[LKL_PATH_MAX]; + int ret; + int fd; + char buf[1024]; + + build_path(path); + fd = lkl_sys_open(path, LKL_O_WRONLY | LKL_O_CREAT, 0); + if (fd < 0) { + fprintf(stderr, "lkl_sys_open %s: %s\n", + path, lkl_strerror(fd)); + return; + } + printf("Input the content and stop by hitting Ctrl-D:\n"); + while(fgets(buf, 1023, stdin)) { + ret = lkl_sys_write(fd, buf, strlen(buf)); + if (ret < 0) { + fprintf(stderr, "lkl_sys_write %s: %s\n", + path, lkl_strerror(fd)); + } + } + lkl_sys_close(fd); +} + +static void pwd() { + printf("%s\n", cur_dir); +} + +static int parse_cmd(char* input) { + char* token; + token = strtok(input, " "); + if (token) strcpy(cmd, token); + else return -1; + + argc = 0; + token = strtok(NULL, " "); + while(token) { + if (argc >=10) { + fprintf(stderr, "To many args > 10\n"); + return -1; + } + strcpy(argv[argc++], token); + token = strtok(NULL, " "); + } + return 0; +} + +static void run_cmd() { + if(strcmp(cmd, "cat") == 0) cat(); + else if(strcmp(cmd, "cd") == 0) cd(); + else if(strcmp(cmd, "help") == 0) help(); + else if(strcmp(cmd, "ls") == 0) ls(); + else if(strcmp(cmd, "mount") == 0) mount(); + else if(strcmp(cmd, "overwrite") == 0) overwrite(); + else if(strcmp(cmd, "pwd") == 0) pwd(); + else { + fprintf(stderr, "Unknown command: %s\n", cmd); + } +} + +static void dbg_entrance() { + char input[MAX_BUF + 1]; + int ret; + int c; + + printf("Type help to see a list of commands\n"); + do { + printf("%s ", PROMOTE); + ret = scanf("%" xstr(MAX_BUF) "[^\n]s", input); + while ((c = getchar()) != '\n' && c != EOF); + if (ret == 0) continue; + if (ret != 1 && errno != EINTR) { + perror("scanf"); + continue; + } + if (strlen(input) == MAX_BUF) { + fprintf(stderr, "Too long input > %d\n", MAX_BUF - 1); + continue; + } + if (parse_cmd(input)) continue; + if (strcmp(cmd, "exit") == 0) break; + run_cmd(); + } while(1); +} static void dbg_thread(void* arg) { lkl_host_ops.thread_detach();