--- testsuite/Makefile.in | 2 testsuite/configure | 3 testsuite/configure.ac | 2 testsuite/gdb.remote/Makefile.in | 16 testsuite/gdb.remote/autoload-breakpoints-test.c | 543 +++++++++++++++++++++ testsuite/gdb.remote/autoload-breakpoints-test.exp | 97 +++ 6 files changed, 660 insertions(+), 3 deletions(-) --- a/testsuite/Makefile.in +++ b/testsuite/Makefile.in @@ -37,7 +37,7 @@ ALL_SUBDIRS = gdb.ada gdb.arch gdb.asm g gdb.dwarf2 gdb.fortran gdb.gdb gdb.hp \ gdb.java gdb.linespec gdb.mi gdb.modula2 gdb.multi \ gdb.objc gdb.opencl gdb.opt gdb.pascal gdb.python gdb.server \ - gdb.stabs gdb.reverse gdb.threads gdb.trace gdb.xml \ + gdb.stabs gdb.reverse gdb.threads gdb.trace gdb.xml gdb.remote \ $(SUBDIRS) EXPECT = `if [ -f $${rootme}/../../expect/expect ] ; then \ --- a/testsuite/configure +++ b/testsuite/configure @@ -3448,7 +3448,7 @@ done -ac_config_files="$ac_config_files Makefile gdb.ada/Makefile gdb.arch/Makefile gdb.asm/Makefile gdb.base/Makefile gdb.cell/Makefile gdb.cp/Makefile gdb.disasm/Makefile gdb.dwarf2/Makefile gdb.fortran/Makefile gdb.go/Makefile gdb.server/Makefile gdb.java/Makefile gdb.hp/Makefile gdb.hp/gdb.objdbg/Makefile gdb.hp/gdb.base-hp/Makefile gdb.hp/gdb.aCC/Makefile gdb.hp/gdb.compat/Makefile gdb.hp/gdb.defects/Makefile gdb.linespec/Makefile gdb.mi/Makefile gdb.modula2/Makefile gdb.multi/Makefile gdb.objc/Makefile gdb.opencl/Makefile gdb.opt/Makefile gdb.pascal/Makefile gdb.python/Makefile gdb.reverse/Makefile gdb.stabs/Makefile gdb.threads/Makefile gdb.trace/Makefile gdb.xml/Makefile" +ac_config_files="$ac_config_files Makefile gdb.ada/Makefile gdb.arch/Makefile gdb.asm/Makefile gdb.base/Makefile gdb.cell/Makefile gdb.cp/Makefile gdb.disasm/Makefile gdb.dwarf2/Makefile gdb.fortran/Makefile gdb.go/Makefile gdb.server/Makefile gdb.java/Makefile gdb.hp/Makefile gdb.hp/gdb.objdbg/Makefile gdb.hp/gdb.base-hp/Makefile gdb.hp/gdb.aCC/Makefile gdb.hp/gdb.compat/Makefile gdb.hp/gdb.defects/Makefile gdb.linespec/Makefile gdb.mi/Makefile gdb.modula2/Makefile gdb.multi/Makefile gdb.objc/Makefile gdb.opencl/Makefile gdb.opt/Makefile gdb.pascal/Makefile gdb.python/Makefile gdb.reverse/Makefile gdb.stabs/Makefile gdb.threads/Makefile gdb.trace/Makefile gdb.xml/Makefile gdb.remote/Makefile" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure @@ -4181,6 +4181,7 @@ do "gdb.threads/Makefile") CONFIG_FILES="$CONFIG_FILES gdb.threads/Makefile" ;; "gdb.trace/Makefile") CONFIG_FILES="$CONFIG_FILES gdb.trace/Makefile" ;; "gdb.xml/Makefile") CONFIG_FILES="$CONFIG_FILES gdb.xml/Makefile" ;; + "gdb.remote/Makefile") CONFIG_FILES="$CONFIG_FILES gdb.remote/Makefile" ;; *) as_fn_error "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac --- a/testsuite/configure.ac +++ b/testsuite/configure.ac @@ -98,4 +98,4 @@ AC_OUTPUT([Makefile \ gdb.mi/Makefile gdb.modula2/Makefile gdb.multi/Makefile \ gdb.objc/Makefile gdb.opencl/Makefile gdb.opt/Makefile gdb.pascal/Makefile \ gdb.python/Makefile gdb.reverse/Makefile gdb.stabs/Makefile \ - gdb.threads/Makefile gdb.trace/Makefile gdb.xml/Makefile]) + gdb.threads/Makefile gdb.trace/Makefile gdb.xml/Makefile gdb.remote/Makefile]) --- /dev/null +++ b/testsuite/gdb.remote/Makefile.in @@ -0,0 +1,16 @@ +VPATH = @srcdir@ +srcdir = @srcdir@ + +EXECUTABLES = autoload-breakpoints-test + +MISCELLANEOUS = + +all info install-info dvi install uninstall installcheck check: + @echo "Nothing to be done for $@..." + +clean mostlyclean: + rm -f *~ *.o *.x *.ci *.sl a.out core + rm -f $(EXECUTABLES) $(MISCELLANEOUS) + +distclean maintainer-clean realclean: clean + rm -f Makefile config.status config.log site.* gdb.log gdb.sum --- /dev/null +++ b/testsuite/gdb.remote/autoload-breakpoints-test.c @@ -0,0 +1,543 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2012 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 . */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int listen_desc = -1; +int remote_desc = -1; +int loop_test_begin = 0; +int got_pkg = 0; +int inside_send_notificationasync_pkg = 0; + +#define INT2CHAR(h) ((h) > 9 ? (h) + 'a' - 10 : (h) + '0') + +int +hex2int(unsigned char hex, int *i) +{ + if ((hex >= '0') && (hex <= '9')) + { + *i = hex - '0'; + return 1; + } + if ((hex >= 'a') && (hex <= 'f')) + { + *i = hex - 'a' + 10; + return 1; + } + if ((hex >= 'A') && (hex <= 'F')) + { + *i = hex - 'A' + 10; + return 1; + } + + return 0; +} + +/* Convert number NIB to a hex digit. */ + +static int +tohex (int nib) +{ + if (nib < 10) + return '0' + nib; + else + return 'a' + nib - 10; +} + +int +bin2hex (char *bin, char *hex, int count) +{ + int i; + + /* May use a length, or a nul-terminated string as input. */ + if (count == 0) + count = strlen ((char *) bin); + + for (i = 0; i < count; i++) + { + *hex++ = tohex ((*bin >> 4) & 0xf); + *hex++ = tohex (*bin++ & 0xf); + } + *hex = 0; + return i; +} + +int readchar_buffer_ch = -1; + +int +readchar (void) +{ + int ret; + unsigned char ch; + + if (readchar_buffer_ch != -1) + { + ch = readchar_buffer_ch; + readchar_buffer_ch = -1; + return ch; + } + + if (remote_desc < 0) + { + printf ("Remote socket is closed.\n"); + return -1; + } + + ret = read(remote_desc, &ch, 1); + if (ret == 0) + { + printf ("Remote socket is closed.\n"); + close (remote_desc); + remote_desc = -1; + return -1; + } + else if (ret < 0) + { + perror ("Read got error"); + exit (-errno); + } + + return (int) ch; +} + +void +readchar_buffer_put (int ch) +{ + readchar_buffer_ch = ch; +} + +void +accept_remote (void) +{ + struct sockaddr_in sockaddr; + socklen_t tmp; + + tmp = sizeof (sockaddr); + remote_desc = accept (listen_desc, (struct sockaddr *) &sockaddr, &tmp); + if (remote_desc == -1) + perror ("Accept failed"); + + /* Enable TCP keep alive process. */ + tmp = 1; + setsockopt (remote_desc, SOL_SOCKET, SO_KEEPALIVE, + (char *) &tmp, sizeof (tmp)); + + /* Tell TCP not to delay small packets. This greatly speeds up + interactive response. */ + tmp = 1; + setsockopt (remote_desc, IPPROTO_TCP, TCP_NODELAY, + (char *) &tmp, sizeof (tmp)); +} + +int +read_rsppkg(unsigned char *buf, int max_size) +{ + int len = 0; + unsigned char *bufw = NULL; + unsigned char csum = 0; + + while (1) + { + int ch = readchar(); + if (ch < 0) + return -1; + + switch (ch) + { + case '$': + case '%': + bufw = buf; + len = 0; + csum = 0; + if (!inside_send_notificationasync_pkg) + got_pkg = 1; + break; + + case '#': + if (bufw) + { + int c1, c2; + + c1 = readchar(); + if (c1 < 0) + return -1; + c2 = readchar(); + if (c2 < 0) + return -1; + if (!hex2int (c1, &c1) || !hex2int (c2, &c2) + || csum != (c1 << 4) + c2) + write (remote_desc, "-" , 1); + else + { + write (remote_desc, "+" , 1); + bufw[0] = '\0'; + goto out; + } + } + break; + + default: + if (bufw) + { + if (len >= max_size) + { + printf ("The GDB rsp package is too big.\n"); + exit (-1); + } + + bufw[0] = (unsigned char) ch; + csum += bufw[0]; + len ++; + bufw ++; + } + break; + } + } + +out: + return 0; +} + +void +write_rsppkg (unsigned char *buf, int is_notif) +{ + int buf_size = strlen (buf); + char *send_buf = alloca(buf_size + 4); + unsigned char csum = 0; + int i; + + if (is_notif) + send_buf[0] = '%'; + else + send_buf[0] = '$'; + + memcpy(send_buf + 1, buf, buf_size); + + for (i = 0; i < buf_size; i ++) + csum += buf[i]; + + send_buf[buf_size + 1] = '#'; + send_buf[buf_size + 2] = INT2CHAR(csum >> 4); + send_buf[buf_size + 3] = INT2CHAR(csum & 0x0f); + + if (write (remote_desc, send_buf, buf_size + 4) != buf_size + 4) + { + perror ("Write got error"); + exit (-errno); + } +} + +struct uploaded_bpcmd + { + struct uploaded_bpcmd *next; + char *str; + }; + +struct uploaded_bp + { + struct uploaded_bp *prev; + int removed; + int id; + char enable; + char *addr_string; + char type; + char *ignore_count; + char *condition; + struct uploaded_bpcmd *commands; + }; + +struct uploaded_bp *b_list = NULL; +int cur_id; +struct uploaded_bp *cur_b = NULL; +char *cur_con = NULL; +struct uploaded_bpcmd *cur_com = NULL; + +void +b_list_add (char enable, char *addr, char type, char *ignore_count) +{ + struct uploaded_bp *new = calloc (1, sizeof (struct uploaded_bp)); + static int id = 0; + + if (!new) + { + printf ("Calloc failed\n"); + exit (-1); + } + + new->addr_string = malloc (3 + strlen (addr) + 1); + if (!new->addr_string) + { + printf ("Strudp failed\n"); + exit (-1); + } + sprintf (new->addr_string, "*0x%s", addr); + + new->ignore_count = strdup (ignore_count); + if (!new->ignore_count) + { + printf ("Strudp failed\n"); + exit (-1); + } + + id++; + new->id = id; + new->enable = enable; + new->type = type; + + new->prev = b_list; + b_list = new; + + printf ("Add breakpoint %d.\n", id); +} + +void +b_list_remove_one (void) +{ + struct uploaded_bp *e; + unsigned char rspbuf[4096]; + int head; + + if (got_pkg) + return; + + inside_send_notificationasync_pkg = 1; + for (e = b_list; e; e = e->prev) + { + if (!e->removed) + { + e->removed = 1; + break; + } + } + + if (!e) + { + printf ("Do not have breakpoint to delete.\n"); + exit(-1); + } + + printf ("Try to remove breakpoint %d.\n", e->id); + + snprintf (rspbuf, 4096, "QBDP:%d:R", e->id); + write_rsppkg (rspbuf, 1); + head = readchar(); + readchar_buffer_put (head); + if (head != '%') + { + printf ("Send %s, but GDB didn't answer it.\n", rspbuf); + return; + } + read_rsppkg (rspbuf, 4096); + + if (strcmp(rspbuf, "OK") != 0) + { + printf ("Try to remove breakpoint %d got error: %s\n", e->id, rspbuf); + exit (-1); + } + inside_send_notificationasync_pkg = 0; + printf ("Done.\n"); +} + +void +set_autoload_b(char *buf, int size, struct uploaded_bp *b) +{ + char *hex = alloca (strlen (b->addr_string) * 2); + int end = bin2hex (b->addr_string, hex, 0); + + hex[end * 2] = '\0'; + snprintf(buf, size, "%x:%c:%s:%c:%s", b->id, b->enable, hex, + b->type, b->ignore_count); +} + +void +set_autoload_b_con(char *buf, int size, int id, char *con) +{ + snprintf(buf, size, "%x:O:%s",id, con); +} + +void +set_autoload_b_com(char *buf, int size, int id, struct uploaded_bpcmd *com) +{ + snprintf(buf, size, "%x:C:%s", id, com->str); +} + +static void +handle_alrm(int signo) +{ + b_list_remove_one (); +} + +int +main(int argc, char *argv[]) +{ + socklen_t tmp; + struct sockaddr_in sockaddr; + unsigned char rspbuf[4096]; + + if (signal (SIGALRM, handle_alrm) == SIG_ERR) + { + perror("Can't call signal"); + exit(-errno); + } + + /* Init listen_desc. */ + if (argc != 2) + { + printf ("Usage: %s port\n", argv[0]); + exit (-1); + } + listen_desc = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP); + if (listen_desc == -1) + { + perror ("Can't open socket"); + exit (-errno); + } + setsockopt (listen_desc, SOL_SOCKET, SO_REUSEADDR, (char *) &tmp, + sizeof (tmp)); + sockaddr.sin_family = PF_INET; + sockaddr.sin_port = htons (atoi(argv[1])); + sockaddr.sin_addr.s_addr = INADDR_ANY; + if (bind (listen_desc, (struct sockaddr *) &sockaddr, sizeof (sockaddr)) + || listen (listen_desc, 1)) + { + printf ("Can't bind port\n"); + exit (-errno); + } + else + printf ("Listening on %d\n", atoi(argv[1])); + + accept_remote (); + + while (1) + { + got_pkg = 0; + if (read_rsppkg (rspbuf, 4096)) + { + loop_test_begin = 1; + accept_remote (); + continue; + } + + switch (rspbuf[0]) + { + case '?': + write_rsppkg ("S05", 0); + break; + + case 'g': + case 'm': + case 'p': + if (sizeof (long) == 8) + write_rsppkg ("0000000000000000", 0); + else + write_rsppkg ("00000000", 0); + break; + + case 'Z': + if (!loop_test_begin && strncmp("Z0,", rspbuf, 3) == 0) + { + char *addr = rspbuf + 3; + int i; + + for (i = 0; addr[i] != ',' && addr[i] != '\0'; i++) + ; + addr[i] = '\0'; + b_list_add ('E', addr, 'S', "0"); + } + case 'z': + write_rsppkg ("OK", 0); + break; + + case 'c': + if (loop_test_begin) + { + got_pkg = 0; + b_list_remove_one (); + alarm (1); + } + write_rsppkg ("S05", 0); + break; + + case 'q': + if (strncmp("qSupported", rspbuf, strlen ("qSupported")) == 0) + write_rsppkg ("NotificationAsync+;AutoloadBreakpoints+;", 0); + else if (strncmp("qBfP", rspbuf, 4) == 0) + { + if (b_list) + { + cur_b = b_list; + cur_con = cur_b->condition; + cur_com = cur_b->commands; + cur_id = cur_b->id; + set_autoload_b (rspbuf, 4096, cur_b); + write_rsppkg(rspbuf, 0); + cur_b = cur_b->prev; + } + else + write_rsppkg ("l", 0); + } + else if (strncmp("qBsP", rspbuf, 4) == 0) + { + if (cur_con) + { + set_autoload_b_con (rspbuf, 4096, cur_id, cur_con); + write_rsppkg(rspbuf, 0); + cur_con = NULL; + } + else if (cur_com) + { + set_autoload_b_com (rspbuf, 4096, cur_id, cur_com); + write_rsppkg(rspbuf, 0); + cur_com = cur_com->next; + } + else if (cur_b) + { + cur_id = cur_b->id; + set_autoload_b (rspbuf, 4096, cur_b); + write_rsppkg(rspbuf, 0); + cur_con = cur_b->condition; + cur_com = cur_b->commands; + cur_b = cur_b->prev; + } + else + write_rsppkg ("l", 0); + } + else + write_rsppkg ("", 0); + break; + + case 'k': + exit (0); + break; + + default: + write_rsppkg ("", 0); + break; + } + + } + + return 0; +} --- /dev/null +++ b/testsuite/gdb.remote/autoload-breakpoints-test.exp @@ -0,0 +1,97 @@ +# This testcase is part of GDB, the GNU debugger. + +# Copyright 2012 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 . + +load_lib gdbserver-support.exp + +set testfile "autoload-breakpoints-test" +set srcfile ${testfile}.c +set binfile ${objdir}/${subdir}/${testfile} + +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } { + untested autoload-breakpoints-test.exp + return -1 +} + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir + +# Make sure we're disconnected, in case we're testing with an +# extended-remote board, therefore already connected. +gdb_test "disconnect" ".*" + +send_gdb "show remote notification-async\n" +gdb_expect 10 { + -re "Undefined show remote command" { + fail "NotificationAsync support" + return + } + -re "Support for the `NotificationAsync' packet is auto-detected" { + pass "NotificationAsync support" + } +} + +send_gdb "show remote autoload-breakpoints-packet\n" +gdb_expect 10 { + -re "Undefined show remote command" { + fail "Autoload breakpoints support" + return + } + -re "Support for the `AutoloadBreakpoints' packet is auto-detected" { + pass "Autoload breakpoints support" + } +} + +#Let GDB connect to test server +set portnum 2345 +while 1 { + set server_spawn_id [remote_spawn target "$binfile $portnum"] + expect { + -i $server_spawn_id + -notransfer + -re "Listening on" {} + -re "Can't bind port" { + incr portnum + continue + } + } + break +} +gdb_target_cmd "remote" ":$portnum" + +gdb_test "set breakpoint autoload merge" ".*" + +gdb_test "b *0x10" ".*" +gdb_test "b *0x20" ".*" +gdb_test "continue" ".*" +gdb_test "set confirm off" ".*" +gdb_test "delete" ".*" +gdb_test "disconnect" ".*" + +gdb_target_cmd "remote" ":$portnum" +gdb_test "info breakpoints" ".*autoload-breakpoint 2.*autoload-breakpoint 1." +gdb_test "disconnect" ".*" + +gdb_target_cmd "remote" ":$portnum" +gdb_test "info breakpoints" ".*autoload-breakpoint 2.*autoload-breakpoint 1." +gdb_test "disconnect" ".*" + +gdb_target_cmd "remote" ":$portnum" + +gdb_test "continue" ".*" +exec sleep 2 +gdb_test "info breakpoints" "No breakpoints or watchpoints."