From mboxrd@z Thu Jan 1 00:00:00 1970 From: Don Howard To: Subject: Re: error-catching mechanism for scripts Date: Tue, 27 Nov 2001 08:43:00 -0000 Message-id: X-SW-Source: 2001-11/msg00291.html > I've been trying to find a way to make gdb command scripts handle errors > in a flexible way -- either making continue-on-error an option or some > kind of simple exception catching mechanism: > > > set script-continue-on-error 1 > > -- or -- > > try > commands > catch > commands > end > > > I'd like to know what others think. Ok, I've got a partial implementation of the try/catch idea that I'd like to get some feedback on. (Let me know if I'm headed the right way before I spend too much time on this) I know that the keywords try/catch (esp catch) won't work, as gdb already has a catch command. I'd appreciate a suggestion on what to name this command. For now I've simple gone with CATCH (all caps) to avoid name collisions. Index: defs.h =================================================================== RCS file: /cvs/src/src/gdb/defs.h,v retrieving revision 1.64 diff -p -u -w -r1.64 defs.h --- defs.h 2001/10/17 20:35:31 1.64 +++ defs.h 2001/11/27 08:07:06 @@ -815,16 +815,18 @@ enum misc_command_type ok_command, end_command, else_command, + CATCH_command, nop_command }; enum command_control_type { - simple_control, + simple_control = 1, break_control, continue_control, while_control, if_control, + try_control, invalid_control }; Index: cli/cli-cmds.c =================================================================== RCS file: /cvs/src/src/gdb/cli/cli-cmds.c,v retrieving revision 1.10 diff -p -u -w -r1.10 cli-cmds.c --- cli-cmds.c 2001/09/01 21:38:05 1.10 +++ cli-cmds.c 2001/11/27 08:07:07 @@ -721,6 +721,9 @@ The conditional expression must follow t followed by a new line. The nested commands must be entered one per line,\n\ and should be terminated by the word `end'."); + add_com ("try", class_support, try_command, + "Try/Catch support"); + add_com ("if", class_support, if_command, "Execute nested commands once IF the conditional expression is non zero.\n\ The conditional expression must follow the word `if' and must in turn be\n\ Index: cli/cli-script.c =================================================================== RCS file: /cvs/src/src/gdb/cli/cli-script.c,v retrieving revision 1.7 diff -p -u -w -r1.7 cli-script.c --- cli-script.c 2001/06/17 15:16:12 1.7 +++ cli-script.c 2001/11/27 08:07:08 @@ -210,6 +210,34 @@ print_command_lines (struct ui_out *uiou continue; } + /* A try command. Recursively print the try and catch blocks + before continuing. */ + if (list->control_type == try_control) + { + ui_out_text (uiout, "try"); + ui_out_field_fmt (uiout, NULL, "try\n"); + ui_out_text (uiout, "\n"); + /* The true arm. */ + print_command_lines (uiout, list->body_list[0], depth + 1); + + /* Show the false arm if it exists. */ + if (list->body_count == 2) + { + if (depth) + ui_out_spaces (uiout, 2 * depth); + ui_out_field_string (uiout, NULL, "CATCH"); + ui_out_text (uiout, "CATCH\n"); + print_command_lines (uiout, list->body_list[1], depth + 1); + } + + ui_out_field_string (uiout, NULL, "end"); + if (depth) + ui_out_spaces (uiout, 2 * depth); + ui_out_text (uiout, "end\n"); + list = list->next; + continue; + } + /* ignore illegal command type and try next */ list = list->next; } /* while (list) */ @@ -292,6 +320,33 @@ print_command_line (struct command_line } fputs_filtered ("end\n", stream); } + + /* A try command. Recursively print both try and catch blocks. */ + if (cmd->control_type == try_control) + { + fputs_filtered ("try", stream); + fputs_filtered (cmd->line, stream); + fputs_filtered ("\n", stream); + /* The true arm. */ + print_command_line (cmd->body_list[0], depth + 1, stream); + + /* Show the catch block if it exists. */ + if (cmd->body_count == 2) + { + if (depth) + { + for (i = 0; i < depth; i++) + fputs_filtered (" ", stream); + } + fputs_filtered ("CATCH\n", stream); + print_command_line (cmd->body_list[1], depth + 1, stream); + } + if (depth) + { + for (i = 0; i < depth; i++) + fputs_filtered (" ", stream); + } + fputs_filtered ("end\n", stream); } } #endif @@ -461,6 +516,24 @@ execute_control_command (struct command_ break; } + case try_control: + { + for (current = cmd->body_list[0]; current; current = current->next) + { + ret = catch_errors (execute_control_command, current, + "try -> CATCH", 0); + + if (ret == 0 || ret == invalid_control) + { + if (cmd->body_count == 2) + current = cmd->body_list[1]; + else + current = NULL; + } + } + break; + } + default: warning ("Invalid control type in command structure."); return invalid_control; @@ -508,6 +581,21 @@ if_command (char *arg, int from_tty) free_command_lines (&command); } +void +try_command (char *block, int from_tty) +{ + struct command_line *command = NULL; + + control_level = 1; + command = get_command_line (try_control, block); + + if (command == NULL) + return; + + execute_control_command (command); + free_command_lines (&command); +} + /* Cleanup */ static void arg_cleanup (void *ignore) @@ -760,12 +848,18 @@ read_next_line (struct command_line **co if (p1 - p == 4 && !strncmp (p, "else", 4)) return else_command; + /* Is the catch clause of an if try structure? */ + if (p1 - p == 5 && !strncmp (p, "CATCH", 5)) + return CATCH_command; + /* Check for while, if, break, continue, etc and build a new command line structure for them. */ if (p1 - p > 5 && !strncmp (p, "while", 5)) *command = build_command_line (while_control, p + 6); else if (p1 - p > 2 && !strncmp (p, "if", 2)) *command = build_command_line (if_control, p + 3); + else if (p1 - p > 3 && !strncmp (p, "try", 3)) + *command = build_command_line (if_control, p + 4); else if (p1 - p == 10 && !strncmp (p, "loop_break", 10)) { *command = (struct command_line *) @@ -847,7 +941,8 @@ recurse_read_control_structure (struct c if (val == end_command) { if (current_cmd->control_type == while_control - || current_cmd->control_type == if_control) + || current_cmd->control_type == if_control + || current_cmd->control_type == try_control) { /* Success reading an entire control structure. */ ret = simple_control; @@ -877,6 +972,23 @@ recurse_read_control_structure (struct c break; } } + else if (val == CATCH_command) + { + if (current_cmd->control_type == try_control + && current_body == 1) + { + realloc_body_list (current_cmd, 2); + current_body = 2; + child_tail = NULL; + continue; + } + else + { + ret = invalid_control; + break; + } + } + if (child_tail) { @@ -897,7 +1009,8 @@ recurse_read_control_structure (struct c /* If the latest line is another control structure, then recurse on it. */ if (next->control_type == while_control - || next->control_type == if_control) + || next->control_type == if_control + || next->control_type == try_control) { control_level++; ret = recurse_read_control_structure (next); @@ -964,7 +1077,8 @@ read_command_lines (char *prompt_arg, in } if (next->control_type == while_control - || next->control_type == if_control) + || next->control_type == if_control + || next->control_type == try_control) { control_level++; ret = recurse_read_control_structure (next); Index: cli/cli-script.h =================================================================== RCS file: /cvs/src/src/gdb/cli/cli-script.h,v retrieving revision 1.2 diff -p -u -w -r1.2 cli-script.h --- cli-script.h 2001/03/06 08:21:20 1.2 +++ cli-script.h 2001/11/27 08:07:08 @@ -31,6 +31,8 @@ extern void while_command (char *arg, in extern void if_command (char *arg, int from_tty); +extern void try_command (char *block, int from_tty); + extern void show_user_1 (struct cmd_list_element *c, struct ui_file *stream); /* Exported to gdb/breakpoint.c */ -- dhoward@redhat.com gdb engineering From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 3144 invoked by alias); 27 Nov 2001 16:43:11 -0000 Mailing-List: contact gdb-help@sourceware.cygnus.com; run by ezmlm Precedence: bulk List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-owner@sources.redhat.com Received: (qmail 3111 invoked from network); 27 Nov 2001 16:43:06 -0000 Received: from unknown (HELO cygnus.com) (205.180.230.5) by hostedprojects.ges.redhat.com with SMTP; 27 Nov 2001 16:43:06 -0000 Received: from theotherone.redhat-remotie.org (taarna.cygnus.com [205.180.230.102]) by runyon.cygnus.com (8.8.7-cygnus/8.8.7) with ESMTP id IAA16129 for ; Tue, 27 Nov 2001 08:43:04 -0800 (PST) Received: from localhost (localhost.fidalgo.net [127.0.0.1]) by theotherone.redhat-remotie.org (Postfix) with ESMTP id 8A489BB279 for ; Tue, 27 Nov 2001 08:35:11 -0800 (PST) Date: Sat, 17 Nov 2001 12:21:00 -0000 From: Don Howard X-X-Sender: To: Subject: Re: error-catching mechanism for scripts Message-ID: MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII X-SW-Source: 2001-11/txt/msg00184.txt.bz2 Message-ID: <20011117122100.lzfV9EijqdIORR9LaJWJtFkWoXNFjL_WD099YwwL_7A@z> > I've been trying to find a way to make gdb command scripts handle errors > in a flexible way -- either making continue-on-error an option or some > kind of simple exception catching mechanism: > > > set script-continue-on-error 1 > > -- or -- > > try > commands > catch > commands > end > > > I'd like to know what others think. Ok, I've got a partial implementation of the try/catch idea that I'd like to get some feedback on. (Let me know if I'm headed the right way before I spend too much time on this) I know that the keywords try/catch (esp catch) won't work, as gdb already has a catch command. I'd appreciate a suggestion on what to name this command. For now I've simple gone with CATCH (all caps) to avoid name collisions. Index: defs.h =================================================================== RCS file: /cvs/src/src/gdb/defs.h,v retrieving revision 1.64 diff -p -u -w -r1.64 defs.h --- defs.h 2001/10/17 20:35:31 1.64 +++ defs.h 2001/11/27 08:07:06 @@ -815,16 +815,18 @@ enum misc_command_type ok_command, end_command, else_command, + CATCH_command, nop_command }; enum command_control_type { - simple_control, + simple_control = 1, break_control, continue_control, while_control, if_control, + try_control, invalid_control }; Index: cli/cli-cmds.c =================================================================== RCS file: /cvs/src/src/gdb/cli/cli-cmds.c,v retrieving revision 1.10 diff -p -u -w -r1.10 cli-cmds.c --- cli-cmds.c 2001/09/01 21:38:05 1.10 +++ cli-cmds.c 2001/11/27 08:07:07 @@ -721,6 +721,9 @@ The conditional expression must follow t followed by a new line. The nested commands must be entered one per line,\n\ and should be terminated by the word `end'."); + add_com ("try", class_support, try_command, + "Try/Catch support"); + add_com ("if", class_support, if_command, "Execute nested commands once IF the conditional expression is non zero.\n\ The conditional expression must follow the word `if' and must in turn be\n\ Index: cli/cli-script.c =================================================================== RCS file: /cvs/src/src/gdb/cli/cli-script.c,v retrieving revision 1.7 diff -p -u -w -r1.7 cli-script.c --- cli-script.c 2001/06/17 15:16:12 1.7 +++ cli-script.c 2001/11/27 08:07:08 @@ -210,6 +210,34 @@ print_command_lines (struct ui_out *uiou continue; } + /* A try command. Recursively print the try and catch blocks + before continuing. */ + if (list->control_type == try_control) + { + ui_out_text (uiout, "try"); + ui_out_field_fmt (uiout, NULL, "try\n"); + ui_out_text (uiout, "\n"); + /* The true arm. */ + print_command_lines (uiout, list->body_list[0], depth + 1); + + /* Show the false arm if it exists. */ + if (list->body_count == 2) + { + if (depth) + ui_out_spaces (uiout, 2 * depth); + ui_out_field_string (uiout, NULL, "CATCH"); + ui_out_text (uiout, "CATCH\n"); + print_command_lines (uiout, list->body_list[1], depth + 1); + } + + ui_out_field_string (uiout, NULL, "end"); + if (depth) + ui_out_spaces (uiout, 2 * depth); + ui_out_text (uiout, "end\n"); + list = list->next; + continue; + } + /* ignore illegal command type and try next */ list = list->next; } /* while (list) */ @@ -292,6 +320,33 @@ print_command_line (struct command_line } fputs_filtered ("end\n", stream); } + + /* A try command. Recursively print both try and catch blocks. */ + if (cmd->control_type == try_control) + { + fputs_filtered ("try", stream); + fputs_filtered (cmd->line, stream); + fputs_filtered ("\n", stream); + /* The true arm. */ + print_command_line (cmd->body_list[0], depth + 1, stream); + + /* Show the catch block if it exists. */ + if (cmd->body_count == 2) + { + if (depth) + { + for (i = 0; i < depth; i++) + fputs_filtered (" ", stream); + } + fputs_filtered ("CATCH\n", stream); + print_command_line (cmd->body_list[1], depth + 1, stream); + } + if (depth) + { + for (i = 0; i < depth; i++) + fputs_filtered (" ", stream); + } + fputs_filtered ("end\n", stream); } } #endif @@ -461,6 +516,24 @@ execute_control_command (struct command_ break; } + case try_control: + { + for (current = cmd->body_list[0]; current; current = current->next) + { + ret = catch_errors (execute_control_command, current, + "try -> CATCH", 0); + + if (ret == 0 || ret == invalid_control) + { + if (cmd->body_count == 2) + current = cmd->body_list[1]; + else + current = NULL; + } + } + break; + } + default: warning ("Invalid control type in command structure."); return invalid_control; @@ -508,6 +581,21 @@ if_command (char *arg, int from_tty) free_command_lines (&command); } +void +try_command (char *block, int from_tty) +{ + struct command_line *command = NULL; + + control_level = 1; + command = get_command_line (try_control, block); + + if (command == NULL) + return; + + execute_control_command (command); + free_command_lines (&command); +} + /* Cleanup */ static void arg_cleanup (void *ignore) @@ -760,12 +848,18 @@ read_next_line (struct command_line **co if (p1 - p == 4 && !strncmp (p, "else", 4)) return else_command; + /* Is the catch clause of an if try structure? */ + if (p1 - p == 5 && !strncmp (p, "CATCH", 5)) + return CATCH_command; + /* Check for while, if, break, continue, etc and build a new command line structure for them. */ if (p1 - p > 5 && !strncmp (p, "while", 5)) *command = build_command_line (while_control, p + 6); else if (p1 - p > 2 && !strncmp (p, "if", 2)) *command = build_command_line (if_control, p + 3); + else if (p1 - p > 3 && !strncmp (p, "try", 3)) + *command = build_command_line (if_control, p + 4); else if (p1 - p == 10 && !strncmp (p, "loop_break", 10)) { *command = (struct command_line *) @@ -847,7 +941,8 @@ recurse_read_control_structure (struct c if (val == end_command) { if (current_cmd->control_type == while_control - || current_cmd->control_type == if_control) + || current_cmd->control_type == if_control + || current_cmd->control_type == try_control) { /* Success reading an entire control structure. */ ret = simple_control; @@ -877,6 +972,23 @@ recurse_read_control_structure (struct c break; } } + else if (val == CATCH_command) + { + if (current_cmd->control_type == try_control + && current_body == 1) + { + realloc_body_list (current_cmd, 2); + current_body = 2; + child_tail = NULL; + continue; + } + else + { + ret = invalid_control; + break; + } + } + if (child_tail) { @@ -897,7 +1009,8 @@ recurse_read_control_structure (struct c /* If the latest line is another control structure, then recurse on it. */ if (next->control_type == while_control - || next->control_type == if_control) + || next->control_type == if_control + || next->control_type == try_control) { control_level++; ret = recurse_read_control_structure (next); @@ -964,7 +1077,8 @@ read_command_lines (char *prompt_arg, in } if (next->control_type == while_control - || next->control_type == if_control) + || next->control_type == if_control + || next->control_type == try_control) { control_level++; ret = recurse_read_control_structure (next); Index: cli/cli-script.h =================================================================== RCS file: /cvs/src/src/gdb/cli/cli-script.h,v retrieving revision 1.2 diff -p -u -w -r1.2 cli-script.h --- cli-script.h 2001/03/06 08:21:20 1.2 +++ cli-script.h 2001/11/27 08:07:08 @@ -31,6 +31,8 @@ extern void while_command (char *arg, in extern void if_command (char *arg, int from_tty); +extern void try_command (char *block, int from_tty); + extern void show_user_1 (struct cmd_list_element *c, struct ui_file *stream); /* Exported to gdb/breakpoint.c */ -- dhoward@redhat.com gdb engineering