X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Fmi%2Fmi-cmd-break.c;h=cfe2d34f23fdd9823a025d82bd4c405d258f92aa;hb=93921405a46c0a58eae19fffb92e02416082801a;hp=5d15aa98b8a7fd52fdd7478234b4ffcf1af565ee;hpb=2ee563b53258d390d7446e90a67f465d504ae44c;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/mi/mi-cmd-break.c b/gdb/mi/mi-cmd-break.c index 5d15aa98b8..cfe2d34f23 100644 --- a/gdb/mi/mi-cmd-break.c +++ b/gdb/mi/mi-cmd-break.c @@ -1,12 +1,12 @@ /* MI Command Set - breakpoint and watchpoint commands. - Copyright 2000, 2001, 2002 Free Software Foundation, Inc. + Copyright (C) 2000-2017 Free Software Foundation, Inc. Contributed by Cygnus Solutions (a Red Hat company). This file is part of GDB. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -15,41 +15,46 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ + along with this program. If not, see . */ #include "defs.h" +#include "arch-utils.h" #include "mi-cmds.h" #include "ui-out.h" #include "mi-out.h" #include "breakpoint.h" -#include "gdb_string.h" #include "mi-getopt.h" -#include "gdb-events.h" #include "gdb.h" +#include "observer.h" +#include "mi-main.h" +#include "mi-cmd-break.h" +#include "language.h" +#include "location.h" +#include "linespec.h" +#include "gdb_obstack.h" +#include enum { FROM_TTY = 0 }; -/* Output a single breakpoint. */ +/* True if MI breakpoint observers have been registered. */ -static void -breakpoint_notify (int b) -{ - gdb_breakpoint_query (uiout, b); -} +static int mi_breakpoint_observers_installed; +/* Control whether breakpoint_notify may act. */ -struct gdb_events breakpoint_hooks = -{ - breakpoint_notify, - breakpoint_notify, - breakpoint_notify, -}; +static int mi_can_breakpoint_notify; + +/* Output a single breakpoint, when allowed. */ +static void +breakpoint_notify (struct breakpoint *b) +{ + if (mi_can_breakpoint_notify) + gdb_breakpoint_query (current_uiout, b->number, NULL); +} enum bp_type { @@ -58,48 +63,165 @@ enum bp_type REGEXP_BP }; -/* Insert a breakpoint. The type of breakpoint is specified by the - first argument: -break-insert --> insert a regular - breakpoint. -break-insert -t --> insert a temporary - breakpoint. -break-insert -h --> insert an hardware - breakpoint. -break-insert -t -h --> insert a temporary - hw bp. - -break-insert -r --> insert a bp at functions matching - */ - -enum mi_cmd_result -mi_cmd_break_insert (char *command, char **argv, int argc) +/* Arrange for all new breakpoints and catchpoints to be reported to + CURRENT_UIOUT until the cleanup returned by this function is run. + + Note that MI output will be probably invalid if more than one + breakpoint is created inside one MI command. */ + +struct cleanup * +setup_breakpoint_reporting (void) +{ + struct cleanup *rev_flag; + + if (! mi_breakpoint_observers_installed) + { + observer_attach_breakpoint_created (breakpoint_notify); + mi_breakpoint_observers_installed = 1; + } + + rev_flag = make_cleanup_restore_integer (&mi_can_breakpoint_notify); + mi_can_breakpoint_notify = 1; + + return rev_flag; +} + + +/* Convert arguments in ARGV to the string in "format",argv,argv... + and return it. */ + +static char * +mi_argv_to_format (char **argv, int argc) +{ + int i; + struct obstack obstack; + char *ret; + + obstack_init (&obstack); + + /* Convert ARGV[OIND + 1] to format string and save to FORMAT. */ + obstack_1grow (&obstack, '\"'); + for (i = 0; i < strlen (argv[0]); i++) + { + switch (argv[0][i]) + { + case '\\': + obstack_grow (&obstack, "\\\\", 2); + break; + case '\a': + obstack_grow (&obstack, "\\a", 2); + break; + case '\b': + obstack_grow (&obstack, "\\b", 2); + break; + case '\f': + obstack_grow (&obstack, "\\f", 2); + break; + case '\n': + obstack_grow (&obstack, "\\n", 2); + break; + case '\r': + obstack_grow (&obstack, "\\r", 2); + break; + case '\t': + obstack_grow (&obstack, "\\t", 2); + break; + case '\v': + obstack_grow (&obstack, "\\v", 2); + break; + case '"': + obstack_grow (&obstack, "\\\"", 2); + break; + default: + if (isprint (argv[0][i])) + obstack_grow (&obstack, argv[0] + i, 1); + else + { + char tmp[5]; + + xsnprintf (tmp, sizeof (tmp), "\\%o", + (unsigned char) argv[0][i]); + obstack_grow (&obstack, tmp, strlen (tmp)); + } + break; + } + } + obstack_1grow (&obstack, '\"'); + + /* Apply other argv to FORMAT. */ + for (i = 1; i < argc; i++) + { + obstack_1grow (&obstack, ','); + obstack_grow (&obstack, argv[i], strlen (argv[i])); + } + obstack_1grow (&obstack, '\0'); + + ret = xstrdup ((const char *) obstack_finish (&obstack)); + obstack_free (&obstack, NULL); + + return ret; +} + +/* Insert breakpoint. + If dprintf is true, it will insert dprintf. + If not, it will insert other type breakpoint. */ + +static void +mi_cmd_break_insert_1 (int dprintf, const char *command, char **argv, int argc) { char *address = NULL; - enum bp_type type = REG_BP; + int hardware = 0; int temp_p = 0; int thread = -1; int ignore_count = 0; char *condition = NULL; - enum gdb_rc rc; - struct gdb_events *old_hooks; + int pending = 0; + int enabled = 1; + int tracepoint = 0; + struct cleanup *back_to = make_cleanup (null_cleanup, NULL); + enum bptype type_wanted; + event_location_up location; + struct breakpoint_ops *ops; + int is_explicit = 0; + struct explicit_location explicit_loc; + char *extra_string = NULL; + enum opt { - HARDWARE_OPT, TEMP_OPT /*, REGEXP_OPT */ , CONDITION_OPT, - IGNORE_COUNT_OPT, THREAD_OPT + HARDWARE_OPT, TEMP_OPT, CONDITION_OPT, + IGNORE_COUNT_OPT, THREAD_OPT, PENDING_OPT, DISABLE_OPT, + TRACEPOINT_OPT, + EXPLICIT_SOURCE_OPT, EXPLICIT_FUNC_OPT, + EXPLICIT_LABEL_OPT, EXPLICIT_LINE_OPT }; - static struct mi_opt opts[] = + static const struct mi_opt opts[] = { {"h", HARDWARE_OPT, 0}, {"t", TEMP_OPT, 0}, {"c", CONDITION_OPT, 1}, {"i", IGNORE_COUNT_OPT, 1}, {"p", THREAD_OPT, 1}, - 0 + {"f", PENDING_OPT, 0}, + {"d", DISABLE_OPT, 0}, + {"a", TRACEPOINT_OPT, 0}, + {"-source" , EXPLICIT_SOURCE_OPT, 1}, + {"-function", EXPLICIT_FUNC_OPT, 1}, + {"-label", EXPLICIT_LABEL_OPT, 1}, + {"-line", EXPLICIT_LINE_OPT, 1}, + { 0, 0, 0 } }; /* Parse arguments. It could be -r or -h or -t, or ``--'' to denote the end of the option list. */ - int optind = 0; - char *optarg; + int oind = 0; + char *oarg; + + initialize_explicit_location (&explicit_loc); + while (1) { - int opt = mi_getopt ("mi_cmd_break_insert", argc, argv, opts, &optind, &optarg); + int opt = mi_getopt ("-break-insert", argc, argv, + opts, &oind, &oarg); if (opt < 0) break; switch ((enum opt) opt) @@ -108,64 +230,148 @@ mi_cmd_break_insert (char *command, char **argv, int argc) temp_p = 1; break; case HARDWARE_OPT: - type = HW_BP; - break; -#if 0 - case REGEXP_OPT: - type = REGEXP_BP; + hardware = 1; break; -#endif case CONDITION_OPT: - condition = optarg; + condition = oarg; break; case IGNORE_COUNT_OPT: - ignore_count = atol (optarg); + ignore_count = atol (oarg); break; case THREAD_OPT: - thread = atol (optarg); + thread = atol (oarg); + break; + case PENDING_OPT: + pending = 1; + break; + case DISABLE_OPT: + enabled = 0; + break; + case TRACEPOINT_OPT: + tracepoint = 1; + break; + case EXPLICIT_SOURCE_OPT: + is_explicit = 1; + explicit_loc.source_filename = oarg; + break; + case EXPLICIT_FUNC_OPT: + is_explicit = 1; + explicit_loc.function_name = oarg; + break; + case EXPLICIT_LABEL_OPT: + is_explicit = 1; + explicit_loc.label_name = oarg; + break; + case EXPLICIT_LINE_OPT: + is_explicit = 1; + explicit_loc.line_offset = linespec_parse_line_offset (oarg); break; } } - if (optind >= argc) - error ("mi_cmd_break_insert: Missing "); - if (optind < argc - 1) - error ("mi_cmd_break_insert: Garbage following "); - address = argv[optind]; + if (oind >= argc && !is_explicit) + error (_("-%s-insert: Missing "), + dprintf ? "dprintf" : "break"); + if (dprintf) + { + int format_num = is_explicit ? oind : oind + 1; - /* Now we have what we need, let's insert the breakpoint! */ - old_hooks = set_gdb_event_hooks (&breakpoint_hooks); - switch (type) + if (hardware || tracepoint) + error (_("-dprintf-insert: does not support -h or -a")); + if (format_num >= argc) + error (_("-dprintf-insert: Missing ")); + + extra_string = mi_argv_to_format (argv + format_num, argc - format_num); + make_cleanup (xfree, extra_string); + address = argv[oind]; + } + else { - case REG_BP: - rc = gdb_breakpoint (address, condition, - 0 /*hardwareflag */ , temp_p, - thread, ignore_count); - break; - case HW_BP: - rc = gdb_breakpoint (address, condition, - 1 /*hardwareflag */ , temp_p, - thread, ignore_count); - break; -#if 0 - case REGEXP_BP: - if (temp_p) - error ("mi_cmd_break_insert: Unsupported tempoary regexp breakpoint"); + if (is_explicit) + { + if (oind < argc) + error (_("-break-insert: Garbage following explicit location")); + } else - rbreak_command_wrapper (address, FROM_TTY); - return MI_CMD_DONE; - break; -#endif - default: - internal_error (__FILE__, __LINE__, - "mi_cmd_break_insert: Bad switch."); + { + if (oind < argc - 1) + error (_("-break-insert: Garbage following ")); + address = argv[oind]; + } } - set_gdb_event_hooks (old_hooks); - if (rc == GDB_RC_FAIL) - return MI_CMD_CAUGHT_ERROR; + /* Now we have what we need, let's insert the breakpoint! */ + setup_breakpoint_reporting (); + + if (tracepoint) + { + /* Note that to request a fast tracepoint, the client uses the + "hardware" flag, although there's nothing of hardware related to + fast tracepoints -- one can implement slow tracepoints with + hardware breakpoints, but fast tracepoints are always software. + "fast" is a misnomer, actually, "jump" would be more appropriate. + A simulator or an emulator could conceivably implement fast + regular non-jump based tracepoints. */ + type_wanted = hardware ? bp_fast_tracepoint : bp_tracepoint; + ops = &tracepoint_breakpoint_ops; + } + else if (dprintf) + { + type_wanted = bp_dprintf; + ops = &dprintf_breakpoint_ops; + } else - return MI_CMD_DONE; + { + type_wanted = hardware ? bp_hardware_breakpoint : bp_breakpoint; + ops = &bkpt_breakpoint_ops; + } + + if (is_explicit) + { + /* Error check -- we must have one of the other + parameters specified. */ + if (explicit_loc.source_filename != NULL + && explicit_loc.function_name == NULL + && explicit_loc.label_name == NULL + && explicit_loc.line_offset.sign == LINE_OFFSET_UNKNOWN) + error (_("-%s-insert: --source option requires --function, --label," + " or --line"), dprintf ? "dprintf" : "break"); + + location = new_explicit_location (&explicit_loc); + } + else + { + location = string_to_event_location_basic (&address, current_language); + if (*address) + error (_("Garbage '%s' at end of location"), address); + } + + create_breakpoint (get_current_arch (), location.get (), condition, thread, + extra_string, + 0 /* condition and thread are valid. */, + temp_p, type_wanted, + ignore_count, + pending ? AUTO_BOOLEAN_TRUE : AUTO_BOOLEAN_FALSE, + ops, 0, enabled, 0, 0); + do_cleanups (back_to); +} + +/* Implements the -break-insert command. + See the MI manual for the list of possible options. */ + +void +mi_cmd_break_insert (const char *command, char **argv, int argc) +{ + mi_cmd_break_insert_1 (0, command, argv, argc); +} + +/* Implements the -dprintf-insert command. + See the MI manual for the list of possible options. */ + +void +mi_cmd_dprintf_insert (const char *command, char **argv, int argc) +{ + mi_cmd_break_insert_1 (1, command, argv, argc); } enum wp_type @@ -175,14 +381,39 @@ enum wp_type ACCESS_WP }; +void +mi_cmd_break_passcount (const char *command, char **argv, int argc) +{ + int n; + int p; + struct tracepoint *t; + + if (argc != 2) + error (_("Usage: tracepoint-number passcount")); + + n = atoi (argv[0]); + p = atoi (argv[1]); + t = get_tracepoint (n); + + if (t) + { + t->pass_count = p; + observer_notify_breakpoint_modified (&t->base); + } + else + { + error (_("Could not find tracepoint %d"), n); + } +} + /* Insert a watchpoint. The type of watchpoint is specified by the first argument: -break-watch --> insert a regular wp. -break-watch -r --> insert a read watchpoint. - -break-watch -a --> insert an access wp. */ + -break-watch -a --> insert an access wp. */ -enum mi_cmd_result -mi_cmd_break_watch (char *command, char **argv, int argc) +void +mi_cmd_break_watch (const char *command, char **argv, int argc) { char *expr = NULL; enum wp_type type = REG_WP; @@ -190,19 +421,22 @@ mi_cmd_break_watch (char *command, char **argv, int argc) { READ_OPT, ACCESS_OPT }; - static struct mi_opt opts[] = + static const struct mi_opt opts[] = { {"r", READ_OPT, 0}, {"a", ACCESS_OPT, 0}, - 0 + { 0, 0, 0 } }; /* Parse arguments. */ - int optind = 0; - char *optarg; + int oind = 0; + char *oarg; + while (1) { - int opt = mi_getopt ("mi_cmd_break_watch", argc, argv, opts, &optind, &optarg); + int opt = mi_getopt ("-break-watch", argc, argv, + opts, &oind, &oarg); + if (opt < 0) break; switch ((enum opt) opt) @@ -215,26 +449,80 @@ mi_cmd_break_watch (char *command, char **argv, int argc) break; } } - if (optind >= argc) - error ("mi_cmd_break_watch: Missing "); - if (optind < argc - 1) - error ("mi_cmd_break_watch: Garbage following "); - expr = argv[optind]; + if (oind >= argc) + error (_("-break-watch: Missing ")); + if (oind < argc - 1) + error (_("-break-watch: Garbage following ")); + expr = argv[oind]; - /* Now we have what we need, let's insert the watchpoint! */ + /* Now we have what we need, let's insert the watchpoint! */ switch (type) { case REG_WP: - watch_command_wrapper (expr, FROM_TTY); + watch_command_wrapper (expr, FROM_TTY, 0); break; case READ_WP: - rwatch_command_wrapper (expr, FROM_TTY); + rwatch_command_wrapper (expr, FROM_TTY, 0); break; case ACCESS_WP: - awatch_command_wrapper (expr, FROM_TTY); + awatch_command_wrapper (expr, FROM_TTY, 0); break; default: - error ("mi_cmd_break_watch: Unknown watchpoint type."); + error (_("-break-watch: Unknown watchpoint type.")); } - return MI_CMD_DONE; } + +/* The mi_read_next_line consults these variable to return successive + command lines. While it would be clearer to use a closure pointer, + it is not expected that any future code will use read_command_lines_1, + therefore no point of overengineering. */ + +static char **mi_command_line_array; +static int mi_command_line_array_cnt; +static int mi_command_line_array_ptr; + +static char * +mi_read_next_line (void) +{ + if (mi_command_line_array_ptr == mi_command_line_array_cnt) + return NULL; + else + return mi_command_line_array[mi_command_line_array_ptr++]; +} + +void +mi_cmd_break_commands (const char *command, char **argv, int argc) +{ + command_line_up break_command; + char *endptr; + int bnum; + struct breakpoint *b; + + if (argc < 1) + error (_("USAGE: %s [ [...]]"), command); + + bnum = strtol (argv[0], &endptr, 0); + if (endptr == argv[0]) + error (_("breakpoint number argument \"%s\" is not a number."), + argv[0]); + else if (*endptr != '\0') + error (_("junk at the end of breakpoint number argument \"%s\"."), + argv[0]); + + b = get_breakpoint (bnum); + if (b == NULL) + error (_("breakpoint %d not found."), bnum); + + mi_command_line_array = argv; + mi_command_line_array_ptr = 1; + mi_command_line_array_cnt = argc; + + if (is_tracepoint (b)) + break_command = read_command_lines_1 (mi_read_next_line, 1, + check_tracepoint_command, b); + else + break_command = read_command_lines_1 (mi_read_next_line, 1, 0, 0); + + breakpoint_set_commands (b, std::move (break_command)); +} +