This patch fixes the target double-close problem (PR remote/15266),
and in the process removes pop_target entire (PR remote/15256).
The first issue is that pop_target calls target_close. However, it
then calls unpush_target, which also calls target_close. This means
targets must be able to be closed twice. Not only is this strange,
but it also directly contradicts the contract of to_xclose targets.
(We currently have just a single such target, and it is never pushed;
but I plan to add more, and so this latent bug is triggered.)
The second issue is that it seems to me that calling pop_target is
often unsafe. This is what cropped up in 15256, where the remote
target assumed that it could pop_target -- but there was another
target higher on the stack, leading to confusion.
But, it is always just as easy to call unpush_target as it is to call
pop_target; and it is also safer. So, removing pop_target seemed like
an improvement.
Finally, this adds an assertion to target_close to ensure that no
currently-pushed target can be closed.
Built and regtested on x86-64 Fedora 18; both natively and using the
native-gdbserver board file.
PR remote/15256, PR remote/15266:
* bfd-target.c (target_bfd_reopen): Initialize to_magic.
* monitor.c (monitor_detach): Use unpush_target.
* remote-m32r-sdi.c (m32r_detach): Use unpush_target.
* remote-mips.c (mips_detach): Use unpush_target. Don't
call mips_close.
* remote-sim.c (gdbsim_detach): Use unpush_target.
* target.c (pop_target): Remove.
(pop_all_targets_above): Don't call target_close.
(target_close): Assert that the target is unpushed.
* target.h (pop_target): Don't declare.
* tracepoint.c (tfile_open): Use unpush_target.
2013-07-25 Tom Tromey <tromey@redhat.com>
2013-07-25 Tom Tromey <tromey@redhat.com>
+ PR remote/15256, PR remote/15266:
+ * bfd-target.c (target_bfd_reopen): Initialize to_magic.
+ * monitor.c (monitor_detach): Use unpush_target.
+ * remote-m32r-sdi.c (m32r_detach): Use unpush_target.
+ * remote-mips.c (mips_detach): Use unpush_target. Don't
+ call mips_close.
+ * remote-sim.c (gdbsim_detach): Use unpush_target.
+ * target.c (pop_target): Remove.
+ (pop_all_targets_above): Don't call target_close.
+ (target_close): Assert that the target is unpushed.
+ * target.h (pop_target): Don't declare.
+ * tracepoint.c (tfile_open): Use unpush_target.
+
+2013-07-25 Tom Tromey <tromey@redhat.com>
+
* linux-thread-db.c (init_thread_db_ops): Call
complete_target_initialization.
(_initialize_thread_db): Don't call add_target.
* linux-thread-db.c (init_thread_db_ops): Call
complete_target_initialization.
(_initialize_thread_db): Don't call add_target.
t->to_xfer_partial = target_bfd_xfer_partial;
t->to_xclose = target_bfd_xclose;
t->to_data = data;
t->to_xfer_partial = target_bfd_xfer_partial;
t->to_xclose = target_bfd_xclose;
t->to_data = data;
+ t->to_magic = OPS_MAGIC;
static void
monitor_detach (struct target_ops *ops, char *args, int from_tty)
{
static void
monitor_detach (struct target_ops *ops, char *args, int from_tty)
{
- pop_target (); /* calls monitor_close to do the real work. */
+ unpush_target (ops); /* calls monitor_close to do the real work. */
if (from_tty)
printf_unfiltered (_("Ending remote %s debugging\n"), target_shortname);
}
if (from_tty)
printf_unfiltered (_("Ending remote %s debugging\n"), target_shortname);
}
m32r_resume (ops, inferior_ptid, 0, GDB_SIGNAL_0);
/* Calls m32r_close to do the real work. */
m32r_resume (ops, inferior_ptid, 0, GDB_SIGNAL_0);
/* Calls m32r_close to do the real work. */
if (from_tty)
fprintf_unfiltered (gdb_stdlog, "Ending remote %s debugging\n",
target_shortname);
if (from_tty)
fprintf_unfiltered (gdb_stdlog, "Ending remote %s debugging\n",
target_shortname);
if (args)
error (_("Argument given to \"detach\" when remotely debugging."));
if (args)
error (_("Argument given to \"detach\" when remotely debugging."));
- pop_target ();
-
- mips_close ();
if (from_tty)
printf_unfiltered ("Ending remote MIPS debugging.\n");
if (from_tty)
printf_unfiltered ("Ending remote MIPS debugging.\n");
if (remote_debug)
printf_filtered ("gdbsim_detach: args \"%s\"\n", args);
if (remote_debug)
printf_filtered ("gdbsim_detach: args \"%s\"\n", args);
- pop_target (); /* calls gdbsim_close to do the real work */
+ unpush_target (ops); /* calls gdbsim_close to do the real work */
if (from_tty)
printf_filtered ("Ending simulator %s debugging\n", target_shortname);
}
if (from_tty)
printf_filtered ("Ending simulator %s debugging\n", target_shortname);
}
-pop_target (void)
-{
- target_close (target_stack); /* Let it clean up. */
- if (unpush_target (target_stack) == 1)
- return;
-
- fprintf_unfiltered (gdb_stderr,
- "pop_target couldn't find target %s\n",
- current_target.to_shortname);
- internal_error (__FILE__, __LINE__,
- _("failed internal consistency check"));
-}
-
-void
pop_all_targets_above (enum strata above_stratum)
{
while ((int) (current_target.to_stratum) > (int) above_stratum)
{
pop_all_targets_above (enum strata above_stratum)
{
while ((int) (current_target.to_stratum) > (int) above_stratum)
{
- target_close (target_stack);
if (!unpush_target (target_stack))
{
fprintf_unfiltered (gdb_stderr,
if (!unpush_target (target_stack))
{
fprintf_unfiltered (gdb_stderr,
void
target_close (struct target_ops *targ)
{
void
target_close (struct target_ops *targ)
{
+ gdb_assert (!target_is_pushed (targ));
+
if (targ->to_xclose != NULL)
targ->to_xclose (targ);
else if (targ->to_close != NULL)
if (targ->to_xclose != NULL)
targ->to_xclose (targ);
else if (targ->to_close != NULL)
unpush_target: Remove this from the stack of currently used targets,
no matter where it is on the list. Returns 0 if no
unpush_target: Remove this from the stack of currently used targets,
no matter where it is on the list. Returns 0 if no
- change, 1 if removed from stack.
-
- pop_target: Remove the top thing on the stack of current targets. */
+ change, 1 if removed from stack. */
extern void add_target (struct target_ops *);
extern void add_target (struct target_ops *);
extern void target_preopen (int);
extern void target_preopen (int);
-extern void pop_target (void);
-
/* Does whatever cleanup is required to get rid of all pushed targets. */
extern void pop_all_targets (void);
/* Does whatever cleanup is required to get rid of all pushed targets. */
extern void pop_all_targets (void);
- /* Pop the partially set up target. */
- pop_target ();
+ /* Remove the partially set up target. */
+ unpush_target (&tfile_ops);