6ef284bd18
Original patch: https://sourceware.org/ml/gdb-patches/2014-04/msg00552.html New in v2: * In remote.c:escape_buffer, pass '\\' to fputstrn_unfiltered/printchar to make sure backslashes are escaped in remote debug output. * Updated function documentation for printchar. See updated ChangeLog below. -------------------- The quoting in whatever goes in the event_channel of MI is little bit broken. Link for the lazy: https://sourceware.org/bugzilla/show_bug.cgi?id=15806 Here is an example of a =library-loaded event with an ill-named directory, /tmp/how"are\you (the problem is present with every directory on Windows since it uses backslashes as a path separator). The result will be the following: =library-loaded,id="/tmp/how"are\\you/libexpat.so.1",... The " between 'how' and 'are' should be escaped. Another bad behavior is double escaping in =breakpoint-created, for example: =breakpoint-created,bkpt={...,fullname="/tmp/how\\"are\\\\you/test.c",...} The two backslashes before 'how' should be one and the four before 'you' should be two. The reason for this is that when sending something to an MI console, escaping can take place at two different moments (the actual escaping work is always done in the printchar function): 1. When generating the content, if ui_out_field_* functions are used. Here, fields are automatically quoted with " and properly escaped. At least mi_field_string does it, not sure about mi_field_fmt, I need to investigate further. 2. When gdb_flush is called, to send the data in the buffer of the console to the actual output (stdout). At this point, mi_console_raw_packet takes the whole string in the buffer, quotes it, and escapes all occurences of the quoting character and backslashes. The event_channel does not specify a quoting character, so quotes are not escaped here, only backslashes. The problem with =library-loaded is that it does use fprintf_unfiltered, which doesn't do escaping (so, no #1). When gdb_flush is called, backslashes are escaped (#2). The problem with =breakpoint-created is that it first uses ui_out_field_* functions to generate its output, so backslashes and quotes are escaped there (#1). backslashes are escaped again in #2, leading to an overdose of backslashes. In retrospect, there is no way escaping can be done reliably in mi_console_raw_packet for data that is already formatted, such as event_channel. At this point, there is no way to differentiate quotes that delimit field values from those that should be escaped. In the case of other MI consoles, it is ok since mi_console_raw_packet receives one big string that should be quoted and escaped as a whole. So, first part of the fix: for the MI channels that specify no quoting character, no escaping at all should be done in mi_console_raw_packet (that's the change in printchar, thanks to Yuanhui Zhang for this). For those channels, whoever generates the content is responsible for proper quoting and escaping. This will fix the =breakpoint-created kind of problem. Second part of the fix is to make =library-loaded generate content that is properly escaped. For this, we use ui_out_field_* functions, instead of one big fprintf_unfiltered. =library-unloaded suffered from the same problem so it is modified as well. There might be other events that need fixing too, but that's all I found with a quick scan. Those that use fprintf_unfiltered but whose sole variable data is a %d are not critical, since it won't generate a " or a \. Finally, a test has been fixed, as it was expecting an erroneous output. Otherwise, all other tests that were previously passing still pass (x86-64 linux). gdb/ChangeLog: 2014-06-02 Simon Marchi <simon.marchi@ericsson.com> PR mi/15806 * utils.c (printchar): Don't escape at all if quoter is NUL. Update function documentation to clarify effect of parameter QUOTER. * remote.c (escape_buffer): Pass '\\' as the quoter to fputstrn_unfiltered. * mi/mi-interp.c (mi_solib_loaded): Use ui_out_field_* functions to generate the output. (mi_solib_unloaded): Same. gdb/testsuite/ChangeLog: 2014-06-02 Simon Marchi <simon.marchi@ericsson.com> * gdb.mi/mi-breakpoint-changed.exp (test_insert_delete_modify): Fix erroneous dprintf expected input.
254 lines
7.4 KiB
Text
254 lines
7.4 KiB
Text
# Copyright 2012-2014 Free Software Foundation, Inc.
|
|
|
|
# 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 <http://www.gnu.org/licenses/>.
|
|
|
|
if {[skip_shlib_tests]} {
|
|
return 0
|
|
}
|
|
|
|
load_lib mi-support.exp
|
|
|
|
standard_testfile pending.c
|
|
set libfile1 "pendshr1"
|
|
set libfile2 "pendshr2"
|
|
set executable $testfile
|
|
set libsrc1 $srcdir/$subdir/$libfile1.c
|
|
set libsrc2 $srcdir/$subdir/$libfile2.c
|
|
set lib_sl1 [standard_output_file pendshr1.sl]
|
|
set lib_sl2 [standard_output_file pendshr2.sl]
|
|
set lib_opts "debug"
|
|
|
|
if { [gdb_compile_shlib $libsrc1 $lib_sl1 $lib_opts] != ""
|
|
|| [gdb_compile_shlib $libsrc2 $lib_sl2 $lib_opts] != ""} {
|
|
untested "Could not compile either $libsrc1 or $libsrc2"
|
|
return -1
|
|
}
|
|
|
|
set MIFLAGS "-i=mi"
|
|
|
|
set exec_opts [list debug shlib=$lib_sl1 shlib_load]
|
|
if { [gdb_compile $srcdir/$subdir/$srcfile $binfile executable $exec_opts] != "" } {
|
|
untested "Failed to compile $srcfile"
|
|
return -1
|
|
}
|
|
|
|
proc test_insert_delete_modify { } {
|
|
global mi_gdb_prompt
|
|
|
|
gdb_exit
|
|
if [mi_gdb_start] {
|
|
continue
|
|
}
|
|
|
|
mi_run_to_main
|
|
|
|
mi_gdb_test "break marker" \
|
|
{(&.*)*.*~"Breakpoint 2 at.*\\n".*=breakpoint-created,bkpt=\{number="2",type="breakpoint".*\}.*\n\^done}
|
|
|
|
# Verify that '=breakpoint-modified' notification is correctly emitted:
|
|
|
|
# 1. when modifying command
|
|
send_gdb "commands\n"
|
|
gdb_expect {
|
|
-re "End with" {
|
|
}
|
|
}
|
|
|
|
send_gdb "silent\nend\n"
|
|
set test "change command"
|
|
gdb_expect {
|
|
-re ".*=breakpoint-modified.*${mi_gdb_prompt}$" {
|
|
pass $test
|
|
}
|
|
-re ".*${mi_gdb_prompt}$" {
|
|
fail $test
|
|
}
|
|
timeout {
|
|
fail "$test (timeout)"
|
|
}
|
|
}
|
|
|
|
# Verify that '=breakpoint-created' notification is correctly emitted when
|
|
# creating any type of breakpoint.
|
|
|
|
set test "watch watch"
|
|
mi_gdb_test ${test} \
|
|
{(&.*)*.*~".*atchpoint 3: .*\\n".*=breakpoint-created,bkpt=\{number="3",type="(hw |)watchpoint".*\}.*\n\^done} \
|
|
$test
|
|
set test "trace marker"
|
|
mi_gdb_test $test \
|
|
{(&.*)*.*~"Tracepoint 4 at .*\\n".*=breakpoint-created,bkpt=\{number="4",type="tracepoint".*\}.*\n\^done} \
|
|
$test
|
|
set test "catch syscall"
|
|
mi_gdb_test $test \
|
|
{(&.*)*.*~"Catchpoint 5 .*\\n".*=breakpoint-created,bkpt=\{number="5",type="catchpoint".*\}.*\n\^done} \
|
|
$test
|
|
set test "dprintf marker, \"arg\" \""
|
|
mi_gdb_test $test \
|
|
{.*=breakpoint-created,bkpt=\{number="6",type="dprintf".*,script=\{\"printf \\\"arg\\\" \\\"\"\}.*\}\r\n\^done} \
|
|
$test
|
|
|
|
# 2. when modifying condition
|
|
set test "condition 2 main > 0x0"
|
|
mi_gdb_test $test \
|
|
{.*=breakpoint-modified,bkpt=\{number="2",.*,cond=\"main > 0x0\".*\}.*\n\^done} \
|
|
$test
|
|
# Modify condition through MI command shouldn't trigger MI notification.
|
|
mi_gdb_test "-break-condition 2 main == 0x0" "\\^done" \
|
|
"-break-condition 2 main == 0x0"
|
|
|
|
# 3. when modifying enableness
|
|
set test "disable 3"
|
|
mi_gdb_test $test \
|
|
{.*=breakpoint-modified,bkpt=\{number="3",.*,enabled=\"n\".*\}.*\n\^done} \
|
|
$test
|
|
set test "enable 3"
|
|
mi_gdb_test $test \
|
|
{.*=breakpoint-modified,bkpt=\{number="3",.*,enabled=\"y\".*\}.*\n\^done} \
|
|
$test
|
|
# Modify enableness through MI commands shouldn't trigger MI
|
|
# notification.
|
|
mi_gdb_test "-break-enable 3" "\\^done" "-break-enable 3"
|
|
mi_gdb_test "-break-disable 3" "\\^done" "-break-disable 3"
|
|
|
|
# 4. when modifying ignore count.
|
|
set test "ignore 5 1"
|
|
mi_gdb_test $test \
|
|
{.*=breakpoint-modified,bkpt=\{number="5",.*,ignore=\"1\".*\}.*\n\^done} \
|
|
$test
|
|
# Modify ignore count through MI command shouldn't trigger MI
|
|
# notification.
|
|
mi_gdb_test "-break-after 5 1" "\\^done" \
|
|
"-break-after 5 1"
|
|
|
|
# 5. when modifying pass count.
|
|
set test "passcount 1 4"
|
|
mi_gdb_test $test \
|
|
{.*=breakpoint-modified,bkpt=\{number="4",.*pass="1".*\}.*\n\^done} \
|
|
$test
|
|
# Modify pass count through MI command shouldn't trigger MI
|
|
# notification.
|
|
mi_gdb_test "-break-passcount 4 1" "\\^done" \
|
|
"-break-passcount 4 1"
|
|
|
|
# Delete some breakpoints and verify that '=breakpoint-deleted
|
|
# notification is correctly emitted.
|
|
for {set i 3} {$i < 7} {incr i} {
|
|
mi_gdb_test "delete ${i}" ".*=breakpoint-deleted,id=\"${i}\".*\\^done" \
|
|
"delete ${i}"
|
|
}
|
|
}
|
|
|
|
test_insert_delete_modify
|
|
|
|
# Test 'breakpoint-modified' notification is emited when pending breakpoints are
|
|
# resolved.
|
|
|
|
proc test_pending_resolved { } {
|
|
with_test_prefix "pending resolved" {
|
|
global decimal hex
|
|
global srcdir
|
|
global subdir
|
|
global binfile
|
|
global lib_sl1 lib_sl2
|
|
global mi_gdb_prompt
|
|
|
|
gdb_exit
|
|
if [mi_gdb_start] {
|
|
continue
|
|
}
|
|
mi_gdb_reinitialize_dir $srcdir/$subdir
|
|
mi_gdb_load ${binfile}
|
|
mi_load_shlibs $lib_sl1 $lib_sl2
|
|
|
|
# Create a pending breakpoint on pendfunc1
|
|
mi_gdb_test "-break-insert -f pendfunc1" \
|
|
{.*\^done,bkpt=.*addr=\"<PENDING>\".*} \
|
|
"insert breakpoint on pendfunc1"
|
|
mi_run_cmd
|
|
|
|
set test "breakpoint on pendfunc1 resolved"
|
|
gdb_expect {
|
|
-re ".*=breakpoint-modified,bkpt=\{number=\"1\".*addr=\"${hex}\".*,times=\"0\"" {
|
|
pass $test
|
|
exp_continue
|
|
}
|
|
-re ".*=breakpoint-modified,bkpt=\{number=\"1\".*addr=\"${hex}\".*,times=\"1\"" {
|
|
pass "$test: hit_count is updated"
|
|
}
|
|
-re ".*${mi_gdb_prompt}$" {
|
|
fail $test
|
|
}
|
|
timeout {
|
|
fail "$test (timeout)"
|
|
}
|
|
}
|
|
mi_expect_stop "breakpoint-hit" "pendfunc1" ""\
|
|
".*" ".*" {"" "disp=\"keep\""} \
|
|
"continue to pendfunc1 breakpoint"
|
|
|
|
# Delete breakpoint on pendfunc1
|
|
mi_gdb_test "-break-delete 1" {\^done} \
|
|
"delete breakpoint on pendfunc1"
|
|
# Insert breakpoint on marker
|
|
mi_gdb_test "-break-insert marker" {.*\^done,bkpt=.*} \
|
|
"insert breakpoint on marker"
|
|
# Create a pending breakpoint on pendfunc3
|
|
mi_gdb_test "-break-insert -f pendfunc3" \
|
|
{.*\^done,bkpt=.*addr=\"<PENDING>\".*} \
|
|
"insert breakpoint on pendfunc3"
|
|
|
|
mi_execute_to "exec-continue" "breakpoint-hit" "marker" ".*" ".*" ".*" \
|
|
{"" "disp=\"keep\""} "continue to marker 1"
|
|
|
|
mi_send_resuming_command "exec-continue" "continuing execution to marker"
|
|
|
|
set test "breakpoint on pendfunc3 resolved"
|
|
gdb_expect {
|
|
-re ".*=breakpoint-modified,bkpt=\{number=\"2\".*addr=\"${hex}\",.*func=\"marker\",.*times=\"1\"" {
|
|
pass "$test: hit_count is updated"
|
|
exp_continue
|
|
}
|
|
-re ".*=breakpoint-modified,bkpt=\{number=\"3\".*addr=\"${hex}\",.*func=\"pendfunc3\",.*times=\"0\"" {
|
|
pass $test
|
|
}
|
|
-re ".*${mi_gdb_prompt}$" {
|
|
fail $test
|
|
}
|
|
timeout {
|
|
fail "$test (timeout)"
|
|
}
|
|
}
|
|
mi_expect_stop "breakpoint-hit" "marker" ".*" ".*" ".*" \
|
|
{"" "disp=\"keep\""} "continue to marker 2"
|
|
|
|
mi_send_resuming_command "exec-continue" "continuing to exit"
|
|
set test "breakpoint on pendfunc3 pending again"
|
|
gdb_expect {
|
|
-re ".*=breakpoint-modified,bkpt=\{number=\"3\".*addr=\"<PENDING>\"" {
|
|
pass $test
|
|
}
|
|
-re ".*${mi_gdb_prompt}$" {
|
|
fail $test
|
|
}
|
|
timeout {
|
|
fail "$test (timeout)"
|
|
}
|
|
}
|
|
|
|
mi_expect_stop "exited-normally" "" "" "" "" "" ""
|
|
}
|
|
}
|
|
|
|
test_pending_resolved
|