diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-03-09 13:19:22 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-03-09 13:19:22 +0000 |
commit | c21c3b0befeb46a51b6bf3758ffa30813bea0ff0 (patch) | |
tree | 9754ff1ca740f6346cf8483ec915d4054bc5da2d /web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-debugger/tools/mrdb/cmdmisc.c | |
parent | Adding upstream version 1.43.2. (diff) | |
download | netdata-c21c3b0befeb46a51b6bf3758ffa30813bea0ff0.tar.xz netdata-c21c3b0befeb46a51b6bf3758ffa30813bea0ff0.zip |
Adding upstream version 1.44.3.upstream/1.44.3
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-debugger/tools/mrdb/cmdmisc.c')
-rw-r--r-- | web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-debugger/tools/mrdb/cmdmisc.c | 501 |
1 files changed, 501 insertions, 0 deletions
diff --git a/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-debugger/tools/mrdb/cmdmisc.c b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-debugger/tools/mrdb/cmdmisc.c new file mode 100644 index 000000000..5984b623b --- /dev/null +++ b/web/server/h2o/libh2o/deps/mruby/mrbgems/mruby-bin-debugger/tools/mrdb/cmdmisc.c @@ -0,0 +1,501 @@ +/* +** cmdmisc.c - mruby debugger miscellaneous command functions +** +*/ + +#include <ctype.h> +#include <stdlib.h> +#include <string.h> + +#include "apilist.h" +#include <mruby/compile.h> + +typedef struct help_msg { + const char *cmd1; + const char *cmd2; + const char *short_msg; + const char *long_msg; +} help_msg; + +static help_msg help_msg_list[] = { + { + "b[reak]", NULL, "Set breakpoint", + "Usage: break [file:]line\n" + " break [class:]method\n" + "\n" + "Set breakpoint at specified line or method.\n" + "If \'[file:]line\' is specified, break at start of code for that line (in a file).\n" + "If \'[class:]method\' is specified, break at start of code for that method (of the class).\n" + }, + { + "c[ontinue]", NULL, "Continue program being debugged", + "Usage: continue [N]\n" + "\n" + "Continue program stopped by a breakpoint.\n" + "If N, which is non negative value, is passed,\n" + "proceed program until the N-th breakpoint is coming.\n" + "If N is not passed, N is assumed 1.\n" + }, + { + "d[elete]", NULL, "Delete some breakpoints", + "Usage: delete [bpno1 [bpno2 [... [bpnoN]]]]\n" + "\n" + "Delete some breakpoints.\n" + "Arguments are breakpoint numbers with spaces in between.\n" + "To delete all breakpoints, give no argument.\n" + }, + { + "dis[able]", NULL, "Disable some breakpoints", + "Usage: disable [bpno1 [bpno2 [... [bpnoN]]]]\n" + "\n" + "Disable some breakpoints.\n" + "Arguments are breakpoint numbers with spaces in between.\n" + "To disable all breakpoints, give no argument.\n" + }, + { + "en[able]", NULL, "Enable some breakpoints", + "Usage: enable [bpno1 [bpno2 [... [bpnoN]]]]\n" + "\n" + "Enable some breakpoints.\n" + "Arguments are breakpoint numbers with spaces in between.\n" + "To enable all breakpoints, give no argument.\n" + }, + { + "ev[al]", NULL, "Evaluate expression", + "Usage: eval expr\n" + "\n" + "It evaluates and prints the value of the mruby expression.\n" + "This is equivalent to the \'print\' command.\n" + }, + { + "h[elp]", NULL, "Print this help", + "Usage: help [command]\n" + "\n" + "With no arguments, help displays a short list of commands.\n" + "With a command name as help argument, help displays how to use that command.\n" + }, + { + "i[nfo]", "b[reakpoints]", "Status of breakpoints", + "Usage: info breakpoints [bpno1 [bpno2 [... [bpnoN]]]]\n" + "\n" + "Status of specified breakpoints (all user-settable breakpoints if no argument).\n" + "Arguments are breakpoint numbers with spaces in between.\n" + }, + { + "l[ist]", NULL, "List specified line", + "Usage: list\n" + " list first[,last]\n" + " list filename:first[,last]\n" + "\n" + "Print lines from a source file.\n" + "\n" + "With first and last, list prints lines from first to last.\n" + "When last is empty, it stands for ten lines away from first.\n" + "With filename, list prints lines in the specified source file.\n" + }, + { + "p[rint]", NULL, "Print value of expression", + "Usage: print expr\n" + "\n" + "It evaluates and prints the value of the mruby expression.\n" + "This is equivalent to the \'eval\' command.\n" + }, + { + "q[uit]", NULL, "Exit mrdb", + "Usage: quit\n" + "\n" + "Exit mrdb.\n" + }, + { + "r[un]", NULL, "Start debugged program", + "Usage: run\n" + "\n" + "Start debugged program.\n" + }, + { + "s[tep]", NULL, "Step program until it reaches a different source line", + "Usage: step\n" + "\n" + "Step program until it reaches a different source line.\n" + }, + { NULL, NULL, NULL, NULL } +}; + +typedef struct listcmd_parser_state { + mrb_bool parse_error; + mrb_bool has_line_min; + mrb_bool has_line_max; + char *filename; + uint16_t line_min; + uint16_t line_max; +} listcmd_parser_state; + +static listcmd_parser_state* +listcmd_parser_state_new(mrb_state *mrb) +{ + listcmd_parser_state *st = mrb_malloc(mrb, sizeof(listcmd_parser_state)); + memset(st, 0, sizeof(listcmd_parser_state)); + return st; +} + +static void +listcmd_parser_state_free(mrb_state *mrb, listcmd_parser_state *st) +{ + if (st != NULL) { + if (st->filename != NULL) { + mrb_free(mrb, st->filename); + } + mrb_free(mrb, st); + } +} + +static mrb_bool +parse_uint(char **sp, uint16_t *n) +{ + char *p; + int i; + + if (*sp == NULL || **sp == '\0') { + return FALSE; + } + + for (p = *sp; *p != '\0' && ISDIGIT(*p); p++) ; + + if (p != *sp && (i = atoi(*sp)) >= 0) { + *n = (uint16_t)i; + *sp = p; + return TRUE; + } + return FALSE; +} + +static mrb_bool +skip_char(char **sp, char c) +{ + if (*sp != NULL && **sp == c) { + ++*sp; + return TRUE; + } + return FALSE; +} + +static mrb_bool +parse_lineno(mrb_state *mrb, char **sp, listcmd_parser_state *st) +{ + if (*sp == NULL || **sp == '\0') { + return FALSE; + } + + st->has_line_min = FALSE; + st->has_line_max = FALSE; + + if (parse_uint(sp, &st->line_min)) { + st->has_line_min = TRUE; + } + else { + return FALSE; + } + + if (skip_char(sp, ',')) { + if (parse_uint(sp, &st->line_max)) { + st->has_line_max = TRUE; + } + else { + st->parse_error = TRUE; + return FALSE; + } + } + return TRUE; +} + +static mrb_bool +parse_filename(mrb_state *mrb, char **sp, listcmd_parser_state *st) +{ + char *p; + int len; + + if (st->filename != NULL) { + mrb_free(mrb, st->filename); + st->filename = NULL; + } + + if ((p = strchr(*sp, ':')) != NULL) { + len = p - *sp; + } + else { + len = strlen(*sp); + } + + if (len > 0) { + st->filename = mrb_malloc(mrb, len + 1); + strncpy(st->filename, *sp, len); + st->filename[len] = '\0'; + *sp += len; + return TRUE; + } + else { + return FALSE; + } +} + +char* +replace_ext(mrb_state *mrb, const char *filename, const char *ext) +{ + size_t len; + char *p, *s; + + if (filename == NULL) { + return NULL; + } + + if ((p = strrchr(filename, '.')) != NULL && strchr(p, '/') == NULL) { + len = p - filename; + } + else { + len = strlen(filename); + } + + s = mrb_malloc(mrb, len + strlen(ext) + 1); + memset(s, '\0', len + strlen(ext) + 1); + strncpy(s, filename, len); + strcat(s, ext); + + return s; +} + +static mrb_bool +parse_listcmd_args(mrb_state *mrb, mrdb_state *mrdb, listcmd_parser_state *st) +{ + char *p; + + switch (mrdb->wcnt) { + case 2: + p = mrdb->words[1]; + + /* mrdb->words[1] ::= <lineno> | <filename> ':' <lineno> | <filename> */ + if (!parse_lineno(mrb, &p, st)) { + if (parse_filename(mrb, &p, st)) { + if (skip_char(&p, ':')) { + if (!parse_lineno(mrb, &p, st)) { + st->parse_error = TRUE; + } + } + } + else { + st->parse_error = TRUE; + } + } + if (*p != '\0') { + st->parse_error = TRUE; + } + break; + case 1: + case 0: + /* do nothing */ + break; + default: + st->parse_error = TRUE; + printf("too many arguments\n"); + break; + } + + if (!st->parse_error) { + if (!st->has_line_min) { + st->line_min = (!st->filename && mrdb->dbg->prvline > 0) ? mrdb->dbg->prvline : 1; + } + + if (!st->has_line_max) { + st->line_max = st->line_min + 9; + } + + if (st->filename == NULL) { + if (mrdb->dbg->prvfile && strcmp(mrdb->dbg->prvfile, "-")) { + st->filename = replace_ext(mrb, mrdb->dbg->prvfile, ".rb"); + } + } + } + + if (st->parse_error || st->filename == NULL) { + return FALSE; + } + + return TRUE; +} + +static mrb_bool +check_cmd_pattern(const char *pattern, const char *cmd) +{ + char *lbracket, *rbracket, *p, *q; + + if (pattern == NULL && cmd == NULL) { + return TRUE; + } + if (pattern == NULL || cmd == NULL) { + return FALSE; + } + if ((lbracket = strchr(pattern, '[')) == NULL) { + return !strcmp(pattern, cmd); + } + if ((rbracket = strchr(pattern, ']')) == NULL) { + return FALSE; + } + if (strncmp(pattern, cmd, lbracket - pattern)) { + return FALSE; + } + + p = lbracket + 1; + q = (char *)cmd + (lbracket - pattern); + + for ( ; p < rbracket && *q != '\0'; p++, q++) { + if (*p != *q) { + break; + } + } + return *q == '\0'; +} + +static help_msg* +get_help_msg(char *cmd1, char *cmd2) +{ + help_msg *p; + + if (cmd1 == NULL) { + return NULL; + } + for (p = help_msg_list; p->cmd1 != NULL; p++) { + if (check_cmd_pattern(p->cmd1, cmd1) && check_cmd_pattern(p->cmd2, cmd2)) { + return p; + } + } + return NULL; +} + +static mrb_bool +show_short_help(void) +{ + help_msg *p; + + printf("Commands\n"); + + for (p = help_msg_list; p->cmd1 != NULL; p++) { + if (p->cmd2 == NULL) { + printf(" %s -- %s\n", p->cmd1, p->short_msg); + } + else { + printf(" %s %s -- %s\n", p->cmd1, p->cmd2, p->short_msg); + } + } + return TRUE; +} + +static mrb_bool +show_long_help(char *cmd1, char *cmd2) +{ + help_msg *help; + + if ((help = get_help_msg(cmd1, cmd2)) == NULL) { + return FALSE; + } + printf("%s", help->long_msg); + return TRUE; +} + +dbgcmd_state +dbgcmd_list(mrb_state *mrb, mrdb_state *mrdb) +{ + char *filename; + listcmd_parser_state *st = listcmd_parser_state_new(mrb); + + if (parse_listcmd_args(mrb, mrdb, st)) { + if ((filename = mrb_debug_get_source(mrb, mrdb, mrdb->srcpath, st->filename)) == NULL) { + filename = st->filename; + } + mrb_debug_list(mrb, mrdb->dbg, filename, st->line_min, st->line_max); + + if (filename != NULL && filename != st->filename) { + mrb_free(mrb, filename); + } + listcmd_parser_state_free(mrb, st); + } + + return DBGST_PROMPT; +} + +dbgcmd_state +dbgcmd_help(mrb_state *mrb, mrdb_state *mrdb) +{ + mrb_bool is_valid; + int i; + + switch (mrdb->wcnt) { + case 0: + case 1: + is_valid = show_short_help(); + break; + case 2: + is_valid = show_long_help(mrdb->words[1], NULL); + break; + case 3: + is_valid = show_long_help(mrdb->words[1], mrdb->words[2]); + break; + default: + is_valid = FALSE; + break; + } + + if (!is_valid) { + printf("Invalid command \""); + for (i = 1; i < mrdb->wcnt; i++) { + printf("%s%s", i == 1 ? "" : " ", mrdb->words[i]); + } + printf("\". Try \"help\".\n"); + } + + return DBGST_PROMPT; +} + +dbgcmd_state +dbgcmd_quit(mrb_state *mrb, mrdb_state *mrdb) +{ + switch (mrdb->dbg->xm) { + case DBG_RUN: + case DBG_STEP: + case DBG_NEXT: + while (1) { + char c; + int buf; + + printf("The program is running. Exit anyway? (y or n) "); + fflush(stdout); + + if ((buf = getchar()) == EOF) { + mrdb->dbg->xm = DBG_QUIT; + break; + } + c = buf; + while (buf != '\n' && (buf = getchar()) != EOF) ; + + if (c == 'y' || c == 'Y') { + mrdb->dbg->xm = DBG_QUIT; + break; + } + else if (c == 'n' || c == 'N') { + break; + } + else { + printf("Please answer y or n.\n"); + } + } + break; + default: + mrdb->dbg->xm = DBG_QUIT; + break; + } + + if (mrdb->dbg->xm == DBG_QUIT) { + struct RClass *exc; + exc = mrb_define_class(mrb, "DebuggerExit", mrb_class_get(mrb, "Exception")); + mrb_raise(mrb, exc, "Exit mrdb."); + } + return DBGST_PROMPT; +} |