From: Hui Zhu Date: Tue, 21 May 2013 04:18:55 +0000 (+0000) Subject: 2013-05-21 Hui Zhu X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=c5867ab65ce98cb27943606d66eee564c60a7d23;p=binutils-gdb.git 2013-05-21 Hui Zhu * breakpoint.c (dprintf_breakpoint_ops): Remove its static. * breakpoint.h (dprintf_breakpoint_ops): Add extern. * mi/mi-cmd-break.c (ctype.h): New include. (gdb_obstack.h): New include. (mi_argv_to_format, mi_cmd_break_insert_1): New. (mi_cmd_break_insert): Call mi_cmd_break_insert_1. (mi_cmd_dprintf_insert): New. * mi/mi-cmds.c (mi_cmds): Add "dprintf-insert". * mi/mi-cmds.h (mi_cmd_dprintf_insert): New extern. 2013-05-21 Hui Zhu * gdb.texinfo (GDB/MI Breakpoint Commands): Describe the "-dprintf-insert" command. 2013-05-21 Hui Zhu * gdb.mi/Makefile.in (PROGS): Add "mi-dprintf". * gdb.mi/mi-dprintf.exp, gdb.mi/mi-dprintf.c: New. --- diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 160aeacce82..19a4cd6d2c8 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,15 @@ +2013-05-21 Hui Zhu + + * breakpoint.c (dprintf_breakpoint_ops): Remove its static. + * breakpoint.h (dprintf_breakpoint_ops): Add extern. + * mi/mi-cmd-break.c (ctype.h): New include. + (gdb_obstack.h): New include. + (mi_argv_to_format, mi_cmd_break_insert_1): New. + (mi_cmd_break_insert): Call mi_cmd_break_insert_1. + (mi_cmd_dprintf_insert): New. + * mi/mi-cmds.c (mi_cmds): Add "dprintf-insert". + * mi/mi-cmds.h (mi_cmd_dprintf_insert): New extern. + 2013-05-20 Tom Tromey * python/py-prettyprint.c (search_pp_list): Decref 'attr'. diff --git a/gdb/NEWS b/gdb/NEWS index 9ea0b147d23..e09907cf39a 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -70,6 +70,8 @@ show debug nios2 ** The -trace-save MI command can optionally save trace buffer in Common Trace Format now. + ** The new command -dprintf-insert sets a dynamic printf breakpoint. + *** Changes in GDB 7.6 * Target record has been renamed to record-full. diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c index f4f9325ab64..bbbaaf56ab3 100644 --- a/gdb/breakpoint.c +++ b/gdb/breakpoint.c @@ -301,7 +301,7 @@ struct breakpoint_ops bkpt_breakpoint_ops; static struct breakpoint_ops bkpt_probe_breakpoint_ops; /* Dynamic printf class type. */ -static struct breakpoint_ops dprintf_breakpoint_ops; +struct breakpoint_ops dprintf_breakpoint_ops; /* The style in which to perform a dynamic printf. This is a user option because different output options have different tradeoffs; diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h index 7df1122ed50..06afd12397b 100644 --- a/gdb/breakpoint.h +++ b/gdb/breakpoint.h @@ -1212,6 +1212,7 @@ extern void tbreak_command (char *, int); extern struct breakpoint_ops base_breakpoint_ops; extern struct breakpoint_ops bkpt_breakpoint_ops; extern struct breakpoint_ops tracepoint_breakpoint_ops; +extern struct breakpoint_ops dprintf_breakpoint_ops; extern void initialize_breakpoint_ops (void); diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog index 5222cd840ec..41e08b80a59 100644 --- a/gdb/doc/ChangeLog +++ b/gdb/doc/ChangeLog @@ -1,3 +1,8 @@ +2013-05-21 Hui Zhu + + * gdb.texinfo (GDB/MI Breakpoint Commands): Describe the + "-dprintf-insert" command. + 2013-05-17 Doug Evans * gdb.texinfo (Maintenance Commands): Update doc for diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 1907e59cbb4..43b01046165 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -29789,6 +29789,84 @@ times="0"@}]@} @c (gdb) @end smallexample +@subheading The @code{-dprintf-insert} Command +@findex -dprintf-insert + +@subsubheading Synopsis + +@smallexample + -dprintf-insert [ -t ] [ -f ] [ -d ] + [ -c @var{condition} ] [ -i @var{ignore-count} ] + [ -p @var{thread-id} ] [ @var{location} ] [ @var{format} ] + [ @var{argument} ] +@end smallexample + +@noindent +If specified, @var{location}, can be one of: + +@itemize @bullet +@item @var{function} +@c @item +offset +@c @item -offset +@c @item @var{linenum} +@item @var{filename}:@var{linenum} +@item @var{filename}:function +@item *@var{address} +@end itemize + +The possible optional parameters of this command are: + +@table @samp +@item -t +Insert a temporary breakpoint. +@item -f +If @var{location} cannot be parsed (for example, if it +refers to unknown files or functions), create a pending +breakpoint. Without this flag, @value{GDBN} will report +an error, and won't create a breakpoint, if @var{location} +cannot be parsed. +@item -d +Create a disabled breakpoint. +@item -c @var{condition} +Make the breakpoint conditional on @var{condition}. +@item -i @var{ignore-count} +Set the ignore count of the breakpoint (@pxref{Conditions, ignore count}) +to @var{ignore-count}. +@item -p @var{thread-id} +Restrict the breakpoint to the specified @var{thread-id}. +@end table + +@subsubheading Result + +@xref{GDB/MI Breakpoint Information}, for details on the format of the +resulting breakpoint. + +@c An out-of-band breakpoint instead of part of the result? + +@subsubheading @value{GDBN} Command + +The corresponding @value{GDBN} command is @samp{dprintf}. + +@subsubheading Example + +@smallexample +(gdb) +4-dprintf-insert foo "At foo entry\n" +4^done,bkpt=@{number="1",type="dprintf",disp="keep",enabled="y", +addr="0x000000000040061b",func="foo",file="mi-dprintf.c", +fullname="mi-dprintf.c",line="25",thread-groups=["i1"], +times="0",script=@{"printf \"At foo entry\\n\"","continue"@}, +original-location="foo"@} +(gdb) +5-dprintf-insert 26 "arg=%d, g=%d\n" arg g +5^done,bkpt=@{number="2",type="dprintf",disp="keep",enabled="y", +addr="0x000000000040062a",func="foo",file="mi-dprintf.c", +fullname="mi-dprintf.c",line="26",thread-groups=["i1"], +times="0",script=@{"printf \"arg=%d, g=%d\\n\", arg, g","continue"@}, +original-location="mi-dprintf.c:26"@} +(gdb) +@end smallexample + @subheading The @code{-break-list} Command @findex -break-list diff --git a/gdb/mi/mi-cmd-break.c b/gdb/mi/mi-cmd-break.c index ebc1e6a61e3..050cf3f3c02 100644 --- a/gdb/mi/mi-cmd-break.c +++ b/gdb/mi/mi-cmd-break.c @@ -30,6 +30,8 @@ #include "observer.h" #include "mi-main.h" #include "mi-cmd-break.h" +#include "gdb_obstack.h" +#include enum { @@ -84,11 +86,83 @@ setup_breakpoint_reporting (void) } -/* Implements the -break-insert command. - See the MI manual for the list of possible options. */ +/* Convert arguments in ARGV to the string in "format",argv,argv... + and return it. */ -void -mi_cmd_break_insert (char *command, char **argv, int argc) +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; + default: + if (isprint (argv[0][i])) + obstack_grow (&obstack, argv[0] + i, 1); + else + { + char tmp[5]; + + sprintf (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 (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, char *command, char **argv, int argc) { char *address = NULL; int hardware = 0; @@ -99,9 +173,10 @@ mi_cmd_break_insert (char *command, char **argv, int argc) int pending = 0; int enabled = 1; int tracepoint = 0; - struct cleanup *back_to; + struct cleanup *back_to = make_cleanup (null_cleanup, NULL); enum bptype type_wanted; struct breakpoint_ops *ops; + char *extra_string = NULL; enum opt { @@ -163,35 +238,79 @@ mi_cmd_break_insert (char *command, char **argv, int argc) } if (oind >= argc) - error (_("-break-insert: Missing ")); - if (oind < argc - 1) - error (_("-break-insert: Garbage following ")); + error (_("-%s-insert: Missing "), + dprintf ? "dprintf" : "break"); address = argv[oind]; + if (dprintf) + { + int format_num = oind + 1; + + 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); + } + else + { + if (oind < argc - 1) + error (_("-break-insert: Garbage following ")); + } /* Now we have what we need, let's insert the breakpoint! */ - back_to = setup_breakpoint_reporting (); - - /* 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 = (tracepoint - ? (hardware ? bp_fast_tracepoint : bp_tracepoint) - : (hardware ? bp_hardware_breakpoint : bp_breakpoint)); - ops = tracepoint ? &tracepoint_breakpoint_ops : &bkpt_breakpoint_ops; + 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 + { + type_wanted = hardware ? bp_hardware_breakpoint : bp_breakpoint; + ops = &bkpt_breakpoint_ops; + } create_breakpoint (get_current_arch (), address, condition, thread, - NULL, + 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 (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 (char *command, char **argv, int argc) +{ + mi_cmd_break_insert_1 (1, command, argv, argc); } enum wp_type diff --git a/gdb/mi/mi-cmds.c b/gdb/mi/mi-cmds.c index c9efa815af0..124a9dd8249 100644 --- a/gdb/mi/mi-cmds.c +++ b/gdb/mi/mi-cmds.c @@ -61,6 +61,8 @@ static struct mi_cmd mi_cmds[] = DEF_MI_CMD_CLI ("break-info", "info break", 1), DEF_MI_CMD_MI_1 ("break-insert", mi_cmd_break_insert, &mi_suppress_notification.breakpoint), + DEF_MI_CMD_MI_1 ("dprintf-insert", mi_cmd_dprintf_insert, + &mi_suppress_notification.breakpoint), DEF_MI_CMD_CLI ("break-list", "info break", 0), DEF_MI_CMD_MI_1 ("break-passcount", mi_cmd_break_passcount, &mi_suppress_notification.breakpoint), diff --git a/gdb/mi/mi-cmds.h b/gdb/mi/mi-cmds.h index 4b9fb7ade6c..8199d15ad2c 100644 --- a/gdb/mi/mi-cmds.h +++ b/gdb/mi/mi-cmds.h @@ -39,6 +39,7 @@ typedef void (mi_cmd_argv_ftype) (char *command, char **argv, int argc); extern mi_cmd_argv_ftype mi_cmd_ada_task_info; extern mi_cmd_argv_ftype mi_cmd_add_inferior; extern mi_cmd_argv_ftype mi_cmd_break_insert; +extern mi_cmd_argv_ftype mi_cmd_dprintf_insert; extern mi_cmd_argv_ftype mi_cmd_break_commands; extern mi_cmd_argv_ftype mi_cmd_break_passcount; extern mi_cmd_argv_ftype mi_cmd_break_watch; diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 3af60673cc9..e436c6b5a37 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2013-05-21 Hui Zhu + + * gdb.mi/Makefile.in (PROGS): Add "mi-dprintf". + * gdb.mi/mi-dprintf.exp, gdb.mi/mi-dprintf.c: New. + 2013-05-20 Doug Evans * lib/dwarf.exp (Dwarf): New variable _abbrev_section. diff --git a/gdb/testsuite/gdb.mi/Makefile.in b/gdb/testsuite/gdb.mi/Makefile.in index 3f9bbb7df6e..661add2d453 100644 --- a/gdb/testsuite/gdb.mi/Makefile.in +++ b/gdb/testsuite/gdb.mi/Makefile.in @@ -3,7 +3,7 @@ srcdir = @srcdir@ PROGS = basics c_variable cpp_variable var-cmd dw2-ref-missing-frame \ gdb669-pthreads gdb701 gdb792 mi-async mi-basics mi-break \ - mi-cli mi-console mi-disassemble mi-eval mi-file \ + mi-cli mi-console mi-disassemble mi-dprintf mi-eval mi-file \ mi-file-transfer mi-non-stop mi-non-stop-exit \ mi-ns-stale-regcache mi-nsintrall mi-nsmoribund mi-nsthrexec \ mi-pending mi-pthreads mi-read-memory mi-regs mi-return \ diff --git a/gdb/testsuite/gdb.mi/mi-dprintf.c b/gdb/testsuite/gdb.mi/mi-dprintf.c new file mode 100644 index 00000000000..a6700dc367a --- /dev/null +++ b/gdb/testsuite/gdb.mi/mi-dprintf.c @@ -0,0 +1,59 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright (C) 2013 Free Software Foundation, Inc. + Contributed by Hui Zhu + + 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, see . */ + +#include +#include + +static int g; + +void +foo (int arg) +{ + g += arg; + g *= 2; /* set dprintf 1 here */ + g /= 2.5; /* set breakpoint 1 here */ +} + +int +main (int argc, char *argv[]) +{ + int loc = 1234; + + /* Ensure these functions are available. */ + printf ("kickoff %d\n", loc); + fprintf (stderr, "also to stderr %d\n", loc); + + foo (loc++); + foo (loc++); + foo (loc++); + return g; +} + +/* Make sure function 'malloc' is linked into program. On some bare-metal + port, if we don't use 'malloc', it will not be linked in program. 'malloc' + is needed, otherwise we'll see such error message + evaluation of this expression requires the program to have a function + "malloc". */ + +void +bar (void) +{ + void *p = malloc (16); + + free (p); +} diff --git a/gdb/testsuite/gdb.mi/mi-dprintf.exp b/gdb/testsuite/gdb.mi/mi-dprintf.exp new file mode 100644 index 00000000000..457f33207c4 --- /dev/null +++ b/gdb/testsuite/gdb.mi/mi-dprintf.exp @@ -0,0 +1,145 @@ +# Copyright (C) 2013 Free Software Foundation, Inc. +# Contributed by Hui Zhu + +# 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 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# 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, see . + +load_lib mi-support.exp +set MIFLAGS "-i=mi" + +gdb_exit +if [mi_gdb_start] { + continue +} + +standard_testfile + +if {[build_executable $testfile.exp $testfile $srcfile {debug}] == -1} { + untested "failed to compile $testfile" + return -1 +} + +mi_delete_breakpoints + +set bp_location1 [gdb_get_line_number "set breakpoint 1 here"] +set dp_location1 [gdb_get_line_number "set dprintf 1 here"] + +mi_run_to_main + +mi_gdb_test "1-dprintf-insert" \ + "1\\^error,msg=\"-dprintf-insert: Missing \"" "mi insert without location" + +mi_gdb_test "2-dprintf-insert foo" \ + "2\\^error,msg=\"-dprintf-insert: Missing \"" "mi insert breakpoint without format string" + +mi_gdb_test "3-dprintf-insert 29" \ + "3\\^error,msg=\"-dprintf-insert: Missing \"" "mi insert second breakpoint without format string" + +mi_gdb_test "-break-insert main" ".*" "mi insert breakpoint main" +mi_delete_breakpoints + +mi_gdb_test "4-dprintf-insert foo \"At foo entry\\n\"" \ + "4\\^done,bkpt=\{number=\".*\",type=\"dprintf\".*func=\"foo\",file=\".*mi-dprintf.c\",fullname=\".*mi-dprintf.c\",line=\".*\".*" "mi insert dprintf foo" + +mi_gdb_test "5-dprintf-insert $dp_location1 \"arg=%d, g=%d\\n\" arg g" \ + "5\\^done,bkpt=\{number=\".*\",type=\"dprintf\".*func=\"foo\",file=\".*mi-dprintf.c\",fullname=\".*mi-dprintf.c\",line=\"$dp_location1\".*" \ + "mi insert dprintf dp_location1" + +mi_gdb_test "6-break-info" \ + "6\\^done,BreakpointTable=\{nr_rows=\".\",nr_cols=\".\",hdr=\\\[\{width=\".*\",alignment=\".*\",col_name=\"number\",colhdr=\"Num\"\},\{width=\".*\",alignment=\".*\",col_name=\"type\",colhdr=\"Type\"\},\{width=\".*\",alignment=\".*\",col_name=\"disp\",colhdr=\"Disp\"\},\{width=\".*\",alignment=\".*\",col_name=\"enabled\",colhdr=\"Enb\"\},\{width=\".*\",alignment=\".*\",col_name=\"addr\",colhdr=\"Address\"\},\{width=\".*\",alignment=\".*\",col_name=\"what\",colhdr=\"What\"\}\\\],body=\\\[bkpt=\{number=\"3\",type=\"dprintf\".*func=\"foo\",file=\".*mi-dprintf.c\",fullname=\".*mi-dprintf.c\",line=\".*\".*,bkpt=\{number=\".*\",type=\"dprintf\".*func=\"foo\",file=\".*mi-dprintf.c\",fullname=\".*mi-dprintf.c\",line=\"$dp_location1\".*" \ + "mi info dprintf" + +mi_gdb_test "-break-insert $bp_location1" ".*" "mi insert breakpoint bp_location1" + +proc mi_continue_dprintf {args} { + with_test_prefix $args { + global mi_gdb_prompt + + mi_run_cmd + set msg "mi 1st dprintf" + gdb_expect { + -re ".*At foo entry.*arg=1234, g=1234.*" { + pass $msg + } + -re ".*$mi_gdb_prompt$" { + fail $msg + } + timeout { + fail $msg + } + } + mi_expect_stop ".*" ".*" ".*" ".*" ".*" "" "$msg stop" + + set msg "mi 2nd dprintf" + mi_send_resuming_command "exec-continue" "$msg continue" + gdb_expect { + -re ".*At foo entry.*arg=1235, g=2222.*" { + pass $msg + } + -re ".*$mi_gdb_prompt$" { + fail $msg + } + timeout { + fail $msg + } + } + } +} + +mi_continue_dprintf "gdb" + +# The "call" style depends on having I/O functions available, so test. + +if ![target_info exists gdb,noinferiorio] { + + # Now switch styles and rerun; in the absence of redirection the + # output should be the same. + + mi_gdb_test "set dprintf-style call" ".*" "mi set dprintf style to call" + mi_continue_dprintf "call" + + mi_gdb_test "set dprintf-function fprintf" ".*" "mi set dprintf-channel stderr" + mi_gdb_test "set dprintf-channel stderr" ".*" "mi set dprintf channel" + mi_continue_dprintf "fprintf" +} + +set target_can_dprintf 0 +set msg "set dprintf style to agent" +send_gdb "set dprintf-style agent\n" +gdb_expect { + -re "warning: Target cannot run dprintf commands, falling back to GDB printf.*$mi_gdb_prompt$" { + unsupported "$msg" + } + -re ".*done.*$mi_gdb_prompt$" { + set target_can_dprintf 1 + pass "$msg" + } + -re ".*$mi_gdb_prompt$" { + fail "$msg" + } + timeout { + fail "$msg" + } +} + +if $target_can_dprintf { + mi_run_cmd + + mi_gdb_test "continue" ".*breakpoint-hit.*func=\"foo\".*" "mi 1st dprintf, agent" + + mi_gdb_test "continue" ".*breakpoint-hit.*func=\"foo\".*" "mi 2nd dprintf, agent" + + mi_gdb_test "6-break-info" ".*modified.*" "mi info dprintf second time" +} + +mi_gdb_test "set dprintf-style foobar" ".*error.*" "mi set dprintf style to an unrecognized type"