From patchwork Mon Jun 25 13:09:29 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Burgess X-Patchwork-Id: 28010 Received: (qmail 6651 invoked by alias); 25 Jun 2018 13:09:39 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 6523 invoked by uid 89); 25 Jun 2018 13:09:38 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-24.5 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_PASS autolearn=ham version=3.3.2 spammy=expose X-HELO: mail-wm0-f65.google.com Received: from mail-wm0-f65.google.com (HELO mail-wm0-f65.google.com) (74.125.82.65) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Mon, 25 Jun 2018 13:09:36 +0000 Received: by mail-wm0-f65.google.com with SMTP id e16-v6so9203554wmd.0 for ; Mon, 25 Jun 2018 06:09:36 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:in-reply-to:references; bh=+2EK9MaaZr4L0V/1wXNXDEmFX67B4Wv8BoxvbBd267o=; b=CMRKq6mFbyA+73RoXS8SWm44v08pAx//gsWoXOOJAzQ3FGhS1AfwXhOWX6APQ+5N6d fnHltiAm9fKxHr/qI+W3YpI7gRJpnNmO9HpUp23k7qQdHAQr28g8fYim7lOvWlKwWk9U oRlcPCPRA58hNiXG57ZLcsG+cFu3QqmvFc9RqHmKk5SIlFY+ZMLzmVr7MWtEq3/ChNMx b+T8ERrYkHRCdlP7W0i1jKYDdtmAaVinyLLfP0TdiEgu4m06DkLLcC08aDZM09Ot+0NC a26h9zxI15/AMpS8mjZyU2E27LYJr7Ifd8ZxIYCEMislIZA81lINH5vjxfg1IHAAu1Md Bm2w== X-Gm-Message-State: APt69E2kzPpScJ295M78Uv97PGh8ZObo+G6y/D+4VZlQNevDHmO50GR+ I082uSEVf8HelC2zfedpVQwxKGwN X-Google-Smtp-Source: AAOMgpeMrOwf6dbuXVaWYDJeSvzDlFDQ0SiZ2pkMkNQhg8UQUMGUc1bLgnMPePYDbBzZN0SA4D4olg== X-Received: by 2002:a1c:c006:: with SMTP id q6-v6mr955005wmf.107.1529932174074; Mon, 25 Jun 2018 06:09:34 -0700 (PDT) Received: from localhost (host81-140-212-80.range81-140.btcentralplus.com. [81.140.212.80]) by smtp.gmail.com with ESMTPSA id c10-v6sm14388334wrs.6.2018.06.25.06.09.33 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 25 Jun 2018 06:09:33 -0700 (PDT) From: Andrew Burgess To: gdb-patches@sourceware.org Cc: Andrew Burgess Subject: [PATCH 1/2] gdb: Fix assert for extended-remote target Date: Mon, 25 Jun 2018 14:09:29 +0100 Message-Id: <9b7c5013767047fe963564e3f0c99cbcdc72922b.1529931757.git.andrew.burgess@embecosm.com> In-Reply-To: References: In-Reply-To: References: X-IsSubscribed: yes Consider the following GDB session: (gdb) target extended-remote :2347 (gdb) file /path/to/exe (gdb) set remote exec-file /path/to/exe (gdb) set detach-on-fork off (gdb) break breakpt (gdb) run # ... hits breakpoint (gdb) info inferiors Num Description Executable * 1 process 17001 /path/to/exe 2 process 17002 /path/to/exe (gdb) kill (gdb) info inferiors Num Description Executable * 1 /path/to/exe 2 process 17002 /path/to/exe (gdb) target extended-remote :2348 ../../src/gdb/thread.c:660: internal-error: thread_info* any_thread_of_process(int): Assertion `pid != 0' failed. A problem internal to GDB has been detected, further debugging may prove unreliable. The issue is calling target.c:dispose_inferior with a killed inferior in the inferior list. This assertion is fixed in this commit. The new test for this issue only runs on platforms that support 'detach-on-fork', and when using '--target_board=native-extended-gdbserver'. gdb/ChangeLog: * target.c (dispose_inferior): Don't dispose of inferiors that are already killed. gdb/testsuite/ChangeLog: * gdb.base/extended-remote-restart.c: New file. * gdb.base/extended-remote-restart.exp: New file. --- gdb/ChangeLog | 5 + gdb/target.c | 6 + gdb/testsuite/ChangeLog | 5 + gdb/testsuite/gdb.base/extended-remote-restart.c | 60 ++++++++++ gdb/testsuite/gdb.base/extended-remote-restart.exp | 132 +++++++++++++++++++++ 5 files changed, 208 insertions(+) create mode 100644 gdb/testsuite/gdb.base/extended-remote-restart.c create mode 100644 gdb/testsuite/gdb.base/extended-remote-restart.exp diff --git a/gdb/target.c b/gdb/target.c index a082957d5bd..7c297495703 100644 --- a/gdb/target.c +++ b/gdb/target.c @@ -2025,6 +2025,12 @@ target_pre_inferior (int from_tty) static int dispose_inferior (struct inferior *inf, void *args) { + /* Not all killed inferiors can, or will ever be, removed from the + inferior list. Killed inferiors clearly don't need to be killed + again, so, we're done. */ + if (inf->pid == 0) + return 0; + thread_info *thread = any_thread_of_inferior (inf); if (thread != NULL) { diff --git a/gdb/testsuite/gdb.base/extended-remote-restart.c b/gdb/testsuite/gdb.base/extended-remote-restart.c new file mode 100644 index 00000000000..e195f48e080 --- /dev/null +++ b/gdb/testsuite/gdb.base/extended-remote-restart.c @@ -0,0 +1,60 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2018 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 + +static void +breakpt () +{ + asm ("" ::: "memory"); +} + +static void +go_child () +{ + breakpt (); + + while (1) + sleep (1); +} + +static void +go_parent () +{ + breakpt (); + + while (1) + sleep (1); +} + +int +main () +{ + pid_t pid; + + pid = fork (); + if (pid == -1) + abort (); + + if (pid == 0) + go_child (); + else + go_parent (); + + exit (EXIT_SUCCESS); +} diff --git a/gdb/testsuite/gdb.base/extended-remote-restart.exp b/gdb/testsuite/gdb.base/extended-remote-restart.exp new file mode 100644 index 00000000000..39fcb9e2e58 --- /dev/null +++ b/gdb/testsuite/gdb.base/extended-remote-restart.exp @@ -0,0 +1,132 @@ +# Copyright 2018 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 . + +# This test is about restarting execution of a forked application when +# using gdb extended remote target. +# +# There are two issues that the test tries to expose in GDB: +# +# 1. GDB would throw an assertion upon reconnecting to a remote target +# if there was more than one inferior already active in GDB, and +# +# 2. GDB would not prune transient inferiors from the inferior list +# when reconnecting to a remote target. So, for example, an inferior +# created by GDB to track the child of a fork would usually be removed +# from the inferior list once the child exited. However, reconnecting +# to a remote target would result in the child inferior remaining in +# the inferior list. + +# This test is only for extended remote targets. +if {[target_info gdb_protocol] != "extended-remote"} { + continue +} + +# This test also makes use of 'detach-on-fork' which is not supported +# on all platforms. +if { ![istarget "*-*-linux*"] && ![istarget "*-*-openbsd*"] } then { + continue +} + +# And we need to be able to reconnect to gdbserver. +set gdbserver_reconnect_p 1 +if { [info proc gdb_reconnect] == "" } { + return 0 +} + +standard_testfile + +if {[prepare_for_testing "failed to prepare" $testfile $srcfile debug]} { + return -1 +} + +# Core of the test. DO_KILL_P controls whether we kill one of the +# inferiors before reconnecting. And FOLLOW_CHILD_P controls whether +# we follow the child or the parent at the fork. +proc test_reload { do_kill_p follow_child_p } { + global decimal + global binfile + + clean_restart ${binfile} + + if ![runto_main] then { + fail "can't run to main" + return 0 + } + + # Set detach-on-fork off + gdb_test_no_output "set detach-on-fork off" + + set live_inf_ptn "process $decimal" + set dead_inf_ptn "" + + if ${follow_child_p} { + gdb_test_no_output "set follow-fork child" + set parent_prefix " " + set child_prefix "\\*" + set parent_inf_after_kill_ptn ${live_inf_ptn} + set child_inf_after_kill_ptn ${dead_inf_ptn} + } else { + gdb_test_no_output "set follow-fork parent" + set parent_prefix "\\*" + set child_prefix " " + set parent_inf_after_kill_ptn ${dead_inf_ptn} + set child_inf_after_kill_ptn ${live_inf_ptn} + } + + gdb_breakpoint "breakpt" + gdb_continue_to_breakpoint "breakpt" + + # Check we have the expected inferiors. + gdb_test "info inferiors" \ + [multi_line \ + " Num Description Executable.*" \ + "${parent_prefix} 1 +${live_inf_ptn} \[^\r\n\]+" \ + "${child_prefix} 2 +${live_inf_ptn} \[^\r\n\]+" ] \ + "Check inferiors at breakpoint" + + if { $do_kill_p } { + # (Optional) Kill one of the inferiors. + gdb_test "kill" \ + "" \ + "Kill inferior" \ + "Kill the program being debugged.*y or n. $" \ + "y" + + # Check the first inferior really did die. + gdb_test "info inferiors" \ + [multi_line \ + " Num Description Executable.*" \ + "${parent_prefix} 1 +${parent_inf_after_kill_ptn} \[^\r\n\]+" \ + "${child_prefix} 2 +${child_inf_after_kill_ptn} \[^\r\n\]+" ] \ + "Check inferior was killed" + } + + # Reconnect to the target. + if { [gdb_reconnect] == 0 } { + pass "reconnect after fork" + } else { + fail "reconnect after fork" + } +} + +# Run all combinations of the test. +foreach do_kill_p [list 1 0] { + foreach follow_child_p [list 1 0] { + with_test_prefix \ + "kill: ${do_kill_p}, follow-child ${follow_child_p}" { + test_reload ${do_kill_p} ${follow_child_p} + } + } +}