Allow making GDB not automatically connect to the native target.
Sometimes it's useful to be able to disable the automatic connection to the native target. E.g., sometimes GDB disconnects from the extended-remote target I was debugging, without me noticing it, and then I do "run". That starts the program locally, and only after a little head scratch session do I figure out the program is running locally instead of remotely as intended. Same thing with "attach", "info os", etc. With the patch, we now can have this instead: (gdb) set auto-connect-native-target off (gdb) target extended-remote :9999 ... *gdb disconnects* (gdb) run Don't know how to run. Try "help target". To still be able to connect to the native target with auto-connect-native-target set to off, I've made "target native" work instead of erroring out as today. Before: (gdb) target native Use the "run" command to start a native process. After: (gdb) target native Done. Use the "run" command to start a process. (gdb) maint print target-stack The current target stack is: - native (Native process) - exec (Local exec file) - None (None) (gdb) run Starting program: ./a.out ... I've also wanted this for the testsuite, when running against the native-extended-gdbserver.exp board (runs against gdbserver in extended-remote mode). With a non-native-target board, it's always a bug to launch a program with the native target. Turns out we still have one such case this patch catches: (gdb) break main Breakpoint 1 at 0x4009e5: file ../../../src/gdb/testsuite/gdb.base/coremaker.c, line 138. (gdb) run Don't know how to run. Try "help target". (gdb) FAIL: gdb.base/corefile.exp: run: with core On the patch itself, probably the least obvious bit is the need to go through all targets, and move the unpush_target call to after the generic_mourn_inferior call instead of before. This is what inf-ptrace.c does too, ever since multi-process support was added. The reason inf-ptrace.c does things in that order is that in the current multi-process/single-target model, we shouldn't unpush the target if there are still other live inferiors being debugged. The check for that is "have_inferiors ()" (a misnomer nowadays...), which does: have_inferiors (void) { for (inf = inferior_list; inf; inf = inf->next) if (inf->pid != 0) return 1; It's generic_mourn_inferior that ends up clearing inf->pid, so we need to call it before the have_inferiors check. To make all native targets behave the same WRT to explicit "target native", I've added an inf_child_maybe_unpush_target function that targets call instead of calling unpush_target directly, and as that includes the have_inferiors check, I needed to adjust the targets. Tested on x86_64 Fedora 20, native, and also with the extended-gdbserver board. Confirmed a cross build of djgpp gdb still builds. Smoke tested a cross build of Windows gdb under Wine. Untested otherwise. gdb/ 2014-05-21 Pedro Alves <palves@redhat.com> * inf-child.c (inf_child_ops, inf_child_explicitly_opened): New globals. (inf_child_open_target): New function. (inf_child_open): Use inf_child_open_target to push the target instead of erroring out. (inf_child_disconnect, inf_child_close) (inf_child_maybe_unpush_target): New functions. (inf_child_target): Install inf_child_disconnect and inf_child_close. Store a pointer to the returned object. * inf-child.h (inf_child_open_target, inf_child_maybe_unpush): New declarations. * target.c (auto_connect_native_target): New global. (show_default_run_target): New function. (find_default_run_target): Return NULL if automatically connecting to the native target is disabled. (_initialize_target): Install set/show auto-connect-native-target. * NEWS: Mention "set auto-connect-native-target", and "target native". * linux-nat.c (super_close): New global. (linux_nat_close): Call super_close. (linux_nat_add_target): Store a pointer to the base class's to_close method. * inf-ptrace.c (inf_ptrace_mourn_inferior, inf_ptrace_detach): Use inf_child_maybe_unpush. * inf-ttrace.c (inf_ttrace_him): Don't push the target if it is already pushed. (inf_ttrace_mourn_inferior): Only unpush the target after mourning the inferior. Use inf_child_maybe_unpush_target. (inf_ttrace_attach): Don't push the target if it is already pushed. (inf_ttrace_detach): Use inf_child_maybe_unpush_target. * darwin-nat.c (darwin_mourn_inferior): Only unpush the target after mourning the inferior. Use inf_child_maybe_unpush_target. (darwin_attach_pid): Don't push the target if it is already pushed. * gnu-nat.c (gnu_mourn_inferior): Only unpush the target after mourning the inferior. Use inf_child_maybe_unpush_target. (gnu_detach): Use inf_child_maybe_unpush_target. * go32-nat.c (go32_create_inferior): Don't push the target if it is already pushed. (go32_mourn_inferior): Use inf_child_maybe_unpush_target. * nto-procfs.c (procfs_is_nto_target): Adjust comment. (procfs_open): Rename to ... (procfs_open_1): ... this. Add target_ops parameter. Adjust comments. Can target_preopen before changing node. Call inf_child_open_target to push the target explicitly. (procfs_attach): Don't push the target if it is already pushed. (procfs_detach): Use inf_child_maybe_unpush_target. (procfs_create_inferior): Don't push the target if it is already pushed. (nto_native_ops): New global. (procfs_open): Reimplement. (procfs_native_open): New function. (init_procfs_targets): Install procfs_native_open as to_open of "target native". Store a pointer to the "native" target in nto_native_ops. * procfs.c (procfs_attach): Don't push the target if it is already pushed. (procfs_detach): Use inf_child_maybe_unpush_target. (procfs_mourn_inferior): Only unpush the target after mourning the inferior. Use inf_child_maybe_unpush_target. (procfs_init_inferior): Don't push the target if it is already pushed. * windows-nat.c (do_initial_windows_stuff): Don't push the target if it is already pushed. (windows_detach): Use inf_child_maybe_unpush_target. (windows_mourn_inferior): Only unpush the target after mourning the inferior. Use inf_child_maybe_unpush_target. gdb/doc/ 2014-05-21 Pedro Alves <palves@redhat.com> * gdb.texinfo (Starting): Document "set/show auto-connect-native-target". (Target Commands): Document "target native". gdb/testsuite/ 2014-05-21 Pedro Alves <palves@redhat.com> * boards/gdbserver-base.exp (GDBFLAGS): Set to "set auto-connect-native-target off". * gdb.base/auto-connect-native-target.c: New file. * gdb.base/auto-connect-native-target.exp: New file.
This commit is contained in:
parent
930ee1b1bf
commit
6a3cb8e88a
20 changed files with 574 additions and 47 deletions
|
@ -1,3 +1,71 @@
|
|||
2014-05-21 Pedro Alves <palves@redhat.com>
|
||||
|
||||
* inf-child.c (inf_child_ops, inf_child_explicitly_opened): New
|
||||
globals.
|
||||
(inf_child_open_target): New function.
|
||||
(inf_child_open): Use inf_child_open_target to push the target
|
||||
instead of erroring out.
|
||||
(inf_child_disconnect, inf_child_close)
|
||||
(inf_child_maybe_unpush_target): New functions.
|
||||
(inf_child_target): Install inf_child_disconnect and
|
||||
inf_child_close. Store a pointer to the returned object.
|
||||
* inf-child.h (inf_child_open_target, inf_child_maybe_unpush): New
|
||||
declarations.
|
||||
* target.c (auto_connect_native_target): New global.
|
||||
(show_default_run_target): New function.
|
||||
(find_default_run_target): Return NULL if automatically connecting
|
||||
to the native target is disabled.
|
||||
(_initialize_target): Install set/show auto-connect-native-target.
|
||||
* NEWS: Mention "set auto-connect-native-target", and "target
|
||||
native".
|
||||
* linux-nat.c (super_close): New global.
|
||||
(linux_nat_close): Call super_close.
|
||||
(linux_nat_add_target): Store a pointer to the base class's
|
||||
to_close method.
|
||||
* inf-ptrace.c (inf_ptrace_mourn_inferior, inf_ptrace_detach): Use
|
||||
inf_child_maybe_unpush.
|
||||
* inf-ttrace.c (inf_ttrace_him): Don't push the target if it is
|
||||
already pushed.
|
||||
(inf_ttrace_mourn_inferior): Only unpush the target after mourning
|
||||
the inferior. Use inf_child_maybe_unpush_target.
|
||||
(inf_ttrace_attach): Don't push the target if it is already
|
||||
pushed.
|
||||
(inf_ttrace_detach): Use inf_child_maybe_unpush_target.
|
||||
* darwin-nat.c (darwin_mourn_inferior): Only unpush the target
|
||||
after mourning the inferior. Use inf_child_maybe_unpush_target.
|
||||
(darwin_attach_pid): Don't push the target if it is already
|
||||
pushed.
|
||||
* gnu-nat.c (gnu_mourn_inferior): Only unpush the target after
|
||||
mourning the inferior. Use inf_child_maybe_unpush_target.
|
||||
(gnu_detach): Use inf_child_maybe_unpush_target.
|
||||
* go32-nat.c (go32_create_inferior): Don't push the target if it
|
||||
is already pushed.
|
||||
(go32_mourn_inferior): Use inf_child_maybe_unpush_target.
|
||||
* nto-procfs.c (procfs_is_nto_target): Adjust comment.
|
||||
(procfs_open): Rename to ...
|
||||
(procfs_open_1): ... this. Add target_ops parameter. Adjust
|
||||
comments. Can target_preopen before changing node. Call
|
||||
inf_child_open_target to push the target explicitly.
|
||||
(procfs_attach): Don't push the target if it is already pushed.
|
||||
(procfs_detach): Use inf_child_maybe_unpush_target.
|
||||
(procfs_create_inferior): Don't push the target if it is already
|
||||
pushed.
|
||||
(nto_native_ops): New global.
|
||||
(procfs_open): Reimplement.
|
||||
(procfs_native_open): New function.
|
||||
(init_procfs_targets): Install procfs_native_open as to_open of
|
||||
"target native". Store a pointer to the "native" target in
|
||||
nto_native_ops.
|
||||
* procfs.c (procfs_attach): Don't push the target if it is already
|
||||
pushed.
|
||||
(procfs_detach): Use inf_child_maybe_unpush_target.
|
||||
(procfs_mourn_inferior): Only unpush the target after mourning the
|
||||
inferior. Use inf_child_maybe_unpush_target.
|
||||
(procfs_init_inferior): Don't push the target if it is already
|
||||
pushed.
|
||||
* windows-nat.c (do_initial_windows_stuff): Don't push the target
|
||||
if it is already pushed.
|
||||
|
||||
2014-05-21 Pedro Alves <palves@redhat.com>
|
||||
|
||||
* NEWS: Mention that the "child", "GNU, "djgpp", "darwin-child"
|
||||
|
|
10
gdb/NEWS
10
gdb/NEWS
|
@ -61,6 +61,12 @@ maint ada show ignore-descriptive-types
|
|||
the user manual for more details on descriptive types and the intended
|
||||
usage of this option.
|
||||
|
||||
set auto-connect-native-target
|
||||
|
||||
Control whether GDB is allowed to automatically connect to the
|
||||
native target for the run, attach, etc. commands when not connected
|
||||
to any target yet. See also "target native" below.
|
||||
|
||||
* New features in the GDB remote stub, GDBserver
|
||||
|
||||
** New option --debug-format=option1[,option2,...] allows one to add
|
||||
|
@ -108,6 +114,10 @@ maint ada show ignore-descriptive-types
|
|||
commands: "help target", "info target", "info files", "maint print
|
||||
target-stack".
|
||||
|
||||
* The "target native" command now connects to the native target. This
|
||||
can be used to launch native programs even when "set
|
||||
auto-connect-native-target" is set to off.
|
||||
|
||||
* New remote packets
|
||||
|
||||
qXfer:btrace:read's annex
|
||||
|
|
|
@ -1214,8 +1214,6 @@ darwin_mourn_inferior (struct target_ops *ops)
|
|||
mach_port_t prev;
|
||||
int i;
|
||||
|
||||
unpush_target (darwin_ops);
|
||||
|
||||
/* Deallocate threads. */
|
||||
if (inf->private->threads)
|
||||
{
|
||||
|
@ -1271,6 +1269,7 @@ darwin_mourn_inferior (struct target_ops *ops)
|
|||
inf->private = NULL;
|
||||
|
||||
generic_mourn_inferior ();
|
||||
inf_child_maybe_unpush_target (ops);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1506,7 +1505,8 @@ impact on the debugging session."));
|
|||
"returned: %d"),
|
||||
kret);
|
||||
|
||||
push_target (darwin_ops);
|
||||
if (!target_is_pushed (darwin_ops))
|
||||
push_target (darwin_ops);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
2014-05-21 Pedro Alves <palves@redhat.com>
|
||||
|
||||
* gdb.texinfo (Starting): Document "set/show
|
||||
auto-connect-native-target".
|
||||
(Target Commands): Document "target native".
|
||||
|
||||
2014-05-20 Pedro Alves <palves@redhat.com>
|
||||
|
||||
* gdb.texinfo (Memory) <compare-sections>: Generalize comments to
|
||||
|
|
|
@ -2148,6 +2148,57 @@ initialization file---such as @file{.cshrc} for C-shell,
|
|||
$@file{.zshenv} for the Z shell, or the file specified in the
|
||||
@samp{BASH_ENV} environment variable for BASH.
|
||||
|
||||
@anchor{set auto-connect-native-target}
|
||||
@kindex set auto-connect-native-target
|
||||
@item set auto-connect-native-target
|
||||
@itemx set auto-connect-native-target on
|
||||
@itemx set auto-connect-native-target off
|
||||
@itemx show auto-connect-native-target
|
||||
|
||||
By default, if not connected to any target yet (e.g., with
|
||||
@code{target remote}), the @code{run} command starts your program as a
|
||||
native process under @value{GDBN}, on your local machine. If you're
|
||||
sure you don't want to debug programs on your local machine, you can
|
||||
tell @value{GDBN} to not connect to the native target automatically
|
||||
with the @code{set auto-connect-native-target off} command.
|
||||
|
||||
If @code{on}, which is the default, and if @value{GDBN} is not
|
||||
connected to a target already, the @code{run} command automaticaly
|
||||
connects to the native target, if one is available.
|
||||
|
||||
If @code{off}, and if @value{GDBN} is not connected to a target
|
||||
already, the @code{run} command fails with an error:
|
||||
|
||||
@smallexample
|
||||
(@value{GDBP}) run
|
||||
Don't know how to run. Try "help target".
|
||||
@end smallexample
|
||||
|
||||
If @value{GDBN} is already connected to a target, @value{GDBN} always
|
||||
uses it with the @code{run} command.
|
||||
|
||||
In any case, you can explicitly connect to the native target with the
|
||||
@code{target native} command. For example,
|
||||
|
||||
@smallexample
|
||||
(@value{GDBP}) set auto-connect-native-target off
|
||||
(@value{GDBP}) run
|
||||
Don't know how to run. Try "help target".
|
||||
(@value{GDBP}) target native
|
||||
(@value{GDBP}) run
|
||||
Starting program: ./a.out
|
||||
[Inferior 1 (process 10421) exited normally]
|
||||
@end smallexample
|
||||
|
||||
In case you connected explicitly to the @code{native} target,
|
||||
@value{GDBN} remains connected even if all inferiors exit, ready for
|
||||
the next @code{run} command. Use the @code{disconnect} command to
|
||||
disconnect.
|
||||
|
||||
Examples of other commands that likewise respect the
|
||||
@code{auto-connect-native-target} setting: @code{attach}, @code{info
|
||||
proc}, @code{info os}.
|
||||
|
||||
@kindex set disable-randomization
|
||||
@item set disable-randomization
|
||||
@itemx set disable-randomization on
|
||||
|
@ -18079,6 +18130,13 @@ provide these. For info about any processor-specific simulator details,
|
|||
see the appropriate section in @ref{Embedded Processors, ,Embedded
|
||||
Processors}.
|
||||
|
||||
@item target native
|
||||
@cindex native target
|
||||
Setup for local/native process debugging. Useful to make the
|
||||
@code{run} command spawn native processes (likewise @code{attach},
|
||||
etc.@:) even when @code{set auto-connect-native-target} is @code{off}
|
||||
(@pxref{set auto-connect-native-target}).
|
||||
|
||||
@end table
|
||||
|
||||
Different targets are available on different configurations of @value{GDBN};
|
||||
|
|
|
@ -2080,8 +2080,8 @@ gnu_mourn_inferior (struct target_ops *ops)
|
|||
{
|
||||
inf_debug (gnu_current_inf, "rip");
|
||||
inf_detach (gnu_current_inf);
|
||||
unpush_target (ops);
|
||||
generic_mourn_inferior ();
|
||||
inf_child_maybe_unpush_target (ops);
|
||||
}
|
||||
|
||||
|
||||
|
@ -2253,7 +2253,7 @@ gnu_detach (struct target_ops *ops, const char *args, int from_tty)
|
|||
inferior_ptid = null_ptid;
|
||||
detach_inferior (pid);
|
||||
|
||||
unpush_target (ops); /* Pop out of handling an inferior. */
|
||||
inf_child_maybe_unpush_target (ops);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
@ -710,7 +710,8 @@ go32_create_inferior (struct target_ops *ops, char *exec_file,
|
|||
inf = current_inferior ();
|
||||
inferior_appeared (inf, SOME_PID);
|
||||
|
||||
push_target (ops);
|
||||
if (!target_is_pushed (ops))
|
||||
push_target (ops);
|
||||
|
||||
add_thread_silent (inferior_ptid);
|
||||
|
||||
|
@ -744,8 +745,8 @@ go32_mourn_inferior (struct target_ops *ops)
|
|||
delete_thread_silent (ptid);
|
||||
prog_has_started = 0;
|
||||
|
||||
unpush_target (ops);
|
||||
generic_mourn_inferior ();
|
||||
inf_child_maybe_unpush_target (ops);
|
||||
}
|
||||
|
||||
/* Hardware watchpoint support. */
|
||||
|
|
|
@ -40,6 +40,11 @@
|
|||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* A pointer to what is returned by inf_child_target. Used by
|
||||
inf_child_open to push the most-derived target in reaction to
|
||||
"target native". */
|
||||
static struct target_ops *inf_child_ops = NULL;
|
||||
|
||||
/* Helper function for child_wait and the derivatives of child_wait.
|
||||
HOSTSTATUS is the waitstatus from wait() or the equivalent; store our
|
||||
translation of that in OURSTATUS. */
|
||||
|
@ -109,10 +114,58 @@ inf_child_prepare_to_store (struct target_ops *self,
|
|||
{
|
||||
}
|
||||
|
||||
/* True if the user did "target native". In that case, we won't
|
||||
unpush the child target automatically when the last inferior is
|
||||
gone. */
|
||||
static int inf_child_explicitly_opened;
|
||||
|
||||
/* See inf-child.h. */
|
||||
|
||||
void
|
||||
inf_child_open_target (struct target_ops *target, char *arg, int from_tty)
|
||||
{
|
||||
target_preopen (from_tty);
|
||||
push_target (target);
|
||||
inf_child_explicitly_opened = 1;
|
||||
if (from_tty)
|
||||
printf_filtered ("Done. Use the \"run\" command to start a process.\n");
|
||||
}
|
||||
|
||||
static void
|
||||
inf_child_open (char *arg, int from_tty)
|
||||
{
|
||||
error (_("Use the \"run\" command to start a process."));
|
||||
inf_child_open_target (inf_child_ops, arg, from_tty);
|
||||
}
|
||||
|
||||
/* Implement the to_disconnect target_ops method. */
|
||||
|
||||
static void
|
||||
inf_child_disconnect (struct target_ops *target, char *args, int from_tty)
|
||||
{
|
||||
if (args != NULL)
|
||||
error (_("Argument given to \"disconnect\"."));
|
||||
|
||||
/* This offers to detach/kill current inferiors, and then pops all
|
||||
targets. */
|
||||
target_preopen (from_tty);
|
||||
}
|
||||
|
||||
/* Implement the to_close target_ops method. */
|
||||
|
||||
static void
|
||||
inf_child_close (struct target_ops *target)
|
||||
{
|
||||
/* In case we were forcibly closed. */
|
||||
inf_child_explicitly_opened = 0;
|
||||
}
|
||||
|
||||
/* See inf-child.h. */
|
||||
|
||||
void
|
||||
inf_child_maybe_unpush_target (struct target_ops *ops)
|
||||
{
|
||||
if (!inf_child_explicitly_opened && !have_inferiors ())
|
||||
unpush_target (ops);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -410,6 +463,8 @@ inf_child_target (void)
|
|||
t->to_longname = "Native process";
|
||||
t->to_doc = "Native process (started by the \"run\" command).";
|
||||
t->to_open = inf_child_open;
|
||||
t->to_close = inf_child_close;
|
||||
t->to_disconnect = inf_child_disconnect;
|
||||
t->to_post_attach = inf_child_post_attach;
|
||||
t->to_fetch_registers = inf_child_fetch_inferior_registers;
|
||||
t->to_store_registers = inf_child_store_inferior_registers;
|
||||
|
@ -445,5 +500,10 @@ inf_child_target (void)
|
|||
t->to_magic = OPS_MAGIC;
|
||||
t->to_use_agent = inf_child_use_agent;
|
||||
t->to_can_use_agent = inf_child_can_use_agent;
|
||||
|
||||
/* Store a pointer so we can push the most-derived target from
|
||||
inf_child_open. */
|
||||
inf_child_ops = t;
|
||||
|
||||
return t;
|
||||
}
|
||||
|
|
|
@ -30,4 +30,19 @@ extern struct target_ops *inf_child_target (void);
|
|||
/* This is for native targets which use a unix/POSIX-style waitstatus. */
|
||||
extern void store_waitstatus (struct target_waitstatus *, int);
|
||||
|
||||
/* This is to be called by the native target's open routine to push
|
||||
the target, in case it need to override to_open. */
|
||||
|
||||
extern void inf_child_open_target (struct target_ops *target,
|
||||
char *arg, int from_tty);
|
||||
|
||||
/* Unpush the target if it wasn't explicitly open with "target native"
|
||||
and there are no live inferiors left. Note: if calling this as a
|
||||
result of a mourn or detach, the current inferior shall already
|
||||
have its PID cleared, so it isn't counted as live. That's usually
|
||||
done by calling either generic_mourn_inferior or
|
||||
detach_inferior. */
|
||||
|
||||
extern void inf_child_maybe_unpush_target (struct target_ops *ops);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -176,8 +176,7 @@ inf_ptrace_mourn_inferior (struct target_ops *ops)
|
|||
|
||||
generic_mourn_inferior ();
|
||||
|
||||
if (!have_inferiors ())
|
||||
unpush_target (ops);
|
||||
inf_child_maybe_unpush_target (ops);
|
||||
}
|
||||
|
||||
/* Attach to the process specified by ARGS. If FROM_TTY is non-zero,
|
||||
|
@ -297,8 +296,7 @@ inf_ptrace_detach (struct target_ops *ops, const char *args, int from_tty)
|
|||
inferior_ptid = null_ptid;
|
||||
detach_inferior (pid);
|
||||
|
||||
if (!have_inferiors ())
|
||||
unpush_target (ops);
|
||||
inf_child_maybe_unpush_target (ops);
|
||||
}
|
||||
|
||||
/* Kill the inferior. */
|
||||
|
|
|
@ -644,7 +644,8 @@ inf_ttrace_him (struct target_ops *ops, int pid)
|
|||
|
||||
do_cleanups (old_chain);
|
||||
|
||||
push_target (ops);
|
||||
if (!target_is_pushed (ops))
|
||||
push_target (ops);
|
||||
|
||||
startup_inferior (START_INFERIOR_TRAPS_EXPECTED);
|
||||
|
||||
|
@ -695,8 +696,8 @@ inf_ttrace_mourn_inferior (struct target_ops *ops)
|
|||
}
|
||||
inf_ttrace_page_dict.count = 0;
|
||||
|
||||
unpush_target (ops);
|
||||
generic_mourn_inferior ();
|
||||
inf_child_maybe_unpush_target (ops);
|
||||
}
|
||||
|
||||
/* Assuming we just attached the debugger to a new inferior, create
|
||||
|
@ -796,7 +797,8 @@ inf_ttrace_attach (struct target_ops *ops, char *args, int from_tty)
|
|||
(uintptr_t)&tte, sizeof tte, 0) == -1)
|
||||
perror_with_name (("ttrace"));
|
||||
|
||||
push_target (ops);
|
||||
if (!target_is_pushed (ops))
|
||||
push_target (ops);
|
||||
|
||||
inf_ttrace_create_threads_after_attach (pid);
|
||||
}
|
||||
|
@ -837,7 +839,7 @@ inf_ttrace_detach (struct target_ops *ops, const char *args, int from_tty)
|
|||
inferior_ptid = null_ptid;
|
||||
detach_inferior (pid);
|
||||
|
||||
unpush_target (ops);
|
||||
inf_child_maybe_unpush_target (ops);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
@ -201,6 +201,10 @@ static int (*linux_nat_siginfo_fixup) (siginfo_t *,
|
|||
Called by our to_xfer_partial. */
|
||||
static target_xfer_partial_ftype *super_xfer_partial;
|
||||
|
||||
/* The saved to_close method, inherited from inf-ptrace.c.
|
||||
Called by our to_close. */
|
||||
static void (*super_close) (struct target_ops *);
|
||||
|
||||
static unsigned int debug_linux_nat;
|
||||
static void
|
||||
show_debug_linux_nat (struct ui_file *file, int from_tty,
|
||||
|
@ -4775,6 +4779,8 @@ linux_nat_close (struct target_ops *self)
|
|||
|
||||
if (linux_ops->to_close)
|
||||
linux_ops->to_close (linux_ops);
|
||||
|
||||
super_close (self);
|
||||
}
|
||||
|
||||
/* When requests are passed down from the linux-nat layer to the
|
||||
|
@ -4856,6 +4862,8 @@ linux_nat_add_target (struct target_ops *t)
|
|||
t->to_async = linux_nat_async;
|
||||
t->to_terminal_inferior = linux_nat_terminal_inferior;
|
||||
t->to_terminal_ours = linux_nat_terminal_ours;
|
||||
|
||||
super_close = t->to_close;
|
||||
t->to_close = linux_nat_close;
|
||||
|
||||
/* Methods for non-stop support. */
|
||||
|
|
|
@ -54,8 +54,6 @@ static void (*ofunc) ();
|
|||
|
||||
static procfs_run run;
|
||||
|
||||
static void procfs_open (char *, int);
|
||||
|
||||
static ptid_t do_attach (ptid_t ptid);
|
||||
|
||||
static int procfs_can_use_hw_breakpoint (struct target_ops *self,
|
||||
|
@ -71,7 +69,7 @@ static int procfs_remove_hw_watchpoint (struct target_ops *self,
|
|||
|
||||
static int procfs_stopped_by_watchpoint (struct target_ops *ops);
|
||||
|
||||
/* These two globals are only ever set in procfs_open(), but are
|
||||
/* These two globals are only ever set in procfs_open_1, but are
|
||||
referenced elsewhere. 'nto_procfs_node' is a flag used to say
|
||||
whether we are local, or we should get the current node descriptor
|
||||
for the remote QNX node. */
|
||||
|
@ -103,12 +101,12 @@ procfs_is_nto_target (bfd *abfd)
|
|||
return GDB_OSABI_QNXNTO;
|
||||
}
|
||||
|
||||
/* This is called when we call 'target procfs <arg>' from the (gdb) prompt.
|
||||
For QNX6 (nto), the only valid arg will be a QNX node string,
|
||||
eg: "/net/some_node". If arg is not a valid QNX node, we will
|
||||
default to local. */
|
||||
/* This is called when we call 'target native' or 'target procfs
|
||||
<arg>' from the (gdb) prompt. For QNX6 (nto), the only valid arg
|
||||
will be a QNX node string, eg: "/net/some_node". If arg is not a
|
||||
valid QNX node, we will default to local. */
|
||||
static void
|
||||
procfs_open (char *arg, int from_tty)
|
||||
procfs_open_1 (struct target_ops *ops, char *arg, int from_tty)
|
||||
{
|
||||
char *nodestr;
|
||||
char *endstr;
|
||||
|
@ -117,6 +115,9 @@ procfs_open (char *arg, int from_tty)
|
|||
procfs_sysinfo *sysinfo;
|
||||
struct cleanup *cleanups;
|
||||
|
||||
/* Offer to kill previous inferiors before opening this target. */
|
||||
target_preopen (from_tty);
|
||||
|
||||
nto_is_nto_target = procfs_is_nto_target;
|
||||
|
||||
/* Set the default node used for spawning to this one,
|
||||
|
@ -197,6 +198,8 @@ procfs_open (char *arg, int from_tty)
|
|||
}
|
||||
}
|
||||
do_cleanups (cleanups);
|
||||
|
||||
inf_child_open_target (ops, arg, from_tty);
|
||||
printf_filtered ("Debugging using %s\n", nto_procfs_path);
|
||||
}
|
||||
|
||||
|
@ -628,7 +631,8 @@ procfs_attach (struct target_ops *ops, char *args, int from_tty)
|
|||
inferior_appeared (inf, pid);
|
||||
inf->attach_flag = 1;
|
||||
|
||||
push_target (ops);
|
||||
if (!target_is_pushed (ops))
|
||||
push_target (ops);
|
||||
|
||||
procfs_find_new_threads (ops);
|
||||
}
|
||||
|
@ -904,7 +908,7 @@ procfs_detach (struct target_ops *ops, const char *args, int from_tty)
|
|||
inferior_ptid = null_ptid;
|
||||
detach_inferior (pid);
|
||||
init_thread_list ();
|
||||
unpush_target (ops); /* Pop out of handling an inferior. */
|
||||
inf_child_maybe_unpush_target (ops);
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -1023,8 +1027,8 @@ procfs_mourn_inferior (struct target_ops *ops)
|
|||
}
|
||||
inferior_ptid = null_ptid;
|
||||
init_thread_list ();
|
||||
unpush_target (ops);
|
||||
generic_mourn_inferior ();
|
||||
inf_child_maybe_unpush_target (ops);
|
||||
}
|
||||
|
||||
/* This function breaks up an argument string into an argument
|
||||
|
@ -1207,7 +1211,8 @@ procfs_create_inferior (struct target_ops *ops, char *exec_file,
|
|||
/* warning( "Failed to set Kill-on-Last-Close flag: errno = %d(%s)\n",
|
||||
errn, strerror(errn) ); */
|
||||
}
|
||||
push_target (ops);
|
||||
if (!target_is_pushed (ops))
|
||||
push_target (ops);
|
||||
target_terminal_init ();
|
||||
|
||||
if (exec_bfd != NULL
|
||||
|
@ -1385,6 +1390,25 @@ procfs_can_run (struct target_ops *self)
|
|||
/* "target procfs". */
|
||||
static struct target_ops nto_procfs_ops;
|
||||
|
||||
/* "target native". */
|
||||
static struct target_ops *nto_native_ops;
|
||||
|
||||
/* to_open implementation for "target procfs". */
|
||||
|
||||
static void
|
||||
procfs_open (char *arg, int from_tty)
|
||||
{
|
||||
procfs_open_1 (&nto_procfs_ops, arg, from_tty);
|
||||
}
|
||||
|
||||
/* to_open implementation for "target native". */
|
||||
|
||||
static void
|
||||
procfs_native_open (char *arg, int from_tty)
|
||||
{
|
||||
procfs_open_1 (nto_native_ops, arg, from_tty);
|
||||
}
|
||||
|
||||
/* Create the "native" and "procfs" targets. */
|
||||
|
||||
static void
|
||||
|
@ -1395,7 +1419,7 @@ init_procfs_targets (void)
|
|||
/* Leave to_shortname as "native". */
|
||||
t->to_longname = "QNX Neutrino local process";
|
||||
t->to_doc = "QNX Neutrino local process (started by the \"run\" command).";
|
||||
t->to_open = procfs_open;
|
||||
t->to_open = procfs_native_open;
|
||||
t->to_attach = procfs_attach;
|
||||
t->to_post_attach = procfs_post_attach;
|
||||
t->to_detach = procfs_detach;
|
||||
|
@ -1424,6 +1448,8 @@ init_procfs_targets (void)
|
|||
t->to_have_continuable_watchpoint = 1;
|
||||
t->to_extra_thread_info = nto_extra_thread_info;
|
||||
|
||||
nto_native_ops = t;
|
||||
|
||||
/* Register "target native". This is the default run target. */
|
||||
add_target (t);
|
||||
|
||||
|
@ -1433,6 +1459,8 @@ init_procfs_targets (void)
|
|||
nto_procfs_ops.to_can_run = procfs_can_run;
|
||||
t->to_longname = "QNX Neutrino local or remote process";
|
||||
t->to_doc = "QNX Neutrino process. target procfs <node>";
|
||||
t->to_open = procfs_open;
|
||||
|
||||
add_target (&nto_procfs_ops);
|
||||
}
|
||||
|
||||
|
|
13
gdb/procfs.c
13
gdb/procfs.c
|
@ -3062,7 +3062,8 @@ procfs_attach (struct target_ops *ops, char *args, int from_tty)
|
|||
fflush (stdout);
|
||||
}
|
||||
inferior_ptid = do_attach (pid_to_ptid (pid));
|
||||
push_target (ops);
|
||||
if (!target_is_pushed (ops))
|
||||
push_target (ops);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -3091,7 +3092,7 @@ procfs_detach (struct target_ops *ops, const char *args, int from_tty)
|
|||
|
||||
inferior_ptid = null_ptid;
|
||||
detach_inferior (pid);
|
||||
unpush_target (ops);
|
||||
inf_child_maybe_unpush_target (ops);
|
||||
}
|
||||
|
||||
static ptid_t
|
||||
|
@ -4340,7 +4341,8 @@ procfs_mourn_inferior (struct target_ops *ops)
|
|||
if (pi)
|
||||
destroy_procinfo (pi);
|
||||
}
|
||||
unpush_target (ops);
|
||||
|
||||
generic_mourn_inferior ();
|
||||
|
||||
if (dbx_link_bpt != NULL)
|
||||
{
|
||||
|
@ -4349,7 +4351,7 @@ procfs_mourn_inferior (struct target_ops *ops)
|
|||
dbx_link_bpt = NULL;
|
||||
}
|
||||
|
||||
generic_mourn_inferior ();
|
||||
inf_child_maybe_unpush_target (ops);
|
||||
}
|
||||
|
||||
/* When GDB forks to create a runnable inferior process, this function
|
||||
|
@ -4367,7 +4369,8 @@ procfs_init_inferior (struct target_ops *ops, int pid)
|
|||
|
||||
/* This routine called on the parent side (GDB side)
|
||||
after GDB forks the inferior. */
|
||||
push_target (ops);
|
||||
if (!target_is_pushed (ops))
|
||||
push_target (ops);
|
||||
|
||||
if ((pi = create_procinfo (pid, 0)) == NULL)
|
||||
perror (_("procfs: out of memory in 'init_inferior'"));
|
||||
|
|
48
gdb/target.c
48
gdb/target.c
|
@ -2436,6 +2436,20 @@ target_require_runnable (void)
|
|||
internal_error (__FILE__, __LINE__, _("No targets found"));
|
||||
}
|
||||
|
||||
/* Whether GDB is allowed to fall back to the default run target for
|
||||
"run", "attach", etc. when no target is connected yet. */
|
||||
static int auto_connect_native_target = 1;
|
||||
|
||||
static void
|
||||
show_auto_connect_native_target (struct ui_file *file, int from_tty,
|
||||
struct cmd_list_element *c, const char *value)
|
||||
{
|
||||
fprintf_filtered (file,
|
||||
_("Whether GDB may automatically connect to the "
|
||||
"native target is %s.\n"),
|
||||
value);
|
||||
}
|
||||
|
||||
/* Look through the list of possible targets for a target that can
|
||||
execute a run or attach command without any other data. This is
|
||||
used to locate the default process stratum.
|
||||
|
@ -2446,23 +2460,28 @@ target_require_runnable (void)
|
|||
static struct target_ops *
|
||||
find_default_run_target (char *do_mesg)
|
||||
{
|
||||
struct target_ops **t;
|
||||
struct target_ops *runable = NULL;
|
||||
int count;
|
||||
|
||||
count = 0;
|
||||
|
||||
for (t = target_structs; t < target_structs + target_struct_size;
|
||||
++t)
|
||||
if (auto_connect_native_target)
|
||||
{
|
||||
if ((*t)->to_can_run != delegate_can_run && target_can_run (*t))
|
||||
struct target_ops **t;
|
||||
int count = 0;
|
||||
|
||||
for (t = target_structs; t < target_structs + target_struct_size;
|
||||
++t)
|
||||
{
|
||||
runable = *t;
|
||||
++count;
|
||||
if ((*t)->to_can_run != delegate_can_run && target_can_run (*t))
|
||||
{
|
||||
runable = *t;
|
||||
++count;
|
||||
}
|
||||
}
|
||||
|
||||
if (count != 1)
|
||||
runable = NULL;
|
||||
}
|
||||
|
||||
if (count != 1)
|
||||
if (runable == NULL)
|
||||
{
|
||||
if (do_mesg)
|
||||
error (_("Don't know how to %s. Try \"help target\"."), do_mesg);
|
||||
|
@ -4270,4 +4289,13 @@ When this permission is on, GDB may interrupt/stop the target's execution.\n\
|
|||
Otherwise, any attempt to interrupt or stop will be ignored."),
|
||||
set_target_permissions, NULL,
|
||||
&setlist, &showlist);
|
||||
|
||||
add_setshow_boolean_cmd ("auto-connect-native-target", class_support,
|
||||
&auto_connect_native_target, _("\
|
||||
Set whether GDB may automatically connect to the native target."), _("\
|
||||
Show whether GDB may automatically connect to the native target."), _("\
|
||||
When on, and GDB is not connected to a target yet, GDB\n\
|
||||
attempts \"run\" and other commands with the native target."),
|
||||
NULL, show_auto_connect_native_target,
|
||||
&setlist, &showlist);
|
||||
}
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
2014-05-21 Pedro Alves <palves@redhat.com>
|
||||
|
||||
* boards/gdbserver-base.exp (GDBFLAGS): Set to "set
|
||||
auto-connect-native-target off".
|
||||
* gdb.base/auto-connect-native-target.c: New file.
|
||||
* gdb.base/auto-connect-native-target.exp: New file.
|
||||
|
||||
2014-05-21 Pedro Alves <palves@redhat.com>
|
||||
|
||||
* gdb.base/default.exp: Test "target native" instead of "target
|
||||
|
|
|
@ -34,6 +34,8 @@ set_board_info gdb,nofileio 1
|
|||
# The predefined TSVs in GDBserver.
|
||||
set_board_info gdb,predefined_tsv "\\\$trace_timestamp"
|
||||
|
||||
set GDBFLAGS "${GDBFLAGS} -ex \"set auto-connect-native-target off\""
|
||||
|
||||
proc ${board}_file { dest op args } {
|
||||
if { $op == "delete" } {
|
||||
return 0
|
||||
|
|
23
gdb/testsuite/gdb.base/auto-connect-native-target.c
Normal file
23
gdb/testsuite/gdb.base/auto-connect-native-target.c
Normal file
|
@ -0,0 +1,23 @@
|
|||
/* This testcase is part of GDB, the GNU debugger.
|
||||
|
||||
Copyright 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/>. */
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
209
gdb/testsuite/gdb.base/auto-connect-native-target.exp
Normal file
209
gdb/testsuite/gdb.base/auto-connect-native-target.exp
Normal file
|
@ -0,0 +1,209 @@
|
|||
# Copyright 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/>.
|
||||
|
||||
# Test "set auto-connect-native-target off" and "target native" on
|
||||
# native targets.
|
||||
|
||||
standard_testfile
|
||||
|
||||
if {[prepare_for_testing "failed to prepare" $testfile $srcfile debug]} {
|
||||
return -1
|
||||
}
|
||||
|
||||
# Whether this GDB is configured with a "native" target.
|
||||
set have_native 0
|
||||
|
||||
set test "help target native"
|
||||
gdb_test_multiple $test $test {
|
||||
-re "Undefined target command.* $gdb_prompt $" {
|
||||
set have_native 0
|
||||
}
|
||||
-re "Native process.*$gdb_prompt $" {
|
||||
set have_native 1
|
||||
}
|
||||
}
|
||||
|
||||
if { !$have_native } {
|
||||
unsupported "No \"target native\" support."
|
||||
return
|
||||
}
|
||||
|
||||
# Returns the topmost target pushed on the target stack. TEST is used
|
||||
# as test message.
|
||||
|
||||
proc get_topmost_target {test} {
|
||||
global gdb_prompt
|
||||
|
||||
set topmost "unknown"
|
||||
|
||||
gdb_test_multiple "maint print target-stack" $test {
|
||||
-re "The current target stack is:\r\n - (\[^ \]+) .*$gdb_prompt $" {
|
||||
set topmost $expect_out(1,string)
|
||||
pass $test
|
||||
}
|
||||
}
|
||||
|
||||
return $topmost
|
||||
}
|
||||
|
||||
set topmost [get_topmost_target "check whether a target is already connected"]
|
||||
|
||||
# Testing against the extended-remote board, for example?
|
||||
if { $topmost != "exec" } {
|
||||
unsupported "Already connected to target $topmost."
|
||||
return
|
||||
}
|
||||
|
||||
# Check which target this board connects to. If testing with a native
|
||||
# target board, this should cause the native target to auto connect.
|
||||
if ![runto_main] then {
|
||||
fail "Can't run to main"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Returns true if the native target is pushed on the target stack.
|
||||
# TEST is used as test message.
|
||||
|
||||
proc check_native_target {test} {
|
||||
global gdb_prompt
|
||||
|
||||
gdb_test_multiple "maint print target-stack" $test {
|
||||
-re " native .*$gdb_prompt $" {
|
||||
pass $test
|
||||
return 1
|
||||
}
|
||||
-re "$gdb_prompt $" {
|
||||
pass $test
|
||||
}
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# Testing against a remote board, for example?
|
||||
if { ![check_native_target "check whether board tests the native target"] } {
|
||||
unsupported "Not testing the native target."
|
||||
return
|
||||
}
|
||||
|
||||
# Kill program. TEST is used as test message.
|
||||
|
||||
proc kill_program {test} {
|
||||
global gdb_prompt
|
||||
|
||||
gdb_test_multiple "kill" $test {
|
||||
-re "Kill the program being debugged\\? .y or n. $" {
|
||||
send_gdb "y\n"
|
||||
exp_continue
|
||||
}
|
||||
-re "$gdb_prompt $" {
|
||||
pass $test
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Kill the program. This should pop the target. The "start" test
|
||||
# below will fail otherwise.
|
||||
kill_program "kill"
|
||||
|
||||
# Now prevent the native target from auto connecting.
|
||||
gdb_test_no_output "set auto-connect-native-target off"
|
||||
|
||||
# Commands that rely on the native target auto-connecting should no longer work.
|
||||
gdb_test "start" "Don't know how to run.*" "start no longer works"
|
||||
|
||||
# Explicitly connect to the native target.
|
||||
gdb_test "target native" \
|
||||
"Done. Use the \"run\" command to start a process.*" \
|
||||
"explicitly connect to the native target"
|
||||
|
||||
proc test_native_target_remains_pushed {} {
|
||||
gdb_test "maint print target-stack" \
|
||||
"The current target stack is:\r\n .* native .* exec .*" \
|
||||
"native target remains pushed"
|
||||
}
|
||||
|
||||
# Test a set of "inferior gone" scenarios, making sure the target
|
||||
# remains pushed.
|
||||
|
||||
with_test_prefix "kill" {
|
||||
gdb_test "start" "main.*" "start"
|
||||
|
||||
kill_program "kill"
|
||||
|
||||
test_native_target_remains_pushed
|
||||
}
|
||||
|
||||
with_test_prefix "detach" {
|
||||
gdb_test "start" "main.*"
|
||||
|
||||
set test "detach"
|
||||
gdb_test_multiple $test $test {
|
||||
-re "Detach the program being debugged\\? .y or n. $" {
|
||||
send_gdb "y\n"
|
||||
exp_continue
|
||||
}
|
||||
-re "$gdb_prompt $" {
|
||||
pass $test
|
||||
}
|
||||
}
|
||||
|
||||
test_native_target_remains_pushed
|
||||
}
|
||||
|
||||
with_test_prefix "run to exit" {
|
||||
gdb_test "start" "Temporary breakpoint .* main .*"
|
||||
|
||||
gdb_test "c" "$inferior_exited_re normally.*"
|
||||
|
||||
test_native_target_remains_pushed
|
||||
}
|
||||
|
||||
# Now test disconnecting. Commands that rely on the native target
|
||||
# auto-connecting should no longer work (again) after this.
|
||||
|
||||
with_test_prefix "disconnect" {
|
||||
gdb_test "start" "Temporary breakpoint .* main .*"
|
||||
|
||||
set test "disconnect"
|
||||
gdb_test_multiple $test $test {
|
||||
-re "A program is being debugged already.* .y or n. $" {
|
||||
send_gdb "y\n"
|
||||
exp_continue
|
||||
}
|
||||
-re "$gdb_prompt $" {
|
||||
pass $test
|
||||
}
|
||||
}
|
||||
|
||||
set topmost \
|
||||
[get_topmost_target "check whether the target is no longer connected"]
|
||||
|
||||
set test "no longer connected to a target"
|
||||
if { $topmost == "exec" } {
|
||||
pass $test
|
||||
} else {
|
||||
fail $test
|
||||
}
|
||||
|
||||
gdb_test "start" "Don't know how to run.*" "start no longer works"
|
||||
}
|
||||
|
||||
# Reenable auto-connecting to the native target. Plain "start" should
|
||||
# start working again.
|
||||
gdb_test_no_output "set auto-connect-native-target on"
|
||||
|
||||
gdb_test "start" "Temporary breakpoint .* main .*" \
|
||||
"start auto-connects to the native target after reenabling auto-connect"
|
|
@ -1726,7 +1726,8 @@ do_initial_windows_stuff (struct target_ops *ops, DWORD pid, int attaching)
|
|||
#endif
|
||||
current_event.dwProcessId = pid;
|
||||
memset (¤t_event, 0, sizeof (current_event));
|
||||
push_target (ops);
|
||||
if (!target_is_pushed (ops))
|
||||
push_target (ops);
|
||||
disable_breakpoints_in_shlibs ();
|
||||
windows_clear_solib ();
|
||||
clear_proceed_status ();
|
||||
|
@ -1914,7 +1915,7 @@ windows_detach (struct target_ops *ops, const char *args, int from_tty)
|
|||
inferior_ptid = null_ptid;
|
||||
detach_inferior (current_event.dwProcessId);
|
||||
|
||||
unpush_target (ops);
|
||||
inf_child_maybe_unpush_target (ops);
|
||||
}
|
||||
|
||||
/* Try to determine the executable filename.
|
||||
|
@ -2367,8 +2368,8 @@ windows_mourn_inferior (struct target_ops *ops)
|
|||
CHECK (CloseHandle (current_process_handle));
|
||||
open_process_used = 0;
|
||||
}
|
||||
unpush_target (ops);
|
||||
generic_mourn_inferior ();
|
||||
inf_child_maybe_unpush_target (ops);
|
||||
}
|
||||
|
||||
/* Send a SIGINT to the process group. This acts just like the user typed a
|
||||
|
|
Loading…
Reference in a new issue