[3/3] Add -file-list-shared-libraries MI command
Commit Message
This change adds the MI equivalent for the "info sharedlibrary"
command. The command was already partially documented but ignored as
it was not implemented. The new MI command works similarly to the CLI
command, taking an optional regular expression as an argument and
outputting the library information.
I included a test for the new command in mi-solib.exp.
gdb/doc/ChangeLog:
* gdb.texinfo (gdb/mi Symbol Query Commands): Document new MI
command file-list-shared-libraries
gdb/ChangeLog:
* mi/mi-cmd-file.c (mi_cmd_file_list_shared_libraries):
New function definition.
* mi/mi-cmds.c (mi_cmds): Add -file-list-shared-libraries command.
* mi/mi-cmds.h (mi_cmd_file_list_shared_libraries):
New function declaration.
* solib.c (info_sharedlibrary_command): Replace for loop with
ALL_SO_LIBS macro
* solib.h (update_solib_list): New function declaration.
* solist.h (ALL_SO_LIBS): New macro.
gdb/testsuite/ChangeLog:
* gdb.mi/mi-solib.exp (test_file_list_shared_libraries):
New procedure.
Signed-off-by: Marc-Andre Laperle <marc-andre.laperle@ericsson.com>
---
gdb/doc/gdb.texinfo | 15 +++++++--
gdb/mi/mi-cmd-file.c | 67 +++++++++++++++++++++++++++++++++++++++
gdb/mi/mi-cmds.c | 2 ++
gdb/mi/mi-cmds.h | 1 +
gdb/solib.c | 18 ++---------
gdb/solib.h | 18 +++++++++++
gdb/solist.h | 5 +++
gdb/testsuite/gdb.mi/mi-solib.exp | 50 ++++++++++++++++++++---------
8 files changed, 142 insertions(+), 34 deletions(-)
Comments
The patch looks good to me in general. I wrote a few minor comments
inline.
On 2016-09-12 16:27, Marc-Andre Laperle wrote:
> @@ -108,3 +111,67 @@ mi_cmd_file_list_exec_source_files (char
> *command, char **argv, int argc)
>
> ui_out_end (uiout, ui_out_type_list);
> }
> +
> +void
> +mi_cmd_file_list_shared_libraries (char *command, char **argv, int
> argc)
> +{
> + struct ui_out *uiout = current_uiout;
> + const char *pattern;
> + struct so_list *so = NULL;
> + struct gdbarch *gdbarch = target_gdbarch ();
> +
> + switch (argc)
> + {
> + case 0:
> + pattern = NULL;
> + break;
> + case 1:
> + pattern = argv[0];
> + break;
> + default:
> + error (_("Usage: -file-list-shared-libraries [REGEXP]"));
> + break;
> + }
> +
> + if (pattern != NULL)
> + {
> + char *re_err = re_comp (pattern);
const ?
> +
> + if (re_err != NULL)
> + error (_("Invalid regexp: %s"), re_err);
> + }
> +
> + update_solib_list (1);
> +
> + /* Print the table header. */
> + ui_out_begin (uiout, ui_out_type_list, "shared-libraries");
It's not a big deal, but you could use
make_cleanup_ui_out_list_begin_end, which avoids accidentally forgetting
the corresponding ui_out_end.
> +
> + ALL_SO_LIBS (so)
> + {
> + if (so->so_name[0] == '\0')
> + continue;
> + if (pattern != NULL && !re_exec (so->so_name))
> + continue;
> +
> + ui_out_begin (uiout, ui_out_type_tuple, NULL);
Same here, but with make_cleanup_ui_out_tuple_begin_end.
> + if (so->addr_high != 0)
> + {
> + ui_out_field_core_addr (uiout, "from", gdbarch, so->addr_low);
> + ui_out_field_core_addr (uiout, "to", gdbarch, so->addr_high);
> + }
> + else
> + {
> + ui_out_field_skip (uiout, "from");
> + ui_out_field_skip (uiout, "to");
> + }
You might be able to just remove the else. I think ui_out_field_skip is
only relevant for tables (which was used in the code that you took
inspiration from), since you need to explicitly tell if you want to skip
a table cell. For tuples, if you want to omit a field, you just don't
emit it.
> diff --git a/gdb/solib.h b/gdb/solib.h
> index 75490b6..ee621ce 100644
> --- a/gdb/solib.h
> +++ b/gdb/solib.h
> @@ -73,6 +73,24 @@ extern void no_shared_libraries (char *ignored, int
> from_tty);
> extern void set_solib_ops (struct gdbarch *gdbarch,
> const struct target_so_ops *new_ops);
>
> +/* Synchronize GDB's shared object list with inferior's.
> +
> + Extract the list of currently loaded shared objects from the
> + inferior, and compare it with the list of shared objects currently
> + in GDB's so_list_head list. Edit so_list_head to bring it in sync
> + with the inferior's new list.
> +
> + If we notice that the inferior has unloaded some shared objects,
> + free any symbolic info GDB had read about those shared objects.
> +
> + Don't load symbolic info for any new shared objects; just add them
> + to the list, and leave their symbols_loaded flag clear.
> +
> + If FROM_TTY is non-null, feel free to print messages about what
> + we're doing. */
I noticed that this comment, which you moved from the .c to the .h,
refers so_list_head. so_list_head is a define present in the .c, so the
comment makes less sense now. What about bringing the define to the .h,
and at the same time you could use it in the definition of ALL_SO_LIBS?
> + mi_gdb_test "222-file-list-shared-libraries" \
> + "222\\^done,shared-libraries=\\\[.*\{from=\".*\",to=\".*\",syms-read=\"1\",name=\".*${libname}.so\"\}.*]"
> \
> + "Getting a list of shared libraries."
For consistency with all tests, I would suggest changing the test name
to "get the list of shared libraries" (no period at the end,
non-capitalized, neutral verb tense which I don't the name).
> }
>
> -mi_expect_stop solib-event .* .* .* .* .* "check for solib event"
> +test_stop_on_solib_events
> +test_file_list_shared_libraries
> +mi_gdb_exit
I often see some tests ending with gdb_exit or mi_gdb_exit, but I don't
think it's really required. The code in lib/gdb.exp (e.g. gdb_exit)
should take care of that, but I could be mistaken.
Hi Marc-Andre,
Great that you're tackling this. Thanks much for digging into GDB. :-)
I like this. As for following GDB's code standards, it's almost perfect.
But I have questions on the MI output, though. See below.
On 09/12/2016 09:27 PM, Marc-Andre Laperle wrote:
> diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
> index d1a5e7c..c6b2133 100644
> --- a/gdb/doc/gdb.texinfo
> +++ b/gdb/doc/gdb.texinfo
> @@ -31401,26 +31401,35 @@ The @value{GDBN} equivalent is @samp{info sources}.
> (gdb)
> @end smallexample
>
> -@ignore
> @subheading The @code{-file-list-shared-libraries} Command
> @findex -file-list-shared-libraries
>
> @subsubheading Synopsis
>
> @smallexample
> - -file-list-shared-libraries
> + -file-list-shared-libraries [ @var{regexp} ]
> @end smallexample
>
> List the shared libraries in the program.
> +With a regular expression @var{regexp}, only those libraries whose
> +names match @var{regexp} are listed.
>
> @subsubheading @value{GDBN} Command
>
> The corresponding @value{GDBN} command is @samp{info shared}.
>
> @subsubheading Example
> -N.A.
> +@smallexample
> +(gdb)
> +-file-list-exec-source-files
> +^done,shared-libraries=[
> +@{from="0x72815989",to="0x728162c0",syms-read="1",name="/lib/libfoo.so"@},
> +@{from="0x76ee48c0",to="0x76ee9160",syms-read="1",name="/lib/libbar.so"@}]
I don't see where the documentation describes what the
attributes of each list element are. Sorry if I missed it.
I find it surprising that the attributes output don't match
attributes output by =library-loaded ? I'd think they should
match. That'd simplify the documentation too, as one place
would refer to the other for attributes list.
BTW, =library-loaded doesn't output from/to. ISTR that that
was discussed and left out, because from/to assume there's
a contiguous range to report, while that's not true on all
targets (i.e., assumes a single segment). So it seems to
me that that's a separate discussion/patch would better
be addressed in both places.
> +void
> +mi_cmd_file_list_shared_libraries (char *command, char **argv, int argc)
> +{
> + struct ui_out *uiout = current_uiout;
> + const char *pattern;
> + struct so_list *so = NULL;
> + struct gdbarch *gdbarch = target_gdbarch ();
> +
> + switch (argc)
> + {
> + case 0:
> + pattern = NULL;
> + break;
> + case 1:
> + pattern = argv[0];
> + break;
> + default:
> + error (_("Usage: -file-list-shared-libraries [REGEXP]"));
> + break;
error doesn't return. No need for the break.
> + }
> +
> + if (pattern != NULL)
> + {
> + char *re_err = re_comp (pattern);
> +
> + if (re_err != NULL)
> + error (_("Invalid regexp: %s"), re_err);
> + }
> +
> + update_solib_list (1);
> +
> + /* Print the table header. */
> + ui_out_begin (uiout, ui_out_type_list, "shared-libraries");
> +
> + ALL_SO_LIBS (so)
> + {
> + if (so->so_name[0] == '\0')
> + continue;
> + if (pattern != NULL && !re_exec (so->so_name))
> + continue;
> +
> + ui_out_begin (uiout, ui_out_type_tuple, NULL);
> +
> + if (so->addr_high != 0)
> + {
> + ui_out_field_core_addr (uiout, "from", gdbarch, so->addr_low);
> + ui_out_field_core_addr (uiout, "to", gdbarch, so->addr_high);
> + }
> + else
> + {
> + ui_out_field_skip (uiout, "from");
> + ui_out_field_skip (uiout, "to");
> + }
> +
> + ui_out_field_int (uiout, "syms-read", so->symbols_loaded ? 1 : 0);
> +
> + ui_out_field_string (uiout, "name", so->so_name);
So seems to me that the inner body of this loop would be better
calling a function that is shared with =library-loaded.
> +
> --- a/gdb/solist.h
> +++ b/gdb/solist.h
> @@ -23,6 +23,11 @@
> /* For domain_enum domain. */
> #include "symtab.h"
>
> +#define ALL_SO_LIBS(so) \
> + for (so = current_program_space->so_list; \
> + so; \
Write explicit 'so != NULL'.
> + so = so->next)
> +
> /* Forward declaration for target specific link map information. This
> struct is opaque to all but the target specific file. */
> struct lm_info;
> diff --git a/gdb/testsuite/gdb.mi/mi-solib.exp b/gdb/testsuite/gdb.mi/mi-solib.exp
> index 2227987..4c40ba4 100644
> --- a/gdb/testsuite/gdb.mi/mi-solib.exp
> +++ b/gdb/testsuite/gdb.mi/mi-solib.exp
> @@ -48,27 +48,47 @@ if { [gdb_compile_shlib ${srcfile_lib} ${binfile_lib} $lib_flags] != ""
>
> mi_delete_breakpoints
> mi_gdb_reinitialize_dir $srcdir/$subdir
> -mi_gdb_reinitialize_dir $srcdir/$subdir
> mi_gdb_load ${binfile}
>
> mi_load_shlibs $binfile_lib
>
> -mi_gdb_test "777-gdb-set stop-on-solib-events 1" "777\\^done" \
> - "set stop-on-solib-events"
> +proc test_stop_on_solib_events {} {
Looks like a good candidate for the the new proc_with_prefix.
> + mi_gdb_test "777-gdb-set stop-on-solib-events 1" "777\\^done" \
> + "set stop-on-solib-events"
>
> -# We use "run" rather than "-exec-run" here in order to test that CLI
> -# commands still cause the correct MI output to be generated.
> -mi_run_with_cli
> + # We use "run" rather than "-exec-run" here in order to test that CLI
> + # commands still cause the correct MI output to be generated.
> + mi_run_with_cli
>
> -# Also test that the CLI solib event note is output.
> -set test "CLI prints solib event"
> -gdb_expect {
> - -re "~\"Stopped due to shared library event \\(no libraries added or removed\\)\\\\n" {
> - pass "$test"
> - }
> - timeout {
> - fail "$test (timeout)"
> + # Also test that the CLI solib event note is output.
> + set test "CLI prints solib event"
> + gdb_expect {
> + -re "~\"Stopped due to shared library event \\(no libraries added or removed\\)\\\\n" {
> + pass "$test"
> + }
> + timeout {
> + fail "$test (timeout)"
> + }
> }
> +
> + mi_expect_stop solib-event .* .* .* .* .* "check for solib event"
> +
> + # Unset solib events to avoid interfering with other tests.
> + mi_gdb_test "778-gdb-set stop-on-solib-events 0" "778\\^done" \
> + "unset stop-on-solib-events"
> +}
> +
> +proc test_file_list_shared_libraries {} {
> + global libname
> + global binfile
> +
> + mi_continue_to main
> +
> + mi_gdb_test "222-file-list-shared-libraries" \
> + "222\\^done,shared-libraries=\\\[.*\{from=\".*\",to=\".*\",syms-read=\"1\",name=\".*${libname}.so\"\}.*]" \
> + "Getting a list of shared libraries."
Lowercase, no period at end, and use imperative:
"get list of shared libraries"
Thanks,
Pedro Alves
Thanks for the comments! A few questions/suggestions below.
On 2016-11-23 08:06 AM, Pedro Alves wrote:
> Hi Marc-Andre,
>
> Great that you're tackling this. Thanks much for digging into GDB. :-)
> I like this. As for following GDB's code standards, it's almost perfect.
>
> But I have questions on the MI output, though. See below.
>
> On 09/12/2016 09:27 PM, Marc-Andre Laperle wrote:
>
>> diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
>> index d1a5e7c..c6b2133 100644
>> --- a/gdb/doc/gdb.texinfo
>> +++ b/gdb/doc/gdb.texinfo
>> @@ -31401,26 +31401,35 @@ The @value{GDBN} equivalent is @samp{info sources}.
>> (gdb)
>> @end smallexample
>>
>> -@ignore
>> @subheading The @code{-file-list-shared-libraries} Command
>> @findex -file-list-shared-libraries
>>
>> @subsubheading Synopsis
>>
>> @smallexample
>> - -file-list-shared-libraries
>> + -file-list-shared-libraries [ @var{regexp} ]
>> @end smallexample
>>
>> List the shared libraries in the program.
>> +With a regular expression @var{regexp}, only those libraries whose
>> +names match @var{regexp} are listed.
>>
>> @subsubheading @value{GDBN} Command
>>
>> The corresponding @value{GDBN} command is @samp{info shared}.
>>
>> @subsubheading Example
>> -N.A.
>> +@smallexample
>> +(gdb)
>> +-file-list-exec-source-files
>> +^done,shared-libraries=[
>> +@{from="0x72815989",to="0x728162c0",syms-read="1",name="/lib/libfoo.so"@},
>> +@{from="0x76ee48c0",to="0x76ee9160",syms-read="1",name="/lib/libbar.so"@}]
> I don't see where the documentation describes what the
> attributes of each list element are. Sorry if I missed it.
>
> I find it surprising that the attributes output don't match
> attributes output by =library-loaded ? I'd think they should
> match. That'd simplify the documentation too, as one place
> would refer to the other for attributes list.
>
> BTW, =library-loaded doesn't output from/to. ISTR that that
> was discussed and left out, because from/to assume there's
> a contiguous range to report, while that's not true on all
> targets (i.e., assumes a single segment). So it seems to
> me that that's a separate discussion/patch would better
> be addressed in both places.
Those attributes are from the "info shared" command which is what this
new MI command is inspired from. The from/to are shown in Eclipse and I
personally use it to know in which library a given stack frame is, in
absence of debug symbols. I could change the attributes to be just like
"=library-loaded" but it would be inconsistent with "info shared" and
will remove information that was available before. Perhaps the best way
forward would be to make all attributes the same as "=library-loaded"
but also add the from/to.
To make the MI more future proof, it could be a list of from/to segments
instead, but for now it will only one segment. What do you think?
>> +void
>> +mi_cmd_file_list_shared_libraries (char *command, char **argv, int argc)
>> +{
>> + struct ui_out *uiout = current_uiout;
>> + const char *pattern;
>> + struct so_list *so = NULL;
>> + struct gdbarch *gdbarch = target_gdbarch ();
>> +
>> + switch (argc)
>> + {
>> + case 0:
>> + pattern = NULL;
>> + break;
>> + case 1:
>> + pattern = argv[0];
>> + break;
>> + default:
>> + error (_("Usage: -file-list-shared-libraries [REGEXP]"));
>> + break;
> error doesn't return. No need for the break.
>
>> + }
>> +
>> + if (pattern != NULL)
>> + {
>> + char *re_err = re_comp (pattern);
>> +
>> + if (re_err != NULL)
>> + error (_("Invalid regexp: %s"), re_err);
>> + }
>> +
>> + update_solib_list (1);
>> +
>> + /* Print the table header. */
>> + ui_out_begin (uiout, ui_out_type_list, "shared-libraries");
>> +
>> + ALL_SO_LIBS (so)
>> + {
>> + if (so->so_name[0] == '\0')
>> + continue;
>> + if (pattern != NULL && !re_exec (so->so_name))
>> + continue;
>> +
>> + ui_out_begin (uiout, ui_out_type_tuple, NULL);
>> +
>> + if (so->addr_high != 0)
>> + {
>> + ui_out_field_core_addr (uiout, "from", gdbarch, so->addr_low);
>> + ui_out_field_core_addr (uiout, "to", gdbarch, so->addr_high);
>> + }
>> + else
>> + {
>> + ui_out_field_skip (uiout, "from");
>> + ui_out_field_skip (uiout, "to");
>> + }
>> +
>> + ui_out_field_int (uiout, "syms-read", so->symbols_loaded ? 1 : 0);
>> +
>> + ui_out_field_string (uiout, "name", so->so_name);
> So seems to me that the inner body of this loop would be better
> calling a function that is shared with =library-loaded.
>
>> +
>> --- a/gdb/solist.h
>> +++ b/gdb/solist.h
>> @@ -23,6 +23,11 @@
>> /* For domain_enum domain. */
>> #include "symtab.h"
>>
>> +#define ALL_SO_LIBS(so) \
>> + for (so = current_program_space->so_list; \
>> + so; \
> Write explicit 'so != NULL'.
>
>> + so = so->next)
>> +
>> /* Forward declaration for target specific link map information. This
>> struct is opaque to all but the target specific file. */
>> struct lm_info;
>> diff --git a/gdb/testsuite/gdb.mi/mi-solib.exp b/gdb/testsuite/gdb.mi/mi-solib.exp
>> index 2227987..4c40ba4 100644
>> --- a/gdb/testsuite/gdb.mi/mi-solib.exp
>> +++ b/gdb/testsuite/gdb.mi/mi-solib.exp
>> @@ -48,27 +48,47 @@ if { [gdb_compile_shlib ${srcfile_lib} ${binfile_lib} $lib_flags] != ""
>>
>> mi_delete_breakpoints
>> mi_gdb_reinitialize_dir $srcdir/$subdir
>> -mi_gdb_reinitialize_dir $srcdir/$subdir
>> mi_gdb_load ${binfile}
>>
>> mi_load_shlibs $binfile_lib
>>
>> -mi_gdb_test "777-gdb-set stop-on-solib-events 1" "777\\^done" \
>> - "set stop-on-solib-events"
>> +proc test_stop_on_solib_events {} {
> Looks like a good candidate for the the new proc_with_prefix.
>
>> + mi_gdb_test "777-gdb-set stop-on-solib-events 1" "777\\^done" \
>> + "set stop-on-solib-events"
>>
>> -# We use "run" rather than "-exec-run" here in order to test that CLI
>> -# commands still cause the correct MI output to be generated.
>> -mi_run_with_cli
>> + # We use "run" rather than "-exec-run" here in order to test that CLI
>> + # commands still cause the correct MI output to be generated.
>> + mi_run_with_cli
>>
>> -# Also test that the CLI solib event note is output.
>> -set test "CLI prints solib event"
>> -gdb_expect {
>> - -re "~\"Stopped due to shared library event \\(no libraries added or removed\\)\\\\n" {
>> - pass "$test"
>> - }
>> - timeout {
>> - fail "$test (timeout)"
>> + # Also test that the CLI solib event note is output.
>> + set test "CLI prints solib event"
>> + gdb_expect {
>> + -re "~\"Stopped due to shared library event \\(no libraries added or removed\\)\\\\n" {
>> + pass "$test"
>> + }
>> + timeout {
>> + fail "$test (timeout)"
>> + }
>> }
>> +
>> + mi_expect_stop solib-event .* .* .* .* .* "check for solib event"
>> +
>> + # Unset solib events to avoid interfering with other tests.
>> + mi_gdb_test "778-gdb-set stop-on-solib-events 0" "778\\^done" \
>> + "unset stop-on-solib-events"
>> +}
>> +
>> +proc test_file_list_shared_libraries {} {
>> + global libname
>> + global binfile
>> +
>> + mi_continue_to main
>> +
>> + mi_gdb_test "222-file-list-shared-libraries" \
>> + "222\\^done,shared-libraries=\\\[.*\{from=\".*\",to=\".*\",syms-read=\"1\",name=\".*${libname}.so\"\}.*]" \
>> + "Getting a list of shared libraries."
> Lowercase, no period at end, and use imperative:
>
> "get list of shared libraries"
>
> Thanks,
> Pedro Alves
>
On 01/04/2017 05:18 PM, Marc-André Laperle wrote:
> Perhaps the best way
> forward would be to make all attributes the same as "=library-loaded"
> but also add the from/to.
I think so too.
> To make the MI more future proof, it could be a list of from/to segments
> instead, but for now it will only one segment. What do you think?
That's a good idea. I like it.
Thanks,
Pedro Alves
@@ -31401,26 +31401,35 @@ The @value{GDBN} equivalent is @samp{info sources}.
(gdb)
@end smallexample
-@ignore
@subheading The @code{-file-list-shared-libraries} Command
@findex -file-list-shared-libraries
@subsubheading Synopsis
@smallexample
- -file-list-shared-libraries
+ -file-list-shared-libraries [ @var{regexp} ]
@end smallexample
List the shared libraries in the program.
+With a regular expression @var{regexp}, only those libraries whose
+names match @var{regexp} are listed.
@subsubheading @value{GDBN} Command
The corresponding @value{GDBN} command is @samp{info shared}.
@subsubheading Example
-N.A.
+@smallexample
+(gdb)
+-file-list-exec-source-files
+^done,shared-libraries=[
+@{from="0x72815989",to="0x728162c0",syms-read="1",name="/lib/libfoo.so"@},
+@{from="0x76ee48c0",to="0x76ee9160",syms-read="1",name="/lib/libbar.so"@}]
+(gdb)
+@end smallexample
+@ignore
@subheading The @code{-file-list-symbol-files} Command
@findex -file-list-symbol-files
@@ -25,6 +25,9 @@
#include "source.h"
#include "objfiles.h"
#include "psymtab.h"
+#include "solib.h"
+#include "solist.h"
+#include "xregex.h"
/* Return to the client the absolute path and line number of the
current file being executed. */
@@ -108,3 +111,67 @@ mi_cmd_file_list_exec_source_files (char *command, char **argv, int argc)
ui_out_end (uiout, ui_out_type_list);
}
+
+void
+mi_cmd_file_list_shared_libraries (char *command, char **argv, int argc)
+{
+ struct ui_out *uiout = current_uiout;
+ const char *pattern;
+ struct so_list *so = NULL;
+ struct gdbarch *gdbarch = target_gdbarch ();
+
+ switch (argc)
+ {
+ case 0:
+ pattern = NULL;
+ break;
+ case 1:
+ pattern = argv[0];
+ break;
+ default:
+ error (_("Usage: -file-list-shared-libraries [REGEXP]"));
+ break;
+ }
+
+ if (pattern != NULL)
+ {
+ char *re_err = re_comp (pattern);
+
+ if (re_err != NULL)
+ error (_("Invalid regexp: %s"), re_err);
+ }
+
+ update_solib_list (1);
+
+ /* Print the table header. */
+ ui_out_begin (uiout, ui_out_type_list, "shared-libraries");
+
+ ALL_SO_LIBS (so)
+ {
+ if (so->so_name[0] == '\0')
+ continue;
+ if (pattern != NULL && !re_exec (so->so_name))
+ continue;
+
+ ui_out_begin (uiout, ui_out_type_tuple, NULL);
+
+ if (so->addr_high != 0)
+ {
+ ui_out_field_core_addr (uiout, "from", gdbarch, so->addr_low);
+ ui_out_field_core_addr (uiout, "to", gdbarch, so->addr_high);
+ }
+ else
+ {
+ ui_out_field_skip (uiout, "from");
+ ui_out_field_skip (uiout, "to");
+ }
+
+ ui_out_field_int (uiout, "syms-read", so->symbols_loaded ? 1 : 0);
+
+ ui_out_field_string (uiout, "name", so->so_name);
+
+ ui_out_end (uiout, ui_out_type_tuple);
+ }
+
+ ui_out_end (uiout, ui_out_type_list);
+}
@@ -115,6 +115,8 @@ static struct mi_cmd mi_cmds[] =
mi_cmd_file_list_exec_source_file),
DEF_MI_CMD_MI ("file-list-exec-source-files",
mi_cmd_file_list_exec_source_files),
+ DEF_MI_CMD_MI ("file-list-shared-libraries",
+ mi_cmd_file_list_shared_libraries),
DEF_MI_CMD_CLI ("file-symbol-file", "symbol-file", 1),
DEF_MI_CMD_MI ("gdb-exit", mi_cmd_gdb_exit),
DEF_MI_CMD_CLI_1 ("gdb-set", "set", 1,
@@ -70,6 +70,7 @@ extern mi_cmd_argv_ftype mi_cmd_exec_step;
extern mi_cmd_argv_ftype mi_cmd_exec_step_instruction;
extern mi_cmd_argv_ftype mi_cmd_file_list_exec_source_file;
extern mi_cmd_argv_ftype mi_cmd_file_list_exec_source_files;
+extern mi_cmd_argv_ftype mi_cmd_file_list_shared_libraries;
extern mi_cmd_argv_ftype mi_cmd_gdb_exit;
extern mi_cmd_argv_ftype mi_cmd_inferior_tty_set;
extern mi_cmd_argv_ftype mi_cmd_inferior_tty_show;
@@ -737,21 +737,7 @@ solib_used (const struct so_list *const known)
return 0;
}
-/* Synchronize GDB's shared object list with inferior's.
-
- Extract the list of currently loaded shared objects from the
- inferior, and compare it with the list of shared objects currently
- in GDB's so_list_head list. Edit so_list_head to bring it in sync
- with the inferior's new list.
-
- If we notice that the inferior has unloaded some shared objects,
- free any symbolic info GDB had read about those shared objects.
-
- Don't load symbolic info for any new shared objects; just add them
- to the list, and leave their symbols_loaded flag clear.
-
- If FROM_TTY is non-null, feel free to print messages about what
- we're doing. */
+/* See solib.h. */
void
update_solib_list (int from_tty)
@@ -1096,7 +1082,7 @@ info_sharedlibrary_command (char *pattern, int from_tty)
ui_out_table_body (uiout);
- for (so = so_list_head; so; so = so->next)
+ ALL_SO_LIBS (so)
{
struct cleanup *lib_cleanup;
@@ -73,6 +73,24 @@ extern void no_shared_libraries (char *ignored, int from_tty);
extern void set_solib_ops (struct gdbarch *gdbarch,
const struct target_so_ops *new_ops);
+/* Synchronize GDB's shared object list with inferior's.
+
+ Extract the list of currently loaded shared objects from the
+ inferior, and compare it with the list of shared objects currently
+ in GDB's so_list_head list. Edit so_list_head to bring it in sync
+ with the inferior's new list.
+
+ If we notice that the inferior has unloaded some shared objects,
+ free any symbolic info GDB had read about those shared objects.
+
+ Don't load symbolic info for any new shared objects; just add them
+ to the list, and leave their symbols_loaded flag clear.
+
+ If FROM_TTY is non-null, feel free to print messages about what
+ we're doing. */
+
+extern void update_solib_list (int from_tty);
+
/* Return non-zero if NAME is the libpthread shared library. */
extern int libpthread_name_p (const char *name);
@@ -23,6 +23,11 @@
/* For domain_enum domain. */
#include "symtab.h"
+#define ALL_SO_LIBS(so) \
+ for (so = current_program_space->so_list; \
+ so; \
+ so = so->next)
+
/* Forward declaration for target specific link map information. This
struct is opaque to all but the target specific file. */
struct lm_info;
@@ -48,27 +48,47 @@ if { [gdb_compile_shlib ${srcfile_lib} ${binfile_lib} $lib_flags] != ""
mi_delete_breakpoints
mi_gdb_reinitialize_dir $srcdir/$subdir
-mi_gdb_reinitialize_dir $srcdir/$subdir
mi_gdb_load ${binfile}
mi_load_shlibs $binfile_lib
-mi_gdb_test "777-gdb-set stop-on-solib-events 1" "777\\^done" \
- "set stop-on-solib-events"
+proc test_stop_on_solib_events {} {
+ mi_gdb_test "777-gdb-set stop-on-solib-events 1" "777\\^done" \
+ "set stop-on-solib-events"
-# We use "run" rather than "-exec-run" here in order to test that CLI
-# commands still cause the correct MI output to be generated.
-mi_run_with_cli
+ # We use "run" rather than "-exec-run" here in order to test that CLI
+ # commands still cause the correct MI output to be generated.
+ mi_run_with_cli
-# Also test that the CLI solib event note is output.
-set test "CLI prints solib event"
-gdb_expect {
- -re "~\"Stopped due to shared library event \\(no libraries added or removed\\)\\\\n" {
- pass "$test"
- }
- timeout {
- fail "$test (timeout)"
+ # Also test that the CLI solib event note is output.
+ set test "CLI prints solib event"
+ gdb_expect {
+ -re "~\"Stopped due to shared library event \\(no libraries added or removed\\)\\\\n" {
+ pass "$test"
+ }
+ timeout {
+ fail "$test (timeout)"
+ }
}
+
+ mi_expect_stop solib-event .* .* .* .* .* "check for solib event"
+
+ # Unset solib events to avoid interfering with other tests.
+ mi_gdb_test "778-gdb-set stop-on-solib-events 0" "778\\^done" \
+ "unset stop-on-solib-events"
+}
+
+proc test_file_list_shared_libraries {} {
+ global libname
+ global binfile
+
+ mi_continue_to main
+
+ mi_gdb_test "222-file-list-shared-libraries" \
+ "222\\^done,shared-libraries=\\\[.*\{from=\".*\",to=\".*\",syms-read=\"1\",name=\".*${libname}.so\"\}.*]" \
+ "Getting a list of shared libraries."
}
-mi_expect_stop solib-event .* .* .* .* .* "check for solib event"
+test_stop_on_solib_events
+test_file_list_shared_libraries
+mi_gdb_exit