From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 21286 invoked by alias); 8 Feb 2010 19:20:32 -0000 Received: (qmail 21265 invoked by uid 22791); 8 Feb 2010 19:20:26 -0000 X-SWARE-Spam-Status: No, hits=-0.9 required=5.0 tests=AWL,BAYES_20,SPF_PASS,ZMIde_GENERICSPAM1 X-Spam-Check-By: sourceware.org Received: from mail.codesourcery.com (HELO mail.codesourcery.com) (38.113.113.100) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Mon, 08 Feb 2010 19:20:17 +0000 Received: (qmail 9935 invoked from network); 8 Feb 2010 19:20:14 -0000 Received: from unknown (HELO orlando) (pedro@127.0.0.2) by mail.codesourcery.com with ESMTPA; 8 Feb 2010 19:20:14 -0000 From: Pedro Alves To: gdb-patches@sourceware.org Subject: Re: Multiexec MI Date: Mon, 08 Feb 2010 19:20:00 -0000 User-Agent: KMail/1.9.10 Cc: Vladimir Prus References: <201001132329.30212.vladimir@codesourcery.com> In-Reply-To: <201001132329.30212.vladimir@codesourcery.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Content-Disposition: inline Message-Id: <201002081920.13920.pedro@codesourcery.com> X-IsSubscribed: yes Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2010-02/txt/msg00218.txt.bz2 On Wednesday 13 January 2010 20:29:30, Vladimir Prus wrote: > This patch implements MI support for multiexec. I attach my notes on desi= gn, as well > as patch. The patch also contains documentation updates. >=20 > The executive summary is: > * thread groups of types 'process' are redefined to mean inferior, and th= erefore > =C2=A0 can exist before process is started, and outlive the process. > * The --thread-group option, previously available for select MI commands,= is now > =C2=A0 globally available. Therefore, things like: >=20 > =C2=A0 =C2=A0 =C2=A0 =C2=A0-file-exec-and-symbols --thread-group i1 foobar > =C2=A0=20 > =C2=A0 works. > * The --all option to MI exec commands now affects threads in all inferio= rs. >=20 > The important caveat is that multiexec MI is only really working in non-s= top. > At least the --all option, in all-stops, runs into various core issues. I= t's not > presently known how many are there and whether they are fixable. Yeah. I tried it on a simple test I use often, much like schedlock.c (spawns a few threads that go busy looping), creating a few inferiors using that program, and `-exec-run --all' didn't behave correctly; it didn't crash, but a bunch of threads missing. I haven't investigated fully, but there's the option of not supporting it until it actually works.. >=20 > - Volodya > multiexec-mi.diff > commit 8fb18657cf8d53b951c84e76002e5a57dc75a944 > Author: Vladimir Prus > Date: =C2=A0 Sat Dec 19 17:38:00 2009 +0300 >=20 > =C2=A0 =C2=A0 Multiexec MI > =C2=A0 =C2=A0=20 > =C2=A0 =C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0gdb/ > =C2=A0 =C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0* breakpoint.c (clear_syscall_count= s): Take struct inferior*. > =C2=A0 =C2=A0=20 > =C2=A0 =C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0gdb/doc/ > =C2=A0 =C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0* gdb.texinfo (GDB/MI Command Synta= x): Document notification > =C2=A0 =C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0changes. > =C2=A0 =C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0(GDB/MI Program Execution): Documen= t current behaviour of > =C2=A0 =C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0--all and --thread-group. > =C2=A0 =C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0(GDB/MI Miscellaneous Commands): Do= cument -add-inferior and > =C2=A0 =C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0-remove-inferior. > =C2=A0 =C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0* observer.texi (inferior_added, in= ferior_removed): New > =C2=A0 =C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0observers. > =C2=A0 =C2=A0=20 > =C2=A0 =C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0* inferior.c (add_inferior_silent):= Notify inferior_added > =C2=A0 =C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0observer. > =C2=A0 =C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0(delete_inferior_1): Notify inferio= r_removed observer. > =C2=A0 =C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0(exit_inferior_1): Pass inferior, n= ot pid, to observer. > =C2=A0 =C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0(inferior_appeared): Likewise. > =C2=A0 =C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0(add_inferior_with_spaces): New. > =C2=A0 =C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0(add_inferior_command): Use the abo= ve. > =C2=A0 =C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0* inferior.h (delete_inferior_1, ad= d_inferior_with_spaces): > =C2=A0 =C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0Declare. > =C2=A0 =C2=A0=20 > =C2=A0 =C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0* inflow.c (inflow_inferior_exit): = Likewise. > =C2=A0 =C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0* jit.c (jit_inferior_exit_hook): L= ikewise. > =C2=A0 =C2=A0=20 > =C2=A0 =C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0* mi/mi-cmds.c (mi_cmds): Register = add-inferior and > =C2=A0 =C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0remove-inferior. > =C2=A0 =C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0* mi/mi-cmds.h (mi_cmd_add_inferior= , mi_cmd_remove_inferior): New. > =C2=A0 =C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0* mi/mi-interp.c (mi_inferior_added= , mi_inferior_removed): New. > =C2=A0 =C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0(report_initial_inferior): New. > =C2=A0 =C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0(mi_inferior_removed): Register the= above. Make sure > =C2=A0 =C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0inferior_added observer is called o= n the first inferior. > =C2=A0 =C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0(mi_new_thread, mi_thread_exit): Th= read group is now identified by > =C2=A0 =C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0inferior number, not pid. > =C2=A0 =C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0(mi_solib_loaded, mi_solib_unloaded= ): Report which inferiors are > =C2=A0 =C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0affected. > =C2=A0 =C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0* mi/mi-main.c (current_context): N= ew. > =C2=A0 =C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0(proceed_thread_callback): Use type= d closure. > =C2=A0 =C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0Proceed everything if pid is 0. > =C2=A0 =C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0(proceed_thread_callback_wrapper): = New. > =C2=A0 =C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0(run_one_inferior): New. > =C2=A0 =C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0(mi_cmd_exec_continue, mi_cmd_exec_= interrupt, mi_cmd_exec_run): > =C2=A0 =C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0Adjust for multiexec behaviour. > =C2=A0 =C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0(mi_cmd_add_inferior, mi_cmd_remove= _inferior): New. > =C2=A0 =C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0(mi_cmd_execute): Handle the 'threa= d-group' option here. > =C2=A0 =C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0Do some extra checks. > =C2=A0 =C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0* mi-parse.c (mi_parse): Handle the= --all and --thread-group > =C2=A0 =C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0options. > =C2=A0 =C2=A0 =C2=A0=C2=A0=C2=A0=C2=A0* mi-parse.h (struct mi_parse): New= fields all and thread_group. >=20 > diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c > index 0dc8474..0d8a471 100644 > --- a/gdb/breakpoint.c > +++ b/gdb/breakpoint.c > @@ -10230,10 +10230,8 @@ add_catch_command (char *name, char *docstring, > =C2=A0} > =C2=A0 > =C2=A0static void > -clear_syscall_counts (int pid) > +clear_syscall_counts (struct inferior *inf) > =C2=A0{ > - =C2=A0struct inferior *inf =3D find_inferior_pid (pid); > - > =C2=A0 =C2=A0inf->total_syscalls_count =3D 0; > =C2=A0 =C2=A0inf->any_syscall_count =3D 0; > =C2=A0 =C2=A0VEC_free (int, inf->syscalls_counts); > diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo > index 02e2bbd..6da2d12 100644 > --- a/gdb/doc/gdb.texinfo > +++ b/gdb/doc/gdb.texinfo > @@ -21528,6 +21528,11 @@ groups can be obtained using @samp{-list-thread-= groups --available}. > =C2=A0In general, the content of a thread group may be only retrieved only > =C2=A0after attaching to that thread group. > =C2=A0 > +Thread groups are related to inferiors (@pxref{Inferiors and > +Programs}). =C2=A0Each inferior corresponds to a thread group of a speci= al=20 > +type @samp{process}, and some additional operations are permitted on > +such thread groups. > + > =C2=A0@c %%%%%%%%%%%%%%%%%%%%%%%%%%%% SECTION %%%%%%%%%%%%%%%%%%%%%%%%%%%= %%%%%%% > =C2=A0@node GDB/MI Command Syntax > =C2=A0@section @sc{gdb/mi} Command Syntax > @@ -21969,9 +21974,24 @@ several threads in the list. =C2=A0The @var{core= } field reports the > =C2=A0processor core on which the stop event has happened. =C2=A0This fie= ld may be absent > =C2=A0if such information is not available. > =C2=A0 > -@item =3Dthread-group-created,id=3D"@var{id}" > +@item =3Dthread-group-added,id=3D"@var{id}" > +@itemx =3Dthread-group-removed,id=3D"@var{id}" > +A thread thread group was either added or removed. =C2=A0The @var{id} fi= eld > +contains the @value{GDBN} identifier of the thread group. =C2=A0When a t= hread > +group is added, it generally might not be associated with a running > +process. =C2=A0When a thread group is removed, its id becomes invalid and > +cannot be used in any way. > + > +@item =3Dthread-group-started,id=3D"@var{id}",pid=3D"@var{pid}" > +A thread group either because associated with a running program, > +either because the program was started or it the thread group > +was attached to a program. =C2=A0The @var{id} field contains the=20 > +@value{GDBN} identifier of the thread group. =C2=A0The @var{pid} field > +contains process identifier, specific to the operating system. > + > =C2=A0@itemx =3Dthread-group-exited,id=3D"@var{id}" > -A thread thread group either was attached to, or has exited/detached > +A thread thread group is no longer associated with a running program, > +either because the program has exited, or because it was detached > =C2=A0from. =C2=A0The @var{id} field contains the @value{GDBN} identifier= of the > =C2=A0thread group. > =C2=A0 > @@ -22002,12 +22022,18 @@ opaque identifier of the library. =C2=A0For rem= ote debugging case, > =C2=A0library file on the target, and on the host respectively. =C2=A0For= native > =C2=A0debugging, both those fields have the same value. =C2=A0The > =C2=A0@var{symbols-loaded} field reports if the debug symbols for this > -library are loaded. > +library are loaded. =C2=A0The @var{thread-group} field, if present, > +contains the id of the thread group in which the library was loaded. > +If the field is absent, it means the library was loaded in all present > +thread groups. > =C2=A0 > =C2=A0@item =3Dlibrary-unloaded,... > =C2=A0Reports that a library was unloaded by the program. =C2=A0This noti= fication > =C2=A0has 3 fields---@var{id}, @var{target-name} and @var{host-name} with > -the same meaning as for the @code{=3Dlibrary-loaded} notification > +the same meaning as for the @code{=3Dlibrary-loaded} notification. =C2= =A0The=20 > +@var{thread-group} field, if present, contains the id of the thread > +group in which the library was loaded. =C2=A0If the field is absent, > +it means the library was loaded in all present thread groups. > =C2=A0 > =C2=A0@end table > =C2=A0 > @@ -23106,7 +23132,7 @@ other cases. > =C2=A0@subsubheading Synopsis > =C2=A0 > =C2=A0@smallexample > - -exec-continue [--all|--thread-group N] > + -exec-continue [--all | --thread-group N] > =C2=A0@end smallexample > =C2=A0 > =C2=A0Resumes the execution of the inferior program until a breakpoint is > @@ -23116,7 +23142,7 @@ depending on the value of the @samp{scheduler-loc= king} variable. =C2=A0In > =C2=A0non-stop mode (@pxref{Non-Stop Mode}), if the @samp{--all} is not > =C2=A0specified, only the thread specified with the @samp{--thread} option > =C2=A0(or current thread, if no @samp{--thread} is provided) is resumed. = =C2=A0If > -@samp{--all} is specified, all threads will be resumed. =C2=A0The > +@samp{--all} is specified, all threads (in all inferiours) will be resum= ed. =C2=A0The s/inferiours/inferiors/ there are more instances of this. > =C2=A0@samp{--all} option is ignored in all-stop mode. =C2=A0If the > =C2=A0@samp{--thread-group} options is specified, then all threads in that > =C2=A0thread group are resumed. > @@ -23206,9 +23232,9 @@ asynchronous just like other execution commands. = =C2=A0That is, first the > =C2=A0reported after that using the @samp{*stopped} notification. > =C2=A0 > =C2=A0In non-stop mode, only the context thread is interrupted by default. > -All threads will be interrupted if the @samp{--all} option is > -specified. =C2=A0If the @samp{--thread-group} option is specified, all > -threads in that group will be interrupted. > +All threads (in all inferiours) will be interrupted if the > +@samp{--all} =C2=A0option is specified. =C2=A0If the @samp{--thread-grou= p} > +option is =C2=A0specified, all threads in that group will be interrupted. ^ looks like spurious space. > =C2=A0 > =C2=A0@subsubheading @value{GDBN} Command > =C2=A0 > @@ -23372,7 +23398,7 @@ fullname=3D"/home/foo/bar/devo/gdb/testsuite/gdb.= mi/basics.c",line=3D"18"@} > =C2=A0@subsubheading Synopsis > =C2=A0 > =C2=A0@smallexample > - -exec-run > + -exec-run [--all | --thread-group N ] > =C2=A0@end smallexample > =C2=A0 > =C2=A0Starts execution of the inferior from the beginning. =C2=A0The infe= rior > @@ -23380,6 +23406,11 @@ executes until either a breakpoint is encountere= d or the program > =C2=A0exits. =C2=A0In the latter case the output will include an exit cod= e, if > =C2=A0the program has exited exceptionally. > =C2=A0 > +When no option is specified, the current inferiour is started. =C2=A0If = the > +@samp{--thread-group} option is specified, it should refer to a thread > +group of type @samp{process}, and that thread group will be started. > +If the @samp{--all} option is specified, then all inferiours will be sta= rted. > + > =C2=A0@subsubheading @value{GDBN} Command > =C2=A0 > =C2=A0The corresponding @value{GDBN} command is @samp{run}. > @@ -26437,7 +26468,8 @@ have the following fields: > =C2=A0 > =C2=A0@table @code > =C2=A0@item id > -Identifier of the thread group. =C2=A0This field is always present. > +Identifier of the thread group. =C2=A0This field is always present. =C2= =A0The > +identifier is an opaque string, and is not necessary an integer. > =C2=A0 > =C2=A0@item type > =C2=A0The type of the thread group. =C2=A0At present, only @samp{process}= is a > @@ -26445,7 +26477,7 @@ valid type. > =C2=A0 > =C2=A0@item pid > =C2=A0The target-specific process identifier. =C2=A0This field is only pr= esent > -for thread groups of type @samp{process}. > +for thread groups of type @samp{process} and only if the process exists. > =C2=A0 > =C2=A0@item num_children > =C2=A0The number of children this thread group has. =C2=A0This field may = be > @@ -26461,6 +26493,11 @@ This field is a list of integers, each identifyi= ng a core that one > =C2=A0thread of the group is running on. =C2=A0This field may be absent if > =C2=A0such information is not available. > =C2=A0 > +@item executable > +The name of the executable file that corresponds to this thread group. > +The field is only present for thread groups of type @samp{process}, > +and only if there is corresponding executable file. > + > =C2=A0@end table > =C2=A0 > =C2=A0@subheading Example > @@ -26487,6 +26524,31 @@ such information is not available. > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0@{id=3D"2",target-id=3D"Thread 0xb7e14b90",cores=3D[2]@}]@= },...] > =C2=A0@end smallexample > =C2=A0 > + > +@subheading The @code{-add-inferior} Command > +@findex -add-inferior > + > +@subheading Synopsis > + > +@smallexample > +-add-inferior > +@end smallexample > + > +Creates a new inferior (@pxref{Inferiors and Programs}). =C2=A0The creat= ed > +inferior is not associated with any executable. =C2=A0Such associated may > +be established with the @samp{-file-exec-and-symbols} command=20 > +(@pxref{GDB/MI File Commands}). =C2=A0The command response has a single > +field, @samp{thread-group}, whose value is the identifier of the > +thread group corresponding to the new inferior. > + > +@subheading Example > + > +@smallexample > +@value{GDBP} > +-add-inferior > +^done,thread-group=3D"i3" > +@end smallexample > + > =C2=A0@subheading The @code{-interpreter-exec} Command > =C2=A0@findex -interpreter-exec > =C2=A0 > diff --git a/gdb/doc/observer.texi b/gdb/doc/observer.texi > index db3d114..fb0cc9d 100644 > --- a/gdb/doc/observer.texi > +++ b/gdb/doc/observer.texi > @@ -199,13 +199,23 @@ The thread's ptid has changed. =C2=A0The @var{old_p= tid} parameter specifies > =C2=A0the old value, and @var{new_ptid} specifies the new value. > =C2=A0@end deftypefun > =C2=A0 > -@deftypefun void inferior_appeared (int @var{pid}) > -@value{GDBN} has attached to a new inferior identified by @var{pid}. > +@deftypefun void inferior_added (struct inferior *@var{inf}) > +The inferior @var{inf} has been added to the list of inferiour. =C2=A0At > +this point, it might not be associated with any process. > =C2=A0@end deftypefun > =C2=A0 > -@deftypefun void inferior_exit (int @var{pid}) > -Either @value{GDBN} detached from the inferior, or the inferior > -exited. =C2=A0The argument @var{pid} identifies the inferior. > +@deftypefun void inferior_appeared (struct inferior *@var{inf}) > +The inferior identified by @var{inf} has been attached to a process. > +@end deftypefun > + > +@deftypefun void inferior_exit (struct inferior *@var{inf}) > +Either the inferior associated with @var{inf} has been detached from the > +process, or the process has exited. > +@end deftypefun > + > +@deftypefun void inferior_removed (struct inferior *@var{inf}) > +The inferior @var{inf} has been removed from the list of inferiors. > +This method is called immediate before freeing @var{inf}. > =C2=A0@end deftypefun > =C2=A0 > =C2=A0@deftypefun void memory_changed (CORE_ADDR @var{addr}, int @var{len= }, const bfd_byte *@var{data}) > @@ -213,8 +223,8 @@ Bytes from @var{data} to @var{data} + @var{len} have = been written > =C2=A0to the current inferior at @var{addr}. > =C2=A0@end deftypefun > =C2=A0 > - @deftypefun void test_notification (int @var{somearg}) > +@deftypefun void test_notification (int @var{somearg}) > =C2=A0This observer is used for internal testing. =C2=A0Do not use. =C2=A0 > =C2=A0See testsuite/gdb.gdb/observer.exp. > - @end deftypefun > +@end deftypefun > =C2=A0 > diff --git a/gdb/inferior.c b/gdb/inferior.c > index d27a3e3..783b8fc 100644 > --- a/gdb/inferior.c > +++ b/gdb/inferior.c > @@ -126,6 +126,8 @@ add_inferior_silent (int pid) > =C2=A0 > =C2=A0 =C2=A0inferior_alloc_data (inf); > =C2=A0 > + =C2=A0observer_notify_inferior_added (inf); > + > =C2=A0 =C2=A0if (pid !=3D 0) > =C2=A0 =C2=A0 =C2=A0inferior_appeared (inf, pid); > =C2=A0 > @@ -187,7 +189,7 @@ delete_threads_of_inferior (int pid) > =C2=A0/* If SILENT then be quiet -- don't announce a inferior death, or t= he > =C2=A0 =C2=A0 exit of its threads. =C2=A0*/ > =C2=A0 > -static void > +void > =C2=A0delete_inferior_1 (struct inferior *todel, int silent) > =C2=A0{ > =C2=A0 =C2=A0struct inferior *inf, *infprev; > @@ -212,6 +214,8 @@ delete_inferior_1 (struct inferior *todel, int silent) > =C2=A0 =C2=A0else > =C2=A0 =C2=A0 =C2=A0inferior_list =3D inf->next; > =C2=A0 > + =C2=A0observer_notify_inferior_removed (inf); > + > =C2=A0 =C2=A0free_inferior (inf); > =C2=A0} > =C2=A0 > @@ -258,7 +262,7 @@ exit_inferior_1 (struct inferior *inftoex, int silent) > =C2=A0 > =C2=A0 =C2=A0/* Notify the observers before removing the inferior from th= e list, > =C2=A0 =C2=A0 =C2=A0 so that the observers have a chance to look it up. = =C2=A0*/ > - =C2=A0observer_notify_inferior_exit (inf->pid); > + =C2=A0observer_notify_inferior_exit (inf); > =C2=A0 > =C2=A0 =C2=A0inf->pid =3D 0; > =C2=A0 =C2=A0if (inf->vfork_parent !=3D NULL) > @@ -308,7 +312,7 @@ inferior_appeared (struct inferior *inf, int pid) > =C2=A0{ > =C2=A0 =C2=A0inf->pid =3D pid; > =C2=A0 > - =C2=A0observer_notify_inferior_appeared (pid); > + =C2=A0observer_notify_inferior_appeared (inf); > =C2=A0} > =C2=A0 > =C2=A0void > @@ -731,6 +735,24 @@ remove_inferior_command (char *args, int from_tty) > =C2=A0 =C2=A0delete_inferior_1 (inf, 1); > =C2=A0} > =C2=A0 > +struct inferior * > +add_inferior_with_spaces (void) > +{ > + =C2=A0struct address_space *aspace; > + =C2=A0struct program_space *pspace; > + =C2=A0struct inferior *inf; > + =C2=A0 > + =C2=A0/* If all inferiors share an address space on this system, this > + =C2=A0 =C2=A0 doesn't really return a new address space; otherwise, it > + =C2=A0 =C2=A0 really does. =C2=A0*/ > + =C2=A0aspace =3D maybe_new_address_space (); > + =C2=A0pspace =3D add_program_space (aspace); > + =C2=A0inf =3D add_inferior (0); > + =C2=A0inf->pspace =3D pspace; > + =C2=A0inf->aspace =3D pspace->aspace; > + > + =C2=A0return inf; > +} > =C2=A0 > =C2=A0/* add-inferior [-copies N] [-exec FILENAME] =C2=A0*/ > =C2=A0 > @@ -775,18 +797,7 @@ add_inferior_command (char *args, int from_tty) > =C2=A0 > =C2=A0 =C2=A0for (i =3D 0; i < copies; ++i) > =C2=A0 =C2=A0 =C2=A0{ > - =C2=A0 =C2=A0 =C2=A0struct address_space *aspace; > - =C2=A0 =C2=A0 =C2=A0struct program_space *pspace; > - =C2=A0 =C2=A0 =C2=A0struct inferior *inf; > - > - =C2=A0 =C2=A0 =C2=A0/* If all inferiors share an address space on this = system, this > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 doesn't really return a new a= ddress space; otherwise, it > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 really does. =C2=A0*/ > - =C2=A0 =C2=A0 =C2=A0aspace =3D maybe_new_address_space (); > - =C2=A0 =C2=A0 =C2=A0pspace =3D add_program_space (aspace); > - =C2=A0 =C2=A0 =C2=A0inf =3D add_inferior (0); > - =C2=A0 =C2=A0 =C2=A0inf->pspace =3D pspace; > - =C2=A0 =C2=A0 =C2=A0inf->aspace =3D pspace->aspace; > + =C2=A0 =C2=A0 =C2=A0struct inferior *inf =3D add_inferior_with_spaces (= ); > =C2=A0 > =C2=A0 =C2=A0 =C2=A0 =C2=A0printf_filtered (_("Added inferior %d\n"), inf= ->num); > =C2=A0 > @@ -794,7 +805,7 @@ add_inferior_command (char *args, int from_tty) > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{ > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0/* Switch over tem= porarily, while reading executable and > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0 =C2=A0 symbols.q = =C2=A0*/ > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0set_current_program_spa= ce (pspace); > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0set_current_program_spa= ce (inf->pspace); > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0set_current_inferi= or (inf); > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0switch_to_thread (= null_ptid); > =C2=A0 > diff --git a/gdb/inferior.h b/gdb/inferior.h > index 048fc11..cc5e571 100644 > --- a/gdb/inferior.h > +++ b/gdb/inferior.h > @@ -520,6 +520,8 @@ extern struct inferior *add_inferior_silent (int pid); > =C2=A0/* Delete an existing inferior list entry, due to inferior exit. = =C2=A0*/ > =C2=A0extern void delete_inferior (int pid); > =C2=A0 > +extern void delete_inferior_1 (struct inferior *todel, int silent); > + > =C2=A0/* Same as delete_inferior, but don't print new inferior notificati= ons > =C2=A0 =C2=A0 to the CLI. =C2=A0*/ > =C2=A0extern void delete_inferior_silent (int pid); > @@ -606,4 +608,6 @@ extern void prune_inferiors (void); > =C2=A0 > =C2=A0extern int number_of_inferiors (void); > =C2=A0 > +extern struct inferior *add_inferior_with_spaces (void); > + > =C2=A0#endif /* !defined (INFERIOR_H) */ > diff --git a/gdb/inflow.c b/gdb/inflow.c > index 599fc69..bb4ca18 100644 > --- a/gdb/inflow.c > +++ b/gdb/inflow.c > @@ -504,9 +504,8 @@ get_inflow_inferior_data (struct inferior *inf) > =C2=A0 =C2=A0 list. =C2=A0*/ > =C2=A0 > =C2=A0static void > -inflow_inferior_exit (int pid) > +inflow_inferior_exit (struct inferior *inf) > =C2=A0{ > - =C2=A0struct inferior *inf =3D find_inferior_pid (pid); > =C2=A0 =C2=A0struct terminal_info *info; > =C2=A0 > =C2=A0 =C2=A0info =3D inferior_data (inf, inflow_inferior_data); > diff --git a/gdb/jit.c b/gdb/jit.c > index 433746a..e17f0ab 100644 > --- a/gdb/jit.c > +++ b/gdb/jit.c > @@ -397,7 +397,7 @@ jit_inferior_created_observer (struct target_ops *obj= file, int from_tty) > =C2=A0 =C2=A0 for example when it crashes. =C2=A0*/ > =C2=A0 > =C2=A0static void > -jit_inferior_exit_hook (int pid) > +jit_inferior_exit_hook (struct inferior *inf) > =C2=A0{ > =C2=A0 =C2=A0struct objfile *objf; > =C2=A0 =C2=A0struct objfile *temp; > diff --git a/gdb/mi/mi-cmds.c b/gdb/mi/mi-cmds.c > index 729cc5f..9c4ba1f 100644 > --- a/gdb/mi/mi-cmds.c > +++ b/gdb/mi/mi-cmds.c > @@ -33,6 +33,7 @@ static void build_table (struct mi_cmd *commands); > =C2=A0 > =C2=A0struct mi_cmd mi_cmds[] =3D > =C2=A0{ > + =C2=A0{ "add-inferior", { NULL, 0}, mi_cmd_add_inferior }, ^ EMISSINGSPACE > =C2=A0 =C2=A0{ "break-after", { "ignore", 1 }, NULL }, > =C2=A0 =C2=A0{ "break-condition", { "cond", 1 }, NULL }, > =C2=A0 =C2=A0{ "break-commands", { NULL, 0 }, mi_cmd_break_commands }, > @@ -84,6 +85,7 @@ struct mi_cmd mi_cmds[] =3D > =C2=A0 =C2=A0{ "list-features", { NULL, 0 }, mi_cmd_list_features}, > =C2=A0 =C2=A0{ "list-target-features", { NULL, 0 }, mi_cmd_list_target_fe= atures}, > =C2=A0 =C2=A0{ "list-thread-groups", { NULL, 0 }, mi_cmd_list_thread_grou= ps }, =C2=A0 > + =C2=A0{ "remove-inferior", { NULL, 0 }, mi_cmd_remove_inferior }, > =C2=A0 =C2=A0{ "stack-info-depth", { NULL, 0 }, mi_cmd_stack_info_depth}, > =C2=A0 =C2=A0{ "stack-info-frame", { NULL, 0 }, mi_cmd_stack_info_frame}, > =C2=A0 =C2=A0{ "stack-list-arguments", { NULL, 0 }, mi_cmd_stack_list_arg= s}, > diff --git a/gdb/mi/mi-cmds.h b/gdb/mi/mi-cmds.h > index 7e1c819..d840104 100644 > --- a/gdb/mi/mi-cmds.h > +++ b/gdb/mi/mi-cmds.h > @@ -36,6 +36,7 @@ extern const char mi_all_values[]; > =C2=A0typedef void (mi_cmd_argv_ftype) (char *command, char **argv, int a= rgc); > =C2=A0 > =C2=A0/* Function implementing each command */ > +extern mi_cmd_argv_ftype mi_cmd_add_inferior; > =C2=A0extern mi_cmd_argv_ftype mi_cmd_break_insert; > =C2=A0extern mi_cmd_argv_ftype mi_cmd_break_commands; > =C2=A0extern mi_cmd_argv_ftype mi_cmd_break_watch; > @@ -72,6 +73,7 @@ extern mi_cmd_argv_ftype mi_cmd_interpreter_exec; > =C2=A0extern mi_cmd_argv_ftype mi_cmd_list_features; > =C2=A0extern mi_cmd_argv_ftype mi_cmd_list_target_features; > =C2=A0extern mi_cmd_argv_ftype mi_cmd_list_thread_groups; > +extern mi_cmd_argv_ftype mi_cmd_remove_inferior; > =C2=A0extern mi_cmd_argv_ftype mi_cmd_stack_info_depth; > =C2=A0extern mi_cmd_argv_ftype mi_cmd_stack_info_frame; > =C2=A0extern mi_cmd_argv_ftype mi_cmd_stack_list_args; > diff --git a/gdb/mi/mi-interp.c b/gdb/mi/mi-interp.c > index 41388bb..04c4124 100644 > --- a/gdb/mi/mi-interp.c > +++ b/gdb/mi/mi-interp.c > @@ -56,13 +56,17 @@ static void mi_on_normal_stop (struct bpstats *bs, in= t print_frame); > =C2=A0 > =C2=A0static void mi_new_thread (struct thread_info *t); > =C2=A0static void mi_thread_exit (struct thread_info *t, int silent); > -static void mi_inferior_appeared (int pid); > -static void mi_inferior_exit (int pid); > +static void mi_inferior_added (struct inferior *inf); > +static void mi_inferior_appeared (struct inferior *inf); > +static void mi_inferior_exit (struct inferior *inf); > +static void mi_inferior_removed (struct inferior *inf); > =C2=A0static void mi_on_resume (ptid_t ptid); > =C2=A0static void mi_solib_loaded (struct so_list *solib); > =C2=A0static void mi_solib_unloaded (struct so_list *solib); > =C2=A0static void mi_about_to_proceed (void); > =C2=A0 > +static int report_initial_inferior (struct inferior *inf, void *closure); > + > =C2=A0static void * > =C2=A0mi_interpreter_init (int top_level) > =C2=A0{ > @@ -86,13 +90,20 @@ mi_interpreter_init (int top_level) > =C2=A0 =C2=A0 =C2=A0{ > =C2=A0 =C2=A0 =C2=A0 =C2=A0observer_attach_new_thread (mi_new_thread); > =C2=A0 =C2=A0 =C2=A0 =C2=A0observer_attach_thread_exit (mi_thread_exit); > + =C2=A0 =C2=A0 =C2=A0observer_attach_inferior_added (mi_inferior_added); > =C2=A0 =C2=A0 =C2=A0 =C2=A0observer_attach_inferior_appeared (mi_inferior= _appeared); > =C2=A0 =C2=A0 =C2=A0 =C2=A0observer_attach_inferior_exit (mi_inferior_exi= t); > + =C2=A0 =C2=A0 =C2=A0observer_attach_inferior_removed (mi_inferior_remov= ed); > =C2=A0 =C2=A0 =C2=A0 =C2=A0observer_attach_normal_stop (mi_on_normal_stop= ); > =C2=A0 =C2=A0 =C2=A0 =C2=A0observer_attach_target_resumed (mi_on_resume); > =C2=A0 =C2=A0 =C2=A0 =C2=A0observer_attach_solib_loaded (mi_solib_loaded); > =C2=A0 =C2=A0 =C2=A0 =C2=A0observer_attach_solib_unloaded (mi_solib_unloa= ded); > =C2=A0 =C2=A0 =C2=A0 =C2=A0observer_attach_about_to_proceed (mi_about_to_= proceed); > + > + =C2=A0 =C2=A0 =C2=A0/* The initial inferior is created before this func= tion is called, so we > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 need to report it explicitly.= =C2=A0Use iteration in case future version > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 of GDB creates more than one = inferior up-front. =C2=A0*/ > + =C2=A0 =C2=A0 =C2=A0iterate_over_inferiors (report_initial_inferior, mi= ); > =C2=A0 =C2=A0 =C2=A0} > =C2=A0 > =C2=A0 =C2=A0return mi; > @@ -285,10 +296,13 @@ static void > =C2=A0mi_new_thread (struct thread_info *t) > =C2=A0{ > =C2=A0 =C2=A0struct mi_interp *mi =3D top_level_interpreter_data (); > + =C2=A0struct inferior *inf =3D find_inferior_pid (t->ptid.pid); Use ptid_get_pid. > + > + =C2=A0gdb_assert (inf); > =C2=A0 > =C2=A0 =C2=A0fprintf_unfiltered (mi->event_channel,=20 > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0 =C2=A0 =C2=A0 =C2=A0"thread-created,id=3D\"%d\",group-id= =3D\"%d\"",=20 > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0 =C2=A0 =C2=A0 =C2=A0t->num, t->ptid.pid); > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0 =C2=A0 =C2=A0 =C2=A0"thread-created,id=3D\"%d\",group-id= =3D\"i%d\"",=20 > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0 =C2=A0 =C2=A0 =C2=A0t->num, inf->num); > =C2=A0 =C2=A0gdb_flush (mi->event_channel); > =C2=A0} > =C2=A0 > @@ -296,38 +310,64 @@ static void > =C2=A0mi_thread_exit (struct thread_info *t, int silent) > =C2=A0{ > =C2=A0 =C2=A0struct mi_interp *mi; > + =C2=A0struct inferior *inf; > =C2=A0 > =C2=A0 =C2=A0if (silent) > =C2=A0 =C2=A0 =C2=A0return; > =C2=A0 > + =C2=A0inf =3D find_inferior_pid (t->ptid.pid); Ditto. > + > =C2=A0 =C2=A0mi =3D top_level_interpreter_data (); > =C2=A0 =C2=A0target_terminal_ours (); > =C2=A0 =C2=A0fprintf_unfiltered (mi->event_channel,=20 > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0 =C2=A0 =C2=A0 =C2=A0"thread-exited,id=3D\"%d\",group-id= =3D\"%d\"",=20 > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0 =C2=A0 =C2=A0 =C2=A0t->num,t->ptid.pid); > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0 =C2=A0 =C2=A0 =C2=A0"thread-exited,id=3D\"%d\",group-id= =3D\"i%d\"",=20 > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0 =C2=A0 =C2=A0 =C2=A0t->num, inf->num); > =C2=A0 =C2=A0gdb_flush (mi->event_channel); > =C2=A0} > =C2=A0 > =C2=A0void > -mi_inferior_appeared (int pid) > +mi_inferior_added (struct inferior *inf) > =C2=A0{ > =C2=A0 =C2=A0struct mi_interp *mi =3D top_level_interpreter_data (); > =C2=A0 =C2=A0target_terminal_ours (); > - =C2=A0fprintf_unfiltered (mi->event_channel, "thread-group-created,id= =3D\"%d\"", > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0 =C2=A0 =C2=A0 =C2=A0pid); > + =C2=A0fprintf_unfiltered (mi->event_channel,=20 > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0 =C2=A0 =C2=A0 =C2=A0"thread-group-added,id=3D\"i%d\"", > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0 =C2=A0 =C2=A0 =C2=A0inf->num); > + =C2=A0gdb_flush (mi->event_channel); > +} > + > +void > +mi_inferior_appeared (struct inferior *inf) Nit: could you make these explicitly "static", although there's a declaration above that makes them static already? > +{ > + =C2=A0struct mi_interp *mi =3D top_level_interpreter_data (); > + =C2=A0target_terminal_ours (); > + =C2=A0fprintf_unfiltered (mi->event_channel,=20 > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0 =C2=A0 =C2=A0 =C2=A0"thread-group-started,id=3D\"i%d\",p= id=3D\"%d\"", > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0 =C2=A0 =C2=A0 =C2=A0inf->num, inf->pid); > =C2=A0 =C2=A0gdb_flush (mi->event_channel); > =C2=A0} > =C2=A0 > =C2=A0static void > -mi_inferior_exit (int pid) > +mi_inferior_exit (struct inferior *inf) > =C2=A0{ > =C2=A0 =C2=A0struct mi_interp *mi =3D top_level_interpreter_data (); > =C2=A0 =C2=A0target_terminal_ours (); > - =C2=A0fprintf_unfiltered (mi->event_channel, "thread-group-exited,id=3D= \"%d\"",=20 > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0 =C2=A0 =C2=A0 =C2=A0pid); > + =C2=A0fprintf_unfiltered (mi->event_channel, "thread-group-exited,id=3D= \"i%d\"",=20 > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0 =C2=A0 =C2=A0 =C2=A0inf->num); > =C2=A0 =C2=A0gdb_flush (mi->event_channel); =C2=A0 > =C2=A0} > =C2=A0 > +void > +mi_inferior_removed (struct inferior *inf) > +{ > + =C2=A0struct mi_interp *mi =3D top_level_interpreter_data (); > + =C2=A0target_terminal_ours (); > + =C2=A0fprintf_unfiltered (mi->event_channel,=20 > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0 =C2=A0 =C2=A0 =C2=A0"thread-group-removed,id=3D\"i%d\"", > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0 =C2=A0 =C2=A0 =C2=A0inf->num); > + =C2=A0gdb_flush (mi->event_channel); > +} > + > =C2=A0static void > =C2=A0mi_on_normal_stop (struct bpstats *bs, int print_frame) > =C2=A0{ > @@ -489,10 +529,18 @@ mi_solib_loaded (struct so_list *solib) > =C2=A0{ > =C2=A0 =C2=A0struct mi_interp *mi =3D top_level_interpreter_data (); > =C2=A0 =C2=A0target_terminal_ours (); > - =C2=A0fprintf_unfiltered (mi->event_channel,=20 > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0 =C2=A0 =C2=A0 =C2=A0"library-loaded,id=3D\"%s\",target-n= ame=3D\"%s\",host-name=3D\"%s\",symbols-loaded=3D\"%d\"",=20 > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0 =C2=A0 =C2=A0 =C2=A0solib->so_original_name, solib->so_o= riginal_name,=20 > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0 =C2=A0 =C2=A0 =C2=A0solib->so_name, solib->symbols_loade= d); > + =C2=A0if (gdbarch_has_global_solist (target_gdbarch)) > + =C2=A0 =C2=A0fprintf_unfiltered (mi->event_channel,=20 > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0"library-= loaded,id=3D\"%s\",target-name=3D\"%s\",host-name=3D\"%s\",symbols-loaded= =3D\"%d\"",=20 > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0solib->so= _original_name, solib->so_original_name,=20 > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0solib->so= _name, solib->symbols_loaded); > + =C2=A0else > + =C2=A0 =C2=A0fprintf_unfiltered (mi->event_channel,=20 > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0"library-= loaded,id=3D\"%s\",target-name=3D\"%s\",host-name=3D\"%s\",symbols-loaded= =3D\"%d\",thread-group=3D\"i%d\"",=20 In C, this: =20 "foo" "bar" is a single string "foobar". So you could split these long lines like, e.g= .: "library-loaded,id=3D\"%s\",target-name=3D\"%s\"," "host-name=3D\"%s\",symbols-loaded=3D\"%d\"," "thread-group=3D\"i%d\"",=20=20 > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0solib->so= _original_name, solib->so_original_name,=20 > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0solib->so= _name, solib->symbols_loaded, > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0current_i= nferior ()->num); > + > =C2=A0 =C2=A0gdb_flush (mi->event_channel); > =C2=A0} > =C2=A0 > @@ -501,13 +549,35 @@ mi_solib_unloaded (struct so_list *solib) > =C2=A0{ > =C2=A0 =C2=A0struct mi_interp *mi =3D top_level_interpreter_data (); > =C2=A0 =C2=A0target_terminal_ours (); > - =C2=A0fprintf_unfiltered (mi->event_channel,=20 > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0 =C2=A0 =C2=A0 =C2=A0"library-unloaded,id=3D\"%s\",target= -name=3D\"%s\",host-name=3D\"%s\"",=20 > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0 =C2=A0 =C2=A0 =C2=A0solib->so_original_name, solib->so_o= riginal_name,=20 > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0 =C2=A0 =C2=A0 =C2=A0solib->so_name); > + =C2=A0if (gdbarch_has_global_solist (target_gdbarch)) > + =C2=A0 =C2=A0fprintf_unfiltered (mi->event_channel,=20 > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0"library-= unloaded,id=3D\"%s\",target-name=3D\"%s\",host-name=3D\"%s\"",=20 > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0solib->so= _original_name, solib->so_original_name,=20 > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0solib->so= _name); > + =C2=A0else > + =C2=A0 =C2=A0fprintf_unfiltered (mi->event_channel,=20 > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0"library-= unloaded,id=3D\"%s\",target-name=3D\"%s\",host-name=3D\"%s\",thread-group= =3D\"i%d\"",=20 > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0solib->so= _original_name, solib->so_original_name,=20 > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0solib->so= _name, current_inferior ()->num); > + > =C2=A0 =C2=A0gdb_flush (mi->event_channel); > =C2=A0} > =C2=A0 > +static int > +report_initial_inferior (struct inferior *inf, void *closure) > +{ > + =C2=A0/* This function is called from mi_intepreter_init, and since > + =C2=A0 =C2=A0 mi_inferior_added assumes that inferior is fully initiali= zed > + =C2=A0 =C2=A0 and top_level_interpreter_data is set, we cannot call > + =C2=A0 =C2=A0 it here. =C2=A0*/ > + =C2=A0struct mi_interp *mi =3D closure; > + =C2=A0target_terminal_ours (); > + =C2=A0fprintf_unfiltered (mi->event_channel,=20 > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0 =C2=A0 =C2=A0 =C2=A0"thread-group-added,id=3D\"i%d\"", > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0 =C2=A0 =C2=A0 =C2=A0inf->num); > + =C2=A0gdb_flush (mi->event_channel); > + =C2=A0return 0; > +} > =C2=A0 > =C2=A0extern initialize_file_ftype _initialize_mi_interp; /* -Wmissing-pr= ototypes */ > =C2=A0 > diff --git a/gdb/mi/mi-main.c b/gdb/mi/mi-main.c > index aa1ffaf..0fad5cf 100644 > --- a/gdb/mi/mi-main.c > +++ b/gdb/mi/mi-main.c > @@ -78,6 +78,11 @@ static struct mi_timestamp *current_command_ts; > =C2=A0static int do_timings =3D 0; > =C2=A0 > =C2=A0char *current_token; > +/* Few commands would like to know if options like --thread-group > + =C2=A0 were explicitly specified. =C2=A0This variable keeps the current > + =C2=A0 parsed command including all option, and make it possible. =C2= =A0*/ > +struct mi_parse *current_context; This could be static? A global named `current_context' (a very generic name), is sort of asking for trouble if someone else adds another `current_context' global somewhere else; the linker may consider them the same variable, and it could go unnoticed. Defensively, globals like these should be either prefixed (e.g., mi_foo), or made static and exported through a function. > + > =C2=A0int running_result_record_printed =3D 1; > =C2=A0 > =C2=A0/* Flag indicating that the target has proceeded since the last > @@ -177,54 +182,83 @@ mi_cmd_exec_jump (char *args, char **argv, int argc) > =C2=A0 =C2=A0/* FIXME: Should call a libgdb function, not a cli wrapper. = =C2=A0*/ > =C2=A0 =C2=A0return mi_execute_async_cli_command ("jump", argv, argc); > =C2=A0} > -=20 > -static int > -proceed_thread_callback (struct thread_info *thread, void *arg) > -{ > - =C2=A0int pid =3D *(int *)arg; > =C2=A0 > + > +static void > +proceed_thread_callback (struct thread_info *thread, int pid) Pedantically, this one is no longer a callback. You could rename this one, and name the new function `proceed_thread_callback', instead of `proceed_thread_callback_wrapper'. > +{ > =C2=A0 =C2=A0if (!is_stopped (thread->ptid)) > - =C2=A0 =C2=A0return 0; > + =C2=A0 =C2=A0return; > =C2=A0 > - =C2=A0if (PIDGET (thread->ptid) !=3D pid) > - =C2=A0 =C2=A0return 0; > + =C2=A0if (pid !=3D 0 && PIDGET (thread->ptid) !=3D pid) > + =C2=A0 =C2=A0return; > =C2=A0 > =C2=A0 =C2=A0switch_to_thread (thread->ptid); > =C2=A0 =C2=A0clear_proceed_status (); > =C2=A0 =C2=A0proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 0); > +} > + > + > +static int > +proceed_thread_callback_wrapper (struct thread_info *thread, void *arg) > +{ > + =C2=A0int pid =3D *(int *)arg; > + =C2=A0proceed_thread_callback (thread, pid); > =C2=A0 =C2=A0return 0; > =C2=A0} > =C2=A0 > =C2=A0void > =C2=A0mi_cmd_exec_continue (char *command, char **argv, int argc) > =C2=A0{ > - =C2=A0if (argc =3D=3D 0) > - =C2=A0 =C2=A0continue_1 (0); > - =C2=A0else if (argc =3D=3D 1 && strcmp (argv[0], "--all") =3D=3D 0) > - =C2=A0 =C2=A0continue_1 (1); > - =C2=A0else if (argc =3D=3D 2 && strcmp (argv[0], "--thread-group") =3D= =3D 0) > + =C2=A0if (non_stop) > =C2=A0 =C2=A0 =C2=A0{ > - =C2=A0 =C2=A0 =C2=A0struct cleanup *old_chain; > - =C2=A0 =C2=A0 =C2=A0int pid; > - =C2=A0 =C2=A0 =C2=A0if (argv[1] =3D=3D NULL || argv[1] =3D=3D '\0') > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0error ("Thread group id not sp= ecified"); > - =C2=A0 =C2=A0 =C2=A0pid =3D atoi (argv[1]); > - =C2=A0 =C2=A0 =C2=A0if (!in_inferior_list (pid)) > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0error ("Invalid thread group i= d '%s'", argv[1]); > + =C2=A0 =C2=A0 =C2=A0/* In non-stop mode, 'resume' always resumes a sing= le thread. =C2=A0Therefore, > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 to resume all threads of the = current inferior, or all threads in all > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 inferiors, we need to iterate= over threads. =C2=A0 > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=20 > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 See comment on infcmd.c:proce= ed_thread_callback for rationale. =C2=A0*/ > + =C2=A0 =C2=A0 =C2=A0if (current_context->all || current_context->thread= _group !=3D -1) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{ > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0int pid =3D 0; > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0struct cleanup *back_to= =3D make_cleanup_restore_current_thread (); > =C2=A0 > - =C2=A0 =C2=A0 =C2=A0old_chain =3D make_cleanup_restore_current_thread (= ); > - =C2=A0 =C2=A0 =C2=A0iterate_over_threads (proceed_thread_callback, &pid= ); > - =C2=A0 =C2=A0 =C2=A0do_cleanups (old_chain); =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0if (!current_context->a= ll) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0 =C2=A0{ > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0 =C2=A0 =C2=A0struct in= ferior *inf =3D find_inferior_id (current_context->thread_group); > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0 =C2=A0 =C2=A0pid =3D i= nf->pid; > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0 =C2=A0} > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0iterate_over_threads (p= roceed_thread_callback_wrapper, &pid); > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0do_cleanups (back_to); > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0} > + =C2=A0 =C2=A0 =C2=A0else > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{ > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0continue_1 (0); > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0} > =C2=A0 =C2=A0 =C2=A0} > =C2=A0 =C2=A0else > - =C2=A0 =C2=A0error ("Usage: -exec-continue [--all|--thread-group id]"); > + =C2=A0 =C2=A0{ > + =C2=A0 =C2=A0 =C2=A0struct cleanup *back_to =3D make_cleanup_restore_in= teger (&sched_multi); > + =C2=A0 =C2=A0 =C2=A0if (current_context->all) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{ > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0sched_multi =3D 1; > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0continue_1 (0);=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0} > + =C2=A0 =C2=A0 =C2=A0else=20 > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{ > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0/* In all-stop mode, -e= xec-continue traditionally resumed either > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0 =C2=A0 all threads, or= one thread, depending on the 'scheduler-locking' > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0 =C2=A0 variable. =C2= =A0Let's continue to do the same. =C2=A0*/ > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0continue_1 (1); > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0} > + =C2=A0 =C2=A0 =C2=A0do_cleanups (back_to); > + =C2=A0 =C2=A0} > =C2=A0} > =C2=A0 > =C2=A0static int > =C2=A0interrupt_thread_callback (struct thread_info *thread, void *arg) > =C2=A0{ > =C2=A0 =C2=A0int pid =3D *(int *)arg; > - > + =C2=A0 > =C2=A0 =C2=A0if (!is_running (thread->ptid)) > =C2=A0 =C2=A0 =C2=A0return 0; > =C2=A0 > @@ -243,36 +277,31 @@ interrupt_thread_callback (struct thread_info *thre= ad, void *arg) > =C2=A0void > =C2=A0mi_cmd_exec_interrupt (char *command, char **argv, int argc) > =C2=A0{ > - =C2=A0if (argc =3D=3D 0) > + =C2=A0/* In all-stop mode, everything stops, so we don't need to try > + =C2=A0 =C2=A0 anything specific. =C2=A0*/ > + =C2=A0if (!non_stop) > =C2=A0 =C2=A0 =C2=A0{ > - =C2=A0 =C2=A0 =C2=A0if (!is_running (inferior_ptid)) > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0error ("Current thread is not = running."); > - > =C2=A0 =C2=A0 =C2=A0 =C2=A0interrupt_target_1 (0); > + =C2=A0 =C2=A0 =C2=A0return; > =C2=A0 =C2=A0 =C2=A0} > - =C2=A0else if (argc =3D=3D 1 && strcmp (argv[0], "--all") =3D=3D 0) > + > + =C2=A0if (current_context->all) > =C2=A0 =C2=A0 =C2=A0{ > - =C2=A0 =C2=A0 =C2=A0if (!any_running ()) > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0error ("Inferior not running."= ); > - =C2=A0 =C2=A0 =C2=A0 > + =C2=A0 =C2=A0 =C2=A0/* This will interrupt all threads in all inferiors= . =C2=A0*/ > =C2=A0 =C2=A0 =C2=A0 =C2=A0interrupt_target_1 (1); > =C2=A0 =C2=A0 =C2=A0} > - =C2=A0else if (argc =3D=3D 2 && strcmp (argv[0], "--thread-group") =3D= =3D 0) > + =C2=A0else if (current_context->thread_group !=3D -1) > =C2=A0 =C2=A0 =C2=A0{ > - =C2=A0 =C2=A0 =C2=A0struct cleanup *old_chain; > - =C2=A0 =C2=A0 =C2=A0int pid; > - =C2=A0 =C2=A0 =C2=A0if (argv[1] =3D=3D NULL || argv[1] =3D=3D '\0') > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0error ("Thread group id not sp= ecified"); > - =C2=A0 =C2=A0 =C2=A0pid =3D atoi (argv[1]); > - =C2=A0 =C2=A0 =C2=A0if (!in_inferior_list (pid)) > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0error ("Invalid thread group i= d '%s'", argv[1]); > - > - =C2=A0 =C2=A0 =C2=A0old_chain =3D make_cleanup_restore_current_thread (= ); > - =C2=A0 =C2=A0 =C2=A0iterate_over_threads (interrupt_thread_callback, &p= id); > - =C2=A0 =C2=A0 =C2=A0do_cleanups (old_chain); > + =C2=A0 =C2=A0 =C2=A0struct inferior *inf =3D find_inferior_id (current_= context->thread_group); > + =C2=A0 =C2=A0 =C2=A0iterate_over_threads (interrupt_thread_callback, &(= inf->pid)); Redundant ()'s. > =C2=A0 =C2=A0 =C2=A0} > =C2=A0 =C2=A0else > - =C2=A0 =C2=A0error ("Usage: -exec-interrupt [--all|--thread-group id]"); > + =C2=A0 =C2=A0{ > + =C2=A0 =C2=A0 =C2=A0/* Interrupt just the current thread -- either expl= icitly > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 specified via --thread or wha= tever was current before > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 MI command was sent. =C2=A0*/ > + =C2=A0 =C2=A0 =C2=A0interrupt_target_1 (0); > + =C2=A0 =C2=A0} > =C2=A0} > =C2=A0 > =C2=A0/* Given MI command arguments, recompose then back into a single st= ring > @@ -349,6 +378,34 @@ mi_cmd_exec_until (char *command, char **argv, int a= rgc) > =C2=A0 =C2=A0do_cleanups (back_to); > =C2=A0} > =C2=A0 > +static int run_one_inferior (struct inferior *inf, void *arg) Function name on column 1, please. > +{ > + =C2=A0struct thread_info *tp =3D 0; > + > + =C2=A0if (inf->pid !=3D 0) > + =C2=A0 =C2=A0{ > + =C2=A0 =C2=A0 =C2=A0if (inf->pid !=3D ptid_get_pid (inferior_ptid)) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{ > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0struct thread_info *tp; > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0 > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0tp =3D any_thread_of_pr= ocess (inf->pid); > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0if (!tp) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0 =C2=A0error (_("Inferi= or has no threads.")); > + > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0switch_to_thread (tp->p= tid); > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0} > + =C2=A0 =C2=A0} > + =C2=A0else > + =C2=A0 =C2=A0{ > + =C2=A0 =C2=A0 =C2=A0set_current_inferior (inf); > + =C2=A0 =C2=A0 =C2=A0switch_to_thread (null_ptid); > + =C2=A0 =C2=A0 =C2=A0set_current_program_space (inf->pspace); > + =C2=A0 =C2=A0} > + =C2=A0mi_execute_cli_command ("run", target_can_async_p (),=20 > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0ta= rget_can_async_p () ? "&" : NULL); > + =C2=A0return 0; > +} > + > =C2=A0void > =C2=A0mi_cmd_exec_run (char *command, char **argv, int argc) > =C2=A0{ > @@ -371,14 +428,26 @@ mi_cmd_exec_run (char *command, char **argv, int ar= gc) > =C2=A0 > =C2=A0 =C2=A0if (argc =3D=3D 0) > =C2=A0 =C2=A0 =C2=A0{ > - =C2=A0 =C2=A0 =C2=A0mi_execute_cli_command ("run", target_can_async_p (= ),=20 > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0 = =C2=A0 =C2=A0target_can_async_p () ? "&" : NULL); > + =C2=A0 =C2=A0 =C2=A0if (current_context->all) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{ > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0struct cleanup *back_to= =3D save_current_space_and_thread (); > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0iterate_over_inferiors = (run_one_inferior, NULL); > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0do_cleanups (back_to); > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0} > + =C2=A0 =C2=A0 =C2=A0else > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{ > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0mi_execute_cli_command = ("run", target_can_async_p (),=20 > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0target_can_async_p () ? "&" := NULL); > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0} > =C2=A0 =C2=A0 =C2=A0} > =C2=A0 =C2=A0else > =C2=A0 =C2=A0 =C2=A0{ > =C2=A0 =C2=A0 =C2=A0 =C2=A0struct cleanup *back_to; > =C2=A0 =C2=A0 =C2=A0 =C2=A0char *r =3D recompose_args (argv, argc, target= _can_async_p ()); > =C2=A0 =C2=A0 =C2=A0 =C2=A0back_to =3D make_cleanup (xfree, r); > + > + =C2=A0 =C2=A0 =C2=A0if (current_context->all) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0error (_("Could not use --all = with explicit arguments")); "Could not", or "Can not" ? > =C2=A0 =C2=A0 =C2=A0 =C2=A0 > =C2=A0 =C2=A0 =C2=A0 =C2=A0mi_execute_cli_command ("run", 1, r); > =C2=A0 > @@ -524,13 +593,23 @@ print_one_inferior (struct inferior *inferior, void= *xdata) > =C2=A0 =C2=A0 =C2=A0 =C2=A0struct cleanup *back_to > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=3D make_cleanup_ui_out_t= uple_begin_end (uiout, NULL); > =C2=A0 > - =C2=A0 =C2=A0 =C2=A0ui_out_field_fmt (uiout, "id", "%d", inferior->pid); > + =C2=A0 =C2=A0 =C2=A0ui_out_field_fmt (uiout, "id", "i%d", inferior->num= ); > =C2=A0 =C2=A0 =C2=A0 =C2=A0ui_out_field_string (uiout, "type", "process"); > - =C2=A0 =C2=A0 =C2=A0ui_out_field_int (uiout, "pid", inferior->pid); > + =C2=A0 =C2=A0 =C2=A0if (inferior->pid !=3D 0) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0ui_out_field_int (uiout, "pid"= , inferior->pid); > + > + =C2=A0 =C2=A0 =C2=A0if (inferior->pspace->ebfd) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{ > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0ui_out_field_string (ui= out, "executable",=20 > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0 = =C2=A0 =C2=A0 bfd_get_filename (inferior->pspace->ebfd)); > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0} > =C2=A0 > - =C2=A0 =C2=A0 =C2=A0data.pid =3D inferior->pid; > =C2=A0 =C2=A0 =C2=A0 =C2=A0data.cores =3D 0; > - =C2=A0 =C2=A0 =C2=A0iterate_over_threads (collect_cores, &data); > + =C2=A0 =C2=A0 =C2=A0if (inferior->pid !=3D 0) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{ > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0data.pid =3D inferior->= pid; > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0iterate_over_threads (c= ollect_cores, &data); > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0} > =C2=A0 > =C2=A0 =C2=A0 =C2=A0 =C2=A0if (!VEC_empty (int, data.cores)) > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{ > @@ -1541,6 +1620,40 @@ mi_cmd_list_target_features (char *command, char *= *argv, int argc) > =C2=A0 =C2=A0error ("-list-target-features should be passed no arguments"= ); > =C2=A0} > =C2=A0 > +void=20 > +mi_cmd_add_inferior (char *command, char **argv, int argc) > +{ > + =C2=A0struct inferior *inf; > + > + =C2=A0if (argc !=3D 0) > + =C2=A0 =C2=A0error ("-add-inferior shuld be passed not arguments"); Something's wrong with this sentence. Also, most MI errors you've added have the string wrapped in _() for i18n, while these do not. > + =C2=A0 =C2=A0 > + =C2=A0inf =3D add_inferior_with_spaces (); > + > + =C2=A0ui_out_field_fmt (uiout, "inferior", "i%d", inf->num); =C2=A0 > +} > + > +void > +mi_cmd_remove_inferior (char *command, char **argv, int argc) > +{ > + =C2=A0int id; > + =C2=A0struct inferior *inf; > + > + =C2=A0if (argc !=3D 1) > + =C2=A0 =C2=A0error ("-remove-iferior should be passed a single argument= "); Typo: "inferior" > + > + =C2=A0if (sscanf (argv[1], "i%d", &id) !=3D 1) > + =C2=A0 =C2=A0error ("the thread group id is syntactically invalid"); > + > + =C2=A0inf =3D find_inferior_id (id); > + =C2=A0if (!inf) > + =C2=A0 =C2=A0error ("the specified thread group does not exist"); > + > + =C2=A0delete_inferior_1 (inf, 1 /* silent */); =C2=A0 =C2=A0 > +} > + > +=0C > + > =C2=A0/* Execute a command within a safe environment. > =C2=A0 =C2=A0 Return <0 for error; >=3D0 for ok. > =C2=A0 > @@ -1740,9 +1853,37 @@ mi_cmd_execute (struct mi_parse *parse) > =C2=A0 > =C2=A0 =C2=A0cleanup =3D make_cleanup (null_cleanup, NULL); > =C2=A0 > + =C2=A0if (parse->all && parse->thread_group !=3D -1) > + =C2=A0 =C2=A0error (_("Cannot specify --thread-group together with --al= l")); > + > + =C2=A0if (parse->all && parse->thread !=3D -1) > + =C2=A0 =C2=A0error (_("Cannot specify --thread together with --all")); > + > + =C2=A0if (parse->thread_group !=3D -1 && parse->thread !=3D -1) > + =C2=A0 =C2=A0error (_("Cannot specify --thread together with --thread-g= roup")); > + > =C2=A0 =C2=A0if (parse->frame !=3D -1 && parse->thread =3D=3D -1) > =C2=A0 =C2=A0 =C2=A0error (_("Cannot specify --frame without --thread")); > =C2=A0 > + =C2=A0if (parse->thread_group !=3D -1) > + =C2=A0 =C2=A0{ > + =C2=A0 =C2=A0 =C2=A0struct inferior *inf =3D find_inferior_id (parse->t= hread_group); > + =C2=A0 =C2=A0 =C2=A0struct thread_info *tp =3D 0; > + > + =C2=A0 =C2=A0 =C2=A0if (!inf) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0error (_("Invalid thread group= for the --tread-group option")); > + > + =C2=A0 =C2=A0 =C2=A0set_current_inferior (inf); > + =C2=A0 =C2=A0 =C2=A0/* This behaviour means that if --thread-group opti= on identifies > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 an inferior with multiple thr= eads, then a random one will be picked. > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 This is not a problem -- fron= tend should always provide --thread if > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 it wishes to operate on a spe= cific thread. =C2=A0*/ > + =C2=A0 =C2=A0 =C2=A0if (inf->pid !=3D 0) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0tp =3D any_thread_of_process (= inf->pid); > + =C2=A0 =C2=A0 =C2=A0switch_to_thread (tp ? tp->ptid : null_ptid); > + =C2=A0 =C2=A0 =C2=A0set_current_program_space (inf->pspace); > + =C2=A0 =C2=A0} > + > =C2=A0 =C2=A0if (parse->thread !=3D -1) > =C2=A0 =C2=A0 =C2=A0{ > =C2=A0 =C2=A0 =C2=A0 =C2=A0struct thread_info *tp =3D find_thread_id (par= se->thread); > @@ -1767,6 +1908,8 @@ mi_cmd_execute (struct mi_parse *parse) > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0error (_("Invalid frame i= d: %d"), frame); > =C2=A0 =C2=A0 =C2=A0} > =C2=A0 > + =C2=A0current_context =3D parse; > + Hmm, aren't the `struct mi_parse' objects leaking for every MI command? I can't see where they're released in mi_execute_command ? > =C2=A0 =C2=A0if (parse->cmd->argv_func !=3D NULL) > =C2=A0 =C2=A0 =C2=A0parse->cmd->argv_func (parse->command, parse->argv, p= arse->argc); > =C2=A0 =C2=A0else if (parse->cmd->cli.cmd !=3D 0) > diff --git a/gdb/mi/mi-parse.c b/gdb/mi/mi-parse.c > index 4ff70ef..ec955aa 100644 > --- a/gdb/mi/mi-parse.c > +++ b/gdb/mi/mi-parse.c > @@ -151,6 +151,8 @@ mi_parse (char *cmd) > =C2=A0 =C2=A0char *chp; > =C2=A0 =C2=A0struct mi_parse *parse =3D XMALLOC (struct mi_parse); > =C2=A0 =C2=A0memset (parse, 0, sizeof (*parse)); > + =C2=A0parse->all =3D 0; > + =C2=A0parse->thread_group =3D -1; > =C2=A0 =C2=A0parse->thread =3D -1; > =C2=A0 =C2=A0parse->frame =3D -1; > =C2=A0 > @@ -210,8 +212,31 @@ mi_parse (char *cmd) > =C2=A0 =C2=A0for (;;) > =C2=A0 =C2=A0 =C2=A0{ > =C2=A0 =C2=A0 =C2=A0 =C2=A0char *start =3D chp; > + =C2=A0 =C2=A0 =C2=A0size_t as =3D sizeof ("--all ") - 1; > + =C2=A0 =C2=A0 =C2=A0size_t tgs =3D sizeof ("--thread-group ") - 1; > =C2=A0 =C2=A0 =C2=A0 =C2=A0size_t ts =3D sizeof ("--thread ") - 1; > =C2=A0 =C2=A0 =C2=A0 =C2=A0size_t fs =3D sizeof ("--frame ") - 1; > + =C2=A0 =C2=A0 =C2=A0if (strncmp (chp, "--all ", as) =3D=3D 0) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{ > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0parse->all =3D 1; > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0chp +=3D as; > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0} > + =C2=A0 =C2=A0 =C2=A0/* See if this --all as the last token in the input= . =C2=A0*/ > + =C2=A0 =C2=A0 =C2=A0if (strncmp (chp, "--all", as) =3D=3D 0) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{ > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0parse->all =3D 1; > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0chp +=3D (as - 1); > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0} In the latter strncmp above: + if (strncmp (chp, "--all", as) =3D=3D 0) AS is always larger than strlen("--all"), so the strncmp's check on AS is useless and confusing here. I think you wanted: if (strcmp (chp, "--all") =3D=3D 0) { parse->all =3D 1; chp +=3D strlen (chp); } > + =C2=A0 =C2=A0 =C2=A0if (strncmp (chp, "--thread-group ", tgs) =3D=3D 0) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{ > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0if (parse->thread_group= !=3D -1) > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0 =C2=A0error ("Duplicat= e '--thread-group' option"); > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0chp +=3D tgs; > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0if (*chp !=3D 'i') > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0 =C2=A0error ("Invalid = thread group id"); > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0chp +=3D 1; > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0parse->thread_group =3D= strtol (chp, &chp, 10); > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0} More of the `to i18n or not to i18n' issue. > =C2=A0 =C2=A0 =C2=A0 =C2=A0if (strncmp (chp, "--thread ", ts) =3D=3D 0) > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0{ > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0if (parse->thread = !=3D -1) > diff --git a/gdb/mi/mi-parse.h b/gdb/mi/mi-parse.h > index a63ee8e..3c6cd9a 100644 > --- a/gdb/mi/mi-parse.h > +++ b/gdb/mi/mi-parse.h > @@ -46,6 +46,8 @@ struct mi_parse > =C2=A0 =C2=A0 =C2=A0char *args; > =C2=A0 =C2=A0 =C2=A0char **argv; > =C2=A0 =C2=A0 =C2=A0int argc; > + =C2=A0 =C2=A0int all; > + =C2=A0 =C2=A0int thread_group; /* At present, the same as inferior numb= er. =C2=A0*/ > =C2=A0 =C2=A0 =C2=A0int thread; > =C2=A0 =C2=A0 =C2=A0int frame; > =C2=A0 =C2=A0}; > diff --git a/gdb/testsuite/gdb.mi/mi-nonstop.exp b/gdb/testsuite/gdb.mi/m= i-nonstop.exp > index 605f48b..397dec5 100644 > --- a/gdb/testsuite/gdb.mi/mi-nonstop.exp > +++ b/gdb/testsuite/gdb.mi/mi-nonstop.exp > @@ -151,7 +151,7 @@ if { [is_remote target] } { > =C2=A0 =C2=A0 =C2=A0unsupported $test > =C2=A0} else { > =C2=A0 =C2=A0 =C2=A0gdb_expect { > -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0-re ".*=3Dthread-exited,id=3D\= "2\",group-id=3D\"\[0-9\]+\"\r\n$" { > +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0-re ".*=3Dthread-exited,id=3D\= "2\",group-id=3D\"i\[0-9\]+\"\r\n$" { > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 =C2=A0 =C2=A0pass $test > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0} > =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0timeout { Otherwise, looks good to me. Do you know if current frontends had bad assumptions, and will behave or misbehave with this change? E.g., CDI, DSF-GDB, kdevelop? --=20 Pedro Alves