* [RFA 1/7] Probes API convenience patch
2013-05-16 14:43 [RFA 0/7] Improved linker-debugger interface Gary Benson
@ 2013-05-16 14:47 ` Gary Benson
2013-05-16 14:48 ` [RFA 3/7] New gdbserver functionality Gary Benson
` (9 subsequent siblings)
10 siblings, 0 replies; 59+ messages in thread
From: Gary Benson @ 2013-05-16 14:47 UTC (permalink / raw)
To: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 203 bytes --]
This patch exposes part of the probes API in a more convenient
way. I've included it for completeness, but it has previously
been approved:
http://www.cygwin.com/ml/gdb-patches/2012-07/msg00340.html
[-- Attachment #2: rtld-probes-1-convenience.patch --]
[-- Type: text/plain, Size: 2849 bytes --]
2013-05-16 Gary Benson <gbenson@redhat.com>
* probe.h (get_probe_argument_count): New declaration.
(evaluate_probe_argument): Likewise.
* probe.c (get_probe_argument_count): New function.
(evaluate_probe_argument): Likewise.
(probe_safe_evaluate_at_pc): Use the above new functions.
diff --git a/gdb/probe.h b/gdb/probe.h
index 8d44ca2..1d29b87 100644
--- a/gdb/probe.h
+++ b/gdb/probe.h
@@ -214,6 +214,16 @@ extern void info_probes_for_ops (char *arg, int from_tty,
extern struct cmd_list_element **info_probes_cmdlist_get (void);
+/* Return the argument count of the specified probe. */
+
+extern unsigned get_probe_argument_count (struct probe *probe);
+
+/* Evaluate argument N of the specified probe. N must be between 0
+ inclusive and get_probe_argument_count exclusive. */
+
+extern struct value *evaluate_probe_argument (struct probe *probe,
+ unsigned n);
+
/* A convenience function that finds a probe at the PC in FRAME and
evaluates argument N, with 0 <= N < number_of_args. If there is no
probe at that location, or if the probe does not have enough arguments,
diff --git a/gdb/probe.c b/gdb/probe.c
index 77f3b13..a61f4ea 100644
--- a/gdb/probe.c
+++ b/gdb/probe.c
@@ -608,28 +608,55 @@ info_probes_command (char *arg, int from_tty)
/* See comments in probe.h. */
+unsigned
+get_probe_argument_count (struct probe *probe)
+{
+ const struct sym_probe_fns *probe_fns;
+
+ gdb_assert (probe->objfile != NULL);
+ gdb_assert (probe->objfile->sf != NULL);
+
+ probe_fns = probe->objfile->sf->sym_probe_fns;
+
+ gdb_assert (probe_fns != NULL);
+
+ return probe_fns->sym_get_probe_argument_count (probe);
+}
+
+/* See comments in probe.h. */
+
+struct value *
+evaluate_probe_argument (struct probe *probe, unsigned n)
+{
+ const struct sym_probe_fns *probe_fns;
+
+ gdb_assert (probe->objfile != NULL);
+ gdb_assert (probe->objfile->sf != NULL);
+
+ probe_fns = probe->objfile->sf->sym_probe_fns;
+
+ gdb_assert (probe_fns != NULL);
+
+ return probe_fns->sym_evaluate_probe_argument (probe, n);
+}
+
+/* See comments in probe.h. */
+
struct value *
probe_safe_evaluate_at_pc (struct frame_info *frame, unsigned n)
{
struct probe *probe;
- const struct sym_probe_fns *probe_fns;
unsigned n_args;
probe = find_probe_by_pc (get_frame_pc (frame));
if (!probe)
return NULL;
- gdb_assert (probe->objfile != NULL);
- gdb_assert (probe->objfile->sf != NULL);
- gdb_assert (probe->objfile->sf->sym_probe_fns != NULL);
-
- probe_fns = probe->objfile->sf->sym_probe_fns;
- n_args = probe_fns->sym_get_probe_argument_count (probe);
-
+ n_args = get_probe_argument_count (probe);
if (n >= n_args)
return NULL;
- return probe_fns->sym_evaluate_probe_argument (probe, n);
+ return evaluate_probe_argument (probe, n);
}
/* See comment in probe.h. */
^ permalink raw reply [flat|nested] 59+ messages in thread* [RFA 3/7] New gdbserver functionality
2013-05-16 14:43 [RFA 0/7] Improved linker-debugger interface Gary Benson
2013-05-16 14:47 ` [RFA 1/7] Probes API convenience patch Gary Benson
@ 2013-05-16 14:48 ` Gary Benson
2013-05-16 18:18 ` Tom Tromey
2013-05-16 14:48 ` [RFA 2/7] API for inhibiting section map updates Gary Benson
` (8 subsequent siblings)
10 siblings, 1 reply; 59+ messages in thread
From: Gary Benson @ 2013-05-16 14:48 UTC (permalink / raw)
To: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 302 bytes --]
This patch updates gdbserver to allow arguments to be passed in the
annex of qXfer:libraries-svr4:read to allow that function to transfer
partial lists of libraries. The ability of gdbserver to support
these arguments is indicated by a qSupported response containing
"augmented-libraries-svr4-read+".
[-- Attachment #2: rtld-probes-3-gdbserver.patch --]
[-- Type: text/plain, Size: 9151 bytes --]
2013-05-16 Gary Benson <gbenson@redhat.com>
* server.c (handle_query): Add "augmented-libraries-svr4-read+"
to qSupported response when appropriate.
(handle_qxfer_libraries_svr4): Allow qXfer:libraries-svr4:read
with nonzero-length annex.
* linux-low.c (linux_qxfer_libraries_svr4): Parse and handle
arguments supplied in annex.
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index 6bb36d8..0a8f68b 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -1115,8 +1115,7 @@ handle_qxfer_libraries_svr4 (const char *annex,
if (writebuf != NULL)
return -2;
- if (annex[0] != '\0' || !target_running ()
- || the_target->qxfer_libraries_svr4 == NULL)
+ if (!target_running () || the_target->qxfer_libraries_svr4 == NULL)
return -1;
return the_target->qxfer_libraries_svr4 (annex, readbuf, writebuf, offset, len);
@@ -1743,7 +1742,8 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
PBUFSIZ - 1);
if (the_target->qxfer_libraries_svr4 != NULL)
- strcat (own_buf, ";qXfer:libraries-svr4:read+");
+ strcat (own_buf, ";qXfer:libraries-svr4:read+"
+ ";augmented-libraries-svr4-read+");
else
{
/* We do not have any hook to indicate whether the non-SVR4 target
diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index 72c51e0..beb3b8f 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -5677,6 +5677,12 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf,
};
const struct link_map_offsets *lmo;
unsigned int machine;
+ int ptr_size;
+ CORE_ADDR lm_addr = 0, lm_prev = 0;
+ int allocated = 1024;
+ char *p;
+ CORE_ADDR l_name, l_addr, l_ld, l_next, l_prev;
+ int header_done = 0;
if (writebuf != NULL)
return -2;
@@ -5687,128 +5693,146 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf,
xsnprintf (filename, sizeof filename, "/proc/%d/exe", pid);
is_elf64 = elf_64_file_p (filename, &machine);
lmo = is_elf64 ? &lmo_64bit_offsets : &lmo_32bit_offsets;
+ ptr_size = is_elf64 ? 8 : 4;
- if (priv->r_debug == 0)
- priv->r_debug = get_r_debug (pid, is_elf64);
+ if (annex[0] == '\0')
+ {
+ int r_version = 0;
- /* We failed to find DT_DEBUG. Such situation will not change for this
- inferior - do not retry it. Report it to GDB as E01, see for the reasons
- at the GDB solib-svr4.c side. */
- if (priv->r_debug == (CORE_ADDR) -1)
- return -1;
+ if (priv->r_debug == 0)
+ priv->r_debug = get_r_debug (pid, is_elf64);
- if (priv->r_debug == 0)
- {
- document = xstrdup ("<library-list-svr4 version=\"1.0\"/>\n");
+ /* We failed to find DT_DEBUG. Such situation will not change
+ for this inferior - do not retry it. Report it to GDB as
+ E01, see for the reasons at the GDB solib-svr4.c side. */
+ if (priv->r_debug == (CORE_ADDR) -1)
+ return -1;
+
+ if (priv->r_debug != 0)
+ {
+ if (linux_read_memory (priv->r_debug + lmo->r_version_offset,
+ (unsigned char *) &r_version,
+ sizeof (r_version)) != 0
+ || r_version != 1)
+ {
+ warning ("unexpected r_debug version %d", r_version);
+ }
+ else if (read_one_ptr (priv->r_debug + lmo->r_map_offset,
+ &lm_addr, ptr_size) != 0)
+ {
+ warning ("unable to read r_map from 0x%lx",
+ (long) priv->r_debug + lmo->r_map_offset);
+ }
+ }
}
else
{
- int allocated = 1024;
- char *p;
- const int ptr_size = is_elf64 ? 8 : 4;
- CORE_ADDR lm_addr, lm_prev, l_name, l_addr, l_ld, l_next, l_prev;
- int r_version, header_done = 0;
-
- document = xmalloc (allocated);
- strcpy (document, "<library-list-svr4 version=\"1.0\"");
- p = document + strlen (document);
-
- r_version = 0;
- if (linux_read_memory (priv->r_debug + lmo->r_version_offset,
- (unsigned char *) &r_version,
- sizeof (r_version)) != 0
- || r_version != 1)
+ while (annex[0] != '\0')
{
- warning ("unexpected r_debug version %d", r_version);
- goto done;
+ const char *sep;
+ CORE_ADDR *addrp;
+ int len;
+
+ sep = strchr (annex, '=');
+ if (!sep)
+ break;
+
+ len = sep - annex;
+ if (len == 5 && !strncmp (annex, "start", 5))
+ addrp = &lm_addr;
+ else if (len == 4 && !strncmp (annex, "prev", 4))
+ addrp = &lm_prev;
+ else
+ {
+ annex = strchr (sep, ';');
+ if (!annex)
+ break;
+ annex++;
+ continue;
+ }
+
+ annex = decode_address_to_semicolon (addrp, sep + 1);
}
+ }
- if (read_one_ptr (priv->r_debug + lmo->r_map_offset,
- &lm_addr, ptr_size) != 0)
+ document = xmalloc (allocated);
+ strcpy (document, "<library-list-svr4 version=\"1.0\"");
+ p = document + strlen (document);
+
+ while (lm_addr
+ && read_one_ptr (lm_addr + lmo->l_name_offset,
+ &l_name, ptr_size) == 0
+ && read_one_ptr (lm_addr + lmo->l_addr_offset,
+ &l_addr, ptr_size) == 0
+ && read_one_ptr (lm_addr + lmo->l_ld_offset,
+ &l_ld, ptr_size) == 0
+ && read_one_ptr (lm_addr + lmo->l_prev_offset,
+ &l_prev, ptr_size) == 0
+ && read_one_ptr (lm_addr + lmo->l_next_offset,
+ &l_next, ptr_size) == 0)
+ {
+ unsigned char libname[PATH_MAX];
+
+ if (lm_prev != l_prev)
{
- warning ("unable to read r_map from 0x%lx",
- (long) priv->r_debug + lmo->r_map_offset);
- goto done;
+ warning ("Corrupted shared library list: 0x%lx != 0x%lx",
+ (long) lm_prev, (long) l_prev);
+ break;
}
- lm_prev = 0;
- while (read_one_ptr (lm_addr + lmo->l_name_offset,
- &l_name, ptr_size) == 0
- && read_one_ptr (lm_addr + lmo->l_addr_offset,
- &l_addr, ptr_size) == 0
- && read_one_ptr (lm_addr + lmo->l_ld_offset,
- &l_ld, ptr_size) == 0
- && read_one_ptr (lm_addr + lmo->l_prev_offset,
- &l_prev, ptr_size) == 0
- && read_one_ptr (lm_addr + lmo->l_next_offset,
- &l_next, ptr_size) == 0)
+ /* Not checking for error because reading may stop before
+ we've got PATH_MAX worth of characters. */
+ libname[0] = '\0';
+ linux_read_memory (l_name, libname, sizeof (libname) - 1);
+ libname[sizeof (libname) - 1] = '\0';
+ if (libname[0] != '\0')
{
- unsigned char libname[PATH_MAX];
+ /* 6x the size for xml_escape_text below. */
+ size_t len = 6 * strlen ((char *) libname);
+ char *name;
- if (lm_prev != l_prev)
+ if (!header_done)
{
- warning ("Corrupted shared library list: 0x%lx != 0x%lx",
- (long) lm_prev, (long) l_prev);
- break;
+ /* Terminate `<library-list-svr4'. */
+ *p++ = '>';
+ header_done = 1;
}
- /* Not checking for error because reading may stop before
- we've got PATH_MAX worth of characters. */
- libname[0] = '\0';
- linux_read_memory (l_name, libname, sizeof (libname) - 1);
- libname[sizeof (libname) - 1] = '\0';
- if (libname[0] != '\0')
+ while (allocated < p - document + len + 200)
{
- /* 6x the size for xml_escape_text below. */
- size_t len = 6 * strlen ((char *) libname);
- char *name;
-
- if (!header_done)
- {
- /* Terminate `<library-list-svr4'. */
- *p++ = '>';
- header_done = 1;
- }
-
- while (allocated < p - document + len + 200)
- {
- /* Expand to guarantee sufficient storage. */
- uintptr_t document_len = p - document;
-
- document = xrealloc (document, 2 * allocated);
- allocated *= 2;
- p = document + document_len;
- }
+ /* Expand to guarantee sufficient storage. */
+ uintptr_t document_len = p - document;
- name = xml_escape_text ((char *) libname);
- p += sprintf (p, "<library name=\"%s\" lm=\"0x%lx\" "
- "l_addr=\"0x%lx\" l_ld=\"0x%lx\"/>",
- name, (unsigned long) lm_addr,
- (unsigned long) l_addr, (unsigned long) l_ld);
- free (name);
- }
- else if (lm_prev == 0)
- {
- sprintf (p, " main-lm=\"0x%lx\"", (unsigned long) lm_addr);
- p = p + strlen (p);
+ document = xrealloc (document, 2 * allocated);
+ allocated *= 2;
+ p = document + document_len;
}
- if (l_next == 0)
- break;
-
- lm_prev = lm_addr;
- lm_addr = l_next;
+ name = xml_escape_text ((char *) libname);
+ p += sprintf (p, "<library name=\"%s\" lm=\"0x%lx\" "
+ "l_addr=\"0x%lx\" l_ld=\"0x%lx\"/>",
+ name, (unsigned long) lm_addr,
+ (unsigned long) l_addr, (unsigned long) l_ld);
+ free (name);
}
- done:
- if (!header_done)
+ else if (lm_prev == 0)
{
- /* Empty list; terminate `<library-list-svr4'. */
- strcpy (p, "/>");
+ sprintf (p, " main-lm=\"0x%lx\"", (unsigned long) lm_addr);
+ p = p + strlen (p);
}
- else
- strcpy (p, "</library-list-svr4>");
+
+ lm_prev = lm_addr;
+ lm_addr = l_next;
}
+ if (!header_done)
+ {
+ /* Empty list; terminate `<library-list-svr4'. */
+ strcpy (p, "/>");
+ }
+ else
+ strcpy (p, "</library-list-svr4>");
+
document_len = strlen (document);
if (offset < document_len)
document_len -= offset;
^ permalink raw reply [flat|nested] 59+ messages in thread* Re: [RFA 3/7] New gdbserver functionality
2013-05-16 14:48 ` [RFA 3/7] New gdbserver functionality Gary Benson
@ 2013-05-16 18:18 ` Tom Tromey
2013-05-24 7:46 ` [RFA 3/7 take 2] " Gary Benson
0 siblings, 1 reply; 59+ messages in thread
From: Tom Tromey @ 2013-05-16 18:18 UTC (permalink / raw)
To: gdb-patches
>>>>> "Gary" == Gary Benson <gbenson@redhat.com> writes:
Gary> This patch updates gdbserver to allow arguments to be passed in the
Gary> annex of qXfer:libraries-svr4:read to allow that function to transfer
Gary> partial lists of libraries. The ability of gdbserver to support
Gary> these arguments is indicated by a qSupported response containing
Gary> "augmented-libraries-svr4-read+".
This needs a documentation patch to reflect the new addition to the
remote protocol.
Tom
^ permalink raw reply [flat|nested] 59+ messages in thread
* [RFA 3/7 take 2] New gdbserver functionality
2013-05-16 18:18 ` Tom Tromey
@ 2013-05-24 7:46 ` Gary Benson
2013-05-25 21:05 ` Jan Kratochvil
2013-05-29 18:50 ` Pedro Alves
0 siblings, 2 replies; 59+ messages in thread
From: Gary Benson @ 2013-05-24 7:46 UTC (permalink / raw)
To: Tom Tromey; +Cc: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 1133 bytes --]
Tom Tromey wrote:
> >>>>> "Gary" == Gary Benson <gbenson@redhat.com> writes:
>
> Gary> This patch updates gdbserver to allow arguments to be passed
> Gary> in the annex of qXfer:libraries-svr4:read to allow that
> Gary> function to transfer partial lists of libraries. The ability
> Gary> of gdbserver to support these arguments is indicated by a
> Gary> qSupported response containing
> Gary> "augmented-libraries-svr4-read+".
>
> This needs a documentation patch to reflect the new addition to the
> remote protocol.
The attached patch adds this documentation.
I have also attached an updated code patch with more robust argument
handling--specifically, if START is unset or set to zero, the stub
will read the start of the library list from r_debug in the usual way.
In the original patch, specifying *any* arguments would bypass that
code, and the code to read the list would see START set to zero.
This didn't affect anything now, as there was no reason to use the
augmented form of qXfer:libraries-svr4:read without setting START,
but it would have caused problems in future if further arguments
were added.
Thanks,
Gary
[-- Attachment #2: rtld-probes-8-docs.patch --]
[-- Type: text/plain, Size: 3453 bytes --]
2013-05-23 Gary Benson <gbenson@redhat.com>
* gdb.texinfo (General Query Packets/qSupported): Added
"qXfer:libraries-svr4:read" and "augmented-libraries-svr4-read".
to the table of currently defined stub features.
Added a more detailed entry for "augmented-libraries-svr4-read".
(General Query Packets/qXfer:libraries-svr4:read): Documented
the augmented form of this packet.
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index b68d2f8..dfe42c9 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -38542,6 +38542,16 @@ These are the currently defined stub features and their properties:
@tab @samp{-}
@tab Yes
+@item @samp{qXfer:libraries-svr4:read}
+@tab No
+@tab @samp{-}
+@tab Yes
+
+@item @samp{augmented-libraries-svr4-read}
+@tab No
+@tab @samp{-}
+@tab No
+
@item @samp{qXfer:memory-map:read}
@tab No
@tab @samp{-}
@@ -38718,6 +38728,11 @@ The remote stub understands the @samp{qXfer:libraries:read} packet
The remote stub understands the @samp{qXfer:libraries-svr4:read} packet
(@pxref{qXfer svr4 library list read}).
+@item augmented-libraries-svr4-read
+The remote stub understands the augmented form of the
+@samp{qXfer:libraries-svr4:read} packet
+(@pxref{qXfer svr4 library list read}).
+
@item qXfer:memory-map:read
The remote stub understands the @samp{qXfer:memory-map:read} packet
(@pxref{qXfer memory map read}).
@@ -39013,7 +39028,10 @@ by supplying an appropriate @samp{qSupported} response (@pxref{qSupported}).
@anchor{qXfer svr4 library list read}
Access the target's list of loaded libraries when the target is an SVR4
platform. @xref{Library List Format for SVR4 Targets}. The annex part
-of the generic @samp{qXfer} packet must be empty (@pxref{qXfer read}).
+of the generic @samp{qXfer} packet must be empty unless the remote
+stub indicated it supports the augmented form of this packet
+by supplying an appropriate @samp{qSupported} response
+(@pxref{qXfer read}, @ref{qSupported}).
This packet is optional for better performance on SVR4 targets.
@value{GDBN} uses memory read packets to read the SVR4 library list otherwise.
@@ -39021,6 +39039,30 @@ This packet is optional for better performance on SVR4 targets.
This packet is not probed by default; the remote stub must request it,
by supplying an appropriate @samp{qSupported} response (@pxref{qSupported}).
+If the remote stub indicates it supports the augmented form of this
+packet then the annex part of the generic @samp{qXfer} packet may
+contain a semicolon-separated list of @samp{@var{name}=@var{value}}
+arguments. The currently supported arguments are:
+
+@table @code
+@item start=@var{address}
+A hexidecimal number specifying the address of the @samp{struct
+link_map} to start reading the library list from. If unset or zero
+then the first @samp{struct link_map} in the library list will be
+chosen as the starting point.
+
+@item prev=@var{address}
+A hexidecimal number specifying the address of the @samp{struct
+link_map} immediately preceding the @samp{struct link_map}
+specified by the @samp{start} argument. If unset or zero then
+the remote stub will expect that no @samp{struct link_map}
+exists prior to the starting point.
+
+@end table
+
+Arguments that are not understood by the remote stub will be silently
+ignored.
+
@item qXfer:memory-map:read::@var{offset},@var{length}
@anchor{qXfer memory map read}
Access the target's @dfn{memory-map}. @xref{Memory Map Format}. The
[-- Attachment #3: rtld-probes-3-gdbserver.patch --]
[-- Type: text/plain, Size: 9134 bytes --]
2013-05-23 Gary Benson <gbenson@redhat.com>
* server.c (handle_query): Add "augmented-libraries-svr4-read+"
to qSupported response when appropriate.
(handle_qxfer_libraries_svr4): Allow qXfer:libraries-svr4:read
with nonzero-length annex.
* linux-low.c (linux_qxfer_libraries_svr4): Parse and handle
arguments supplied in annex.
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index 6bb36d8..0a8f68b 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -1115,8 +1115,7 @@ handle_qxfer_libraries_svr4 (const char *annex,
if (writebuf != NULL)
return -2;
- if (annex[0] != '\0' || !target_running ()
- || the_target->qxfer_libraries_svr4 == NULL)
+ if (!target_running () || the_target->qxfer_libraries_svr4 == NULL)
return -1;
return the_target->qxfer_libraries_svr4 (annex, readbuf, writebuf, offset, len);
@@ -1743,7 +1742,8 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
PBUFSIZ - 1);
if (the_target->qxfer_libraries_svr4 != NULL)
- strcat (own_buf, ";qXfer:libraries-svr4:read+");
+ strcat (own_buf, ";qXfer:libraries-svr4:read+"
+ ";augmented-libraries-svr4-read+");
else
{
/* We do not have any hook to indicate whether the non-SVR4 target
diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index b01b37c..a7c4b07 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -5688,6 +5688,12 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf,
};
const struct link_map_offsets *lmo;
unsigned int machine;
+ int ptr_size;
+ CORE_ADDR lm_addr = 0, lm_prev = 0;
+ int allocated = 1024;
+ char *p;
+ CORE_ADDR l_name, l_addr, l_ld, l_next, l_prev;
+ int header_done = 0;
if (writebuf != NULL)
return -2;
@@ -5698,128 +5704,144 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf,
xsnprintf (filename, sizeof filename, "/proc/%d/exe", pid);
is_elf64 = elf_64_file_p (filename, &machine);
lmo = is_elf64 ? &lmo_64bit_offsets : &lmo_32bit_offsets;
+ ptr_size = is_elf64 ? 8 : 4;
- if (priv->r_debug == 0)
- priv->r_debug = get_r_debug (pid, is_elf64);
+ while (annex[0] != '\0')
+ {
+ const char *sep;
+ CORE_ADDR *addrp;
+ int len;
- /* We failed to find DT_DEBUG. Such situation will not change for this
- inferior - do not retry it. Report it to GDB as E01, see for the reasons
- at the GDB solib-svr4.c side. */
- if (priv->r_debug == (CORE_ADDR) -1)
- return -1;
+ sep = strchr (annex, '=');
+ if (!sep)
+ break;
- if (priv->r_debug == 0)
- {
- document = xstrdup ("<library-list-svr4 version=\"1.0\"/>\n");
+ len = sep - annex;
+ if (len == 5 && !strncmp (annex, "start", 5))
+ addrp = &lm_addr;
+ else if (len == 4 && !strncmp (annex, "prev", 4))
+ addrp = &lm_prev;
+ else
+ {
+ annex = strchr (sep, ';');
+ if (!annex)
+ break;
+ annex++;
+ continue;
+ }
+
+ annex = decode_address_to_semicolon (addrp, sep + 1);
}
- else
+
+ if (lm_addr == 0)
{
- int allocated = 1024;
- char *p;
- const int ptr_size = is_elf64 ? 8 : 4;
- CORE_ADDR lm_addr, lm_prev, l_name, l_addr, l_ld, l_next, l_prev;
- int r_version, header_done = 0;
-
- document = xmalloc (allocated);
- strcpy (document, "<library-list-svr4 version=\"1.0\"");
- p = document + strlen (document);
-
- r_version = 0;
- if (linux_read_memory (priv->r_debug + lmo->r_version_offset,
- (unsigned char *) &r_version,
- sizeof (r_version)) != 0
- || r_version != 1)
+ int r_version = 0;
+
+ if (priv->r_debug == 0)
+ priv->r_debug = get_r_debug (pid, is_elf64);
+
+ /* We failed to find DT_DEBUG. Such situation will not change
+ for this inferior - do not retry it. Report it to GDB as
+ E01, see for the reasons at the GDB solib-svr4.c side. */
+ if (priv->r_debug == (CORE_ADDR) -1)
+ return -1;
+
+ if (priv->r_debug != 0)
{
- warning ("unexpected r_debug version %d", r_version);
- goto done;
+ if (linux_read_memory (priv->r_debug + lmo->r_version_offset,
+ (unsigned char *) &r_version,
+ sizeof (r_version)) != 0
+ || r_version != 1)
+ {
+ warning ("unexpected r_debug version %d", r_version);
+ }
+ else if (read_one_ptr (priv->r_debug + lmo->r_map_offset,
+ &lm_addr, ptr_size) != 0)
+ {
+ warning ("unable to read r_map from 0x%lx",
+ (long) priv->r_debug + lmo->r_map_offset);
+ }
}
+ }
- if (read_one_ptr (priv->r_debug + lmo->r_map_offset,
- &lm_addr, ptr_size) != 0)
+ document = xmalloc (allocated);
+ strcpy (document, "<library-list-svr4 version=\"1.0\"");
+ p = document + strlen (document);
+
+ while (lm_addr
+ && read_one_ptr (lm_addr + lmo->l_name_offset,
+ &l_name, ptr_size) == 0
+ && read_one_ptr (lm_addr + lmo->l_addr_offset,
+ &l_addr, ptr_size) == 0
+ && read_one_ptr (lm_addr + lmo->l_ld_offset,
+ &l_ld, ptr_size) == 0
+ && read_one_ptr (lm_addr + lmo->l_prev_offset,
+ &l_prev, ptr_size) == 0
+ && read_one_ptr (lm_addr + lmo->l_next_offset,
+ &l_next, ptr_size) == 0)
+ {
+ unsigned char libname[PATH_MAX];
+
+ if (lm_prev != l_prev)
{
- warning ("unable to read r_map from 0x%lx",
- (long) priv->r_debug + lmo->r_map_offset);
- goto done;
+ warning ("Corrupted shared library list: 0x%lx != 0x%lx",
+ (long) lm_prev, (long) l_prev);
+ break;
}
- lm_prev = 0;
- while (read_one_ptr (lm_addr + lmo->l_name_offset,
- &l_name, ptr_size) == 0
- && read_one_ptr (lm_addr + lmo->l_addr_offset,
- &l_addr, ptr_size) == 0
- && read_one_ptr (lm_addr + lmo->l_ld_offset,
- &l_ld, ptr_size) == 0
- && read_one_ptr (lm_addr + lmo->l_prev_offset,
- &l_prev, ptr_size) == 0
- && read_one_ptr (lm_addr + lmo->l_next_offset,
- &l_next, ptr_size) == 0)
+ /* Not checking for error because reading may stop before
+ we've got PATH_MAX worth of characters. */
+ libname[0] = '\0';
+ linux_read_memory (l_name, libname, sizeof (libname) - 1);
+ libname[sizeof (libname) - 1] = '\0';
+ if (libname[0] != '\0')
{
- unsigned char libname[PATH_MAX];
+ /* 6x the size for xml_escape_text below. */
+ size_t len = 6 * strlen ((char *) libname);
+ char *name;
- if (lm_prev != l_prev)
+ if (!header_done)
{
- warning ("Corrupted shared library list: 0x%lx != 0x%lx",
- (long) lm_prev, (long) l_prev);
- break;
+ /* Terminate `<library-list-svr4'. */
+ *p++ = '>';
+ header_done = 1;
}
- /* Not checking for error because reading may stop before
- we've got PATH_MAX worth of characters. */
- libname[0] = '\0';
- linux_read_memory (l_name, libname, sizeof (libname) - 1);
- libname[sizeof (libname) - 1] = '\0';
- if (libname[0] != '\0')
+ while (allocated < p - document + len + 200)
{
- /* 6x the size for xml_escape_text below. */
- size_t len = 6 * strlen ((char *) libname);
- char *name;
-
- if (!header_done)
- {
- /* Terminate `<library-list-svr4'. */
- *p++ = '>';
- header_done = 1;
- }
-
- while (allocated < p - document + len + 200)
- {
- /* Expand to guarantee sufficient storage. */
- uintptr_t document_len = p - document;
-
- document = xrealloc (document, 2 * allocated);
- allocated *= 2;
- p = document + document_len;
- }
+ /* Expand to guarantee sufficient storage. */
+ uintptr_t document_len = p - document;
- name = xml_escape_text ((char *) libname);
- p += sprintf (p, "<library name=\"%s\" lm=\"0x%lx\" "
- "l_addr=\"0x%lx\" l_ld=\"0x%lx\"/>",
- name, (unsigned long) lm_addr,
- (unsigned long) l_addr, (unsigned long) l_ld);
- free (name);
- }
- else if (lm_prev == 0)
- {
- sprintf (p, " main-lm=\"0x%lx\"", (unsigned long) lm_addr);
- p = p + strlen (p);
+ document = xrealloc (document, 2 * allocated);
+ allocated *= 2;
+ p = document + document_len;
}
- if (l_next == 0)
- break;
-
- lm_prev = lm_addr;
- lm_addr = l_next;
+ name = xml_escape_text ((char *) libname);
+ p += sprintf (p, "<library name=\"%s\" lm=\"0x%lx\" "
+ "l_addr=\"0x%lx\" l_ld=\"0x%lx\"/>",
+ name, (unsigned long) lm_addr,
+ (unsigned long) l_addr, (unsigned long) l_ld);
+ free (name);
}
- done:
- if (!header_done)
+ else if (lm_prev == 0)
{
- /* Empty list; terminate `<library-list-svr4'. */
- strcpy (p, "/>");
+ sprintf (p, " main-lm=\"0x%lx\"", (unsigned long) lm_addr);
+ p = p + strlen (p);
}
- else
- strcpy (p, "</library-list-svr4>");
+
+ lm_prev = lm_addr;
+ lm_addr = l_next;
}
+ if (!header_done)
+ {
+ /* Empty list; terminate `<library-list-svr4'. */
+ strcpy (p, "/>");
+ }
+ else
+ strcpy (p, "</library-list-svr4>");
+
document_len = strlen (document);
if (offset < document_len)
document_len -= offset;
^ permalink raw reply [flat|nested] 59+ messages in thread* Re: [RFA 3/7 take 2] New gdbserver functionality
2013-05-24 7:46 ` [RFA 3/7 take 2] " Gary Benson
@ 2013-05-25 21:05 ` Jan Kratochvil
2013-05-26 2:45 ` Eli Zaretskii
2013-05-29 18:50 ` Pedro Alves
1 sibling, 1 reply; 59+ messages in thread
From: Jan Kratochvil @ 2013-05-25 21:05 UTC (permalink / raw)
To: gdb-patches; +Cc: Tom Tromey, Eli Zaretskii
On Fri, 24 May 2013 09:46:13 +0200, Gary Benson wrote:
> 2013-05-23 Gary Benson <gbenson@redhat.com>
>
> * gdb.texinfo (General Query Packets/qSupported): Added
> "qXfer:libraries-svr4:read" and "augmented-libraries-svr4-read".
> to the table of currently defined stub features.
> Added a more detailed entry for "augmented-libraries-svr4-read".
> (General Query Packets/qXfer:libraries-svr4:read): Documented
> the augmented form of this packet.
>
> diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
> index b68d2f8..dfe42c9 100644
> --- a/gdb/doc/gdb.texinfo
> +++ b/gdb/doc/gdb.texinfo
[...]
> +@table @code
> +@item start=@var{address}
> +A hexidecimal number specifying the address of the @samp{struct
typo: hexadecimal
> +link_map} to start reading the library list from. If unset or zero
> +then the first @samp{struct link_map} in the library list will be
> +chosen as the starting point.
> +
> +@item prev=@var{address}
> +A hexidecimal number specifying the address of the @samp{struct
typo: hexadecimal
> +link_map} immediately preceding the @samp{struct link_map}
> +specified by the @samp{start} argument. If unset or zero then
> +the remote stub will expect that no @samp{struct link_map}
> +exists prior to the starting point.
[...]
But otherwise it is for approval by Eli.
Thanks,
Jan
^ permalink raw reply [flat|nested] 59+ messages in thread* Re: [RFA 3/7 take 2] New gdbserver functionality
2013-05-24 7:46 ` [RFA 3/7 take 2] " Gary Benson
2013-05-25 21:05 ` Jan Kratochvil
@ 2013-05-29 18:50 ` Pedro Alves
2013-05-30 9:38 ` Gary Benson
1 sibling, 1 reply; 59+ messages in thread
From: Pedro Alves @ 2013-05-29 18:50 UTC (permalink / raw)
To: Tom Tromey, gdb-patches
On 05/16/2013 03:48 PM, Gary Benson wrote:
> + sep = strchr (annex, '=');
> + if (!sep)
Please write
if (sep == NULL)
There are more instances of this in the patch.
> + break;
> +
> + len = sep - annex;
> + if (len == 5 && !strncmp (annex, "start", 5))
strncmp does not return a boolean. Please write:
> + if (len == 5 && strncmp (annex, "start", 5) == 0)
> + else if (len == 4 && !strncmp (annex, "prev", 4))
Ditto.
Otherwise looks good to me too.
There should be a NEWS entry for the new RSP feature too though.
--
Pedro Alves
^ permalink raw reply [flat|nested] 59+ messages in thread* Re: [RFA 3/7 take 2] New gdbserver functionality
2013-05-29 18:50 ` Pedro Alves
@ 2013-05-30 9:38 ` Gary Benson
2013-05-30 10:40 ` Pedro Alves
0 siblings, 1 reply; 59+ messages in thread
From: Gary Benson @ 2013-05-30 9:38 UTC (permalink / raw)
To: Pedro Alves; +Cc: Tom Tromey, gdb-patches
Pedro Alves wrote:
> On 05/16/2013 03:48 PM, Gary Benson wrote:
>
> > + sep = strchr (annex, '=');
> > + if (!sep)
>
> Please write
>
> if (sep == NULL)
>
> There are more instances of this in the patch.
>
> > + break;
> > +
> > + len = sep - annex;
> > + if (len == 5 && !strncmp (annex, "start", 5))
>
> strncmp does not return a boolean. Please write:
>
> > + if (len == 5 && strncmp (annex, "start", 5) == 0)
>
>
> > + else if (len == 4 && !strncmp (annex, "prev", 4))
>
> Ditto.
I have updated the patch with these changes.
> There should be a NEWS entry for the new RSP feature too though.
How does this look?
+* New features in the GDB remote stub, GDBserver
+
+ ** GDBserver now supports the passing of an argument list in the
+ annex field of qXfer:libraries-svr4:read. The remote stub
+ reports support for this argument list to gdb's qSupported query.
+
Thanks,
Gary
^ permalink raw reply [flat|nested] 59+ messages in thread
* Re: [RFA 3/7 take 2] New gdbserver functionality
2013-05-30 9:38 ` Gary Benson
@ 2013-05-30 10:40 ` Pedro Alves
2013-05-30 10:54 ` Gary Benson
0 siblings, 1 reply; 59+ messages in thread
From: Pedro Alves @ 2013-05-30 10:40 UTC (permalink / raw)
To: Pedro Alves, Tom Tromey, gdb-patches, Eli Zaretskii
[Adding Eli.]
Eli, new NEWS entry here.
On 05/30/2013 10:38 AM, Gary Benson wrote:
> Pedro Alves wrote:
>> There should be a NEWS entry for the new RSP feature too though.
>
> How does this look?
>
> +* New features in the GDB remote stub, GDBserver
> +
> + ** GDBserver now supports the passing of an argument list in the
> + annex field of qXfer:libraries-svr4:read. The remote stub
> + reports support for this argument list to gdb's qSupported query.
> +
The emphasis should be in the RSP extension, not on GDBserver.
Something like this, under the existing "New remote packets":
* New remote packets
qXfer:libraries-svr4:read's annex
The previously unused annex of the qXfer:libraries-svr4:read packet
has now been defined to support passing an argument list. The remote
stub reports support for this argument list to gdb's qSupported query.
The defined arguments are "start" and "prev", used to reduce work
necessary for library list updating, resulting in significant speedup.
--
Pedro Alves
^ permalink raw reply [flat|nested] 59+ messages in thread
* Re: [RFA 3/7 take 2] New gdbserver functionality
2013-05-30 10:40 ` Pedro Alves
@ 2013-05-30 10:54 ` Gary Benson
2013-05-30 16:31 ` Eli Zaretskii
0 siblings, 1 reply; 59+ messages in thread
From: Gary Benson @ 2013-05-30 10:54 UTC (permalink / raw)
To: Pedro Alves; +Cc: Tom Tromey, gdb-patches, Eli Zaretskii
Pedro Alves wrote:
> On 05/30/2013 10:38 AM, Gary Benson wrote:
> > Pedro Alves wrote:
> > > There should be a NEWS entry for the new RSP feature too though.
> >
> > How does this look?
> >
> > +* New features in the GDB remote stub, GDBserver
> > +
> > + ** GDBserver now supports the passing of an argument list in the
> > + annex field of qXfer:libraries-svr4:read. The remote stub
> > + reports support for this argument list to gdb's qSupported query.
> > +
>
> The emphasis should be in the RSP extension, not on GDBserver.
> Something like this, under the existing "New remote packets":
>
> * New remote packets
>
> qXfer:libraries-svr4:read's annex
>
> The previously unused annex of the qXfer:libraries-svr4:read packet
> has now been defined to support passing an argument list. The
> remote stub reports support for this argument list to gdb's
> qSupported query. The defined arguments are "start" and "prev",
> used to reduce work necessary for library list updating, resulting
> in significant speedup.
Nice, if Eli approves I will put that in.
Thanks,
Gary
--
http://gbenson.net/
^ permalink raw reply [flat|nested] 59+ messages in thread
* Re: [RFA 3/7 take 2] New gdbserver functionality
2013-05-30 10:54 ` Gary Benson
@ 2013-05-30 16:31 ` Eli Zaretskii
2013-05-30 17:22 ` Gary Benson
0 siblings, 1 reply; 59+ messages in thread
From: Eli Zaretskii @ 2013-05-30 16:31 UTC (permalink / raw)
To: Gary Benson; +Cc: palves, tromey, gdb-patches
> Date: Thu, 30 May 2013 11:54:13 +0100
> From: Gary Benson <gbenson@redhat.com>
> Cc: Tom Tromey <tromey@redhat.com>, gdb-patches@sourceware.org,
> Eli Zaretskii <eliz@gnu.org>
>
> > * New remote packets
> >
> > qXfer:libraries-svr4:read's annex
> >
> > The previously unused annex of the qXfer:libraries-svr4:read packet
> > has now been defined to support passing an argument list. The
^^^^^^^^^^^^^^^^^^^^
"is now used" sounds better.
> > remote stub reports support for this argument list to gdb's
^^^
I believe we use "GDB" in caps elsewhere in NEWS.
> > qSupported query. The defined arguments are "start" and "prev",
> > used to reduce work necessary for library list updating, resulting
> > in significant speedup.
>
> Nice, if Eli approves I will put that in.
Fine with me, with those two fixes.
Thanks.
^ permalink raw reply [flat|nested] 59+ messages in thread* Re: [RFA 3/7 take 2] New gdbserver functionality
2013-05-30 16:31 ` Eli Zaretskii
@ 2013-05-30 17:22 ` Gary Benson
0 siblings, 0 replies; 59+ messages in thread
From: Gary Benson @ 2013-05-30 17:22 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: palves, tromey, gdb-patches
Eli Zaretskii wrote:
> > Date: Thu, 30 May 2013 11:54:13 +0100
> > From: Gary Benson <gbenson@redhat.com>
> > Cc: Tom Tromey <tromey@redhat.com>, gdb-patches@sourceware.org,
> > Eli Zaretskii <eliz@gnu.org>
> >
> > > * New remote packets
> > >
> > > qXfer:libraries-svr4:read's annex
> > >
> > > The previously unused annex of the qXfer:libraries-svr4:read packet
> > > has now been defined to support passing an argument list. The
> ^^^^^^^^^^^^^^^^^^^^
> "is now used" sounds better.
>
> > > remote stub reports support for this argument list to gdb's
> ^^^
> I believe we use "GDB" in caps elsewhere in NEWS.
>
> > > qSupported query. The defined arguments are "start" and "prev",
> > > used to reduce work necessary for library list updating, resulting
> > > in significant speedup.
> >
> > Nice, if Eli approves I will put that in.
>
> Fine with me, with those two fixes.
Awesome, thanks Eli.
Gary
^ permalink raw reply [flat|nested] 59+ messages in thread
* [RFA 2/7] API for inhibiting section map updates
2013-05-16 14:43 [RFA 0/7] Improved linker-debugger interface Gary Benson
2013-05-16 14:47 ` [RFA 1/7] Probes API convenience patch Gary Benson
2013-05-16 14:48 ` [RFA 3/7] New gdbserver functionality Gary Benson
@ 2013-05-16 14:48 ` Gary Benson
2013-05-20 14:22 ` Tom Tromey
2013-05-16 14:48 ` [RFA 4/7] GDB support for new gdbserver functionality Gary Benson
` (7 subsequent siblings)
10 siblings, 1 reply; 59+ messages in thread
From: Gary Benson @ 2013-05-16 14:48 UTC (permalink / raw)
To: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 433 bytes --]
This patch adds a couple of functions to allow section map updates
to be temporarily inhibited. Without this ability, the calls to
evaluate_probe_argument in svr4_handle_solib_event trigger a section
map update every time a group of shared objects are mapped, which
significantly affects performance. The updates are unnecessary in
this case as the sections in question are in the runtime linker and
so already in the section map.
[-- Attachment #2: rtld-probes-2-inhibit-sm-updates.patch --]
[-- Type: text/plain, Size: 5957 bytes --]
2013-05-16 Gary Benson <gbenson@redhat.com>
* objfiles.h (inhibit_section_map_updates): New function
declaration.
(resume_section_map_updates): Likewise.
(resume_section_map_updates_cleanup): Likewise.
* objfiles.c (objfile_pspace_info): Removed field
"objfiles_changed_p". New fields "new_objfiles_available",
"section_map_dirty" and "inhibit_updates".
(allocate_objfile): Set new_objfiles_available.
(free_objfile): Set section_map_dirty.
(objfile_relocate1): Likewise.
(in_plt_section): Likewise.
(find_pc_section): Update the conditions under which the
section map will be updated.
(inhibit_section_map_updates): New function.
(resume_section_map_updates): Likewise.
(resume_section_map_updates_cleanup): Likewise.
diff --git a/gdb/objfiles.h b/gdb/objfiles.h
index 93149e2..0b7eea9 100644
--- a/gdb/objfiles.h
+++ b/gdb/objfiles.h
@@ -501,6 +501,22 @@ extern int in_plt_section (CORE_ADDR, char *);
modules. */
DECLARE_REGISTRY(objfile);
+/* In normal use, the section map will be rebuilt by FIND_PC_SECTION
+ if objfiles have been added, removed or relocated since it was last
+ called. Calling INHIBIT_SECTION_MAP_UPDATES will inhibit this
+ behavior until RESUME_SECTION_MAP_UPDATES is called. If you call
+ INHIBIT_SECTION_MAP_UPDATES you must ensure that every call to
+ FIND_PC_SECTION in the inhibited region relates to a section that
+ is already in the section map and has not since been removed or
+ relocated. */
+extern void inhibit_section_map_updates (void);
+
+/* Resume automatically rebuilding the section map as required. */
+extern void resume_section_map_updates (void);
+
+/* Version of the above suitable for use as a cleanup. */
+extern void resume_section_map_updates_cleanup (void *arg);
+
extern void default_iterate_over_objfiles_in_search_order
(struct gdbarch *gdbarch,
iterate_over_objfiles_in_search_order_cb_ftype *cb,
diff --git a/gdb/objfiles.c b/gdb/objfiles.c
index 3e49ea2..3af1064 100644
--- a/gdb/objfiles.c
+++ b/gdb/objfiles.c
@@ -67,9 +67,18 @@ struct objfile *rt_common_objfile; /* For runtime common symbols */
struct objfile_pspace_info
{
- int objfiles_changed_p;
struct obj_section **sections;
int num_sections;
+
+ /* Nonzero if object files have been added since the section map
+ was last updated. */
+ int new_objfiles_available;
+
+ /* Nonzero if the section map MUST be updated before use. */
+ int section_map_dirty;
+
+ /* Nonzero if section map updates should be inhibited if possible. */
+ int inhibit_updates;
};
/* Per-program-space data key. */
@@ -317,7 +326,7 @@ allocate_objfile (bfd *abfd, int flags)
objfile->flags |= flags;
/* Rebuild section map next time we need it. */
- get_objfile_pspace_data (objfile->pspace)->objfiles_changed_p = 1;
+ get_objfile_pspace_data (objfile->pspace)->new_objfiles_available = 1;
return objfile;
}
@@ -646,7 +655,7 @@ free_objfile (struct objfile *objfile)
obstack_free (&objfile->objfile_obstack, 0);
/* Rebuild section map next time we need it. */
- get_objfile_pspace_data (objfile->pspace)->objfiles_changed_p = 1;
+ get_objfile_pspace_data (objfile->pspace)->section_map_dirty = 1;
xfree (objfile);
}
@@ -826,7 +835,7 @@ objfile_relocate1 (struct objfile *objfile,
}
/* Rebuild section map next time we need it. */
- get_objfile_pspace_data (objfile->pspace)->objfiles_changed_p = 1;
+ get_objfile_pspace_data (objfile->pspace)->section_map_dirty = 1;
/* Update the table in exec_ops, used to read memory. */
ALL_OBJFILE_OSECTIONS (objfile, s)
@@ -1291,11 +1300,14 @@ static void
update_section_map (struct program_space *pspace,
struct obj_section ***pmap, int *pmap_size)
{
+ struct objfile_pspace_info *pspace_info;
int alloc_size, map_size, i;
struct obj_section *s, **map;
struct objfile *objfile;
- gdb_assert (get_objfile_pspace_data (pspace)->objfiles_changed_p != 0);
+ pspace_info = get_objfile_pspace_data (current_program_space);
+ gdb_assert (pspace_info->section_map_dirty != 0
+ || pspace_info->new_objfiles_available != 0);
map = *pmap;
xfree (map);
@@ -1365,7 +1377,9 @@ find_pc_section (CORE_ADDR pc)
return s;
pspace_info = get_objfile_pspace_data (current_program_space);
- if (pspace_info->objfiles_changed_p != 0)
+ if (pspace_info->section_map_dirty
+ || (pspace_info->new_objfiles_available
+ && !pspace_info->inhibit_updates))
{
update_section_map (current_program_space,
&pspace_info->sections,
@@ -1373,7 +1387,8 @@ find_pc_section (CORE_ADDR pc)
/* Don't need updates to section map until objfiles are added,
removed or relocated. */
- pspace_info->objfiles_changed_p = 0;
+ pspace_info->new_objfiles_available = 0;
+ pspace_info->section_map_dirty = 0;
}
/* The C standard (ISO/IEC 9899:TC2) requires the BASE argument to
@@ -1414,14 +1429,38 @@ in_plt_section (CORE_ADDR pc, char *name)
}
\f
-/* Set objfiles_changed_p so section map will be rebuilt next time it
+/* Set section_map_dirty so section map will be rebuilt next time it
is used. Called by reread_symbols. */
void
objfiles_changed (void)
{
/* Rebuild section map next time we need it. */
- get_objfile_pspace_data (current_program_space)->objfiles_changed_p = 1;
+ get_objfile_pspace_data (current_program_space)->section_map_dirty = 1;
+}
+
+/* See comments in objfiles.h. */
+
+void
+inhibit_section_map_updates (void)
+{
+ get_objfile_pspace_data (current_program_space)->inhibit_updates = 1;
+}
+
+/* See comments in objfiles.h. */
+
+void
+resume_section_map_updates (void)
+{
+ get_objfile_pspace_data (current_program_space)->inhibit_updates = 0;
+}
+
+/* See comments in objfiles.h. */
+
+void
+resume_section_map_updates_cleanup (void *arg)
+{
+ resume_section_map_updates ();
}
/* The default implementation for the "iterate_over_objfiles_in_search_order"
^ permalink raw reply [flat|nested] 59+ messages in thread* Re: [RFA 2/7] API for inhibiting section map updates
2013-05-16 14:48 ` [RFA 2/7] API for inhibiting section map updates Gary Benson
@ 2013-05-20 14:22 ` Tom Tromey
2013-05-24 7:47 ` [RFA 2/7 take 2] " Gary Benson
0 siblings, 1 reply; 59+ messages in thread
From: Tom Tromey @ 2013-05-20 14:22 UTC (permalink / raw)
To: gdb-patches
>>>>> "Gary" == Gary Benson <gbenson@redhat.com> writes:
Gary> +void
Gary> +inhibit_section_map_updates (void)
Gary> +{
Gary> + get_objfile_pspace_data (current_program_space)->inhibit_updates = 1;
Gary> +}
Gary> +
Gary> +/* See comments in objfiles.h. */
Gary> +
Gary> +void
Gary> +resume_section_map_updates (void)
Gary> +{
Gary> + get_objfile_pspace_data (current_program_space)->inhibit_updates = 0;
Gary> +}
Gary> +
Gary> +/* See comments in objfiles.h. */
Gary> +
Gary> +void
Gary> +resume_section_map_updates_cleanup (void *arg)
Gary> +{
Gary> + resume_section_map_updates ();
Gary> }
It seems like it might be slightly safer if these all took the program
space as an argument. That way if something happens to change the
current program space, then, e.g., the cleanup will still affect the
program space for which it was made.
What do you think of that?
Tom
^ permalink raw reply [flat|nested] 59+ messages in thread* [RFA 2/7 take 2] API for inhibiting section map updates
2013-05-20 14:22 ` Tom Tromey
@ 2013-05-24 7:47 ` Gary Benson
2013-05-24 14:18 ` Tom Tromey
2013-05-29 17:18 ` Pedro Alves
0 siblings, 2 replies; 59+ messages in thread
From: Gary Benson @ 2013-05-24 7:47 UTC (permalink / raw)
To: Tom Tromey; +Cc: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 1028 bytes --]
Tom Tromey wrote:
> >>>>> "Gary" == Gary Benson <gbenson@redhat.com> writes:
>
> Gary> +void
> Gary> +inhibit_section_map_updates (void)
> Gary> +{
> Gary> + get_objfile_pspace_data (current_program_space)->inhibit_updates = 1;
> Gary> +}
> Gary> +
> Gary> +/* See comments in objfiles.h. */
> Gary> +
> Gary> +void
> Gary> +resume_section_map_updates (void)
> Gary> +{
> Gary> + get_objfile_pspace_data (current_program_space)->inhibit_updates = 0;
> Gary> +}
> Gary> +
> Gary> +/* See comments in objfiles.h. */
> Gary> +
> Gary> +void
> Gary> +resume_section_map_updates_cleanup (void *arg)
> Gary> +{
> Gary> + resume_section_map_updates ();
> Gary> }
>
> It seems like it might be slightly safer if these all took the
> program space as an argument. That way if something happens to
> change the current program space, then, e.g., the cleanup will
> still affect the program space for which it was made.
>
> What do you think of that?
That's an excellent idea. The attached patch implements this.
Cheers,
Gary
[-- Attachment #2: rtld-probes-2-inhibit-sm-updates.patch --]
[-- Type: text/plain, Size: 6026 bytes --]
2013-05-23 Gary Benson <gbenson@redhat.com>
* objfiles.h (inhibit_section_map_updates): New function
declaration.
(resume_section_map_updates): Likewise.
(resume_section_map_updates_cleanup): Likewise.
* objfiles.c (objfile_pspace_info): Removed field
"objfiles_changed_p". New fields "new_objfiles_available",
"section_map_dirty" and "inhibit_updates".
(allocate_objfile): Set new_objfiles_available.
(free_objfile): Set section_map_dirty.
(objfile_relocate1): Likewise.
(in_plt_section): Likewise.
(find_pc_section): Update the conditions under which the
section map will be updated.
(inhibit_section_map_updates): New function.
(resume_section_map_updates): Likewise.
(resume_section_map_updates_cleanup): Likewise.
diff --git a/gdb/objfiles.h b/gdb/objfiles.h
index 93149e2..adb1ef8 100644
--- a/gdb/objfiles.h
+++ b/gdb/objfiles.h
@@ -501,6 +501,22 @@ extern int in_plt_section (CORE_ADDR, char *);
modules. */
DECLARE_REGISTRY(objfile);
+/* In normal use, the section map will be rebuilt by find_pc_section
+ if objfiles have been added, removed or relocated since it was last
+ called. Calling inhibit_section_map_updates will inhibit this
+ behavior until resume_section_map_updates is called. If you call
+ inhibit_section_map_updates you must ensure that every call to
+ find_pc_section in the inhibited region relates to a section that
+ is already in the section map and has not since been removed or
+ relocated. */
+extern void inhibit_section_map_updates (struct program_space *pspace);
+
+/* Resume automatically rebuilding the section map as required. */
+extern void resume_section_map_updates (struct program_space *pspace);
+
+/* Version of the above suitable for use as a cleanup. */
+extern void resume_section_map_updates_cleanup (void *arg);
+
extern void default_iterate_over_objfiles_in_search_order
(struct gdbarch *gdbarch,
iterate_over_objfiles_in_search_order_cb_ftype *cb,
diff --git a/gdb/objfiles.c b/gdb/objfiles.c
index 3e49ea2..8842131 100644
--- a/gdb/objfiles.c
+++ b/gdb/objfiles.c
@@ -67,9 +67,18 @@ struct objfile *rt_common_objfile; /* For runtime common symbols */
struct objfile_pspace_info
{
- int objfiles_changed_p;
struct obj_section **sections;
int num_sections;
+
+ /* Nonzero if object files have been added since the section map
+ was last updated. */
+ int new_objfiles_available;
+
+ /* Nonzero if the section map MUST be updated before use. */
+ int section_map_dirty;
+
+ /* Nonzero if section map updates should be inhibited if possible. */
+ int inhibit_updates;
};
/* Per-program-space data key. */
@@ -317,7 +326,7 @@ allocate_objfile (bfd *abfd, int flags)
objfile->flags |= flags;
/* Rebuild section map next time we need it. */
- get_objfile_pspace_data (objfile->pspace)->objfiles_changed_p = 1;
+ get_objfile_pspace_data (objfile->pspace)->new_objfiles_available = 1;
return objfile;
}
@@ -646,7 +655,7 @@ free_objfile (struct objfile *objfile)
obstack_free (&objfile->objfile_obstack, 0);
/* Rebuild section map next time we need it. */
- get_objfile_pspace_data (objfile->pspace)->objfiles_changed_p = 1;
+ get_objfile_pspace_data (objfile->pspace)->section_map_dirty = 1;
xfree (objfile);
}
@@ -826,7 +835,7 @@ objfile_relocate1 (struct objfile *objfile,
}
/* Rebuild section map next time we need it. */
- get_objfile_pspace_data (objfile->pspace)->objfiles_changed_p = 1;
+ get_objfile_pspace_data (objfile->pspace)->section_map_dirty = 1;
/* Update the table in exec_ops, used to read memory. */
ALL_OBJFILE_OSECTIONS (objfile, s)
@@ -1291,11 +1300,14 @@ static void
update_section_map (struct program_space *pspace,
struct obj_section ***pmap, int *pmap_size)
{
+ struct objfile_pspace_info *pspace_info;
int alloc_size, map_size, i;
struct obj_section *s, **map;
struct objfile *objfile;
- gdb_assert (get_objfile_pspace_data (pspace)->objfiles_changed_p != 0);
+ pspace_info = get_objfile_pspace_data (current_program_space);
+ gdb_assert (pspace_info->section_map_dirty != 0
+ || pspace_info->new_objfiles_available != 0);
map = *pmap;
xfree (map);
@@ -1365,7 +1377,9 @@ find_pc_section (CORE_ADDR pc)
return s;
pspace_info = get_objfile_pspace_data (current_program_space);
- if (pspace_info->objfiles_changed_p != 0)
+ if (pspace_info->section_map_dirty
+ || (pspace_info->new_objfiles_available
+ && !pspace_info->inhibit_updates))
{
update_section_map (current_program_space,
&pspace_info->sections,
@@ -1373,7 +1387,8 @@ find_pc_section (CORE_ADDR pc)
/* Don't need updates to section map until objfiles are added,
removed or relocated. */
- pspace_info->objfiles_changed_p = 0;
+ pspace_info->new_objfiles_available = 0;
+ pspace_info->section_map_dirty = 0;
}
/* The C standard (ISO/IEC 9899:TC2) requires the BASE argument to
@@ -1414,14 +1429,38 @@ in_plt_section (CORE_ADDR pc, char *name)
}
\f
-/* Set objfiles_changed_p so section map will be rebuilt next time it
+/* Set section_map_dirty so section map will be rebuilt next time it
is used. Called by reread_symbols. */
void
objfiles_changed (void)
{
/* Rebuild section map next time we need it. */
- get_objfile_pspace_data (current_program_space)->objfiles_changed_p = 1;
+ get_objfile_pspace_data (current_program_space)->section_map_dirty = 1;
+}
+
+/* See comments in objfiles.h. */
+
+void
+inhibit_section_map_updates (struct program_space *pspace)
+{
+ get_objfile_pspace_data (pspace)->inhibit_updates = 1;
+}
+
+/* See comments in objfiles.h. */
+
+void
+resume_section_map_updates (struct program_space *pspace)
+{
+ get_objfile_pspace_data (pspace)->inhibit_updates = 0;
+}
+
+/* See comments in objfiles.h. */
+
+void
+resume_section_map_updates_cleanup (void *arg)
+{
+ resume_section_map_updates (arg);
}
/* The default implementation for the "iterate_over_objfiles_in_search_order"
^ permalink raw reply [flat|nested] 59+ messages in thread* Re: [RFA 2/7 take 2] API for inhibiting section map updates
2013-05-24 7:47 ` [RFA 2/7 take 2] " Gary Benson
@ 2013-05-24 14:18 ` Tom Tromey
2013-05-29 17:18 ` Pedro Alves
1 sibling, 0 replies; 59+ messages in thread
From: Tom Tromey @ 2013-05-24 14:18 UTC (permalink / raw)
To: gdb-patches
>>>>> "Gary" == Gary Benson <gbenson@redhat.com> writes:
Gary> 2013-05-23 Gary Benson <gbenson@redhat.com>
Gary> * objfiles.h (inhibit_section_map_updates): New function
Gary> declaration.
Gary> (resume_section_map_updates): Likewise.
Gary> (resume_section_map_updates_cleanup): Likewise.
Gary> * objfiles.c (objfile_pspace_info): Removed field
Gary> "objfiles_changed_p". New fields "new_objfiles_available",
Gary> "section_map_dirty" and "inhibit_updates".
Gary> (allocate_objfile): Set new_objfiles_available.
Gary> (free_objfile): Set section_map_dirty.
Gary> (objfile_relocate1): Likewise.
Gary> (in_plt_section): Likewise.
Gary> (find_pc_section): Update the conditions under which the
Gary> section map will be updated.
Gary> (inhibit_section_map_updates): New function.
Gary> (resume_section_map_updates): Likewise.
Gary> (resume_section_map_updates_cleanup): Likewise.
Ok.
Tom
^ permalink raw reply [flat|nested] 59+ messages in thread
* Re: [RFA 2/7 take 2] API for inhibiting section map updates
2013-05-24 7:47 ` [RFA 2/7 take 2] " Gary Benson
2013-05-24 14:18 ` Tom Tromey
@ 2013-05-29 17:18 ` Pedro Alves
2013-05-30 9:12 ` Gary Benson
1 sibling, 1 reply; 59+ messages in thread
From: Pedro Alves @ 2013-05-29 17:18 UTC (permalink / raw)
To: gdb-patches, Gary Benson; +Cc: Tom Tromey
On 05/24/2013 08:47 AM, Gary Benson wrote:
> /* Update the table in exec_ops, used to read memory. */
> ALL_OBJFILE_OSECTIONS (objfile, s)
> @@ -1291,11 +1300,14 @@ static void
> update_section_map (struct program_space *pspace,
> struct obj_section ***pmap, int *pmap_size)
> {
> + struct objfile_pspace_info *pspace_info;
> int alloc_size, map_size, i;
> struct obj_section *s, **map;
> struct objfile *objfile;
>
> - gdb_assert (get_objfile_pspace_data (pspace)->objfiles_changed_p != 0);
> + pspace_info = get_objfile_pspace_data (current_program_space);
Shouldn't this be 'pspace' instead of 'current_program_space'?
> + gdb_assert (pspace_info->section_map_dirty != 0
> + || pspace_info->new_objfiles_available != 0);
>
--
Pedro Alves
^ permalink raw reply [flat|nested] 59+ messages in thread* Re: [RFA 2/7 take 2] API for inhibiting section map updates
2013-05-29 17:18 ` Pedro Alves
@ 2013-05-30 9:12 ` Gary Benson
0 siblings, 0 replies; 59+ messages in thread
From: Gary Benson @ 2013-05-30 9:12 UTC (permalink / raw)
To: Pedro Alves; +Cc: gdb-patches, Tom Tromey
Pedro Alves wrote:
> On 05/24/2013 08:47 AM, Gary Benson wrote:
> > /* Update the table in exec_ops, used to read memory. */
> > ALL_OBJFILE_OSECTIONS (objfile, s)
> > @@ -1291,11 +1300,14 @@ static void
> > update_section_map (struct program_space *pspace,
> > struct obj_section ***pmap, int *pmap_size)
> > {
> > + struct objfile_pspace_info *pspace_info;
> > int alloc_size, map_size, i;
> > struct obj_section *s, **map;
> > struct objfile *objfile;
> >
> > - gdb_assert (get_objfile_pspace_data (pspace)->objfiles_changed_p != 0);
> > + pspace_info = get_objfile_pspace_data (current_program_space);
>
> Shouldn't this be 'pspace' instead of 'current_program_space'?
Good catch, thank you.
Gary
--
http://gbenson.net/
^ permalink raw reply [flat|nested] 59+ messages in thread
* [RFA 4/7] GDB support for new gdbserver functionality
2013-05-16 14:43 [RFA 0/7] Improved linker-debugger interface Gary Benson
` (2 preceding siblings ...)
2013-05-16 14:48 ` [RFA 2/7] API for inhibiting section map updates Gary Benson
@ 2013-05-16 14:48 ` Gary Benson
2013-05-16 14:55 ` [RFA 7/7] Linker-debugger interface tests Gary Benson
` (6 subsequent siblings)
10 siblings, 0 replies; 59+ messages in thread
From: Gary Benson @ 2013-05-16 14:48 UTC (permalink / raw)
To: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 103 bytes --]
This patch adds client support for the new gdbserver functionality
provided by patch 3 of this series.
[-- Attachment #2: rtld-probes-4-remote.patch --]
[-- Type: text/plain, Size: 4593 bytes --]
2013-05-16 Gary Benson <gbenson@redhat.com>
* target.h (target_ops): New field
"to_augmented_libraries_svr4_read".
(target_augmented_libraries_svr4_read): New macro.
* target.c (update_current_target): Handle
to_augmented_libraries_svr4_read.
* remote.c (remote_state): New field
"augmented_libraries_svr4_read".
(remote_augmented_libraries_svr4_read_feature): New function.
(remote_protocol_features): Add entry for
"augmented-libraries-svr4-read".
(remote_augmented_libraries_svr4_read): New function.
(init_remote_ops): Initialize
remote_ops.to_augmented_libraries_svr4_read.
diff --git a/gdb/target.h b/gdb/target.h
index e937d39..a8587e8 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -941,6 +941,10 @@ struct target_ops
(inclusive) to function END (exclusive). */
void (*to_call_history_range) (ULONGEST begin, ULONGEST end, int flags);
+ /* Nonzero if TARGET_OBJECT_LIBRARIES_SVR4 may be read with a
+ non-empty annex. */
+ int (*to_augmented_libraries_svr4_read) (void);
+
int to_magic;
/* Need sub-structure for target machine related rather than comm related?
*/
@@ -1809,6 +1813,9 @@ extern char *target_fileio_read_stralloc (const char *filename);
#define target_can_use_agent() \
(*current_target.to_can_use_agent) ()
+#define target_augmented_libraries_svr4_read() \
+ (*current_target.to_augmented_libraries_svr4_read) ()
+
/* Command logging facility. */
#define target_log_command(p) \
diff --git a/gdb/target.c b/gdb/target.c
index 8653dac..519b97f 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -731,6 +731,7 @@ update_current_target (void)
INHERIT (to_traceframe_info, t);
INHERIT (to_use_agent, t);
INHERIT (to_can_use_agent, t);
+ INHERIT (to_augmented_libraries_svr4_read, t);
INHERIT (to_magic, t);
INHERIT (to_supports_evaluation_of_breakpoint_conditions, t);
INHERIT (to_can_run_breakpoint_commands, t);
@@ -975,6 +976,9 @@ update_current_target (void)
de_fault (to_can_use_agent,
(int (*) (void))
return_zero);
+ de_fault (to_augmented_libraries_svr4_read,
+ (int (*) (void))
+ return_zero);
de_fault (to_execution_direction, default_execution_direction);
#undef de_fault
diff --git a/gdb/remote.c b/gdb/remote.c
index 51bf025..e1cf8a4 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -343,6 +343,10 @@ struct remote_state
/* True if the stub can collect strings using tracenz bytecode. */
int string_tracing;
+ /* True if the stub supports qXfer:libraries-svr4:read with a
+ non-empty annex. */
+ int augmented_libraries_svr4_read;
+
/* Nonzero if the user has pressed Ctrl-C, but the target hasn't
responded to that. */
int ctrlc_pending_p;
@@ -3931,6 +3935,16 @@ remote_string_tracing_feature (const struct protocol_feature *feature,
rs->string_tracing = (support == PACKET_ENABLE);
}
+static void
+remote_augmented_libraries_svr4_read_feature
+ (const struct protocol_feature *feature,
+ enum packet_support support, const char *value)
+{
+ struct remote_state *rs = get_remote_state ();
+
+ rs->augmented_libraries_svr4_read = (support == PACKET_ENABLE);
+}
+
static struct protocol_feature remote_protocol_features[] = {
{ "PacketSize", PACKET_DISABLE, remote_packet_size, -1 },
{ "qXfer:auxv:read", PACKET_DISABLE, remote_supported_packet,
@@ -3941,6 +3955,8 @@ static struct protocol_feature remote_protocol_features[] = {
PACKET_qXfer_libraries },
{ "qXfer:libraries-svr4:read", PACKET_DISABLE, remote_supported_packet,
PACKET_qXfer_libraries_svr4 },
+ { "augmented-libraries-svr4-read", PACKET_DISABLE,
+ remote_augmented_libraries_svr4_read_feature, -1 },
{ "qXfer:memory-map:read", PACKET_DISABLE, remote_supported_packet,
PACKET_qXfer_memory_map },
{ "qXfer:spu:read", PACKET_DISABLE, remote_supported_packet,
@@ -11343,6 +11359,14 @@ remote_read_btrace (struct btrace_target_info *tinfo,
return btrace;
}
+static int
+remote_augmented_libraries_svr4_read (void)
+{
+ struct remote_state *rs = get_remote_state ();
+
+ return rs->augmented_libraries_svr4_read;
+}
+
static void
init_remote_ops (void)
{
@@ -11465,6 +11489,8 @@ Specify the serial device it is connected to\n\
remote_ops.to_disable_btrace = remote_disable_btrace;
remote_ops.to_teardown_btrace = remote_teardown_btrace;
remote_ops.to_read_btrace = remote_read_btrace;
+ remote_ops.to_augmented_libraries_svr4_read =
+ remote_augmented_libraries_svr4_read;
}
/* Set up the extended remote vector by making a copy of the standard
^ permalink raw reply [flat|nested] 59+ messages in thread* [RFA 7/7] Linker-debugger interface tests
2013-05-16 14:43 [RFA 0/7] Improved linker-debugger interface Gary Benson
` (3 preceding siblings ...)
2013-05-16 14:48 ` [RFA 4/7] GDB support for new gdbserver functionality Gary Benson
@ 2013-05-16 14:55 ` Gary Benson
2013-05-19 13:45 ` Jan Kratochvil
2013-05-16 14:55 ` [RFA 5/7] Improved linker-debugger interface Gary Benson
` (5 subsequent siblings)
10 siblings, 1 reply; 59+ messages in thread
From: Gary Benson @ 2013-05-16 14:55 UTC (permalink / raw)
To: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 66 bytes --]
This patch adds some testcases for the linker-debugger interface.
[-- Attachment #2: rtld-probes-7-tests-gb.patch --]
[-- Type: text/plain, Size: 13113 bytes --]
2013-05-16 Gary Benson <gbenson@redhat.com>
* gdb.base/break-probes.exp: New file.
* gdb.base/break-probes.c: Likewise.
* gdb.base/break-probes-solib.c: Likewise.
* gdb.base/info-shared.exp: New file.
* gdb.base/info-shared.c: Likewise.
* gdb.base/info-shared-solib1.c: Likewise.
* gdb.base/info-shared-solib2.c: Likewise.
diff --git a/gdb/testsuite/gdb.base/break-probes.exp b/gdb/testsuite/gdb.base/break-probes.exp
new file mode 100644
index 0000000..8372636
--- /dev/null
+++ b/gdb/testsuite/gdb.base/break-probes.exp
@@ -0,0 +1,77 @@
+# Copyright 2013 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/>.
+
+if { [skip_shlib_tests] } {
+ return 0
+}
+
+standard_testfile
+
+set libname $testfile-solib
+set srcfile_lib $srcdir/$subdir/$libname.c
+set binfile_lib [standard_output_file $libname.so]
+
+set normal_bp "_dl_debug_state"
+set probes_bp "dl_main"
+
+if { [gdb_compile_shlib $srcfile_lib $binfile_lib \
+ [list additional_flags=-fPIC]] != "" } {
+ untested "Could not compile $binfile_lib."
+ return -1
+}
+
+if { [prepare_for_testing $testfile.exp $testfile $srcfile \
+ [list additional_flags=-DSHLIB_NAME\=\"$binfile_lib\" libs=-ldl]] } {
+ return -1
+}
+
+# Enable stop-on-solib-events
+gdb_test_no_output "set stop-on-solib-events 1"
+
+# Start the inferior and run to the first stop
+gdb_run_cmd
+gdb_test "" ".*Stopped due to shared library event.*"
+
+# XFAIL if we are not using probes
+set test "ensure using probes"
+set using_probes 0
+gdb_test_multiple "bt" $test {
+ -re "#0 +\[^\r\n\]*\\m(__GI_)?$normal_bp\\M.*$gdb_prompt $" {
+ xfail $test
+ }
+ -re "#0 +\[^\r\n\]*\\m(__GI_)?$probes_bp\\M.*$gdb_prompt $" {
+ pass $test
+ set using_probes 1
+ }
+}
+
+if { $using_probes } {
+ # Run til it loads our library
+ set test "run til our library loads"
+ set loaded_library 0
+ while { !$loaded_library } {
+ gdb_test_multiple "c" $test {
+ -re "Inferior loaded $binfile_lib\\M.*$gdb_prompt $" {
+ pass $test
+ set loaded_library 1
+ }
+ -re "Stopped due to shared library event\\M.*$gdb_prompt $" {
+ }
+ }
+ }
+
+ # Call something to ensure that relocation occurred
+ gdb_test "call foo(23)" "\\\$.* = 31.*\\\M.*"
+}
diff --git a/gdb/testsuite/gdb.base/break-probes.c b/gdb/testsuite/gdb.base/break-probes.c
new file mode 100644
index 0000000..a778099
--- /dev/null
+++ b/gdb/testsuite/gdb.base/break-probes.c
@@ -0,0 +1,26 @@
+/* Copyright 2013 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/>. */
+
+#include <dlfcn.h>
+
+int
+main ()
+{
+ void *handle = dlopen (SHLIB_NAME, RTLD_LAZY);
+
+ dlclose (handle);
+
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.base/break-probes-solib.c b/gdb/testsuite/gdb.base/break-probes-solib.c
new file mode 100644
index 0000000..bdde2db
--- /dev/null
+++ b/gdb/testsuite/gdb.base/break-probes-solib.c
@@ -0,0 +1,22 @@
+/* Copyright 2013 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/>. */
+
+#include <stdio.h>
+
+int
+foo (int n)
+{
+ return n * n / 17;
+}
diff --git a/gdb/testsuite/gdb.base/info-shared.exp b/gdb/testsuite/gdb.base/info-shared.exp
new file mode 100644
index 0000000..1dabb9f
--- /dev/null
+++ b/gdb/testsuite/gdb.base/info-shared.exp
@@ -0,0 +1,145 @@
+# Copyright 2013 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/>.
+
+if { [skip_shlib_tests] } {
+ return 0
+}
+
+standard_testfile
+
+set lib1name $testfile-solib1
+set srcfile_lib1 $srcdir/$subdir/$lib1name.c
+set binfile_lib1 [standard_output_file $lib1name.so]
+set define1 -DSHLIB1_NAME\=\"$binfile_lib1\"
+
+set lib2name $testfile-solib2
+set srcfile_lib2 $srcdir/$subdir/$lib2name.c
+set binfile_lib2 [standard_output_file $lib2name.so]
+set define2 -DSHLIB2_NAME\=\"$binfile_lib2\"
+
+if { [gdb_compile_shlib $srcfile_lib1 $binfile_lib1 \
+ [list additional_flags=-fPIC]] != "" } {
+ untested "Could not compile $binfile_lib1."
+ return -1
+}
+
+if { [gdb_compile_shlib $srcfile_lib2 $binfile_lib2 \
+ [list additional_flags=-fPIC]] != "" } {
+ untested "Could not compile $binfile_lib2."
+ return -1
+}
+
+set cflags "$define1 $define2"
+if { [prepare_for_testing $testfile.exp $testfile $srcfile \
+ [list additional_flags=$cflags libs=-ldl]] } {
+ return -1
+}
+
+# Run "info sharedlibrary" and check for the presence or absence of
+# our libraries.
+proc check_info_shared { test expect1 expect2 } {
+ global lib1name
+ global lib2name
+ global gdb_prompt
+
+ set actual1 0
+ set actual2 0
+
+ gdb_test_multiple "info sharedlibrary" $test {
+ -re $lib1name {
+ set actual1 1
+ exp_continue
+ }
+ -re $lib2name {
+ set actual2 1
+ exp_continue
+ }
+ -re "\r\n$gdb_prompt $" {
+ if { $actual1 == $expect1 && $actual2 == $expect2 } {
+ pass $test
+ } else {
+ fail $test
+ }
+ }
+ }
+}
+
+# Start the inferior, and check neither of the libraries are loaded at
+# the start.
+runto_main
+check_info_shared "info sharedlibrary #1" 0 0
+
+# Set up breakpoints.
+gdb_test "break stop" {Breakpoint [0-9]+ at .*}
+gdb_test_no_output "set breakpoint pending on"
+gdb_test "break foo" {Breakpoint [0-9]+ \(foo\) pending\.}
+gdb_test "break bar" {Breakpoint [0-9]+ \(bar\) pending\.}
+
+# Run to the first stop and check that only the first library is loaded.
+gdb_test "c" {Breakpoint [0-9]+, .* in stop \(\)}
+check_info_shared "info sharedlibrary #2" 1 0
+
+# Run to the second stop and check that both libraries are loaded.
+gdb_test "c" {Breakpoint [0-9]+, .* in stop \(\)}
+check_info_shared "info sharedlibrary #3" 1 1
+
+# Check that the next stop is in foo.
+gdb_test "c" {Breakpoint [0-9]+, .* in foo \(\) from .*}
+
+# Check that the next stop is in bar.
+gdb_test "c" {Breakpoint [0-9]+, .* in bar \(\) from .*}
+
+# Restart the inferior and make sure there are no breakpoint reset
+# errors. These can happen with the probes-based runtime linker
+# interface if the cache is not cleared correctly.
+set test "restart"
+gdb_run_cmd
+gdb_test_multiple "" $test {
+ -re {Start it from the beginning\? \(y or n\) } {
+ send_gdb "y\n"
+ exp_continue
+ }
+ -re {Error in re-setting breakpoint} {
+ fail $test
+ }
+ -re "\r\n$gdb_prompt $" {
+ pass $test
+ }
+}
+
+# Check that neither library is loaded.
+check_info_shared "info sharedlibrary #4" 0 0
+
+# Run to the first stop and check that only the first library is loaded.
+gdb_test "c" {Breakpoint [0-9]+, .* in stop \(\)}
+check_info_shared "info sharedlibrary #5" 1 0
+
+# Run to the second stop and check that both libraries are loaded.
+gdb_test "c" {Breakpoint [0-9]+, .* in stop \(\)}
+check_info_shared "info sharedlibrary #6" 1 1
+
+# Check that the next stop is in foo.
+gdb_test "c" {Breakpoint [0-9]+, .* in foo \(\) from .*}
+
+# Check that the next stop is in bar.
+gdb_test "c" {Breakpoint [0-9]+, .* in bar \(\) from .*}
+
+# Run to the next stop and check that the first library has been unloaded.
+gdb_test "c" {Breakpoint [0-9]+, .* in stop \(\)}
+check_info_shared "info sharedlibrary #7" 0 1
+
+# Run to the last stop and check that both libraries are gone.
+gdb_test "c" {Breakpoint [0-9]+, .* in stop \(\)}
+check_info_shared "info sharedlibrary #8" 0 0
diff --git a/gdb/testsuite/gdb.base/info-shared.c b/gdb/testsuite/gdb.base/info-shared.c
new file mode 100644
index 0000000..d699a11
--- /dev/null
+++ b/gdb/testsuite/gdb.base/info-shared.c
@@ -0,0 +1,48 @@
+/* Copyright 2013 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/>. */
+
+#include <dlfcn.h>
+
+void
+stop ()
+{
+}
+
+int
+main ()
+{
+ void *handle1, *handle2;
+ void (*func)(int);
+
+ handle1 = dlopen (SHLIB1_NAME, RTLD_LAZY);
+ stop ();
+
+ handle2 = dlopen (SHLIB2_NAME, RTLD_LAZY);
+ stop ();
+
+ func = (void (*)(int)) dlsym (handle1, "foo");
+ func (1);
+
+ func = (void (*)(int)) dlsym (handle2, "bar");
+ func (2);
+
+ dlclose (handle1);
+ stop ();
+
+ dlclose (handle2);
+ stop ();
+
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.base/info-shared-solib1.c b/gdb/testsuite/gdb.base/info-shared-solib1.c
new file mode 100644
index 0000000..9979ee7
--- /dev/null
+++ b/gdb/testsuite/gdb.base/info-shared-solib1.c
@@ -0,0 +1,24 @@
+/* Copyright 2013 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/>. */
+
+#include <stdio.h>
+
+int
+foo (int n)
+{
+ printf ("foo %d\n", n);
+
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.base/info-shared-solib2.c b/gdb/testsuite/gdb.base/info-shared-solib2.c
new file mode 100644
index 0000000..d4ed1e6
--- /dev/null
+++ b/gdb/testsuite/gdb.base/info-shared-solib2.c
@@ -0,0 +1,24 @@
+/* Copyright 2013 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/>. */
+
+#include <stdio.h>
+
+int
+bar (int n)
+{
+ printf ("bar %d\n", n);
+
+ return 0;
+}
^ permalink raw reply [flat|nested] 59+ messages in thread* Re: [RFA 7/7] Linker-debugger interface tests
2013-05-16 14:55 ` [RFA 7/7] Linker-debugger interface tests Gary Benson
@ 2013-05-19 13:45 ` Jan Kratochvil
2013-05-19 16:43 ` Jan Kratochvil
2013-05-24 8:38 ` [RFA 7/7 take 2] " Gary Benson
0 siblings, 2 replies; 59+ messages in thread
From: Jan Kratochvil @ 2013-05-19 13:45 UTC (permalink / raw)
To: gdb-patches
On Thu, 16 May 2013 16:48:57 +0200, Gary Benson wrote:
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/break-probes.exp
> @@ -0,0 +1,77 @@
> +# Copyright 2013 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/>.
> +
> +if { [skip_shlib_tests] } {
> + return 0
> +}
> +
> +standard_testfile
> +
> +set libname $testfile-solib
> +set srcfile_lib $srcdir/$subdir/$libname.c
> +set binfile_lib [standard_output_file $libname.so]
> +
> +set normal_bp "_dl_debug_state"
> +set probes_bp "dl_main"
> +
> +if { [gdb_compile_shlib $srcfile_lib $binfile_lib \
> + [list additional_flags=-fPIC]] != "" } {
> + untested "Could not compile $binfile_lib."
> + return -1
> +}
> +
> +if { [prepare_for_testing $testfile.exp $testfile $srcfile \
> + [list additional_flags=-DSHLIB_NAME\=\"$binfile_lib\" libs=-ldl]] } {
There is an excessive backslash at the '=' sign:
[list additional_flags=-DSHLIB_NAME=\"$binfile_lib\" libs=-ldl]] } {
> + return -1
> +}
> +
> +# Enable stop-on-solib-events
> +gdb_test_no_output "set stop-on-solib-events 1"
> +
> +# Start the inferior and run to the first stop
> +gdb_run_cmd
> +gdb_test "" ".*Stopped due to shared library event.*"
> +
> +# XFAIL if we are not using probes
> +set test "ensure using probes"
> +set using_probes 0
> +gdb_test_multiple "bt" $test {
> + -re "#0 +\[^\r\n\]*\\m(__GI_)?$normal_bp\\M.*$gdb_prompt $" {
> + xfail $test
One should also call: untested "probes not present on this system"
or: xfail "$test (probes not present on this system)"
> + }
> + -re "#0 +\[^\r\n\]*\\m(__GI_)?$probes_bp\\M.*$gdb_prompt $" {
> + pass $test
> + set using_probes 1
> + }
> +}
> +
> +if { $using_probes } {
> + # Run til it loads our library
> + set test "run til our library loads"
> + set loaded_library 0
> + while { !$loaded_library } {
> + gdb_test_multiple "c" $test {
> + -re "Inferior loaded $binfile_lib\\M.*$gdb_prompt $" {
> + pass $test
> + set loaded_library 1
> + }
> + -re "Stopped due to shared library event\\M.*$gdb_prompt $" {
> + }
> + }
> + }
If for some reason the 'pass $test' part never happens the testcase deadlocks:
FAIL: gdb.base/break-probes.exp: run til our library loads (the program is no longer running)
FAIL: gdb.base/break-probes.exp: run til our library loads (the program is no longer running)
FAIL: gdb.base/break-probes.exp: run til our library loads (the program is no longer running)
[... ad infinitum ]
One of the solutions would be for example:
set not_loaded_library 1
while { $not_loaded_library } {
set not_loaded_library 0
gdb_test_multiple "c" $test {
-re "Inferior loaded $binfile_lib\\M.*$gdb_prompt $" {
pass $test
}
-re "Stopped due to shared library event\\M.*$gdb_prompt $" {
set not_loaded_library 1
}
}
}
> +
> + # Call something to ensure that relocation occurred
> + gdb_test "call foo(23)" "\\\$.* = 31.*\\\M.*"
> +}
> diff --git a/gdb/testsuite/gdb.base/break-probes.c b/gdb/testsuite/gdb.base/break-probes.c
> new file mode 100644
> index 0000000..a778099
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/break-probes.c
> @@ -0,0 +1,26 @@
> +/* Copyright 2013 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/>. */
> +
> +#include <dlfcn.h>
> +
> +int
> +main ()
> +{
> + void *handle = dlopen (SHLIB_NAME, RTLD_LAZY);
> +
> + dlclose (handle);
> +
> + return 0;
> +}
> diff --git a/gdb/testsuite/gdb.base/break-probes-solib.c b/gdb/testsuite/gdb.base/break-probes-solib.c
> new file mode 100644
> index 0000000..bdde2db
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/break-probes-solib.c
> @@ -0,0 +1,22 @@
> +/* Copyright 2013 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/>. */
> +
> +#include <stdio.h>
> +
> +int
> +foo (int n)
> +{
> + return n * n / 17;
> +}
> diff --git a/gdb/testsuite/gdb.base/info-shared.exp b/gdb/testsuite/gdb.base/info-shared.exp
> new file mode 100644
> index 0000000..1dabb9f
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/info-shared.exp
> @@ -0,0 +1,145 @@
> +# Copyright 2013 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/>.
> +
> +if { [skip_shlib_tests] } {
> + return 0
> +}
> +
> +standard_testfile
> +
> +set lib1name $testfile-solib1
> +set srcfile_lib1 $srcdir/$subdir/$lib1name.c
> +set binfile_lib1 [standard_output_file $lib1name.so]
> +set define1 -DSHLIB1_NAME\=\"$binfile_lib1\"
Again an excessive backslash before '=', what reason do you see there for it?
> +
> +set lib2name $testfile-solib2
> +set srcfile_lib2 $srcdir/$subdir/$lib2name.c
> +set binfile_lib2 [standard_output_file $lib2name.so]
> +set define2 -DSHLIB2_NAME\=\"$binfile_lib2\"
Again an excessive backslash before '=', what reason do you see there for it?
> +
> +if { [gdb_compile_shlib $srcfile_lib1 $binfile_lib1 \
> + [list additional_flags=-fPIC]] != "" } {
> + untested "Could not compile $binfile_lib1."
> + return -1
> +}
> +
> +if { [gdb_compile_shlib $srcfile_lib2 $binfile_lib2 \
> + [list additional_flags=-fPIC]] != "" } {
> + untested "Could not compile $binfile_lib2."
> + return -1
> +}
> +
> +set cflags "$define1 $define2"
> +if { [prepare_for_testing $testfile.exp $testfile $srcfile \
> + [list additional_flags=$cflags libs=-ldl]] } {
> + return -1
> +}
> +
> +# Run "info sharedlibrary" and check for the presence or absence of
> +# our libraries.
> +proc check_info_shared { test expect1 expect2 } {
> + global lib1name
> + global lib2name
> + global gdb_prompt
> +
> + set actual1 0
> + set actual2 0
> +
> + gdb_test_multiple "info sharedlibrary" $test {
> + -re $lib1name {
> + set actual1 1
> + exp_continue
> + }
> + -re $lib2name {
> + set actual2 1
> + exp_continue
> + }
> + -re "\r\n$gdb_prompt $" {
> + if { $actual1 == $expect1 && $actual2 == $expect2 } {
> + pass $test
> + } else {
> + fail $test
> + }
> + }
> + }
> +}
> +
> +# Start the inferior, and check neither of the libraries are loaded at
> +# the start.
> +runto_main
if ![runto_main] {
return 0
}
> +check_info_shared "info sharedlibrary #1" 0 0
> +
> +# Set up breakpoints.
> +gdb_test "break stop" {Breakpoint [0-9]+ at .*}
gdb_breakpoint ...
More cases below.
> +gdb_test_no_output "set breakpoint pending on"
gdb_breakpoint XXX allow-pending
> +gdb_test "break foo" {Breakpoint [0-9]+ \(foo\) pending\.}
> +gdb_test "break bar" {Breakpoint [0-9]+ \(bar\) pending\.}
> +
> +# Run to the first stop and check that only the first library is loaded.
> +gdb_test "c" {Breakpoint [0-9]+, .* in stop \(\)}
gdb_continue_to_breakpoint
More cases below.
> +check_info_shared "info sharedlibrary #2" 1 0
> +
> +# Run to the second stop and check that both libraries are loaded.
> +gdb_test "c" {Breakpoint [0-9]+, .* in stop \(\)}
> +check_info_shared "info sharedlibrary #3" 1 1
> +
> +# Check that the next stop is in foo.
> +gdb_test "c" {Breakpoint [0-9]+, .* in foo \(\) from .*}
> +
> +# Check that the next stop is in bar.
> +gdb_test "c" {Breakpoint [0-9]+, .* in bar \(\) from .*}
> +
> +# Restart the inferior and make sure there are no breakpoint reset
> +# errors. These can happen with the probes-based runtime linker
> +# interface if the cache is not cleared correctly.
> +set test "restart"
> +gdb_run_cmd
> +gdb_test_multiple "" $test {
> + -re {Start it from the beginning\? \(y or n\) } {
trailing '$':
-re {Start it from the beginning\? \(y or n\) $} {
> + send_gdb "y\n"
> + exp_continue
> + }
> + -re {Error in re-setting breakpoint} {
> + fail $test
> + }
> + -re "\r\n$gdb_prompt $" {
> + pass $test
> + }
> +}
> +
> +# Check that neither library is loaded.
> +check_info_shared "info sharedlibrary #4" 0 0
> +
> +# Run to the first stop and check that only the first library is loaded.
> +gdb_test "c" {Breakpoint [0-9]+, .* in stop \(\)}
> +check_info_shared "info sharedlibrary #5" 1 0
> +
> +# Run to the second stop and check that both libraries are loaded.
> +gdb_test "c" {Breakpoint [0-9]+, .* in stop \(\)}
> +check_info_shared "info sharedlibrary #6" 1 1
> +
> +# Check that the next stop is in foo.
> +gdb_test "c" {Breakpoint [0-9]+, .* in foo \(\) from .*}
> +
> +# Check that the next stop is in bar.
> +gdb_test "c" {Breakpoint [0-9]+, .* in bar \(\) from .*}
> +
> +# Run to the next stop and check that the first library has been unloaded.
> +gdb_test "c" {Breakpoint [0-9]+, .* in stop \(\)}
> +check_info_shared "info sharedlibrary #7" 0 1
> +
> +# Run to the last stop and check that both libraries are gone.
> +gdb_test "c" {Breakpoint [0-9]+, .* in stop \(\)}
> +check_info_shared "info sharedlibrary #8" 0 0
> diff --git a/gdb/testsuite/gdb.base/info-shared.c b/gdb/testsuite/gdb.base/info-shared.c
> new file mode 100644
> index 0000000..d699a11
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/info-shared.c
> @@ -0,0 +1,48 @@
> +/* Copyright 2013 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/>. */
> +
> +#include <dlfcn.h>
> +
> +void
> +stop ()
stop (void)
> +{
> +}
> +
> +int
> +main ()
main (void)
> +{
> + void *handle1, *handle2;
> + void (*func)(int);
> +
> + handle1 = dlopen (SHLIB1_NAME, RTLD_LAZY);
I believe here could be:
assert (handle1 != NULL);
etc. below, if it fails the troubleshooting is easier then.
> + stop ();
> +
> + handle2 = dlopen (SHLIB2_NAME, RTLD_LAZY);
> + stop ();
> +
> + func = (void (*)(int)) dlsym (handle1, "foo");
> + func (1);
> +
> + func = (void (*)(int)) dlsym (handle2, "bar");
> + func (2);
> +
> + dlclose (handle1);
> + stop ();
> +
> + dlclose (handle2);
> + stop ();
> +
> + return 0;
> +}
> diff --git a/gdb/testsuite/gdb.base/info-shared-solib1.c b/gdb/testsuite/gdb.base/info-shared-solib1.c
> new file mode 100644
> index 0000000..9979ee7
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/info-shared-solib1.c
> @@ -0,0 +1,24 @@
> +/* Copyright 2013 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/>. */
> +
> +#include <stdio.h>
> +
> +int
> +foo (int n)
> +{
> + printf ("foo %d\n", n);
> +
> + return 0;
> +}
> diff --git a/gdb/testsuite/gdb.base/info-shared-solib2.c b/gdb/testsuite/gdb.base/info-shared-solib2.c
> new file mode 100644
> index 0000000..d4ed1e6
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/info-shared-solib2.c
> @@ -0,0 +1,24 @@
> +/* Copyright 2013 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/>. */
> +
> +#include <stdio.h>
> +
> +int
> +bar (int n)
> +{
> + printf ("bar %d\n", n);
> +
> + return 0;
> +}
Thanks,
Jan
^ permalink raw reply [flat|nested] 59+ messages in thread* Re: [RFA 7/7] Linker-debugger interface tests
2013-05-19 13:45 ` Jan Kratochvil
@ 2013-05-19 16:43 ` Jan Kratochvil
2013-05-24 8:38 ` [RFA 7/7 take 2] " Gary Benson
1 sibling, 0 replies; 59+ messages in thread
From: Jan Kratochvil @ 2013-05-19 16:43 UTC (permalink / raw)
To: gdb-patches
On Sun, 19 May 2013 15:45:09 +0200, Jan Kratochvil wrote:
> On Thu, 16 May 2013 16:48:57 +0200, Gary Benson wrote:
> > +gdb_test "break foo" {Breakpoint [0-9]+ \(foo\) pending\.}
> > +gdb_test "break bar" {Breakpoint [0-9]+ \(bar\) pending\.}
> > +
> > +# Run to the first stop and check that only the first library is loaded.
> > +gdb_test "c" {Breakpoint [0-9]+, .* in stop \(\)}
>
> gdb_continue_to_breakpoint
>
> More cases below.
Also testcase names should be unique, the current gdb.sum is:
PASS: gdb.base/info-shared.exp: c
PASS: gdb.base/info-shared.exp: info sharedlibrary #2
PASS: gdb.base/info-shared.exp: c
PASS: gdb.base/info-shared.exp: info sharedlibrary #3
PASS: gdb.base/info-shared.exp: c
PASS: gdb.base/info-shared.exp: c
[...]
Regards,
Jan
^ permalink raw reply [flat|nested] 59+ messages in thread* [RFA 7/7 take 2] Linker-debugger interface tests
2013-05-19 13:45 ` Jan Kratochvil
2013-05-19 16:43 ` Jan Kratochvil
@ 2013-05-24 8:38 ` Gary Benson
2013-05-24 8:58 ` Jan Kratochvil
2013-05-25 21:06 ` [RFA 7/7 take 2] Linker-debugger interface tests Jan Kratochvil
1 sibling, 2 replies; 59+ messages in thread
From: Gary Benson @ 2013-05-24 8:38 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 265 bytes --]
Attached an updated patch with all issues fixed as suggested.
The excessive backslashes were copied and pasted from somewhere.
"fgrep -r '\=' gdb/testsuite" reveals three existing files with
it. Would you like me to commit an obvious fix for these?
Thanks,
Gary
[-- Attachment #2: rtld-probes-7-tests-gb.patch --]
[-- Type: text/plain, Size: 13317 bytes --]
2013-05-23 Gary Benson <gbenson@redhat.com>
* gdb.base/break-probes.exp: New file.
* gdb.base/break-probes.c: Likewise.
* gdb.base/break-probes-solib.c: Likewise.
* gdb.base/info-shared.exp: New file.
* gdb.base/info-shared.c: Likewise.
* gdb.base/info-shared-solib1.c: Likewise.
* gdb.base/info-shared-solib2.c: Likewise.
diff --git a/gdb/testsuite/gdb.base/break-probes.exp b/gdb/testsuite/gdb.base/break-probes.exp
new file mode 100644
index 0000000..aa9d28f
--- /dev/null
+++ b/gdb/testsuite/gdb.base/break-probes.exp
@@ -0,0 +1,78 @@
+# Copyright 2013 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/>.
+
+if { [skip_shlib_tests] } {
+ return 0
+}
+
+standard_testfile
+
+set libname $testfile-solib
+set srcfile_lib $srcdir/$subdir/$libname.c
+set binfile_lib [standard_output_file $libname.so]
+
+set normal_bp "_dl_debug_state"
+set probes_bp "dl_main"
+
+if { [gdb_compile_shlib $srcfile_lib $binfile_lib \
+ [list additional_flags=-fPIC]] != "" } {
+ untested "Could not compile $binfile_lib."
+ return -1
+}
+
+if { [prepare_for_testing $testfile.exp $testfile $srcfile \
+ [list additional_flags=-DSHLIB_NAME=\"$binfile_lib\" libs=-ldl]] } {
+ return -1
+}
+
+# Enable stop-on-solib-events
+gdb_test_no_output "set stop-on-solib-events 1"
+
+# Start the inferior and run to the first stop
+gdb_run_cmd
+gdb_test "" ".*Stopped due to shared library event.*"
+
+# XFAIL if we are not using probes
+set test "ensure using probes"
+set using_probes 0
+gdb_test_multiple "bt" $test {
+ -re "#0 +\[^\r\n\]*\\m(__GI_)?$normal_bp\\M.*$gdb_prompt $" {
+ untested "probes not present on this system"
+ }
+ -re "#0 +\[^\r\n\]*\\m(__GI_)?$probes_bp\\M.*$gdb_prompt $" {
+ pass $test
+ set using_probes 1
+ }
+}
+
+if { $using_probes } {
+ # Run til it loads our library
+ set test "run til our library loads"
+ set not_loaded_library 1
+ while { $not_loaded_library } {
+ set not_loaded_library 0
+ gdb_test_multiple "c" $test {
+ -re "Inferior loaded $binfile_lib\\M.*$gdb_prompt $" {
+ pass $test
+ }
+ -re "Stopped due to shared library event\\M.*$gdb_prompt $" {
+ set not_loaded_library 1
+ }
+ }
+ }
+
+ # Call something to ensure that relocation occurred
+ gdb_test "call foo(23)" "\\\$.* = 31.*\\\M.*"
+}
diff --git a/gdb/testsuite/gdb.base/break-probes.c b/gdb/testsuite/gdb.base/break-probes.c
new file mode 100644
index 0000000..5f9cdbb
--- /dev/null
+++ b/gdb/testsuite/gdb.base/break-probes.c
@@ -0,0 +1,30 @@
+/* Copyright 2013 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/>. */
+
+#include <dlfcn.h>
+#include <assert.h>
+#include <stddef.h>
+
+int
+main (void)
+{
+ void *handle = dlopen (SHLIB_NAME, RTLD_LAZY);
+
+ assert (handle != NULL);
+
+ dlclose (handle);
+
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.base/break-probes-solib.c b/gdb/testsuite/gdb.base/break-probes-solib.c
new file mode 100644
index 0000000..bdde2db
--- /dev/null
+++ b/gdb/testsuite/gdb.base/break-probes-solib.c
@@ -0,0 +1,22 @@
+/* Copyright 2013 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/>. */
+
+#include <stdio.h>
+
+int
+foo (int n)
+{
+ return n * n / 17;
+}
diff --git a/gdb/testsuite/gdb.base/info-shared.exp b/gdb/testsuite/gdb.base/info-shared.exp
new file mode 100644
index 0000000..c579a5e
--- /dev/null
+++ b/gdb/testsuite/gdb.base/info-shared.exp
@@ -0,0 +1,146 @@
+# Copyright 2013 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/>.
+
+if { [skip_shlib_tests] } {
+ return 0
+}
+
+standard_testfile
+
+set lib1name $testfile-solib1
+set srcfile_lib1 $srcdir/$subdir/$lib1name.c
+set binfile_lib1 [standard_output_file $lib1name.so]
+set define1 -DSHLIB1_NAME=\"$binfile_lib1\"
+
+set lib2name $testfile-solib2
+set srcfile_lib2 $srcdir/$subdir/$lib2name.c
+set binfile_lib2 [standard_output_file $lib2name.so]
+set define2 -DSHLIB2_NAME=\"$binfile_lib2\"
+
+if { [gdb_compile_shlib $srcfile_lib1 $binfile_lib1 \
+ [list additional_flags=-fPIC]] != "" } {
+ untested "Could not compile $binfile_lib1."
+ return -1
+}
+
+if { [gdb_compile_shlib $srcfile_lib2 $binfile_lib2 \
+ [list additional_flags=-fPIC]] != "" } {
+ untested "Could not compile $binfile_lib2."
+ return -1
+}
+
+set cflags "$define1 $define2"
+if { [prepare_for_testing $testfile.exp $testfile $srcfile \
+ [list additional_flags=$cflags libs=-ldl]] } {
+ return -1
+}
+
+# Run "info sharedlibrary" and check for the presence or absence of
+# our libraries.
+proc check_info_shared { test expect1 expect2 } {
+ global lib1name
+ global lib2name
+ global gdb_prompt
+
+ set actual1 0
+ set actual2 0
+
+ gdb_test_multiple "info sharedlibrary" $test {
+ -re $lib1name {
+ set actual1 1
+ exp_continue
+ }
+ -re $lib2name {
+ set actual2 1
+ exp_continue
+ }
+ -re "\r\n$gdb_prompt $" {
+ if { $actual1 == $expect1 && $actual2 == $expect2 } {
+ pass $test
+ } else {
+ fail $test
+ }
+ }
+ }
+}
+
+# Start the inferior, and check neither of the libraries are loaded at
+# the start.
+if ![runto_main] {
+ return 0
+}
+check_info_shared "info sharedlibrary #1" 0 0
+
+# Set up breakpoints.
+gdb_breakpoint "stop"
+gdb_breakpoint "foo" allow-pending
+gdb_breakpoint "bar" allow-pending
+
+# Run to the first stop and check that only the first library is loaded.
+gdb_continue_to_breakpoint "library load #1" ".*stop.*"
+check_info_shared "info sharedlibrary #2" 1 0
+
+# Run to the second stop and check that both libraries are loaded.
+gdb_continue_to_breakpoint "library load #2" ".*stop.*"
+check_info_shared "info sharedlibrary #3" 1 1
+
+# Check that the next stop is in foo.
+gdb_continue_to_breakpoint "library function #1" ".*foo.*"
+
+# Check that the next stop is in bar.
+gdb_continue_to_breakpoint "library function #2" ".*bar.*"
+
+# Restart the inferior and make sure there are no breakpoint reset
+# errors. These can happen with the probes-based runtime linker
+# interface if the cache is not cleared correctly.
+set test "restart"
+gdb_run_cmd
+gdb_test_multiple "" $test {
+ -re {Start it from the beginning\? \(y or n\) $} {
+ send_gdb "y\n"
+ exp_continue
+ }
+ -re {Error in re-setting breakpoint} {
+ fail $test
+ }
+ -re "\r\n$gdb_prompt $" {
+ pass $test
+ }
+}
+
+# Check that neither library is loaded.
+check_info_shared "info sharedlibrary #4" 0 0
+
+# Run to the first stop and check that only the first library is loaded.
+gdb_continue_to_breakpoint "library load #3" ".*stop.*"
+check_info_shared "info sharedlibrary #5" 1 0
+
+# Run to the second stop and check that both libraries are loaded.
+gdb_continue_to_breakpoint "library load #4" ".*stop.*"
+check_info_shared "info sharedlibrary #6" 1 1
+
+# Check that the next stop is in foo.
+gdb_continue_to_breakpoint "library function #3" ".*foo.*"
+
+# Check that the next stop is in bar.
+gdb_continue_to_breakpoint "library function #4" ".*bar.*"
+
+# Run to the next stop and check that the first library has been unloaded.
+gdb_continue_to_breakpoint "library unload #1" ".*stop.*"
+check_info_shared "info sharedlibrary #7" 0 1
+
+# Run to the last stop and check that both libraries are gone.
+gdb_continue_to_breakpoint "library unload #2" ".*stop.*"
+check_info_shared "info sharedlibrary #8" 0 0
diff --git a/gdb/testsuite/gdb.base/info-shared.c b/gdb/testsuite/gdb.base/info-shared.c
new file mode 100644
index 0000000..1eec7be
--- /dev/null
+++ b/gdb/testsuite/gdb.base/info-shared.c
@@ -0,0 +1,52 @@
+/* Copyright 2013 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/>. */
+
+#include <dlfcn.h>
+#include <assert.h>
+#include <stddef.h>
+
+void
+stop (void)
+{
+}
+
+int
+main (void)
+{
+ void *handle1, *handle2;
+ void (*func)(int);
+
+ handle1 = dlopen (SHLIB1_NAME, RTLD_LAZY);
+ assert (handle1 != NULL);
+ stop ();
+
+ handle2 = dlopen (SHLIB2_NAME, RTLD_LAZY);
+ assert (handle2 != NULL);
+ stop ();
+
+ func = (void (*)(int)) dlsym (handle1, "foo");
+ func (1);
+
+ func = (void (*)(int)) dlsym (handle2, "bar");
+ func (2);
+
+ dlclose (handle1);
+ stop ();
+
+ dlclose (handle2);
+ stop ();
+
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.base/info-shared-solib1.c b/gdb/testsuite/gdb.base/info-shared-solib1.c
new file mode 100644
index 0000000..9979ee7
--- /dev/null
+++ b/gdb/testsuite/gdb.base/info-shared-solib1.c
@@ -0,0 +1,24 @@
+/* Copyright 2013 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/>. */
+
+#include <stdio.h>
+
+int
+foo (int n)
+{
+ printf ("foo %d\n", n);
+
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.base/info-shared-solib2.c b/gdb/testsuite/gdb.base/info-shared-solib2.c
new file mode 100644
index 0000000..d4ed1e6
--- /dev/null
+++ b/gdb/testsuite/gdb.base/info-shared-solib2.c
@@ -0,0 +1,24 @@
+/* Copyright 2013 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/>. */
+
+#include <stdio.h>
+
+int
+bar (int n)
+{
+ printf ("bar %d\n", n);
+
+ return 0;
+}
^ permalink raw reply [flat|nested] 59+ messages in thread* Re: [RFA 7/7 take 2] Linker-debugger interface tests
2013-05-24 8:38 ` [RFA 7/7 take 2] " Gary Benson
@ 2013-05-24 8:58 ` Jan Kratochvil
2013-05-24 14:05 ` [obv] Fix excessive backslashes in testsuite Gary Benson
2013-05-25 21:06 ` [RFA 7/7 take 2] Linker-debugger interface tests Jan Kratochvil
1 sibling, 1 reply; 59+ messages in thread
From: Jan Kratochvil @ 2013-05-24 8:58 UTC (permalink / raw)
To: gdb-patches
On Fri, 24 May 2013 10:38:37 +0200, Gary Benson wrote:
> Attached an updated patch with all issues fixed as suggested.
To be replied later.
> The excessive backslashes were copied and pasted from somewhere.
> "fgrep -r '\=' gdb/testsuite" reveals three existing files with
> it. Would you like me to commit an obvious fix for these?
Yes.
$ fgrep -r '\=' gdb/testsuite
gdb/testsuite/gdb.base/unload.exp:set exec_opts [list debug shlib_load additional_flags=-DSHLIB_NAME\=\"${lib_dlopen}\" additional_flags=-DSHLIB_NAME2\=\"${lib_dlopen2}\"]
gdb/testsuite/gdb.base/solib-disc.exp:set exec_opts [list debug shlib_load additional_flags=-DSHLIB_NAME\=\"${lib_dlopen}\"]
gdb/testsuite/gdb.base/watchpoint-solib.exp:set exec_opts [list debug shlib_load additional_flags=-DSHLIB_NAME\=\"${lib_dlopen}\"]
Thanks,
Jan
^ permalink raw reply [flat|nested] 59+ messages in thread* [obv] Fix excessive backslashes in testsuite
2013-05-24 8:58 ` Jan Kratochvil
@ 2013-05-24 14:05 ` Gary Benson
0 siblings, 0 replies; 59+ messages in thread
From: Gary Benson @ 2013-05-24 14:05 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 340 bytes --]
Jan Kratochvil wrote:
> On Fri, 24 May 2013 10:38:37 +0200, Gary Benson wrote:
> > The excessive backslashes were copied and pasted from somewhere.
> > "fgrep -r '\=' gdb/testsuite" reveals three existing files with
> > it. Would you like me to commit an obvious fix for these?
>
> Yes.
Committed.
Thanks,
Gary
--
http://gbenson.net/
[-- Attachment #2: patch --]
[-- Type: text/plain, Size: 2808 bytes --]
Index: ChangeLog
===================================================================
RCS file: /cvs/src/src/gdb/testsuite/ChangeLog,v
retrieving revision 1.3679
diff -u -r1.3679 ChangeLog
--- ChangeLog 24 May 2013 12:27:39 -0000 1.3679
+++ ChangeLog 24 May 2013 14:00:55 -0000
@@ -1,3 +1,12 @@
+2013-05-24 Gary Benson <gbenson@redhat.com>
+
+ * gdb.base/solib-disc.exp (exec_opts): Remove unnecesary
+ backslash.
+ * gdb.base/unload.exp (exec_opts): Remove two unnecessary
+ backslashes.
+ * gdb.base/watchpoint-solib.exp (exec_opts): Remove unnecesary
+ backslash.
+
2013-05-24 Yao Qi <yao@codesourcery.com>
* gdb.trace/tfile.exp: Test inferior and thread.
Index: gdb.base/solib-disc.exp
===================================================================
RCS file: /cvs/src/src/gdb/testsuite/gdb.base/solib-disc.exp,v
retrieving revision 1.13
diff -u -r1.13 solib-disc.exp
--- gdb.base/solib-disc.exp 1 Jan 2013 06:33:26 -0000 1.13
+++ gdb.base/solib-disc.exp 24 May 2013 14:00:56 -0000
@@ -42,7 +42,7 @@
return -1
}
-set exec_opts [list debug shlib_load additional_flags=-DSHLIB_NAME\=\"${lib_dlopen}\"]
+set exec_opts [list debug shlib_load additional_flags=-DSHLIB_NAME=\"${lib_dlopen}\"]
if { [gdb_compile_shlib $libsrc $libobj {debug}] != ""
|| [gdb_compile $execsrc ${binfile} executable $exec_opts] != "" } {
Index: gdb.base/unload.exp
===================================================================
RCS file: /cvs/src/src/gdb/testsuite/gdb.base/unload.exp,v
retrieving revision 1.26
diff -u -r1.26 unload.exp
--- gdb.base/unload.exp 1 Jan 2013 06:33:26 -0000 1.26
+++ gdb.base/unload.exp 24 May 2013 14:00:56 -0000
@@ -47,7 +47,7 @@
}
set lib_opts debug
-set exec_opts [list debug shlib_load additional_flags=-DSHLIB_NAME\=\"${lib_dlopen}\" additional_flags=-DSHLIB_NAME2\=\"${lib_dlopen2}\"]
+set exec_opts [list debug shlib_load additional_flags=-DSHLIB_NAME=\"${lib_dlopen}\" additional_flags=-DSHLIB_NAME2=\"${lib_dlopen2}\"]
if { [gdb_compile_shlib $libsrc $lib_sl $lib_opts] != ""
|| [gdb_compile_shlib $libsrc2 $lib_sl2 $lib_opts] != ""
Index: gdb.base/watchpoint-solib.exp
===================================================================
RCS file: /cvs/src/src/gdb/testsuite/gdb.base/watchpoint-solib.exp,v
retrieving revision 1.14
diff -u -r1.14 watchpoint-solib.exp
--- gdb.base/watchpoint-solib.exp 1 Jan 2013 06:33:26 -0000 1.14
+++ gdb.base/watchpoint-solib.exp 24 May 2013 14:00:56 -0000
@@ -38,7 +38,7 @@
}
set lib_opts debug
-set exec_opts [list debug shlib_load additional_flags=-DSHLIB_NAME\=\"${lib_dlopen}\"]
+set exec_opts [list debug shlib_load additional_flags=-DSHLIB_NAME=\"${lib_dlopen}\"]
if { [gdb_compile_shlib $libsrc $lib_sl $lib_opts] != ""
|| [gdb_compile $srcfile $binfile executable $exec_opts] != ""} {
^ permalink raw reply [flat|nested] 59+ messages in thread
* Re: [RFA 7/7 take 2] Linker-debugger interface tests
2013-05-24 8:38 ` [RFA 7/7 take 2] " Gary Benson
2013-05-24 8:58 ` Jan Kratochvil
@ 2013-05-25 21:06 ` Jan Kratochvil
1 sibling, 0 replies; 59+ messages in thread
From: Jan Kratochvil @ 2013-05-25 21:06 UTC (permalink / raw)
To: gdb-patches
On Fri, 24 May 2013 10:38:37 +0200, Gary Benson wrote:
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/info-shared.exp
[...]
> +# Set up breakpoints.
> +gdb_breakpoint "stop"
> +gdb_breakpoint "foo" allow-pending
> +gdb_breakpoint "bar" allow-pending
> +
> +# Run to the first stop and check that only the first library is loaded.
> +gdb_continue_to_breakpoint "library load #1" ".*stop.*"
All these regexes please replace by:
s/"\.\*\([a-z]*\)\.\*"/"\1 .*"/
that is
"stop .*"
and others below; it is matched even against the printed source line where it
could have same false positive with the leading '.*'.
OK for check-in with these changes.
Thanks,
Jan
^ permalink raw reply [flat|nested] 59+ messages in thread
* [RFA 5/7] Improved linker-debugger interface
2013-05-16 14:43 [RFA 0/7] Improved linker-debugger interface Gary Benson
` (4 preceding siblings ...)
2013-05-16 14:55 ` [RFA 7/7] Linker-debugger interface tests Gary Benson
@ 2013-05-16 14:55 ` Gary Benson
2013-05-17 19:05 ` Jan Kratochvil
2013-05-16 14:55 ` [RFA 6/7] Linker-debugger interface tests by Jan Gary Benson
` (4 subsequent siblings)
10 siblings, 1 reply; 59+ messages in thread
From: Gary Benson @ 2013-05-16 14:55 UTC (permalink / raw)
To: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 738 bytes --]
This patch implements the probes-based runtime linker interface.
It works as follows:
- On inferior startup, GDB searches the dynamic linker for a
number of named probes.
- If all probes are found, GDB sets a breakpoint on each one.
Otherwise, the standard function _dl_debug_state is used.
- When using probes, a per-pspace list is maintained of all
libraries currently loaded by the inferior. It's updated
as necessary every time a solib event stop occurs.
- When using probes, svr4_current_sos will return a copy of
the cached list. When not using probes the entire list
will be fetched from the inferior as before.
- If any error occurs, GDB will print a warning and revert to
the standard interface.
[-- Attachment #2: rtld-probes-5-main-changes.patch --]
[-- Type: text/plain, Size: 32099 bytes --]
2013-05-16 Gary Benson <gbenson@redhat.com>
* breakpoint.h (handle_solib_event): Moved function declaration
to solib.h.
* breakpoint.c (handle_solib_event): Moved function to solib.c.
(bpstat_stop_status): Pass new argument to handle_solib_event.
* solib.h (update_solib_breakpoints): New function declaration.
(handle_solib_event): Moved function declaration from
breakpoint.h.
* solib.c (update_solib_breakpoints): New function.
(handle_solib_event): Moved function from breakpoint.c.
Updated to call solib_ops->handle_event if not NULL.
* solist.h (target_so_ops): New fields "update_breakpoints" and
"handle_event".
* infrun.c (set_stop_on_solib_events): New function.
(_initialize_infrun): Use the above for "set
stop-on-solib-events".
(handle_inferior_event): Pass new argument to handle_solib_event.
* solib-svr4.c (probe.h): New include.
(svr4_free_library_list): New forward declaration.
(probe_action): New enum.
(probe_info): New struct.
(probe_info): New static variable.
(NUM_PROBES): New definition.
(svr4_info): New fields "using_xfer", "probes_table" and
"solib_list".
(free_probes_table): New function.
(free_solib_list): New function.
(svr4_pspace_data_cleanup): Free probes table and solib list.
(svr4_copy_library_list): New function.
(svr4_current_sos_via_xfer_libraries): New parameter "annex".
(svr4_read_so_list): New parameter "prev_lm".
(svr4_current_sos_direct): Renamed from "svr4_current_sos".
(svr4_current_sos): New function.
(probe_and_action): New struct.
(hash_probe_and_action): New function.
(equal_probe_and_action): Likewise.
(register_solib_event_probe): Likewise.
(solib_event_probe_at): Likewise.
(solib_event_probe_action): Likewise.
(solist_update_full): Likewise.
(solist_update_incremental): Likewise.
(disable_probes_interface_cleanup): Likewise.
(svr4_handle_solib_event): Likewise.
(svr4_update_solib_event_breakpoint): Likewise.
(svr4_update_solib_event_breakpoints): Likewise.
(svr4_create_solib_event_breakpoints): Likewise.
(enable_break): Free probes table before creating breakpoints.
Use svr4_create_solib_event_breakpoints to create breakpoints.
(svr4_solib_create_inferior_hook): Free the solib list.
(_initialize_svr4_solib): Initialise
svr4_so_ops.handle_solib_event and svr4_so_ops.update_breakpoints.
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index 7df1122..e996e54 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -1553,8 +1553,6 @@ extern int user_breakpoint_p (struct breakpoint *);
/* Attempt to determine architecture of location identified by SAL. */
extern struct gdbarch *get_sal_arch (struct symtab_and_line sal);
-extern void handle_solib_event (void);
-
extern void breakpoint_free_objfile (struct objfile *objfile);
extern char *ep_parse_optional_if_clause (char **arg);
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index f4f9325..639ddae 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -5343,21 +5343,6 @@ handle_jit_event (void)
target_terminal_inferior ();
}
-/* Handle an solib event by calling solib_add. */
-
-void
-handle_solib_event (void)
-{
- clear_program_space_solib_cache (current_inferior ()->pspace);
-
- /* Check for any newly added shared libraries if we're supposed to
- be adding them automatically. Switch terminal for any messages
- produced by breakpoint_re_set. */
- target_terminal_ours_for_output ();
- solib_add (NULL, 0, ¤t_target, auto_solib_add);
- target_terminal_inferior ();
-}
-
/* Prepare WHAT final decision for infrun. */
/* Decide what infrun needs to do with this bpstat. */
diff --git a/gdb/solib.h b/gdb/solib.h
index b811866..2108429 100644
--- a/gdb/solib.h
+++ b/gdb/solib.h
@@ -90,4 +90,12 @@ extern CORE_ADDR gdb_bfd_lookup_symbol_from_symtab (bfd *abfd,
void *),
void *data);
+/* Enable or disable optional solib event breakpoints as appropriate. */
+
+extern void update_solib_breakpoints (void);
+
+/* Handle an solib event by calling solib_add. */
+
+extern void handle_solib_event (void);
+
#endif /* SOLIB_H */
diff --git a/gdb/solib.c b/gdb/solib.c
index 72db375..9c7406e 100644
--- a/gdb/solib.c
+++ b/gdb/solib.c
@@ -1208,6 +1208,38 @@ no_shared_libraries (char *ignored, int from_tty)
objfile_purge_solibs ();
}
+/* See solib.h. */
+
+void
+update_solib_breakpoints (void)
+{
+ struct target_so_ops *ops = solib_ops (target_gdbarch ());
+
+ if (ops->update_breakpoints != NULL)
+ ops->update_breakpoints ();
+}
+
+/* See solib.h. */
+
+void
+handle_solib_event (void)
+{
+ struct target_so_ops *ops = solib_ops (target_gdbarch ());
+
+ if (ops->handle_event != NULL)
+ ops->handle_event ();
+
+ clear_program_space_solib_cache (current_inferior ()->pspace);
+
+ /* Check for any newly added shared libraries if we're supposed to
+ be adding them automatically. Switch terminal for any messages
+ produced by breakpoint_re_set. */
+ target_terminal_ours_for_output ();
+ solib_add (NULL, 0, ¤t_target, auto_solib_add);
+ target_terminal_inferior ();
+}
+
+
/* Reload shared libraries, but avoid reloading the same symbol file
we already have loaded. */
diff --git a/gdb/solist.h b/gdb/solist.h
index 0495474..244484a 100644
--- a/gdb/solist.h
+++ b/gdb/solist.h
@@ -153,6 +153,19 @@ struct target_so_ops
core file (in particular, for readonly sections). */
int (*keep_data_in_core) (CORE_ADDR vaddr,
unsigned long size);
+
+ /* Enable or disable optional solib event breakpoints as
+ appropriate. This should be called whenever
+ stop_on_solib_events is changed. This pointer can be
+ NULL, in which case no enabling or disabling is necessary
+ for this target. */
+ void (*update_breakpoints) (void);
+
+ /* Target-specific processing of solib events that will be
+ performed before solib_add is called. This pointer can be
+ NULL, in which case no specific preprocessing is necessary
+ for this target. */
+ void (*handle_event) (void);
};
/* Free the memory associated with a (so_list *). */
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 54e92f2..a020dd6 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -370,6 +370,16 @@ static struct symbol *step_start_function;
/* Nonzero if we want to give control to the user when we're notified
of shared library events by the dynamic linker. */
int stop_on_solib_events;
+
+/* Enable or disable optional shared library event breakpoints
+ as appropriate when the above flag is changed. */
+
+static void
+set_stop_on_solib_events (char *args, int from_tty, struct cmd_list_element *c)
+{
+ update_solib_breakpoints ();
+}
+
static void
show_stop_on_solib_events (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
@@ -7303,7 +7313,7 @@ Show stopping for shared library events."), _("\
If nonzero, gdb will give control to the user when the dynamic linker\n\
notifies gdb of shared library events. The most common event of interest\n\
to the user would be loading/unloading of a new library."),
- NULL,
+ set_stop_on_solib_events,
show_stop_on_solib_events,
&setlist, &showlist);
diff --git a/gdb/solib-svr4.c b/gdb/solib-svr4.c
index 4e09472..6b4bdb0 100644
--- a/gdb/solib-svr4.c
+++ b/gdb/solib-svr4.c
@@ -47,9 +47,12 @@
#include "exceptions.h"
#include "gdb_bfd.h"
+#include "probe.h"
+
static struct link_map_offsets *svr4_fetch_link_map_offsets (void);
static int svr4_have_link_map_offsets (void);
static void svr4_relocate_main_executable (void);
+static void svr4_free_library_list (void *p_list);
/* Link map info to include in an allocated so_list entry. */
@@ -106,6 +109,55 @@ static const char * const main_name_list[] =
NULL
};
+/* What to do when a probe stop occurs. */
+
+enum probe_action
+ {
+ /* Something went seriously wrong. Stop using probes and
+ revert to using the older interface. */
+ PROBES_INTERFACE_FAILED,
+
+ /* No action is required. The shared object list is still
+ valid. */
+ DO_NOTHING,
+
+ /* The shared object list should be reloaded entirely. */
+ FULL_RELOAD,
+
+ /* Attempt to incrementally update the shared object list. If
+ the update fails or is not possible, fall back to reloading
+ the list in full. */
+ UPDATE_OR_RELOAD,
+ };
+
+/* A probe's name and its associated action. */
+
+struct probe_info
+{
+ /* The name of the probe. */
+ const char *name;
+
+ /* What to do when a probe stop occurs. */
+ enum probe_action action;
+};
+
+/* A list of named probes and their associated actions. If all
+ probes are present in the dynamic linker then the probes-based
+ interface will be used. */
+
+static const struct probe_info probe_info[] =
+{
+ { "init_start", DO_NOTHING },
+ { "init_complete", FULL_RELOAD },
+ { "map_start", DO_NOTHING },
+ { "map_failed", DO_NOTHING },
+ { "reloc_complete", UPDATE_OR_RELOAD },
+ { "unmap_start", DO_NOTHING },
+ { "unmap_complete", FULL_RELOAD },
+};
+
+#define NUM_PROBES ARRAY_SIZE (probe_info)
+
/* Return non-zero if GDB_SO_NAME and INFERIOR_SO_NAME represent
the same shared library. */
@@ -313,17 +365,56 @@ struct svr4_info
CORE_ADDR interp_text_sect_high;
CORE_ADDR interp_plt_sect_low;
CORE_ADDR interp_plt_sect_high;
+
+ /* Nonzero if the list of objects was last obtained from the target
+ via qXfer:libraries-svr4:read. */
+ int using_xfer;
+
+ /* Table mapping breakpoint addresses to probes and actions, used
+ by the probes-based interface. */
+ htab_t probes_table;
+
+ /* List of objects loaded into the inferior, used by the probes-
+ based interface. */
+ struct so_list *solib_list;
};
/* Per-program-space data key. */
static const struct program_space_data *solib_svr4_pspace_data;
+/* Free the probes table. */
+
+static void
+free_probes_table (struct svr4_info *info)
+{
+ if (info->probes_table == NULL)
+ return;
+
+ htab_delete (info->probes_table);
+ info->probes_table = NULL;
+}
+
+/* Free the solib list. */
+
+static void
+free_solib_list (struct svr4_info *info)
+{
+ svr4_free_library_list (&info->solib_list);
+ info->solib_list = NULL;
+}
+
static void
svr4_pspace_data_cleanup (struct program_space *pspace, void *arg)
{
struct svr4_info *info;
info = program_space_data (pspace, solib_svr4_pspace_data);
+ if (info == NULL)
+ return;
+
+ free_probes_table (info);
+ free_solib_list (info);
+
xfree (info);
}
@@ -990,6 +1081,36 @@ svr4_free_library_list (void *p_list)
}
}
+/* Copy library list. */
+
+static struct so_list *
+svr4_copy_library_list (struct so_list *src)
+{
+ struct link_map_offsets *lmo = svr4_fetch_link_map_offsets ();
+ struct so_list *dst = NULL;
+ struct so_list **link = &dst;
+
+ while (src != NULL)
+ {
+ struct so_list *new;
+
+ new = XZALLOC (struct so_list);
+
+ memcpy (new, src, sizeof (struct so_list));
+
+ new->lm_info = xmalloc (lmo->link_map_size);
+ memcpy (new->lm_info, src->lm_info, lmo->link_map_size);
+
+ new->next = NULL;
+ *link = new;
+ link = &new->next;
+
+ src = src->next;
+ }
+
+ return dst;
+}
+
#ifdef HAVE_LIBEXPAT
#include "xml-support.h"
@@ -1105,14 +1226,19 @@ svr4_parse_libraries (const char *document, struct svr4_library_list *list)
return 0;
}
-/* Attempt to get so_list from target via qXfer:libraries:read packet.
+/* Attempt to get so_list from target via qXfer:libraries-svr4:read packet.
Return 0 if packet not supported, *SO_LIST_RETURN is not modified in such
case. Return 1 if *SO_LIST_RETURN contains the library list, it may be
- empty, caller is responsible for freeing all its entries. */
+ empty, caller is responsible for freeing all its entries.
+
+ Note that ANNEX must be NULL if the remote does not explicitly allow
+ qXfer:libraries-svr4:read packets with non-empty annexes. Support for
+ this can be checked using target_augmented_libraries_svr4_read (). */
static int
-svr4_current_sos_via_xfer_libraries (struct svr4_library_list *list)
+svr4_current_sos_via_xfer_libraries (struct svr4_library_list *list,
+ const char *annex)
{
char *svr4_library_document;
int result;
@@ -1121,7 +1247,7 @@ svr4_current_sos_via_xfer_libraries (struct svr4_library_list *list)
/* Fetch the list of shared libraries. */
svr4_library_document = target_read_stralloc (¤t_target,
TARGET_OBJECT_LIBRARIES_SVR4,
- NULL);
+ annex);
if (svr4_library_document == NULL)
return 0;
@@ -1135,7 +1261,8 @@ svr4_current_sos_via_xfer_libraries (struct svr4_library_list *list)
#else
static int
-svr4_current_sos_via_xfer_libraries (struct svr4_library_list *list)
+svr4_current_sos_via_xfer_libraries (struct svr4_library_list *list,
+ const char *annex)
{
return 0;
}
@@ -1169,15 +1296,17 @@ svr4_default_sos (void)
return new;
}
-/* Read the whole inferior libraries chain starting at address LM. Add the
- entries to the tail referenced by LINK_PTR_PTR. Ignore the first entry if
- IGNORE_FIRST and set global MAIN_LM_ADDR according to it. */
+/* Read the whole inferior libraries chain starting at address LM.
+ Expect the first entry in the chain's previous entry to be PREV_LM.
+ Add the entries to the tail referenced by LINK_PTR_PTR. Ignore the
+ first entry if IGNORE_FIRST and set global MAIN_LM_ADDR according
+ to it. Returns nonzero upon success. */
-static void
-svr4_read_so_list (CORE_ADDR lm, struct so_list ***link_ptr_ptr,
- int ignore_first)
+static int
+svr4_read_so_list (CORE_ADDR lm, CORE_ADDR prev_lm,
+ struct so_list ***link_ptr_ptr, int ignore_first)
{
- CORE_ADDR prev_lm = 0, next_lm;
+ CORE_ADDR next_lm;
for (; lm != 0; prev_lm = lm, lm = next_lm)
{
@@ -1193,7 +1322,7 @@ svr4_read_so_list (CORE_ADDR lm, struct so_list ***link_ptr_ptr,
if (new->lm_info == NULL)
{
do_cleanups (old_chain);
- break;
+ return 0;
}
next_lm = new->lm_info->l_next;
@@ -1204,7 +1333,7 @@ svr4_read_so_list (CORE_ADDR lm, struct so_list ***link_ptr_ptr,
paddress (target_gdbarch (), prev_lm),
paddress (target_gdbarch (), new->lm_info->l_prev));
do_cleanups (old_chain);
- break;
+ return 0;
}
/* For SVR4 versions, the first entry in the link map is for the
@@ -1250,17 +1379,19 @@ svr4_read_so_list (CORE_ADDR lm, struct so_list ***link_ptr_ptr,
**link_ptr_ptr = new;
*link_ptr_ptr = &new->next;
}
+
+ return 1;
}
-/* Implement the "current_sos" target_so_ops method. */
+/* Read the full list of currently loaded shared objects directly from
+ the inferior. */
static struct so_list *
-svr4_current_sos (void)
+svr4_current_sos_direct (struct svr4_info *info)
{
CORE_ADDR lm;
struct so_list *head = NULL;
struct so_list **link_ptr = &head;
- struct svr4_info *info;
struct cleanup *back_to;
int ignore_first;
struct svr4_library_list library_list;
@@ -1273,19 +1404,16 @@ svr4_current_sos (void)
Unfortunately statically linked inferiors will also fall back through this
suboptimal code path. */
- if (svr4_current_sos_via_xfer_libraries (&library_list))
+ info->using_xfer = svr4_current_sos_via_xfer_libraries (&library_list,
+ NULL);
+ if (info->using_xfer)
{
if (library_list.main_lm)
- {
- info = get_svr4_info ();
- info->main_lm_addr = library_list.main_lm;
- }
+ info->main_lm_addr = library_list.main_lm;
return library_list.head ? library_list.head : svr4_default_sos ();
}
- info = get_svr4_info ();
-
/* Always locate the debug struct, in case it has moved. */
info->debug_base = 0;
locate_base (info);
@@ -1308,7 +1436,7 @@ svr4_current_sos (void)
`struct so_list' nodes. */
lm = solib_svr4_r_map (info);
if (lm)
- svr4_read_so_list (lm, &link_ptr, ignore_first);
+ svr4_read_so_list (lm, 0, &link_ptr, ignore_first);
/* On Solaris, the dynamic linker is not in the normal list of
shared objects, so make sure we pick it up too. Having
@@ -1316,7 +1444,7 @@ svr4_current_sos (void)
for skipping dynamic linker resolver code. */
lm = solib_svr4_r_ldsomap (info);
if (lm)
- svr4_read_so_list (lm, &link_ptr, 0);
+ svr4_read_so_list (lm, 0, &link_ptr, 0);
discard_cleanups (back_to);
@@ -1326,6 +1454,22 @@ svr4_current_sos (void)
return head;
}
+/* Implement the "current_sos" target_so_ops method. */
+
+static struct so_list *
+svr4_current_sos (void)
+{
+ struct svr4_info *info = get_svr4_info ();
+
+ /* If we are using the probes interface and the solib list has
+ been cached then we simply return that. */
+ if (info->solib_list != NULL)
+ return svr4_copy_library_list (info->solib_list);
+
+ /* Otherwise obtain the solib list directly from the inferior. */
+ return svr4_current_sos_direct (info);
+}
+
/* Get the address of the link_map for a given OBJFILE. */
CORE_ADDR
@@ -1408,6 +1552,434 @@ exec_entry_point (struct bfd *abfd, struct target_ops *targ)
return gdbarch_addr_bits_remove (target_gdbarch (), addr);
}
+/* A probe and its associated action. */
+
+struct probe_and_action
+{
+ /* The probe. */
+ struct probe *probe;
+
+ /* The action. */
+ enum probe_action action;
+};
+
+/* Returns a hash code for the probe_and_action referenced by p. */
+
+static hashval_t
+hash_probe_and_action (const void *p)
+{
+ const struct probe_and_action *pa = p;
+
+ return (hashval_t) pa->probe->address;
+}
+
+/* Returns non-zero if the probe_and_actions referenced by p1 and p2
+ are equal. */
+
+static int
+equal_probe_and_action (const void *p1, const void *p2)
+{
+ const struct probe_and_action *pa1 = p1;
+ const struct probe_and_action *pa2 = p2;
+
+ return pa1->probe->address == pa2->probe->address;
+}
+
+/* Register a solib event probe and its associated action in the
+ probes table. */
+
+static void
+register_solib_event_probe (struct probe *probe, enum probe_action action)
+{
+ struct svr4_info *info = get_svr4_info ();
+ struct probe_and_action lookup, *pa;
+ void **slot;
+
+ /* Create the probes table, if necessary. */
+ if (info->probes_table == NULL)
+ {
+ info->probes_table = htab_create_alloc (1, hash_probe_and_action,
+ equal_probe_and_action,
+ xfree, xcalloc, xfree);
+ }
+
+ lookup.probe = probe;
+ slot = htab_find_slot (info->probes_table, &lookup, INSERT);
+ gdb_assert (*slot == HTAB_EMPTY_ENTRY);
+
+ pa = XCNEW (struct probe_and_action);
+ pa->probe = probe;
+ pa->action = action;
+
+ *slot = pa;
+}
+
+/* Get the solib event probe at the specified location, and the
+ action associated with it. Returns NULL if no solib event probe
+ was found. */
+
+static struct probe_and_action *
+solib_event_probe_at (struct svr4_info *info, CORE_ADDR address)
+{
+ struct probe lookup_probe;
+ struct probe_and_action lookup;
+ void **slot;
+
+ lookup_probe.address = address;
+ lookup.probe = &lookup_probe;
+ slot = htab_find_slot (info->probes_table, &lookup, NO_INSERT);
+
+ if (slot == NULL)
+ return NULL;
+
+ return (struct probe_and_action *) *slot;
+}
+
+/* Decide what action to take when the specified solib event probe is
+ hit. */
+
+static enum probe_action
+solib_event_probe_action (struct probe_and_action *pa)
+{
+ enum probe_action action;
+ unsigned probe_argc;
+
+ action = pa->action;
+ if (action == DO_NOTHING || action == PROBES_INTERFACE_FAILED)
+ return action;
+
+ gdb_assert (action == FULL_RELOAD || action == UPDATE_OR_RELOAD);
+
+ /* Check that an appropriate number of arguments has been supplied.
+ We expect:
+ arg0: Lmid_t lmid (mandatory)
+ arg1: struct r_debug *debug_base (mandatory)
+ arg2: struct link_map *new (optional, for incremental updates) */
+ probe_argc = get_probe_argument_count (pa->probe);
+ if (probe_argc == 2)
+ action = FULL_RELOAD;
+ else if (probe_argc < 2)
+ action = PROBES_INTERFACE_FAILED;
+
+ return action;
+}
+
+/* Populate the shared object list by reading the entire list of
+ shared objects from the inferior. Returns nonzero on success. */
+
+static int
+solist_update_full (struct svr4_info *info)
+{
+ svr4_free_library_list (&info->solib_list);
+ info->solib_list = svr4_current_sos_direct (info);
+
+ return 1;
+}
+
+/* Update the shared object list starting from the link-map entry
+ passed by the linker in the probe's third argument. Returns
+ nonzero if the list was successfully updated, or zero to indicate
+ failure. */
+
+static int
+solist_update_incremental (struct svr4_info *info, CORE_ADDR lm)
+{
+ struct so_list *tail;
+ CORE_ADDR prev_lm;
+
+ /* Fall back to a full update if we haven't read anything yet. */
+ if (info->solib_list == NULL)
+ return 0;
+
+ /* Fall back to a full update if we are using a remote target
+ that does not support incremental transfers. */
+ if (info->using_xfer && !target_augmented_libraries_svr4_read())
+ return 0;
+
+ /* Walk to the end of the list. */
+ for (tail = info->solib_list; tail->next; tail = tail->next);
+ prev_lm = tail->lm_info->lm_addr;
+
+ /* Read the new objects. */
+ if (info->using_xfer)
+ {
+ struct svr4_library_list library_list;
+ char annex[64];
+
+ xsnprintf (annex, sizeof (annex), "start=%lx;prev=%lx", lm, prev_lm);
+ if (!svr4_current_sos_via_xfer_libraries (&library_list, annex))
+ return 0;
+
+ tail->next = library_list.head;
+ }
+ else
+ {
+ struct so_list **link = &tail->next;
+
+ if (!svr4_read_so_list (lm, prev_lm, &link, 0))
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Disable the probes-based linker interface and revert to the
+ original interface. We don't reset the breakpoints as the
+ ones set up for the probes-based interface are adequate. */
+
+static void
+disable_probes_interface_cleanup (void *arg)
+{
+ struct svr4_info *info = get_svr4_info ();
+
+ warning (_("Probes-based dynamic linker interface failed.\n"
+ "Reverting to original interface.\n"));
+
+ free_probes_table (info);
+ free_solib_list (info);
+}
+
+/* Update the solib list as appropriate when using the
+ probes-based linker interface. Do nothing if using the
+ standard interface. */
+
+static void
+svr4_handle_solib_event (void)
+{
+ struct svr4_info *info = get_svr4_info ();
+ struct probe_and_action *pa;
+ enum probe_action action;
+ struct cleanup *old_chain, *usm_chain;
+ struct value *val;
+ CORE_ADDR pc, debug_base, lm = 0;
+ int is_initial_ns;
+
+ /* Do nothing if not using the probes interface. */
+ if (info->probes_table == NULL)
+ return;
+
+ /* If anything goes wrong we revert to the original linker
+ interface. */
+ old_chain = make_cleanup (disable_probes_interface_cleanup, NULL);
+
+ pc = regcache_read_pc (get_current_regcache ());
+ pa = solib_event_probe_at (info, pc);
+ if (pa == NULL)
+ goto error;
+
+ action = solib_event_probe_action (pa);
+ if (action == PROBES_INTERFACE_FAILED)
+ goto error;
+
+ if (action == DO_NOTHING)
+ return;
+
+ /* EVALUATE_PROBE_ARGUMENT looks up symbols in the dynamic linker
+ using FIND_PC_SECTION. FIND_PC_SECTION is accelerated by a cache
+ called the section map. The section map is invalidated every
+ time a shared library is loaded or unloaded, and if the inferior
+ is generating a lot of shared library events then the section map
+ will be updated every time SVR4_HANDLE_SOLIB_EVENT is called.
+ We called FIND_PC_SECTION in SVR4_CREATE_SOLIB_EVENT_BREAKPOINTS,
+ so we can guarantee that the dynamic linker's sections are in the
+ section map. We can therefore inhibit section map updates across
+ these calls to EVALUATE_PROBE_ARGUMENT and save a lot of time. */
+ inhibit_section_map_updates ();
+ usm_chain = make_cleanup (resume_section_map_updates_cleanup, NULL);
+
+ val = evaluate_probe_argument (pa->probe, 1);
+ if (val == NULL)
+ goto error;
+
+ debug_base = value_as_address (val);
+ if (debug_base == 0)
+ goto error;
+
+ /* Always locate the debug struct, in case it moved. */
+ info->debug_base = 0;
+ if (locate_base (info) == 0)
+ goto error;
+
+ /* Do not process namespaces other than the initial one. */
+ if (debug_base != info->debug_base)
+ action = DO_NOTHING;
+
+ if (action == UPDATE_OR_RELOAD)
+ {
+ val = evaluate_probe_argument (pa->probe, 2);
+ if (val != NULL)
+ lm = value_as_address (val);
+
+ if (lm == 0)
+ action = FULL_RELOAD;
+ }
+
+ /* Resume section map updates. */
+ do_cleanups (usm_chain);
+
+ if (action == UPDATE_OR_RELOAD)
+ {
+ if (!solist_update_incremental (info, lm))
+ action = FULL_RELOAD;
+ }
+
+ if (action == FULL_RELOAD)
+ {
+ if (!solist_update_full (info))
+ goto error;
+ }
+
+ discard_cleanups (old_chain);
+ return;
+
+ error:
+ /* We should never reach here, but if we do we disable the
+ probes interface and revert to the original interface. */
+
+ do_cleanups (old_chain);
+}
+
+/* Helper function for svr4_update_solib_event_breakpoints. */
+
+static int
+svr4_update_solib_event_breakpoint (struct breakpoint *b, void *arg)
+{
+ struct svr4_info *info = get_svr4_info ();
+ struct bp_location *loc;
+
+ if (b->type != bp_shlib_event)
+ return 0; /* Continue iterating. */
+
+ for (loc = b->loc; loc; loc = loc->next)
+ {
+ struct probe_and_action *pa = solib_event_probe_at (info, loc->address);
+
+ if (pa != NULL)
+ {
+ if (pa->action == DO_NOTHING)
+ b->enable_state = (stop_on_solib_events
+ ? bp_enabled : bp_disabled);
+
+ return 0; /* Continue iterating. */
+ }
+ }
+
+ return 0; /* Continue iterating. */
+}
+
+/* Enable or disable optional solib event breakpoints as appropriate.
+ Called whenever stop_on_solib_events is changed. */
+
+static void
+svr4_update_solib_event_breakpoints (void)
+{
+ struct svr4_info *info = get_svr4_info ();
+
+ if (info->probes_table)
+ iterate_over_breakpoints (svr4_update_solib_event_breakpoint, NULL);
+}
+
+/* Create and register solib event breakpoints. */
+
+static void
+svr4_create_probe_breakpoints (struct gdbarch *gdbarch,
+ VEC (probe_p) **probes)
+{
+ int i;
+
+ for (i = 0; i < NUM_PROBES; i++)
+ {
+ enum probe_action action = probe_info[i].action;
+ struct probe *probe;
+ int ix;
+
+ for (ix = 0;
+ VEC_iterate (probe_p, probes[i], ix, probe);
+ ++ix)
+ {
+ create_solib_event_breakpoint (gdbarch, probe->address);
+ register_solib_event_probe (probe, action);
+ }
+ }
+
+ svr4_update_solib_event_breakpoints ();
+}
+
+/* Both the SunOS and the SVR4 dynamic linkers call a marker function
+ before and after mapping and unmapping shared libraries. The sole
+ purpose of this method is to allow debuggers to set a breakpoint so
+ they can track these changes.
+
+ Some versions of the glibc dynamic linker contain named probes
+ to allow more fine grained stopping. Given the address of the
+ original marker function, this function attempts to find these
+ probes, and if found, sets breakpoints on those instead. If the
+ probes aren't found, a single breakpoint is set on the original
+ marker function. */
+
+static void
+svr4_create_solib_event_breakpoints (struct gdbarch *gdbarch,
+ CORE_ADDR address)
+{
+ struct svr4_info *info = get_svr4_info ();
+ struct obj_section *os;
+
+ os = find_pc_section (address);
+ if (os != NULL)
+ {
+ int with_prefix;
+
+ for (with_prefix = 0; with_prefix <= 1; with_prefix++)
+ {
+ VEC (probe_p) *probes[NUM_PROBES];
+ int all_probes_found = 1;
+ int i;
+
+ memset (probes, 0, sizeof (probes));
+ for (i = 0; i < NUM_PROBES; i++)
+ {
+ char name[32] = { '\0' };
+
+ /* Fedora 17, RHEL 6.2, and RHEL 6.3 shipped with an
+ early version of the probes code in which the probes'
+ names were prefixed with "rtld_" and the "map_failed"
+ probe did not exist. The locations of the probes are
+ otherwise the same, so we check for probes with
+ prefixed names if probes with unprefixed names are
+ not present. */
+
+ if (with_prefix)
+ strncat (name, "rtld_", sizeof (name) - strlen (name) - 1);
+
+ strncat (name, probe_info[i].name,
+ sizeof (name) - strlen (name) - 1);
+
+ probes[i] = find_probes_in_objfile (os->objfile, "rtld", name);
+
+ if (!strcmp (name, "rtld_map_failed"))
+ continue;
+
+ if (!VEC_length (probe_p, probes[i]))
+ {
+ all_probes_found = 0;
+ break;
+ }
+ }
+
+ if (all_probes_found)
+ svr4_create_probe_breakpoints (gdbarch, probes);
+
+ for (i = 0; i < NUM_PROBES; i++)
+ VEC_free (probe_p, probes[i]);
+
+ if (all_probes_found)
+ return;
+ }
+ }
+
+ create_solib_event_breakpoint (gdbarch, address);
+}
+
/* Helper function for gdb_bfd_lookup_symbol. */
static int
@@ -1460,6 +2032,8 @@ enable_break (struct svr4_info *info, int from_tty)
info->interp_text_sect_low = info->interp_text_sect_high = 0;
info->interp_plt_sect_low = info->interp_plt_sect_high = 0;
+ free_probes_table (info);
+
/* If we already have a shared library list in the target, and
r_debug contains r_brk, set the breakpoint there - this should
mean r_brk has already been relocated. Assume the dynamic linker
@@ -1491,7 +2065,7 @@ enable_break (struct svr4_info *info, int from_tty)
That knowledge is encoded in the address, if it's Thumb the low bit
is 1. However, we've stripped that info above and it's not clear
what all the consequences are of passing a non-addr_bits_remove'd
- address to create_solib_event_breakpoint. The call to
+ address to svr4_create_solib_event_breakpoints. The call to
find_pc_section verifies we know about the address and have some
hope of computing the right kind of breakpoint to use (via
symbol info). It does mean that GDB needs to be pointed at a
@@ -1529,7 +2103,7 @@ enable_break (struct svr4_info *info, int from_tty)
+ bfd_section_size (tmp_bfd, interp_sect);
}
- create_solib_event_breakpoint (target_gdbarch (), sym_addr);
+ svr4_create_solib_event_breakpoints (target_gdbarch (), sym_addr);
return 1;
}
}
@@ -1687,7 +2261,8 @@ enable_break (struct svr4_info *info, int from_tty)
if (sym_addr != 0)
{
- create_solib_event_breakpoint (target_gdbarch (), load_addr + sym_addr);
+ svr4_create_solib_event_breakpoints (target_gdbarch (),
+ load_addr + sym_addr);
xfree (interp_name);
return 1;
}
@@ -1713,7 +2288,7 @@ enable_break (struct svr4_info *info, int from_tty)
sym_addr = gdbarch_convert_from_func_ptr_addr (target_gdbarch (),
sym_addr,
¤t_target);
- create_solib_event_breakpoint (target_gdbarch (), sym_addr);
+ svr4_create_solib_event_breakpoints (target_gdbarch (), sym_addr);
return 1;
}
}
@@ -1729,7 +2304,7 @@ enable_break (struct svr4_info *info, int from_tty)
sym_addr = gdbarch_convert_from_func_ptr_addr (target_gdbarch (),
sym_addr,
¤t_target);
- create_solib_event_breakpoint (target_gdbarch (), sym_addr);
+ svr4_create_solib_event_breakpoints (target_gdbarch (), sym_addr);
return 1;
}
}
@@ -2225,6 +2800,9 @@ svr4_solib_create_inferior_hook (int from_tty)
info = get_svr4_info ();
+ /* Free the probes-based interface's solib list. */
+ free_solib_list (info);
+
/* Relocate the main executable if necessary. */
svr4_relocate_main_executable ();
@@ -2467,4 +3045,6 @@ _initialize_svr4_solib (void)
svr4_so_ops.lookup_lib_global_symbol = elf_lookup_lib_symbol;
svr4_so_ops.same = svr4_same;
svr4_so_ops.keep_data_in_core = svr4_keep_data_in_core;
+ svr4_so_ops.update_breakpoints = svr4_update_solib_event_breakpoints;
+ svr4_so_ops.handle_event = svr4_handle_solib_event;
}
^ permalink raw reply [flat|nested] 59+ messages in thread* Re: [RFA 5/7] Improved linker-debugger interface
2013-05-16 14:55 ` [RFA 5/7] Improved linker-debugger interface Gary Benson
@ 2013-05-17 19:05 ` Jan Kratochvil
2013-05-24 8:30 ` [RFA 5/7 take 2] " Gary Benson
0 siblings, 1 reply; 59+ messages in thread
From: Jan Kratochvil @ 2013-05-17 19:05 UTC (permalink / raw)
To: gdb-patches
On Thu, 16 May 2013 16:48:38 +0200, Gary Benson wrote:
[...]
> --- a/gdb/solib.c
> +++ b/gdb/solib.c
> @@ -1208,6 +1208,38 @@ no_shared_libraries (char *ignored, int from_tty)
> objfile_purge_solibs ();
> }
>
> +/* See solib.h. */
> +
> +void
> +update_solib_breakpoints (void)
> +{
> + struct target_so_ops *ops = solib_ops (target_gdbarch ());
> +
> + if (ops->update_breakpoints != NULL)
> + ops->update_breakpoints ();
> +}
> +
> +/* See solib.h. */
> +
> +void
> +handle_solib_event (void)
> +{
> + struct target_so_ops *ops = solib_ops (target_gdbarch ());
> +
> + if (ops->handle_event != NULL)
> + ops->handle_event ();
> +
> + clear_program_space_solib_cache (current_inferior ()->pspace);
> +
> + /* Check for any newly added shared libraries if we're supposed to
> + be adding them automatically. Switch terminal for any messages
> + produced by breakpoint_re_set. */
> + target_terminal_ours_for_output ();
> + solib_add (NULL, 0, ¤t_target, auto_solib_add);
> + target_terminal_inferior ();
> +}
> +
> +
Should be only one empty line.
> /* Reload shared libraries, but avoid reloading the same symbol file
> we already have loaded. */
>
> diff --git a/gdb/solist.h b/gdb/solist.h
> index 0495474..244484a 100644
> --- a/gdb/solist.h
> +++ b/gdb/solist.h
> @@ -153,6 +153,19 @@ struct target_so_ops
> core file (in particular, for readonly sections). */
> int (*keep_data_in_core) (CORE_ADDR vaddr,
> unsigned long size);
> +
> + /* Enable or disable optional solib event breakpoints as
> + appropriate. This should be called whenever
> + stop_on_solib_events is changed. This pointer can be
> + NULL, in which case no enabling or disabling is necessary
> + for this target. */
> + void (*update_breakpoints) (void);
> +
> + /* Target-specific processing of solib events that will be
> + performed before solib_add is called. This pointer can be
> + NULL, in which case no specific preprocessing is necessary
> + for this target. */
> + void (*handle_event) (void);
> };
>
> /* Free the memory associated with a (so_list *). */
> diff --git a/gdb/infrun.c b/gdb/infrun.c
> index 54e92f2..a020dd6 100644
> --- a/gdb/infrun.c
> +++ b/gdb/infrun.c
> @@ -370,6 +370,16 @@ static struct symbol *step_start_function;
> /* Nonzero if we want to give control to the user when we're notified
> of shared library events by the dynamic linker. */
> int stop_on_solib_events;
> +
> +/* Enable or disable optional shared library event breakpoints
> + as appropriate when the above flag is changed. */
> +
> +static void
> +set_stop_on_solib_events (char *args, int from_tty, struct cmd_list_element *c)
> +{
> + update_solib_breakpoints ();
> +}
> +
> static void
> show_stop_on_solib_events (struct ui_file *file, int from_tty,
> struct cmd_list_element *c, const char *value)
> @@ -7303,7 +7313,7 @@ Show stopping for shared library events."), _("\
> If nonzero, gdb will give control to the user when the dynamic linker\n\
> notifies gdb of shared library events. The most common event of interest\n\
> to the user would be loading/unloading of a new library."),
> - NULL,
> + set_stop_on_solib_events,
> show_stop_on_solib_events,
> &setlist, &showlist);
>
> diff --git a/gdb/solib-svr4.c b/gdb/solib-svr4.c
> index 4e09472..6b4bdb0 100644
> --- a/gdb/solib-svr4.c
> +++ b/gdb/solib-svr4.c
> @@ -47,9 +47,12 @@
> #include "exceptions.h"
> #include "gdb_bfd.h"
>
No need for an empty line.
> +#include "probe.h"
> +
> static struct link_map_offsets *svr4_fetch_link_map_offsets (void);
> static int svr4_have_link_map_offsets (void);
> static void svr4_relocate_main_executable (void);
> +static void svr4_free_library_list (void *p_list);
>
> /* Link map info to include in an allocated so_list entry. */
>
> @@ -106,6 +109,55 @@ static const char * const main_name_list[] =
> NULL
> };
>
> +/* What to do when a probe stop occurs. */
> +
> +enum probe_action
> + {
This bracket should have no indentation.
> + /* Something went seriously wrong. Stop using probes and
> + revert to using the older interface. */
> + PROBES_INTERFACE_FAILED,
> +
> + /* No action is required. The shared object list is still
> + valid. */
> + DO_NOTHING,
> +
> + /* The shared object list should be reloaded entirely. */
> + FULL_RELOAD,
> +
> + /* Attempt to incrementally update the shared object list. If
> + the update fails or is not possible, fall back to reloading
> + the list in full. */
> + UPDATE_OR_RELOAD,
> + };
> +
> +/* A probe's name and its associated action. */
> +
> +struct probe_info
> +{
> + /* The name of the probe. */
> + const char *name;
> +
> + /* What to do when a probe stop occurs. */
> + enum probe_action action;
> +};
> +
> +/* A list of named probes and their associated actions. If all
> + probes are present in the dynamic linker then the probes-based
> + interface will be used. */
> +
> +static const struct probe_info probe_info[] =
> +{
> + { "init_start", DO_NOTHING },
> + { "init_complete", FULL_RELOAD },
> + { "map_start", DO_NOTHING },
> + { "map_failed", DO_NOTHING },
> + { "reloc_complete", UPDATE_OR_RELOAD },
> + { "unmap_start", DO_NOTHING },
> + { "unmap_complete", FULL_RELOAD },
> +};
> +
> +#define NUM_PROBES ARRAY_SIZE (probe_info)
> +
> /* Return non-zero if GDB_SO_NAME and INFERIOR_SO_NAME represent
> the same shared library. */
>
> @@ -313,17 +365,56 @@ struct svr4_info
> CORE_ADDR interp_text_sect_high;
> CORE_ADDR interp_plt_sect_low;
> CORE_ADDR interp_plt_sect_high;
> +
> + /* Nonzero if the list of objects was last obtained from the target
> + via qXfer:libraries-svr4:read. */
> + int using_xfer;
> +
> + /* Table mapping breakpoint addresses to probes and actions, used
> + by the probes-based interface. */
As this is not C++ it is not clear here it indexes 'struct probe_and_action'.
Also one could state the lookup is done via probe_and_action->probe->address.
> + htab_t probes_table;
> +
> + /* List of objects loaded into the inferior, used by the probes-
> + based interface. */
> + struct so_list *solib_list;
> };
>
> /* Per-program-space data key. */
> static const struct program_space_data *solib_svr4_pspace_data;
>
> +/* Free the probes table. */
> +
> +static void
> +free_probes_table (struct svr4_info *info)
> +{
> + if (info->probes_table == NULL)
> + return;
> +
> + htab_delete (info->probes_table);
> + info->probes_table = NULL;
> +}
> +
> +/* Free the solib list. */
> +
> +static void
> +free_solib_list (struct svr4_info *info)
> +{
> + svr4_free_library_list (&info->solib_list);
> + info->solib_list = NULL;
> +}
> +
> static void
> svr4_pspace_data_cleanup (struct program_space *pspace, void *arg)
> {
> struct svr4_info *info;
>
> info = program_space_data (pspace, solib_svr4_pspace_data);
> + if (info == NULL)
> + return;
> +
> + free_probes_table (info);
> + free_solib_list (info);
> +
> xfree (info);
> }
>
> @@ -990,6 +1081,36 @@ svr4_free_library_list (void *p_list)
> }
> }
>
> +/* Copy library list. */
> +
> +static struct so_list *
> +svr4_copy_library_list (struct so_list *src)
> +{
> + struct link_map_offsets *lmo = svr4_fetch_link_map_offsets ();
No longer needed after the 2nd comment below.
> + struct so_list *dst = NULL;
> + struct so_list **link = &dst;
> +
> + while (src != NULL)
> + {
> + struct so_list *new;
> +
> + new = XZALLOC (struct so_list);
xmalloc is enough - without clearing. You overwrite the whole allocated space
by the next statement anyway.
> +
> + memcpy (new, src, sizeof (struct so_list));
> +
> + new->lm_info = xmalloc (lmo->link_map_size);
> + memcpy (new->lm_info, src->lm_info, lmo->link_map_size);
Here should be s/lmo->link_map_size/sizeof (struct lm_info)/.
so_list->lm_info is defined as struct lm_info at solib-svr4.c:59:
(gdb) p sizeof (struct lm_info)
$1 = 64
vs.
svr4_ilp32_fetch_link_map_offsets (void)
lmo.link_map_size = 20;
svr4_lp64_fetch_link_map_offsets (void)
lmo.link_map_size = 40;
lmo->link_map_size is the external layout of that data but so_list->lm_info is
its internal representation.
> +
> + new->next = NULL;
> + *link = new;
> + link = &new->next;
> +
> + src = src->next;
> + }
> +
> + return dst;
> +}
> +
> #ifdef HAVE_LIBEXPAT
>
> #include "xml-support.h"
> @@ -1105,14 +1226,19 @@ svr4_parse_libraries (const char *document, struct svr4_library_list *list)
> return 0;
> }
>
> -/* Attempt to get so_list from target via qXfer:libraries:read packet.
> +/* Attempt to get so_list from target via qXfer:libraries-svr4:read packet.
>
> Return 0 if packet not supported, *SO_LIST_RETURN is not modified in such
> case. Return 1 if *SO_LIST_RETURN contains the library list, it may be
> - empty, caller is responsible for freeing all its entries. */
> + empty, caller is responsible for freeing all its entries.
> +
> + Note that ANNEX must be NULL if the remote does not explicitly allow
> + qXfer:libraries-svr4:read packets with non-empty annexes. Support for
> + this can be checked using target_augmented_libraries_svr4_read (). */
So you can gdb_assert such requirement here.
>
> static int
> -svr4_current_sos_via_xfer_libraries (struct svr4_library_list *list)
> +svr4_current_sos_via_xfer_libraries (struct svr4_library_list *list,
> + const char *annex)
> {
> char *svr4_library_document;
> int result;
> @@ -1121,7 +1247,7 @@ svr4_current_sos_via_xfer_libraries (struct svr4_library_list *list)
> /* Fetch the list of shared libraries. */
> svr4_library_document = target_read_stralloc (¤t_target,
> TARGET_OBJECT_LIBRARIES_SVR4,
> - NULL);
> + annex);
> if (svr4_library_document == NULL)
> return 0;
>
> @@ -1135,7 +1261,8 @@ svr4_current_sos_via_xfer_libraries (struct svr4_library_list *list)
> #else
>
> static int
> -svr4_current_sos_via_xfer_libraries (struct svr4_library_list *list)
> +svr4_current_sos_via_xfer_libraries (struct svr4_library_list *list,
> + const char *annex)
> {
> return 0;
> }
> @@ -1169,15 +1296,17 @@ svr4_default_sos (void)
> return new;
> }
>
> -/* Read the whole inferior libraries chain starting at address LM. Add the
> - entries to the tail referenced by LINK_PTR_PTR. Ignore the first entry if
> - IGNORE_FIRST and set global MAIN_LM_ADDR according to it. */
> +/* Read the whole inferior libraries chain starting at address LM.
> + Expect the first entry in the chain's previous entry to be PREV_LM.
> + Add the entries to the tail referenced by LINK_PTR_PTR. Ignore the
> + first entry if IGNORE_FIRST and set global MAIN_LM_ADDR according
> + to it. Returns nonzero upon success. */
Please document what does a failure mean as it is used by the callers,
something like:
If zero is returned the entries stored to LINK_PTR_PTR are still valid
although they may represent only part of the inferior library list.
>
> -static void
> -svr4_read_so_list (CORE_ADDR lm, struct so_list ***link_ptr_ptr,
> - int ignore_first)
> +static int
> +svr4_read_so_list (CORE_ADDR lm, CORE_ADDR prev_lm,
> + struct so_list ***link_ptr_ptr, int ignore_first)
> {
> - CORE_ADDR prev_lm = 0, next_lm;
> + CORE_ADDR next_lm;
>
> for (; lm != 0; prev_lm = lm, lm = next_lm)
> {
> @@ -1193,7 +1322,7 @@ svr4_read_so_list (CORE_ADDR lm, struct so_list ***link_ptr_ptr,
> if (new->lm_info == NULL)
> {
> do_cleanups (old_chain);
> - break;
> + return 0;
> }
>
> next_lm = new->lm_info->l_next;
> @@ -1204,7 +1333,7 @@ svr4_read_so_list (CORE_ADDR lm, struct so_list ***link_ptr_ptr,
> paddress (target_gdbarch (), prev_lm),
> paddress (target_gdbarch (), new->lm_info->l_prev));
> do_cleanups (old_chain);
> - break;
> + return 0;
> }
>
> /* For SVR4 versions, the first entry in the link map is for the
> @@ -1250,17 +1379,19 @@ svr4_read_so_list (CORE_ADDR lm, struct so_list ***link_ptr_ptr,
> **link_ptr_ptr = new;
> *link_ptr_ptr = &new->next;
> }
> +
> + return 1;
> }
>
> -/* Implement the "current_sos" target_so_ops method. */
> +/* Read the full list of currently loaded shared objects directly from
> + the inferior. */
>
> static struct so_list *
> -svr4_current_sos (void)
> +svr4_current_sos_direct (struct svr4_info *info)
Meaning of 'direct' seems ambiguous/unclear to me, maybe 'uncached'?
Just a hint, OK even with 'direct'.
> {
> CORE_ADDR lm;
> struct so_list *head = NULL;
> struct so_list **link_ptr = &head;
> - struct svr4_info *info;
> struct cleanup *back_to;
> int ignore_first;
> struct svr4_library_list library_list;
> @@ -1273,19 +1404,16 @@ svr4_current_sos (void)
> Unfortunately statically linked inferiors will also fall back through this
> suboptimal code path. */
>
> - if (svr4_current_sos_via_xfer_libraries (&library_list))
> + info->using_xfer = svr4_current_sos_via_xfer_libraries (&library_list,
> + NULL);
> + if (info->using_xfer)
> {
> if (library_list.main_lm)
> - {
> - info = get_svr4_info ();
> - info->main_lm_addr = library_list.main_lm;
> - }
> + info->main_lm_addr = library_list.main_lm;
>
> return library_list.head ? library_list.head : svr4_default_sos ();
> }
>
> - info = get_svr4_info ();
> -
> /* Always locate the debug struct, in case it has moved. */
> info->debug_base = 0;
> locate_base (info);
> @@ -1308,7 +1436,7 @@ svr4_current_sos (void)
> `struct so_list' nodes. */
> lm = solib_svr4_r_map (info);
> if (lm)
> - svr4_read_so_list (lm, &link_ptr, ignore_first);
> + svr4_read_so_list (lm, 0, &link_ptr, ignore_first);
>
> /* On Solaris, the dynamic linker is not in the normal list of
> shared objects, so make sure we pick it up too. Having
> @@ -1316,7 +1444,7 @@ svr4_current_sos (void)
> for skipping dynamic linker resolver code. */
> lm = solib_svr4_r_ldsomap (info);
> if (lm)
> - svr4_read_so_list (lm, &link_ptr, 0);
> + svr4_read_so_list (lm, 0, &link_ptr, 0);
>
> discard_cleanups (back_to);
>
> @@ -1326,6 +1454,22 @@ svr4_current_sos (void)
> return head;
> }
>
> +/* Implement the "current_sos" target_so_ops method. */
> +
> +static struct so_list *
> +svr4_current_sos (void)
> +{
> + struct svr4_info *info = get_svr4_info ();
> +
> + /* If we are using the probes interface and the solib list has
> + been cached then we simply return that. */
> + if (info->solib_list != NULL)
> + return svr4_copy_library_list (info->solib_list);
> +
> + /* Otherwise obtain the solib list directly from the inferior. */
> + return svr4_current_sos_direct (info);
> +}
> +
> /* Get the address of the link_map for a given OBJFILE. */
>
> CORE_ADDR
> @@ -1408,6 +1552,434 @@ exec_entry_point (struct bfd *abfd, struct target_ops *targ)
> return gdbarch_addr_bits_remove (target_gdbarch (), addr);
> }
>
> +/* A probe and its associated action. */
> +
> +struct probe_and_action
> +{
> + /* The probe. */
> + struct probe *probe;
> +
> + /* The action. */
> + enum probe_action action;
> +};
> +
> +/* Returns a hash code for the probe_and_action referenced by p. */
> +
> +static hashval_t
> +hash_probe_and_action (const void *p)
> +{
> + const struct probe_and_action *pa = p;
> +
> + return (hashval_t) pa->probe->address;
> +}
> +
> +/* Returns non-zero if the probe_and_actions referenced by p1 and p2
> + are equal. */
> +
> +static int
> +equal_probe_and_action (const void *p1, const void *p2)
> +{
> + const struct probe_and_action *pa1 = p1;
> + const struct probe_and_action *pa2 = p2;
> +
> + return pa1->probe->address == pa2->probe->address;
> +}
> +
> +/* Register a solib event probe and its associated action in the
> + probes table. */
> +
> +static void
> +register_solib_event_probe (struct probe *probe, enum probe_action action)
> +{
> + struct svr4_info *info = get_svr4_info ();
> + struct probe_and_action lookup, *pa;
> + void **slot;
> +
> + /* Create the probes table, if necessary. */
> + if (info->probes_table == NULL)
> + {
These curly brackets are not needed.
> + info->probes_table = htab_create_alloc (1, hash_probe_and_action,
> + equal_probe_and_action,
> + xfree, xcalloc, xfree);
> + }
> +
> + lookup.probe = probe;
> + slot = htab_find_slot (info->probes_table, &lookup, INSERT);
> + gdb_assert (*slot == HTAB_EMPTY_ENTRY);
> +
> + pa = XCNEW (struct probe_and_action);
> + pa->probe = probe;
> + pa->action = action;
> +
> + *slot = pa;
> +}
> +
> +/* Get the solib event probe at the specified location, and the
> + action associated with it. Returns NULL if no solib event probe
> + was found. */
> +
> +static struct probe_and_action *
> +solib_event_probe_at (struct svr4_info *info, CORE_ADDR address)
> +{
> + struct probe lookup_probe;
> + struct probe_and_action lookup;
> + void **slot;
> +
> + lookup_probe.address = address;
> + lookup.probe = &lookup_probe;
> + slot = htab_find_slot (info->probes_table, &lookup, NO_INSERT);
> +
> + if (slot == NULL)
> + return NULL;
> +
> + return (struct probe_and_action *) *slot;
> +}
> +
> +/* Decide what action to take when the specified solib event probe is
> + hit. */
> +
> +static enum probe_action
> +solib_event_probe_action (struct probe_and_action *pa)
> +{
> + enum probe_action action;
> + unsigned probe_argc;
> +
> + action = pa->action;
> + if (action == DO_NOTHING || action == PROBES_INTERFACE_FAILED)
> + return action;
> +
> + gdb_assert (action == FULL_RELOAD || action == UPDATE_OR_RELOAD);
> +
> + /* Check that an appropriate number of arguments has been supplied.
> + We expect:
> + arg0: Lmid_t lmid (mandatory)
> + arg1: struct r_debug *debug_base (mandatory)
> + arg2: struct link_map *new (optional, for incremental updates) */
> + probe_argc = get_probe_argument_count (pa->probe);
> + if (probe_argc == 2)
> + action = FULL_RELOAD;
> + else if (probe_argc < 2)
> + action = PROBES_INTERFACE_FAILED;
> +
> + return action;
> +}
> +
> +/* Populate the shared object list by reading the entire list of
> + shared objects from the inferior. Returns nonzero on success. */
> +
> +static int
> +solist_update_full (struct svr4_info *info)
> +{
> + svr4_free_library_list (&info->solib_list);
I find it a bit fragily this way, I would find worth it here also:
info->solib_list = NULL;
As svr4_current_sos_direct is a pretty big function and it could somehow
check/update even info->solib_list possibly in the future.
Maybe a matter of opinion a bit.
> + info->solib_list = svr4_current_sos_direct (info);
> +
> + return 1;
> +}
> +
> +/* Update the shared object list starting from the link-map entry
> + passed by the linker in the probe's third argument. Returns
> + nonzero if the list was successfully updated, or zero to indicate
> + failure. */
> +
> +static int
> +solist_update_incremental (struct svr4_info *info, CORE_ADDR lm)
> +{
> + struct so_list *tail;
> + CORE_ADDR prev_lm;
> +
> + /* Fall back to a full update if we haven't read anything yet. */
> + if (info->solib_list == NULL)
> + return 0;
> +
> + /* Fall back to a full update if we are using a remote target
> + that does not support incremental transfers. */
> + if (info->using_xfer && !target_augmented_libraries_svr4_read())
> + return 0;
> +
> + /* Walk to the end of the list. */
> + for (tail = info->solib_list; tail->next; tail = tail->next);
Not sure if it is any Coding Style but:
for (tail = info->solib_list; tail->next; tail = tail->next)
/* Nothing. */;
> + prev_lm = tail->lm_info->lm_addr;
> +
> + /* Read the new objects. */
> + if (info->using_xfer)
> + {
> + struct svr4_library_list library_list;
> + char annex[64];
> +
> + xsnprintf (annex, sizeof (annex), "start=%lx;prev=%lx", lm, prev_lm);
CORE_ADDR is not compatible with %lx in some GDB configurations.
One may have Windows 32-bit host GDB with 32-bit long and 64-bit remote target
and therefore also 64-bit CORE_ADDR.
Unfortunately functions like paddress or core_addr_to_string_nz output also
the 0x prefix so you need to use phex_nz (addr, sizeof (addr)).
I hope the width stripping of paddress is not required for solib-svr4.c
targets.
> + if (!svr4_current_sos_via_xfer_libraries (&library_list, annex))
> + return 0;
> +
> + tail->next = library_list.head;
> + }
> + else
> + {
> + struct so_list **link = &tail->next;
> +
> + if (!svr4_read_so_list (lm, prev_lm, &link, 0))
You should set the last IGNORE_FIRST parameter properly. While glibc has ""
there AFAIK some OSes like Solaris may have some valid pathname there which
would confuse GDB listing the executable also as a shared library.
> + return 0;
> + }
> +
> + return 1;
> +}
> +
> +/* Disable the probes-based linker interface and revert to the
> + original interface. We don't reset the breakpoints as the
> + ones set up for the probes-based interface are adequate. */
> +
> +static void
> +disable_probes_interface_cleanup (void *arg)
> +{
> + struct svr4_info *info = get_svr4_info ();
> +
> + warning (_("Probes-based dynamic linker interface failed.\n"
> + "Reverting to original interface.\n"));
> +
> + free_probes_table (info);
> + free_solib_list (info);
> +}
> +
> +/* Update the solib list as appropriate when using the
> + probes-based linker interface. Do nothing if using the
> + standard interface. */
> +
> +static void
> +svr4_handle_solib_event (void)
> +{
> + struct svr4_info *info = get_svr4_info ();
> + struct probe_and_action *pa;
> + enum probe_action action;
> + struct cleanup *old_chain, *usm_chain;
> + struct value *val;
> + CORE_ADDR pc, debug_base, lm = 0;
> + int is_initial_ns;
> +
> + /* Do nothing if not using the probes interface. */
> + if (info->probes_table == NULL)
> + return;
> +
> + /* If anything goes wrong we revert to the original linker
> + interface. */
> + old_chain = make_cleanup (disable_probes_interface_cleanup, NULL);
> +
> + pc = regcache_read_pc (get_current_regcache ());
> + pa = solib_event_probe_at (info, pc);
> + if (pa == NULL)
> + goto error;
> +
> + action = solib_event_probe_action (pa);
> + if (action == PROBES_INTERFACE_FAILED)
> + goto error;
> +
> + if (action == DO_NOTHING)
Leaked OLD_CHAIN cleanups.
> + return;
> +
> + /* EVALUATE_PROBE_ARGUMENT looks up symbols in the dynamic linker
Functions should not be uppercased. Only variables are uppercased if you
refer to their value (it is usually a bit ambiguous if you refer to their
value or to the variable itself but that is offtopic here)..
http://www.gnu.org/prep/standards/standards.html
The variable name itself should be lower case, but write it in upper
case when you are speaking about the value rather than the variable
itself. Thus, “the inode number NODE_NUM” rather than “an inode”.
It is at more places around.
> + using FIND_PC_SECTION. FIND_PC_SECTION is accelerated by a cache
> + called the section map. The section map is invalidated every
> + time a shared library is loaded or unloaded, and if the inferior
> + is generating a lot of shared library events then the section map
> + will be updated every time SVR4_HANDLE_SOLIB_EVENT is called.
> + We called FIND_PC_SECTION in SVR4_CREATE_SOLIB_EVENT_BREAKPOINTS,
> + so we can guarantee that the dynamic linker's sections are in the
> + section map. We can therefore inhibit section map updates across
> + these calls to EVALUATE_PROBE_ARGUMENT and save a lot of time. */
> + inhibit_section_map_updates ();
> + usm_chain = make_cleanup (resume_section_map_updates_cleanup, NULL);
> +
> + val = evaluate_probe_argument (pa->probe, 1);
> + if (val == NULL)
> + goto error;
> +
> + debug_base = value_as_address (val);
> + if (debug_base == 0)
> + goto error;
> +
> + /* Always locate the debug struct, in case it moved. */
> + info->debug_base = 0;
> + if (locate_base (info) == 0)
> + goto error;
> +
> + /* Do not process namespaces other than the initial one. */
I find a more rich description appropriate given how long this issue was being
discussed:
Therefore dlmopen is currently not supported by GDB.
> + if (debug_base != info->debug_base)
> + action = DO_NOTHING;
> +
> + if (action == UPDATE_OR_RELOAD)
> + {
> + val = evaluate_probe_argument (pa->probe, 2);
> + if (val != NULL)
> + lm = value_as_address (val);
> +
> + if (lm == 0)
> + action = FULL_RELOAD;
> + }
> +
> + /* Resume section map updates. */
> + do_cleanups (usm_chain);
> +
> + if (action == UPDATE_OR_RELOAD)
> + {
> + if (!solist_update_incremental (info, lm))
> + action = FULL_RELOAD;
> + }
> +
> + if (action == FULL_RELOAD)
> + {
> + if (!solist_update_full (info))
> + goto error;
> + }
> +
> + discard_cleanups (old_chain);
> + return;
> +
> + error:
> + /* We should never reach here, but if we do we disable the
> + probes interface and revert to the original interface. */
> +
> + do_cleanups (old_chain);
You could just always do { do_cleanups; return; } IMO and avoid the goto but
up to you.
> +}
> +
> +/* Helper function for svr4_update_solib_event_breakpoints. */
> +
> +static int
> +svr4_update_solib_event_breakpoint (struct breakpoint *b, void *arg)
> +{
> + struct svr4_info *info = get_svr4_info ();
> + struct bp_location *loc;
> +
> + if (b->type != bp_shlib_event)
> + return 0; /* Continue iterating. */
Comment should be on a separate line (and therefore this one in a { block } ),
likewise below.
> +
> + for (loc = b->loc; loc; loc = loc->next)
> + {
> + struct probe_and_action *pa = solib_event_probe_at (info, loc->address);
> +
> + if (pa != NULL)
> + {
> + if (pa->action == DO_NOTHING)
> + b->enable_state = (stop_on_solib_events
> + ? bp_enabled : bp_disabled);
> +
> + return 0; /* Continue iterating. */
> + }
> + }
> +
> + return 0; /* Continue iterating. */
> +}
> +
> +/* Enable or disable optional solib event breakpoints as appropriate.
> + Called whenever stop_on_solib_events is changed. */
It seems a bit suspicious that no update_global_location_list* is called.
Why is it safe?
> +
> +static void
> +svr4_update_solib_event_breakpoints (void)
> +{
> + struct svr4_info *info = get_svr4_info ();
> +
> + if (info->probes_table)
According to the GDB Coding Style:
if (info->probes_table != NULL)
> + iterate_over_breakpoints (svr4_update_solib_event_breakpoint, NULL);
> +}
> +
> +/* Create and register solib event breakpoints. */
One should describe the parametr PROBES, that it is an array of NUM_PROBES
elements containing multi-location breakpoints etc.
> +
> +static void
> +svr4_create_probe_breakpoints (struct gdbarch *gdbarch,
> + VEC (probe_p) **probes)
> +{
> + int i;
> +
> + for (i = 0; i < NUM_PROBES; i++)
> + {
> + enum probe_action action = probe_info[i].action;
> + struct probe *probe;
> + int ix;
> +
> + for (ix = 0;
> + VEC_iterate (probe_p, probes[i], ix, probe);
> + ++ix)
> + {
> + create_solib_event_breakpoint (gdbarch, probe->address);
> + register_solib_event_probe (probe, action);
> + }
> + }
> +
> + svr4_update_solib_event_breakpoints ();
Here and also in svr4_update_solib_event_breakpoints seems a bit suspicious
that no update_global_location_list* is called. Why is it safe?
> +}
> +
> +/* Both the SunOS and the SVR4 dynamic linkers call a marker function
> + before and after mapping and unmapping shared libraries. The sole
> + purpose of this method is to allow debuggers to set a breakpoint so
> + they can track these changes.
> +
> + Some versions of the glibc dynamic linker contain named probes
> + to allow more fine grained stopping. Given the address of the
> + original marker function, this function attempts to find these
> + probes, and if found, sets breakpoints on those instead. If the
> + probes aren't found, a single breakpoint is set on the original
> + marker function. */
> +
> +static void
> +svr4_create_solib_event_breakpoints (struct gdbarch *gdbarch,
> + CORE_ADDR address)
> +{
> + struct svr4_info *info = get_svr4_info ();
Unused variable.
> + struct obj_section *os;
> +
> + os = find_pc_section (address);
> + if (os != NULL)
> + {
> + int with_prefix;
> +
> + for (with_prefix = 0; with_prefix <= 1; with_prefix++)
> + {
> + VEC (probe_p) *probes[NUM_PROBES];
> + int all_probes_found = 1;
> + int i;
> +
> + memset (probes, 0, sizeof (probes));
> + for (i = 0; i < NUM_PROBES; i++)
> + {
> + char name[32] = { '\0' };
> +
> + /* Fedora 17, RHEL 6.2, and RHEL 6.3 shipped with an
> + early version of the probes code in which the probes'
> + names were prefixed with "rtld_" and the "map_failed"
> + probe did not exist. The locations of the probes are
> + otherwise the same, so we check for probes with
> + prefixed names if probes with unprefixed names are
> + not present. */
> +
> + if (with_prefix)
> + strncat (name, "rtld_", sizeof (name) - strlen (name) - 1);
> +
> + strncat (name, probe_info[i].name,
> + sizeof (name) - strlen (name) - 1);
> +
> + probes[i] = find_probes_in_objfile (os->objfile, "rtld", name);
> +
Some comment why "rtld_map_failed" failure is ignore would be nice.
> + if (!strcmp (name, "rtld_map_failed"))
> + continue;
> +
> + if (!VEC_length (probe_p, probes[i]))
There is also VEC_empty...
> + {
> + all_probes_found = 0;
> + break;
> + }
> + }
> +
> + if (all_probes_found)
> + svr4_create_probe_breakpoints (gdbarch, probes);
> +
> + for (i = 0; i < NUM_PROBES; i++)
> + VEC_free (probe_p, probes[i]);
> +
> + if (all_probes_found)
> + return;
> + }
> + }
> +
> + create_solib_event_breakpoint (gdbarch, address);
> +}
> +
> /* Helper function for gdb_bfd_lookup_symbol. */
>
> static int
> @@ -1460,6 +2032,8 @@ enable_break (struct svr4_info *info, int from_tty)
> info->interp_text_sect_low = info->interp_text_sect_high = 0;
> info->interp_plt_sect_low = info->interp_plt_sect_high = 0;
>
> + free_probes_table (info);
Why is this one needed and free_solib_list is not needed?
> +
> /* If we already have a shared library list in the target, and
> r_debug contains r_brk, set the breakpoint there - this should
> mean r_brk has already been relocated. Assume the dynamic linker
[...]
Thanks,
Jan
^ permalink raw reply [flat|nested] 59+ messages in thread* [RFA 5/7 take 2] Improved linker-debugger interface
2013-05-17 19:05 ` Jan Kratochvil
@ 2013-05-24 8:30 ` Gary Benson
2013-05-25 21:05 ` Jan Kratochvil
2013-05-29 18:51 ` Pedro Alves
0 siblings, 2 replies; 59+ messages in thread
From: Gary Benson @ 2013-05-24 8:30 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 5274 bytes --]
All issues not explicitly replied to below have been fixed as
suggested.
Jan Kratochvil wrote:
> On Thu, 16 May 2013 16:48:38 +0200, Gary Benson wrote:
> > diff --git a/gdb/solib-svr4.c b/gdb/solib-svr4.c
> > index 4e09472..6b4bdb0 100644
> [...]
> > -/* Implement the "current_sos" target_so_ops method. */
> > +/* Read the full list of currently loaded shared objects directly from
> > + the inferior. */
> >
> > static struct so_list *
> > -svr4_current_sos (void)
> > +svr4_current_sos_direct (struct svr4_info *info)
>
> Meaning of 'direct' seems ambiguous/unclear to me, maybe 'uncached'?
> Just a hint, OK even with 'direct'.
Naming this function was the final thing I did before mailing the
original patch... it has been svr4_current_sos_XXX for some time :)
When I started writing the incremental code I thought of the solibs
as being cached by GDB, but a few versions later I didn't like the
terminology and renamed all the variables. The stuff about caching
in the comments here was a hangover from that.
What I've done in the attached patch is to update the comments so
they don't mention caching. This should hopefully make what is
happening clearer. I've left the name as "direct" here, though
only because I can't think of anything better--I'm not especially
happy with the name myself.
Would "svr4_current_sos_1" be acceptable, or is the "_1" naming
discouraged?
> > +/* Populate the shared object list by reading the entire list of
> > + shared objects from the inferior. Returns nonzero on success. */
> > +
> > +static int
> > +solist_update_full (struct svr4_info *info)
> > +{
> > + svr4_free_library_list (&info->solib_list);
>
> I find it a bit fragily this way, I would find worth it here also:
> info->solib_list = NULL;
>
> As svr4_current_sos_direct is a pretty big function and it could
> somehow check/update even info->solib_list possibly in the future.
>
> Maybe a matter of opinion a bit.
That's a good idea and I've implemented it.
> > +/* Update the shared object list starting from the link-map entry
> > + passed by the linker in the probe's third argument. Returns
> > + nonzero if the list was successfully updated, or zero to indicate
> > + failure. */
> > +
> > +static int
> > +solist_update_incremental (struct svr4_info *info, CORE_ADDR lm)
> > +{
> > + struct so_list *tail;
> > + CORE_ADDR prev_lm;
> > +
> > + /* Fall back to a full update if we haven't read anything yet. */
> > + if (info->solib_list == NULL)
> > + return 0;
> > +
> > + /* Fall back to a full update if we are using a remote target
> > + that does not support incremental transfers. */
> > + if (info->using_xfer && !target_augmented_libraries_svr4_read())
> > + return 0;
> > +
> > + /* Walk to the end of the list. */
> > + for (tail = info->solib_list; tail->next; tail = tail->next);
[...]
> > + prev_lm = tail->lm_info->lm_addr;
> > +
> > + /* Read the new objects. */
> > + if (info->using_xfer)
> > + {
> > + struct svr4_library_list library_list;
> > + char annex[64];
> > +
> > + xsnprintf (annex, sizeof (annex), "start=%lx;prev=%lx", lm, prev_lm);
[...]
> > + if (!svr4_current_sos_via_xfer_libraries (&library_list, annex))
> > + return 0;
> > +
> > + tail->next = library_list.head;
> > + }
> > + else
> > + {
> > + struct so_list **link = &tail->next;
> > +
> > + if (!svr4_read_so_list (lm, prev_lm, &link, 0))
>
> You should set the last IGNORE_FIRST parameter properly. While
> glibc has "" there AFAIK some OSes like Solaris may have some valid
> pathname there which would confuse GDB listing the executable also
> as a shared library.
I set IGNORE_FIRST to zero here because for this particular call
svr4_read_so_list never sees the first element in the list. If
solist_update_incremental is called at the top of the list then
the "if (info->solib_list == NULL) return 0;" at the top of
solist_update_incremental causes it to defer to solist_update_full.
That uses svr4_current_sos_direct, which does set IGNORE_FIRST
correctly.
> > +static void
> > +svr4_handle_solib_event (void)
> > +{
[...]
>
> You could just always do { do_cleanups; return; } IMO and avoid the
> goto but up to you.
I have done this. The original code after the goto was more complex,
but now it is a single line this is a no-brainer.
> > +static int
> > +svr4_update_solib_event_breakpoint (struct breakpoint *b, void *arg)
> > +{
[...]
>
> It seems a bit suspicious that no update_global_location_list* is
> called. Why is it safe?
I didn't know about update_global_location_list. I've updated this
code to use enable_breakpoint and disable_breakpoint.
> > @@ -1460,6 +2032,8 @@ enable_break (struct svr4_info *info, int from_tty)
> > info->interp_text_sect_low = info->interp_text_sect_high = 0;
> > info->interp_plt_sect_low = info->interp_plt_sect_high = 0;
> >
> > + free_probes_table (info);
>
> Why is this one needed and free_solib_list is not needed?
free_solib_list is called in svr4_solib_create_inferior_hook.
I originally had the two calls together, in enable_break, but
doing it that way caused breakpoint resetting errors when the
inferior was restarted. There is a check for this in
info-shared.exp.
Thanks,
Gary
[-- Attachment #2: rtld-probes-5-main-changes.patch --]
[-- Type: text/plain, Size: 33293 bytes --]
2013-05-23 Gary Benson <gbenson@redhat.com>
* breakpoint.h (handle_solib_event): Moved function declaration
to solib.h.
* breakpoint.c (handle_solib_event): Moved function to solib.c.
(bpstat_stop_status): Pass new argument to handle_solib_event.
* solib.h (update_solib_breakpoints): New function declaration.
(handle_solib_event): Moved function declaration from
breakpoint.h.
* solib.c (update_solib_breakpoints): New function.
(handle_solib_event): Moved function from breakpoint.c.
Updated to call solib_ops->handle_event if not NULL.
* solist.h (target_so_ops): New fields "update_breakpoints" and
"handle_event".
* infrun.c (set_stop_on_solib_events): New function.
(_initialize_infrun): Use the above for "set
stop-on-solib-events".
(handle_inferior_event): Pass new argument to handle_solib_event.
* solib-svr4.c (probe.h): New include.
(svr4_free_library_list): New forward declaration.
(probe_action): New enum.
(probe_info): New struct.
(probe_info): New static variable.
(NUM_PROBES): New definition.
(svr4_info): New fields "using_xfer", "probes_table" and
"solib_list".
(free_probes_table): New function.
(free_solib_list): New function.
(svr4_pspace_data_cleanup): Free probes table and solib list.
(svr4_copy_library_list): New function.
(svr4_current_sos_via_xfer_libraries): New parameter "annex".
(svr4_read_so_list): New parameter "prev_lm".
(svr4_current_sos_direct): Renamed from "svr4_current_sos".
(svr4_current_sos): New function.
(probe_and_action): New struct.
(hash_probe_and_action): New function.
(equal_probe_and_action): Likewise.
(register_solib_event_probe): Likewise.
(solib_event_probe_at): Likewise.
(solib_event_probe_action): Likewise.
(solist_update_full): Likewise.
(solist_update_incremental): Likewise.
(disable_probes_interface_cleanup): Likewise.
(svr4_handle_solib_event): Likewise.
(svr4_update_solib_event_breakpoint): Likewise.
(svr4_update_solib_event_breakpoints): Likewise.
(svr4_create_solib_event_breakpoints): Likewise.
(enable_break): Free probes table before creating breakpoints.
Use svr4_create_solib_event_breakpoints to create breakpoints.
(svr4_solib_create_inferior_hook): Free the solib list.
(_initialize_svr4_solib): Initialise
svr4_so_ops.handle_solib_event and svr4_so_ops.update_breakpoints.
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index 7df1122..e996e54 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -1553,8 +1553,6 @@ extern int user_breakpoint_p (struct breakpoint *);
/* Attempt to determine architecture of location identified by SAL. */
extern struct gdbarch *get_sal_arch (struct symtab_and_line sal);
-extern void handle_solib_event (void);
-
extern void breakpoint_free_objfile (struct objfile *objfile);
extern char *ep_parse_optional_if_clause (char **arg);
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index f4f9325..639ddae 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -5343,21 +5343,6 @@ handle_jit_event (void)
target_terminal_inferior ();
}
-/* Handle an solib event by calling solib_add. */
-
-void
-handle_solib_event (void)
-{
- clear_program_space_solib_cache (current_inferior ()->pspace);
-
- /* Check for any newly added shared libraries if we're supposed to
- be adding them automatically. Switch terminal for any messages
- produced by breakpoint_re_set. */
- target_terminal_ours_for_output ();
- solib_add (NULL, 0, ¤t_target, auto_solib_add);
- target_terminal_inferior ();
-}
-
/* Prepare WHAT final decision for infrun. */
/* Decide what infrun needs to do with this bpstat. */
diff --git a/gdb/solib.h b/gdb/solib.h
index b811866..2108429 100644
--- a/gdb/solib.h
+++ b/gdb/solib.h
@@ -90,4 +90,12 @@ extern CORE_ADDR gdb_bfd_lookup_symbol_from_symtab (bfd *abfd,
void *),
void *data);
+/* Enable or disable optional solib event breakpoints as appropriate. */
+
+extern void update_solib_breakpoints (void);
+
+/* Handle an solib event by calling solib_add. */
+
+extern void handle_solib_event (void);
+
#endif /* SOLIB_H */
diff --git a/gdb/solib.c b/gdb/solib.c
index a3479c5..763b93c 100644
--- a/gdb/solib.c
+++ b/gdb/solib.c
@@ -1208,6 +1208,37 @@ no_shared_libraries (char *ignored, int from_tty)
objfile_purge_solibs ();
}
+/* See solib.h. */
+
+void
+update_solib_breakpoints (void)
+{
+ const struct target_so_ops *ops = solib_ops (target_gdbarch ());
+
+ if (ops->update_breakpoints != NULL)
+ ops->update_breakpoints ();
+}
+
+/* See solib.h. */
+
+void
+handle_solib_event (void)
+{
+ const struct target_so_ops *ops = solib_ops (target_gdbarch ());
+
+ if (ops->handle_event != NULL)
+ ops->handle_event ();
+
+ clear_program_space_solib_cache (current_inferior ()->pspace);
+
+ /* Check for any newly added shared libraries if we're supposed to
+ be adding them automatically. Switch terminal for any messages
+ produced by breakpoint_re_set. */
+ target_terminal_ours_for_output ();
+ solib_add (NULL, 0, ¤t_target, auto_solib_add);
+ target_terminal_inferior ();
+}
+
/* Reload shared libraries, but avoid reloading the same symbol file
we already have loaded. */
diff --git a/gdb/solist.h b/gdb/solist.h
index 0495474..244484a 100644
--- a/gdb/solist.h
+++ b/gdb/solist.h
@@ -153,6 +153,19 @@ struct target_so_ops
core file (in particular, for readonly sections). */
int (*keep_data_in_core) (CORE_ADDR vaddr,
unsigned long size);
+
+ /* Enable or disable optional solib event breakpoints as
+ appropriate. This should be called whenever
+ stop_on_solib_events is changed. This pointer can be
+ NULL, in which case no enabling or disabling is necessary
+ for this target. */
+ void (*update_breakpoints) (void);
+
+ /* Target-specific processing of solib events that will be
+ performed before solib_add is called. This pointer can be
+ NULL, in which case no specific preprocessing is necessary
+ for this target. */
+ void (*handle_event) (void);
};
/* Free the memory associated with a (so_list *). */
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 54e92f2..a020dd6 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -370,6 +370,16 @@ static struct symbol *step_start_function;
/* Nonzero if we want to give control to the user when we're notified
of shared library events by the dynamic linker. */
int stop_on_solib_events;
+
+/* Enable or disable optional shared library event breakpoints
+ as appropriate when the above flag is changed. */
+
+static void
+set_stop_on_solib_events (char *args, int from_tty, struct cmd_list_element *c)
+{
+ update_solib_breakpoints ();
+}
+
static void
show_stop_on_solib_events (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
@@ -7303,7 +7313,7 @@ Show stopping for shared library events."), _("\
If nonzero, gdb will give control to the user when the dynamic linker\n\
notifies gdb of shared library events. The most common event of interest\n\
to the user would be loading/unloading of a new library."),
- NULL,
+ set_stop_on_solib_events,
show_stop_on_solib_events,
&setlist, &showlist);
diff --git a/gdb/solib-svr4.c b/gdb/solib-svr4.c
index 055fcb7..066b5f9 100644
--- a/gdb/solib-svr4.c
+++ b/gdb/solib-svr4.c
@@ -46,10 +46,12 @@
#include "auxv.h"
#include "exceptions.h"
#include "gdb_bfd.h"
+#include "probe.h"
static struct link_map_offsets *svr4_fetch_link_map_offsets (void);
static int svr4_have_link_map_offsets (void);
static void svr4_relocate_main_executable (void);
+static void svr4_free_library_list (void *p_list);
/* Link map info to include in an allocated so_list entry. */
@@ -106,6 +108,55 @@ static const char * const main_name_list[] =
NULL
};
+/* What to do when a probe stop occurs. */
+
+enum probe_action
+{
+ /* Something went seriously wrong. Stop using probes and
+ revert to using the older interface. */
+ PROBES_INTERFACE_FAILED,
+
+ /* No action is required. The shared object list is still
+ valid. */
+ DO_NOTHING,
+
+ /* The shared object list should be reloaded entirely. */
+ FULL_RELOAD,
+
+ /* Attempt to incrementally update the shared object list. If
+ the update fails or is not possible, fall back to reloading
+ the list in full. */
+ UPDATE_OR_RELOAD,
+};
+
+/* A probe's name and its associated action. */
+
+struct probe_info
+{
+ /* The name of the probe. */
+ const char *name;
+
+ /* What to do when a probe stop occurs. */
+ enum probe_action action;
+};
+
+/* A list of named probes and their associated actions. If all
+ probes are present in the dynamic linker then the probes-based
+ interface will be used. */
+
+static const struct probe_info probe_info[] =
+{
+ { "init_start", DO_NOTHING },
+ { "init_complete", FULL_RELOAD },
+ { "map_start", DO_NOTHING },
+ { "map_failed", DO_NOTHING },
+ { "reloc_complete", UPDATE_OR_RELOAD },
+ { "unmap_start", DO_NOTHING },
+ { "unmap_complete", FULL_RELOAD },
+};
+
+#define NUM_PROBES ARRAY_SIZE (probe_info)
+
/* Return non-zero if GDB_SO_NAME and INFERIOR_SO_NAME represent
the same shared library. */
@@ -313,17 +364,58 @@ struct svr4_info
CORE_ADDR interp_text_sect_high;
CORE_ADDR interp_plt_sect_low;
CORE_ADDR interp_plt_sect_high;
+
+ /* Nonzero if the list of objects was last obtained from the target
+ via qXfer:libraries-svr4:read. */
+ int using_xfer;
+
+ /* Table of struct probe_and_action instances, used by the
+ probes-based interface to map breakpoint addresses to probes
+ and their associated actions. Lookup is performed using
+ probe_and_action->probe->address. */
+ htab_t probes_table;
+
+ /* List of objects loaded into the inferior, used by the probes-
+ based interface. */
+ struct so_list *solib_list;
};
/* Per-program-space data key. */
static const struct program_space_data *solib_svr4_pspace_data;
+/* Free the probes table. */
+
+static void
+free_probes_table (struct svr4_info *info)
+{
+ if (info->probes_table == NULL)
+ return;
+
+ htab_delete (info->probes_table);
+ info->probes_table = NULL;
+}
+
+/* Free the solib list. */
+
+static void
+free_solib_list (struct svr4_info *info)
+{
+ svr4_free_library_list (&info->solib_list);
+ info->solib_list = NULL;
+}
+
static void
svr4_pspace_data_cleanup (struct program_space *pspace, void *arg)
{
struct svr4_info *info;
info = program_space_data (pspace, solib_svr4_pspace_data);
+ if (info == NULL)
+ return;
+
+ free_probes_table (info);
+ free_solib_list (info);
+
xfree (info);
}
@@ -991,6 +1083,37 @@ svr4_free_library_list (void *p_list)
}
}
+/* Copy library list. */
+
+static struct so_list *
+svr4_copy_library_list (struct so_list *src)
+{
+ struct so_list *dst = NULL;
+ struct so_list **link = &dst;
+
+ while (src != NULL)
+ {
+ struct so_list *new;
+
+ new = xmalloc (sizeof (struct so_list));
+ memcpy (new, src, sizeof (struct so_list));
+
+ if (src->lm_info != NULL)
+ {
+ new->lm_info = xmalloc (sizeof (struct lm_info));
+ memcpy (new->lm_info, src->lm_info, sizeof (struct lm_info));
+ }
+
+ new->next = NULL;
+ *link = new;
+ link = &new->next;
+
+ src = src->next;
+ }
+
+ return dst;
+}
+
#ifdef HAVE_LIBEXPAT
#include "xml-support.h"
@@ -1106,23 +1229,30 @@ svr4_parse_libraries (const char *document, struct svr4_library_list *list)
return 0;
}
-/* Attempt to get so_list from target via qXfer:libraries:read packet.
+/* Attempt to get so_list from target via qXfer:libraries-svr4:read packet.
Return 0 if packet not supported, *SO_LIST_RETURN is not modified in such
case. Return 1 if *SO_LIST_RETURN contains the library list, it may be
- empty, caller is responsible for freeing all its entries. */
+ empty, caller is responsible for freeing all its entries.
+
+ Note that ANNEX must be NULL if the remote does not explicitly allow
+ qXfer:libraries-svr4:read packets with non-empty annexes. Support for
+ this can be checked using target_augmented_libraries_svr4_read (). */
static int
-svr4_current_sos_via_xfer_libraries (struct svr4_library_list *list)
+svr4_current_sos_via_xfer_libraries (struct svr4_library_list *list,
+ const char *annex)
{
char *svr4_library_document;
int result;
struct cleanup *back_to;
+ gdb_assert (annex == NULL || target_augmented_libraries_svr4_read());
+
/* Fetch the list of shared libraries. */
svr4_library_document = target_read_stralloc (¤t_target,
TARGET_OBJECT_LIBRARIES_SVR4,
- NULL);
+ annex);
if (svr4_library_document == NULL)
return 0;
@@ -1136,7 +1266,8 @@ svr4_current_sos_via_xfer_libraries (struct svr4_library_list *list)
#else
static int
-svr4_current_sos_via_xfer_libraries (struct svr4_library_list *list)
+svr4_current_sos_via_xfer_libraries (struct svr4_library_list *list,
+ const char *annex)
{
return 0;
}
@@ -1170,15 +1301,19 @@ svr4_default_sos (void)
return new;
}
-/* Read the whole inferior libraries chain starting at address LM. Add the
- entries to the tail referenced by LINK_PTR_PTR. Ignore the first entry if
- IGNORE_FIRST and set global MAIN_LM_ADDR according to it. */
+/* Read the whole inferior libraries chain starting at address LM.
+ Expect the first entry in the chain's previous entry to be PREV_LM.
+ Add the entries to the tail referenced by LINK_PTR_PTR. Ignore the
+ first entry if IGNORE_FIRST and set global MAIN_LM_ADDR according
+ to it. Returns nonzero upon success. If zero is returned the
+ entries stored to LINK_PTR_PTR are still valid although they may
+ represent only part of the inferior library list. */
-static void
-svr4_read_so_list (CORE_ADDR lm, struct so_list ***link_ptr_ptr,
- int ignore_first)
+static int
+svr4_read_so_list (CORE_ADDR lm, CORE_ADDR prev_lm,
+ struct so_list ***link_ptr_ptr, int ignore_first)
{
- CORE_ADDR prev_lm = 0, next_lm;
+ CORE_ADDR next_lm;
for (; lm != 0; prev_lm = lm, lm = next_lm)
{
@@ -1194,7 +1329,7 @@ svr4_read_so_list (CORE_ADDR lm, struct so_list ***link_ptr_ptr,
if (new->lm_info == NULL)
{
do_cleanups (old_chain);
- break;
+ return 0;
}
next_lm = new->lm_info->l_next;
@@ -1205,7 +1340,7 @@ svr4_read_so_list (CORE_ADDR lm, struct so_list ***link_ptr_ptr,
paddress (target_gdbarch (), prev_lm),
paddress (target_gdbarch (), new->lm_info->l_prev));
do_cleanups (old_chain);
- break;
+ return 0;
}
/* For SVR4 versions, the first entry in the link map is for the
@@ -1251,17 +1386,20 @@ svr4_read_so_list (CORE_ADDR lm, struct so_list ***link_ptr_ptr,
**link_ptr_ptr = new;
*link_ptr_ptr = &new->next;
}
+
+ return 1;
}
-/* Implement the "current_sos" target_so_ops method. */
+/* Read the full list of currently loaded shared objects directly
+ from the inferior, without referring to any libraries read and
+ stored by the probes interface. */
static struct so_list *
-svr4_current_sos (void)
+svr4_current_sos_direct (struct svr4_info *info)
{
CORE_ADDR lm;
struct so_list *head = NULL;
struct so_list **link_ptr = &head;
- struct svr4_info *info;
struct cleanup *back_to;
int ignore_first;
struct svr4_library_list library_list;
@@ -1274,19 +1412,16 @@ svr4_current_sos (void)
Unfortunately statically linked inferiors will also fall back through this
suboptimal code path. */
- if (svr4_current_sos_via_xfer_libraries (&library_list))
+ info->using_xfer = svr4_current_sos_via_xfer_libraries (&library_list,
+ NULL);
+ if (info->using_xfer)
{
if (library_list.main_lm)
- {
- info = get_svr4_info ();
- info->main_lm_addr = library_list.main_lm;
- }
+ info->main_lm_addr = library_list.main_lm;
return library_list.head ? library_list.head : svr4_default_sos ();
}
- info = get_svr4_info ();
-
/* Always locate the debug struct, in case it has moved. */
info->debug_base = 0;
locate_base (info);
@@ -1309,7 +1444,7 @@ svr4_current_sos (void)
`struct so_list' nodes. */
lm = solib_svr4_r_map (info);
if (lm)
- svr4_read_so_list (lm, &link_ptr, ignore_first);
+ svr4_read_so_list (lm, 0, &link_ptr, ignore_first);
/* On Solaris, the dynamic linker is not in the normal list of
shared objects, so make sure we pick it up too. Having
@@ -1317,7 +1452,7 @@ svr4_current_sos (void)
for skipping dynamic linker resolver code. */
lm = solib_svr4_r_ldsomap (info);
if (lm)
- svr4_read_so_list (lm, &link_ptr, 0);
+ svr4_read_so_list (lm, 0, &link_ptr, 0);
discard_cleanups (back_to);
@@ -1327,6 +1462,22 @@ svr4_current_sos (void)
return head;
}
+/* Implement the "current_sos" target_so_ops method. */
+
+static struct so_list *
+svr4_current_sos (void)
+{
+ struct svr4_info *info = get_svr4_info ();
+
+ /* If the solib list has been read and stored by the probes
+ interface then we return a copy of the stored list. */
+ if (info->solib_list != NULL)
+ return svr4_copy_library_list (info->solib_list);
+
+ /* Otherwise obtain the solib list directly from the inferior. */
+ return svr4_current_sos_direct (info);
+}
+
/* Get the address of the link_map for a given OBJFILE. */
CORE_ADDR
@@ -1409,6 +1560,467 @@ exec_entry_point (struct bfd *abfd, struct target_ops *targ)
return gdbarch_addr_bits_remove (target_gdbarch (), addr);
}
+/* A probe and its associated action. */
+
+struct probe_and_action
+{
+ /* The probe. */
+ struct probe *probe;
+
+ /* The action. */
+ enum probe_action action;
+};
+
+/* Returns a hash code for the probe_and_action referenced by p. */
+
+static hashval_t
+hash_probe_and_action (const void *p)
+{
+ const struct probe_and_action *pa = p;
+
+ return (hashval_t) pa->probe->address;
+}
+
+/* Returns non-zero if the probe_and_actions referenced by p1 and p2
+ are equal. */
+
+static int
+equal_probe_and_action (const void *p1, const void *p2)
+{
+ const struct probe_and_action *pa1 = p1;
+ const struct probe_and_action *pa2 = p2;
+
+ return pa1->probe->address == pa2->probe->address;
+}
+
+/* Register a solib event probe and its associated action in the
+ probes table. */
+
+static void
+register_solib_event_probe (struct probe *probe, enum probe_action action)
+{
+ struct svr4_info *info = get_svr4_info ();
+ struct probe_and_action lookup, *pa;
+ void **slot;
+
+ /* Create the probes table, if necessary. */
+ if (info->probes_table == NULL)
+ info->probes_table = htab_create_alloc (1, hash_probe_and_action,
+ equal_probe_and_action,
+ xfree, xcalloc, xfree);
+
+ lookup.probe = probe;
+ slot = htab_find_slot (info->probes_table, &lookup, INSERT);
+ gdb_assert (*slot == HTAB_EMPTY_ENTRY);
+
+ pa = XCNEW (struct probe_and_action);
+ pa->probe = probe;
+ pa->action = action;
+
+ *slot = pa;
+}
+
+/* Get the solib event probe at the specified location, and the
+ action associated with it. Returns NULL if no solib event probe
+ was found. */
+
+static struct probe_and_action *
+solib_event_probe_at (struct svr4_info *info, CORE_ADDR address)
+{
+ struct probe lookup_probe;
+ struct probe_and_action lookup;
+ void **slot;
+
+ lookup_probe.address = address;
+ lookup.probe = &lookup_probe;
+ slot = htab_find_slot (info->probes_table, &lookup, NO_INSERT);
+
+ if (slot == NULL)
+ return NULL;
+
+ return (struct probe_and_action *) *slot;
+}
+
+/* Decide what action to take when the specified solib event probe is
+ hit. */
+
+static enum probe_action
+solib_event_probe_action (struct probe_and_action *pa)
+{
+ enum probe_action action;
+ unsigned probe_argc;
+
+ action = pa->action;
+ if (action == DO_NOTHING || action == PROBES_INTERFACE_FAILED)
+ return action;
+
+ gdb_assert (action == FULL_RELOAD || action == UPDATE_OR_RELOAD);
+
+ /* Check that an appropriate number of arguments has been supplied.
+ We expect:
+ arg0: Lmid_t lmid (mandatory)
+ arg1: struct r_debug *debug_base (mandatory)
+ arg2: struct link_map *new (optional, for incremental updates) */
+ probe_argc = get_probe_argument_count (pa->probe);
+ if (probe_argc == 2)
+ action = FULL_RELOAD;
+ else if (probe_argc < 2)
+ action = PROBES_INTERFACE_FAILED;
+
+ return action;
+}
+
+/* Populate the shared object list by reading the entire list of
+ shared objects from the inferior. Returns nonzero on success. */
+
+static int
+solist_update_full (struct svr4_info *info)
+{
+ free_solib_list (info);
+ info->solib_list = svr4_current_sos_direct (info);
+
+ return 1;
+}
+
+/* Update the shared object list starting from the link-map entry
+ passed by the linker in the probe's third argument. Returns
+ nonzero if the list was successfully updated, or zero to indicate
+ failure. */
+
+static int
+solist_update_incremental (struct svr4_info *info, CORE_ADDR lm)
+{
+ struct so_list *tail;
+ CORE_ADDR prev_lm;
+
+ /* Fall back to a full update if we haven't read anything yet. */
+ if (info->solib_list == NULL)
+ return 0;
+
+ /* Fall back to a full update if we are using a remote target
+ that does not support incremental transfers. */
+ if (info->using_xfer && !target_augmented_libraries_svr4_read())
+ return 0;
+
+ /* Walk to the end of the list. */
+ for (tail = info->solib_list; tail->next; tail = tail->next)
+ /* Nothing. */;
+ prev_lm = tail->lm_info->lm_addr;
+
+ /* Read the new objects. */
+ if (info->using_xfer)
+ {
+ struct svr4_library_list library_list;
+ char annex[64];
+
+ xsnprintf (annex, sizeof (annex), "start=%s;prev=%s",
+ phex_nz (lm, sizeof (lm)),
+ phex_nz (prev_lm, sizeof (prev_lm)));
+ if (!svr4_current_sos_via_xfer_libraries (&library_list, annex))
+ return 0;
+
+ tail->next = library_list.head;
+ }
+ else
+ {
+ struct so_list **link = &tail->next;
+
+ if (!svr4_read_so_list (lm, prev_lm, &link, 0))
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Disable the probes-based linker interface and revert to the
+ original interface. We don't reset the breakpoints as the
+ ones set up for the probes-based interface are adequate. */
+
+static void
+disable_probes_interface_cleanup (void *arg)
+{
+ struct svr4_info *info = get_svr4_info ();
+
+ warning (_("Probes-based dynamic linker interface failed.\n"
+ "Reverting to original interface.\n"));
+
+ free_probes_table (info);
+ free_solib_list (info);
+}
+
+/* Update the solib list as appropriate when using the
+ probes-based linker interface. Do nothing if using the
+ standard interface. */
+
+static void
+svr4_handle_solib_event (void)
+{
+ struct svr4_info *info = get_svr4_info ();
+ struct probe_and_action *pa;
+ enum probe_action action;
+ struct cleanup *old_chain, *usm_chain;
+ struct value *val;
+ CORE_ADDR pc, debug_base, lm = 0;
+ int is_initial_ns;
+
+ /* Do nothing if not using the probes interface. */
+ if (info->probes_table == NULL)
+ return;
+
+ /* If anything goes wrong we revert to the original linker
+ interface. */
+ old_chain = make_cleanup (disable_probes_interface_cleanup, NULL);
+
+ pc = regcache_read_pc (get_current_regcache ());
+ pa = solib_event_probe_at (info, pc);
+ if (pa == NULL)
+ {
+ do_cleanups (old_chain);
+ return;
+ }
+
+ action = solib_event_probe_action (pa);
+ if (action == PROBES_INTERFACE_FAILED)
+ {
+ do_cleanups (old_chain);
+ return;
+ }
+
+ if (action == DO_NOTHING)
+ {
+ discard_cleanups (old_chain);
+ return;
+ }
+
+ /* evaluate_probe_argument looks up symbols in the dynamic linker
+ using find_pc_section. find_pc_section is accelerated by a cache
+ called the section map. The section map is invalidated every
+ time a shared library is loaded or unloaded, and if the inferior
+ is generating a lot of shared library events then the section map
+ will be updated every time svr4_handle_solib_event is called.
+ We called find_pc_section in svr4_create_solib_event_breakpoints,
+ so we can guarantee that the dynamic linker's sections are in the
+ section map. We can therefore inhibit section map updates across
+ these calls to evaluate_probe_argument and save a lot of time. */
+ inhibit_section_map_updates (current_program_space);
+ usm_chain = make_cleanup (resume_section_map_updates_cleanup,
+ current_program_space);
+
+ val = evaluate_probe_argument (pa->probe, 1);
+ if (val == NULL)
+ {
+ do_cleanups (old_chain);
+ return;
+ }
+
+ debug_base = value_as_address (val);
+ if (debug_base == 0)
+ {
+ do_cleanups (old_chain);
+ return;
+ }
+
+ /* Always locate the debug struct, in case it moved. */
+ info->debug_base = 0;
+ if (locate_base (info) == 0)
+ {
+ do_cleanups (old_chain);
+ return;
+ }
+
+ /* GDB does not currently support libraries loaded via dlmopen
+ into namespaces other than the initial one. We must ignore
+ any namespace other than the initial namespace here until
+ support for this is added to GDB. */
+ if (debug_base != info->debug_base)
+ action = DO_NOTHING;
+
+ if (action == UPDATE_OR_RELOAD)
+ {
+ val = evaluate_probe_argument (pa->probe, 2);
+ if (val != NULL)
+ lm = value_as_address (val);
+
+ if (lm == 0)
+ action = FULL_RELOAD;
+ }
+
+ /* Resume section map updates. */
+ do_cleanups (usm_chain);
+
+ if (action == UPDATE_OR_RELOAD)
+ {
+ if (!solist_update_incremental (info, lm))
+ action = FULL_RELOAD;
+ }
+
+ if (action == FULL_RELOAD)
+ {
+ if (!solist_update_full (info))
+ {
+ do_cleanups (old_chain);
+ return;
+ }
+ }
+
+ discard_cleanups (old_chain);
+}
+
+/* Helper function for svr4_update_solib_event_breakpoints. */
+
+static int
+svr4_update_solib_event_breakpoint (struct breakpoint *b, void *arg)
+{
+ struct svr4_info *info = get_svr4_info ();
+ struct bp_location *loc;
+
+ if (b->type != bp_shlib_event)
+ {
+ /* Continue iterating. */
+ return 0;
+ }
+
+ for (loc = b->loc; loc; loc = loc->next)
+ {
+ struct probe_and_action *pa = solib_event_probe_at (info, loc->address);
+
+ if (pa != NULL)
+ {
+ if (pa->action == DO_NOTHING)
+ {
+ if (b->enable_state == bp_disabled && stop_on_solib_events)
+ enable_breakpoint (b);
+ else if (b->enable_state == bp_enabled && !stop_on_solib_events)
+ disable_breakpoint (b);
+ }
+
+ /* Continue iterating. */
+ return 0;
+ }
+ }
+
+ /* Continue iterating. */
+ return 0;
+}
+
+/* Enable or disable optional solib event breakpoints as appropriate.
+ Called whenever stop_on_solib_events is changed. */
+
+static void
+svr4_update_solib_event_breakpoints (void)
+{
+ struct svr4_info *info = get_svr4_info ();
+
+ if (info->probes_table != NULL)
+ iterate_over_breakpoints (svr4_update_solib_event_breakpoint, NULL);
+}
+
+/* Create and register solib event breakpoints. PROBES is an array
+ of NUM_PROBES elements, each of which is vector of probes. A
+ solib event breakpoint will be created and registered for each
+ probe. */
+
+static void
+svr4_create_probe_breakpoints (struct gdbarch *gdbarch,
+ VEC (probe_p) **probes)
+{
+ int i;
+
+ for (i = 0; i < NUM_PROBES; i++)
+ {
+ enum probe_action action = probe_info[i].action;
+ struct probe *probe;
+ int ix;
+
+ for (ix = 0;
+ VEC_iterate (probe_p, probes[i], ix, probe);
+ ++ix)
+ {
+ create_solib_event_breakpoint (gdbarch, probe->address);
+ register_solib_event_probe (probe, action);
+ }
+ }
+
+ svr4_update_solib_event_breakpoints ();
+}
+
+/* Both the SunOS and the SVR4 dynamic linkers call a marker function
+ before and after mapping and unmapping shared libraries. The sole
+ purpose of this method is to allow debuggers to set a breakpoint so
+ they can track these changes.
+
+ Some versions of the glibc dynamic linker contain named probes
+ to allow more fine grained stopping. Given the address of the
+ original marker function, this function attempts to find these
+ probes, and if found, sets breakpoints on those instead. If the
+ probes aren't found, a single breakpoint is set on the original
+ marker function. */
+
+static void
+svr4_create_solib_event_breakpoints (struct gdbarch *gdbarch,
+ CORE_ADDR address)
+{
+ struct obj_section *os;
+
+ os = find_pc_section (address);
+ if (os != NULL)
+ {
+ int with_prefix;
+
+ for (with_prefix = 0; with_prefix <= 1; with_prefix++)
+ {
+ VEC (probe_p) *probes[NUM_PROBES];
+ int all_probes_found = 1;
+ int i;
+
+ memset (probes, 0, sizeof (probes));
+ for (i = 0; i < NUM_PROBES; i++)
+ {
+ char name[32] = { '\0' };
+
+ /* Fedora 17 and Red Hat Enterprise Linux 6.2-6.4
+ shipped with an early version of the probes code in
+ which the probes' names were prefixed with "rtld_"
+ and the "map_failed" probe did not exist. The
+ locations of the probes are otherwise the same, so
+ we check for probes with prefixed names if probes
+ with unprefixed names are not present. */
+
+ if (with_prefix)
+ strncat (name, "rtld_", sizeof (name) - strlen (name) - 1);
+
+ strncat (name, probe_info[i].name,
+ sizeof (name) - strlen (name) - 1);
+
+ probes[i] = find_probes_in_objfile (os->objfile, "rtld", name);
+
+ /* The "map_failed" probe did not exist in early
+ versions of the probes code in which the probes'
+ names were prefixed with "rtld_". */
+ if (!strcmp (name,"rtld_map_failed"))
+ continue;
+
+ if (VEC_empty (probe_p, probes[i]))
+ {
+ all_probes_found = 0;
+ break;
+ }
+ }
+
+ if (all_probes_found)
+ svr4_create_probe_breakpoints (gdbarch, probes);
+
+ for (i = 0; i < NUM_PROBES; i++)
+ VEC_free (probe_p, probes[i]);
+
+ if (all_probes_found)
+ return;
+ }
+ }
+
+ create_solib_event_breakpoint (gdbarch, address);
+}
+
/* Helper function for gdb_bfd_lookup_symbol. */
static int
@@ -1461,6 +2073,8 @@ enable_break (struct svr4_info *info, int from_tty)
info->interp_text_sect_low = info->interp_text_sect_high = 0;
info->interp_plt_sect_low = info->interp_plt_sect_high = 0;
+ free_probes_table (info);
+
/* If we already have a shared library list in the target, and
r_debug contains r_brk, set the breakpoint there - this should
mean r_brk has already been relocated. Assume the dynamic linker
@@ -1492,7 +2106,7 @@ enable_break (struct svr4_info *info, int from_tty)
That knowledge is encoded in the address, if it's Thumb the low bit
is 1. However, we've stripped that info above and it's not clear
what all the consequences are of passing a non-addr_bits_remove'd
- address to create_solib_event_breakpoint. The call to
+ address to svr4_create_solib_event_breakpoints. The call to
find_pc_section verifies we know about the address and have some
hope of computing the right kind of breakpoint to use (via
symbol info). It does mean that GDB needs to be pointed at a
@@ -1530,7 +2144,7 @@ enable_break (struct svr4_info *info, int from_tty)
+ bfd_section_size (tmp_bfd, interp_sect);
}
- create_solib_event_breakpoint (target_gdbarch (), sym_addr);
+ svr4_create_solib_event_breakpoints (target_gdbarch (), sym_addr);
return 1;
}
}
@@ -1688,7 +2302,8 @@ enable_break (struct svr4_info *info, int from_tty)
if (sym_addr != 0)
{
- create_solib_event_breakpoint (target_gdbarch (), load_addr + sym_addr);
+ svr4_create_solib_event_breakpoints (target_gdbarch (),
+ load_addr + sym_addr);
xfree (interp_name);
return 1;
}
@@ -1714,7 +2329,7 @@ enable_break (struct svr4_info *info, int from_tty)
sym_addr = gdbarch_convert_from_func_ptr_addr (target_gdbarch (),
sym_addr,
¤t_target);
- create_solib_event_breakpoint (target_gdbarch (), sym_addr);
+ svr4_create_solib_event_breakpoints (target_gdbarch (), sym_addr);
return 1;
}
}
@@ -1730,7 +2345,7 @@ enable_break (struct svr4_info *info, int from_tty)
sym_addr = gdbarch_convert_from_func_ptr_addr (target_gdbarch (),
sym_addr,
¤t_target);
- create_solib_event_breakpoint (target_gdbarch (), sym_addr);
+ svr4_create_solib_event_breakpoints (target_gdbarch (), sym_addr);
return 1;
}
}
@@ -2226,6 +2841,9 @@ svr4_solib_create_inferior_hook (int from_tty)
info = get_svr4_info ();
+ /* Free the probes-based interface's solib list. */
+ free_solib_list (info);
+
/* Relocate the main executable if necessary. */
svr4_relocate_main_executable ();
@@ -2468,4 +3086,6 @@ _initialize_svr4_solib (void)
svr4_so_ops.lookup_lib_global_symbol = elf_lookup_lib_symbol;
svr4_so_ops.same = svr4_same;
svr4_so_ops.keep_data_in_core = svr4_keep_data_in_core;
+ svr4_so_ops.update_breakpoints = svr4_update_solib_event_breakpoints;
+ svr4_so_ops.handle_event = svr4_handle_solib_event;
}
^ permalink raw reply [flat|nested] 59+ messages in thread* Re: [RFA 5/7 take 2] Improved linker-debugger interface
2013-05-24 8:30 ` [RFA 5/7 take 2] " Gary Benson
@ 2013-05-25 21:05 ` Jan Kratochvil
2013-05-29 18:51 ` Pedro Alves
1 sibling, 0 replies; 59+ messages in thread
From: Jan Kratochvil @ 2013-05-25 21:05 UTC (permalink / raw)
To: gdb-patches
On Fri, 24 May 2013 10:30:44 +0200, Gary Benson wrote:
> Jan Kratochvil wrote:
> > Meaning of 'direct' seems ambiguous/unclear to me, maybe 'uncached'?
> > Just a hint, OK even with 'direct'.
[...]
> Would "svr4_current_sos_1" be acceptable, or is the "_1" naming
> discouraged?
*_direct seems already more explanatory to me than *_1.
Your new function comment explains it better:
/* Read the full list of currently loaded shared objects directly
from the inferior, without referring to any libraries read and
stored by the probes interface. */
> > > + if (!svr4_read_so_list (lm, prev_lm, &link, 0))
> >
> > You should set the last IGNORE_FIRST parameter properly. While
> > glibc has "" there AFAIK some OSes like Solaris may have some valid
> > pathname there which would confuse GDB listing the executable also
> > as a shared library.
>
> I set IGNORE_FIRST to zero here because for this particular call
> svr4_read_so_list never sees the first element in the list. If
> solist_update_incremental is called at the top of the list then
> the "if (info->solib_list == NULL) return 0;" at the top of
> solist_update_incremental causes it to defer to solist_update_full.
> That uses svr4_current_sos_direct, which does set IGNORE_FIRST
> correctly.
OK, that makes sense. But it does not seem obvious to me, add there
a comment please, something like:
/* The IGNORE_FIRST parameter does not need to be used as this point of code
doing incremental fetch is never used for the first element of the list.
solist_update_full is called for the first element instead. */
> > > @@ -1460,6 +2032,8 @@ enable_break (struct svr4_info *info, int from_tty)
> > > info->interp_text_sect_low = info->interp_text_sect_high = 0;
> > > info->interp_plt_sect_low = info->interp_plt_sect_high = 0;
> > >
> > > + free_probes_table (info);
> >
> > Why is this one needed and free_solib_list is not needed?
>
> free_solib_list is called in svr4_solib_create_inferior_hook.
> I originally had the two calls together, in enable_break, but
> doing it that way caused breakpoint resetting errors when the
> inferior was restarted. There is a check for this in
> info-shared.exp.
When I add free_solib_list call there info-shared.exp still PASSes, even if
I also remove the free_solib_list call from svr4_solib_create_inferior_hook.
I do not see why free_solib_list should be called at one place and
free_probes_table at other place, if it is really needed it would be worth
a comment as I do not understand now why.
The difference between placing it to svr4_solib_create_inferior_hook vs.
placing it to enable_break is only in svr4_relocate_main_executable being
called in the meantime. I may miss something but I do not see how
svr4_relocate_main_executable could be dependent on the shared library list
state.
It is pre-approved if you call free_probes_table and free_solib_list together,
otherwise I would like another reply mail about it.
> +/* Copy library list. */
> +
> +static struct so_list *
> +svr4_copy_library_list (struct so_list *src)
> +{
> + struct so_list *dst = NULL;
> + struct so_list **link = &dst;
> +
> + while (src != NULL)
> + {
> + struct so_list *new;
> +
> + new = xmalloc (sizeof (struct so_list));
> + memcpy (new, src, sizeof (struct so_list));
> +
> + if (src->lm_info != NULL)
svr4 lm_info can never be NULL.
If you refer to
[patch] Fix crash in svr4_clear_so
http://sourceware.org/ml/gdb-patches/2013-05/msg00792.html
that could happen only when creating struct so_list in svr4_read_so_list but
here struct so_list has to be already finished.
Other solib-svr4.c code also assumes so_list->lm_info is not NULL.
> + {
> + new->lm_info = xmalloc (sizeof (struct lm_info));
> + memcpy (new->lm_info, src->lm_info, sizeof (struct lm_info));
> + }
> +
> + new->next = NULL;
> + *link = new;
> + link = &new->next;
> +
> + src = src->next;
> + }
> +
> + return dst;
> +}
[...]
> static int
> -svr4_current_sos_via_xfer_libraries (struct svr4_library_list *list)
> +svr4_current_sos_via_xfer_libraries (struct svr4_library_list *list,
> + const char *annex)
> {
> char *svr4_library_document;
> int result;
> struct cleanup *back_to;
>
> + gdb_assert (annex == NULL || target_augmented_libraries_svr4_read());
GNU Coding Standards:
gdb_assert (annex == NULL || target_augmented_libraries_svr4_read ());
> +
> /* Fetch the list of shared libraries. */
> svr4_library_document = target_read_stralloc (¤t_target,
> TARGET_OBJECT_LIBRARIES_SVR4,
> - NULL);
> + annex);
> if (svr4_library_document == NULL)
> return 0;
>
[...]
> +/* Create and register solib event breakpoints. PROBES is an array
> + of NUM_PROBES elements, each of which is vector of probes. A
^^^
Maybe "An" but you know better, nitpick.
> + solib event breakpoint will be created and registered for each
> + probe. */
> +
> +static void
> +svr4_create_probe_breakpoints (struct gdbarch *gdbarch,
> + VEC (probe_p) **probes)
[...]
OK for commit with the changes above and depending on the free_probes_table
and free_solib_list enable_break issue resolution.
Thanks,
Jan
^ permalink raw reply [flat|nested] 59+ messages in thread* Re: [RFA 5/7 take 2] Improved linker-debugger interface
2013-05-24 8:30 ` [RFA 5/7 take 2] " Gary Benson
2013-05-25 21:05 ` Jan Kratochvil
@ 2013-05-29 18:51 ` Pedro Alves
2013-05-30 10:43 ` [RFA 5/7 take 3] " Gary Benson
1 sibling, 1 reply; 59+ messages in thread
From: Pedro Alves @ 2013-05-29 18:51 UTC (permalink / raw)
To: Jan Kratochvil, gdb-patches
On 05/24/2013 09:30 AM, Gary Benson wrote:
> +static int
> +svr4_update_solib_event_breakpoint (struct breakpoint *b, void *arg)
> +{
> + struct svr4_info *info = get_svr4_info ();
> + struct bp_location *loc;
> +
...
> + for (loc = b->loc; loc; loc = loc->next)
> + {
> + struct probe_and_action *pa = solib_event_probe_at (info, loc->address);
There's no relation between INFO and the locations' inferior/program space.
IOW, I believe this is doing the wrong thing for multi-process.
> + for (tail = info->solib_list; tail->next; tail = tail->next)
tail->next != NULL
> + for (loc = b->loc; loc; loc = loc->next)
loc != NULL.
> + if (!strcmp (name,"rtld_map_failed"))
strcmp (name,"rtld_map_failed") == 0
There may be other instances in your patches. It'd be
nice to have them fixed.
Otherwise, looks about ready to me too (with Jan's comments
addressed).
--
Pedro Alves
^ permalink raw reply [flat|nested] 59+ messages in thread* [RFA 5/7 take 3] Improved linker-debugger interface
2013-05-29 18:51 ` Pedro Alves
@ 2013-05-30 10:43 ` Gary Benson
2013-05-30 17:18 ` Pedro Alves
0 siblings, 1 reply; 59+ messages in thread
From: Gary Benson @ 2013-05-30 10:43 UTC (permalink / raw)
To: Pedro Alves; +Cc: Jan Kratochvil, gdb-patches
[-- Attachment #1: Type: text/plain, Size: 1188 bytes --]
Pedro Alves wrote:
> On 05/24/2013 09:30 AM, Gary Benson wrote:
> > + for (tail = info->solib_list; tail->next; tail = tail->next)
>
> tail->next != NULL
>
> > + for (loc = b->loc; loc; loc = loc->next)
>
> loc != NULL.
>
> > + if (!strcmp (name,"rtld_map_failed"))
>
> strcmp (name,"rtld_map_failed") == 0
>
> There may be other instances in your patches. It'd be nice to
> have them fixed.
I had a look this morning, but I think you caught them all :)
> > +static int
> > +svr4_update_solib_event_breakpoint (struct breakpoint *b, void *arg)
> > +{
> > + struct svr4_info *info = get_svr4_info ();
> > + struct bp_location *loc;
> > +
> ...
>
> > + for (loc = b->loc; loc; loc = loc->next)
> > + {
> > + struct probe_and_action *pa = solib_event_probe_at (info, loc->address);
>
> There's no relation between INFO and the locations' inferior/program
> space. IOW, I believe this is doing the wrong thing for multi-process.
It took me a while to figure out what you meant here, but I think I
see what you mean. I've attached an updated patch with this function
reworked. Could you let me know if it looks correct?
Thanks,
Gary
--
http://gbenson.net/
[-- Attachment #2: rtld-probes-5-main-changes.patch --]
[-- Type: text/plain, Size: 33392 bytes --]
2013-05-30 Gary Benson <gbenson@redhat.com>
* breakpoint.h (handle_solib_event): Moved function declaration
to solib.h.
* breakpoint.c (handle_solib_event): Moved function to solib.c.
(bpstat_stop_status): Pass new argument to handle_solib_event.
* solib.h (update_solib_breakpoints): New function declaration.
(handle_solib_event): Moved function declaration from
breakpoint.h.
* solib.c (update_solib_breakpoints): New function.
(handle_solib_event): Moved function from breakpoint.c.
Updated to call solib_ops->handle_event if not NULL.
* solist.h (target_so_ops): New fields "update_breakpoints" and
"handle_event".
* infrun.c (set_stop_on_solib_events): New function.
(_initialize_infrun): Use the above for "set
stop-on-solib-events".
(handle_inferior_event): Pass new argument to handle_solib_event.
* solib-svr4.c (probe.h): New include.
(svr4_free_library_list): New forward declaration.
(probe_action): New enum.
(probe_info): New struct.
(probe_info): New static variable.
(NUM_PROBES): New definition.
(svr4_info): New fields "using_xfer", "probes_table" and
"solib_list".
(free_probes_table): New function.
(free_solib_list): New function.
(svr4_pspace_data_cleanup): Free probes table and solib list.
(svr4_copy_library_list): New function.
(svr4_current_sos_via_xfer_libraries): New parameter "annex".
(svr4_read_so_list): New parameter "prev_lm".
(svr4_current_sos_direct): Renamed from "svr4_current_sos".
(svr4_current_sos): New function.
(probe_and_action): New struct.
(hash_probe_and_action): New function.
(equal_probe_and_action): Likewise.
(register_solib_event_probe): Likewise.
(solib_event_probe_at): Likewise.
(solib_event_probe_action): Likewise.
(solist_update_full): Likewise.
(solist_update_incremental): Likewise.
(disable_probes_interface_cleanup): Likewise.
(svr4_handle_solib_event): Likewise.
(svr4_update_solib_event_breakpoint): Likewise.
(svr4_update_solib_event_breakpoints): Likewise.
(svr4_create_solib_event_breakpoints): Likewise.
(enable_break): Free probes table before creating breakpoints.
Use svr4_create_solib_event_breakpoints to create breakpoints.
(svr4_solib_create_inferior_hook): Free the solib list.
(_initialize_svr4_solib): Initialise
svr4_so_ops.handle_solib_event and svr4_so_ops.update_breakpoints.
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index 7df1122..e996e54 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -1553,8 +1553,6 @@ extern int user_breakpoint_p (struct breakpoint *);
/* Attempt to determine architecture of location identified by SAL. */
extern struct gdbarch *get_sal_arch (struct symtab_and_line sal);
-extern void handle_solib_event (void);
-
extern void breakpoint_free_objfile (struct objfile *objfile);
extern char *ep_parse_optional_if_clause (char **arg);
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index f4f9325..639ddae 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -5343,21 +5343,6 @@ handle_jit_event (void)
target_terminal_inferior ();
}
-/* Handle an solib event by calling solib_add. */
-
-void
-handle_solib_event (void)
-{
- clear_program_space_solib_cache (current_inferior ()->pspace);
-
- /* Check for any newly added shared libraries if we're supposed to
- be adding them automatically. Switch terminal for any messages
- produced by breakpoint_re_set. */
- target_terminal_ours_for_output ();
- solib_add (NULL, 0, ¤t_target, auto_solib_add);
- target_terminal_inferior ();
-}
-
/* Prepare WHAT final decision for infrun. */
/* Decide what infrun needs to do with this bpstat. */
diff --git a/gdb/solib.h b/gdb/solib.h
index b811866..2108429 100644
--- a/gdb/solib.h
+++ b/gdb/solib.h
@@ -90,4 +90,12 @@ extern CORE_ADDR gdb_bfd_lookup_symbol_from_symtab (bfd *abfd,
void *),
void *data);
+/* Enable or disable optional solib event breakpoints as appropriate. */
+
+extern void update_solib_breakpoints (void);
+
+/* Handle an solib event by calling solib_add. */
+
+extern void handle_solib_event (void);
+
#endif /* SOLIB_H */
diff --git a/gdb/solib.c b/gdb/solib.c
index a3479c5..763b93c 100644
--- a/gdb/solib.c
+++ b/gdb/solib.c
@@ -1208,6 +1208,37 @@ no_shared_libraries (char *ignored, int from_tty)
objfile_purge_solibs ();
}
+/* See solib.h. */
+
+void
+update_solib_breakpoints (void)
+{
+ const struct target_so_ops *ops = solib_ops (target_gdbarch ());
+
+ if (ops->update_breakpoints != NULL)
+ ops->update_breakpoints ();
+}
+
+/* See solib.h. */
+
+void
+handle_solib_event (void)
+{
+ const struct target_so_ops *ops = solib_ops (target_gdbarch ());
+
+ if (ops->handle_event != NULL)
+ ops->handle_event ();
+
+ clear_program_space_solib_cache (current_inferior ()->pspace);
+
+ /* Check for any newly added shared libraries if we're supposed to
+ be adding them automatically. Switch terminal for any messages
+ produced by breakpoint_re_set. */
+ target_terminal_ours_for_output ();
+ solib_add (NULL, 0, ¤t_target, auto_solib_add);
+ target_terminal_inferior ();
+}
+
/* Reload shared libraries, but avoid reloading the same symbol file
we already have loaded. */
diff --git a/gdb/solist.h b/gdb/solist.h
index 0495474..244484a 100644
--- a/gdb/solist.h
+++ b/gdb/solist.h
@@ -153,6 +153,19 @@ struct target_so_ops
core file (in particular, for readonly sections). */
int (*keep_data_in_core) (CORE_ADDR vaddr,
unsigned long size);
+
+ /* Enable or disable optional solib event breakpoints as
+ appropriate. This should be called whenever
+ stop_on_solib_events is changed. This pointer can be
+ NULL, in which case no enabling or disabling is necessary
+ for this target. */
+ void (*update_breakpoints) (void);
+
+ /* Target-specific processing of solib events that will be
+ performed before solib_add is called. This pointer can be
+ NULL, in which case no specific preprocessing is necessary
+ for this target. */
+ void (*handle_event) (void);
};
/* Free the memory associated with a (so_list *). */
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 54e92f2..a020dd6 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -370,6 +370,16 @@ static struct symbol *step_start_function;
/* Nonzero if we want to give control to the user when we're notified
of shared library events by the dynamic linker. */
int stop_on_solib_events;
+
+/* Enable or disable optional shared library event breakpoints
+ as appropriate when the above flag is changed. */
+
+static void
+set_stop_on_solib_events (char *args, int from_tty, struct cmd_list_element *c)
+{
+ update_solib_breakpoints ();
+}
+
static void
show_stop_on_solib_events (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
@@ -7303,7 +7313,7 @@ Show stopping for shared library events."), _("\
If nonzero, gdb will give control to the user when the dynamic linker\n\
notifies gdb of shared library events. The most common event of interest\n\
to the user would be loading/unloading of a new library."),
- NULL,
+ set_stop_on_solib_events,
show_stop_on_solib_events,
&setlist, &showlist);
diff --git a/gdb/solib-svr4.c b/gdb/solib-svr4.c
index 055fcb7..46e0c7f 100644
--- a/gdb/solib-svr4.c
+++ b/gdb/solib-svr4.c
@@ -46,10 +46,12 @@
#include "auxv.h"
#include "exceptions.h"
#include "gdb_bfd.h"
+#include "probe.h"
static struct link_map_offsets *svr4_fetch_link_map_offsets (void);
static int svr4_have_link_map_offsets (void);
static void svr4_relocate_main_executable (void);
+static void svr4_free_library_list (void *p_list);
/* Link map info to include in an allocated so_list entry. */
@@ -106,6 +108,55 @@ static const char * const main_name_list[] =
NULL
};
+/* What to do when a probe stop occurs. */
+
+enum probe_action
+{
+ /* Something went seriously wrong. Stop using probes and
+ revert to using the older interface. */
+ PROBES_INTERFACE_FAILED,
+
+ /* No action is required. The shared object list is still
+ valid. */
+ DO_NOTHING,
+
+ /* The shared object list should be reloaded entirely. */
+ FULL_RELOAD,
+
+ /* Attempt to incrementally update the shared object list. If
+ the update fails or is not possible, fall back to reloading
+ the list in full. */
+ UPDATE_OR_RELOAD,
+};
+
+/* A probe's name and its associated action. */
+
+struct probe_info
+{
+ /* The name of the probe. */
+ const char *name;
+
+ /* What to do when a probe stop occurs. */
+ enum probe_action action;
+};
+
+/* A list of named probes and their associated actions. If all
+ probes are present in the dynamic linker then the probes-based
+ interface will be used. */
+
+static const struct probe_info probe_info[] =
+{
+ { "init_start", DO_NOTHING },
+ { "init_complete", FULL_RELOAD },
+ { "map_start", DO_NOTHING },
+ { "map_failed", DO_NOTHING },
+ { "reloc_complete", UPDATE_OR_RELOAD },
+ { "unmap_start", DO_NOTHING },
+ { "unmap_complete", FULL_RELOAD },
+};
+
+#define NUM_PROBES ARRAY_SIZE (probe_info)
+
/* Return non-zero if GDB_SO_NAME and INFERIOR_SO_NAME represent
the same shared library. */
@@ -313,17 +364,58 @@ struct svr4_info
CORE_ADDR interp_text_sect_high;
CORE_ADDR interp_plt_sect_low;
CORE_ADDR interp_plt_sect_high;
+
+ /* Nonzero if the list of objects was last obtained from the target
+ via qXfer:libraries-svr4:read. */
+ int using_xfer;
+
+ /* Table of struct probe_and_action instances, used by the
+ probes-based interface to map breakpoint addresses to probes
+ and their associated actions. Lookup is performed using
+ probe_and_action->probe->address. */
+ htab_t probes_table;
+
+ /* List of objects loaded into the inferior, used by the probes-
+ based interface. */
+ struct so_list *solib_list;
};
/* Per-program-space data key. */
static const struct program_space_data *solib_svr4_pspace_data;
+/* Free the probes table. */
+
+static void
+free_probes_table (struct svr4_info *info)
+{
+ if (info->probes_table == NULL)
+ return;
+
+ htab_delete (info->probes_table);
+ info->probes_table = NULL;
+}
+
+/* Free the solib list. */
+
+static void
+free_solib_list (struct svr4_info *info)
+{
+ svr4_free_library_list (&info->solib_list);
+ info->solib_list = NULL;
+}
+
static void
svr4_pspace_data_cleanup (struct program_space *pspace, void *arg)
{
struct svr4_info *info;
info = program_space_data (pspace, solib_svr4_pspace_data);
+ if (info == NULL)
+ return;
+
+ free_probes_table (info);
+ free_solib_list (info);
+
xfree (info);
}
@@ -991,6 +1083,34 @@ svr4_free_library_list (void *p_list)
}
}
+/* Copy library list. */
+
+static struct so_list *
+svr4_copy_library_list (struct so_list *src)
+{
+ struct so_list *dst = NULL;
+ struct so_list **link = &dst;
+
+ while (src != NULL)
+ {
+ struct so_list *new;
+
+ new = xmalloc (sizeof (struct so_list));
+ memcpy (new, src, sizeof (struct so_list));
+
+ new->lm_info = xmalloc (sizeof (struct lm_info));
+ memcpy (new->lm_info, src->lm_info, sizeof (struct lm_info));
+
+ new->next = NULL;
+ *link = new;
+ link = &new->next;
+
+ src = src->next;
+ }
+
+ return dst;
+}
+
#ifdef HAVE_LIBEXPAT
#include "xml-support.h"
@@ -1106,23 +1226,30 @@ svr4_parse_libraries (const char *document, struct svr4_library_list *list)
return 0;
}
-/* Attempt to get so_list from target via qXfer:libraries:read packet.
+/* Attempt to get so_list from target via qXfer:libraries-svr4:read packet.
Return 0 if packet not supported, *SO_LIST_RETURN is not modified in such
case. Return 1 if *SO_LIST_RETURN contains the library list, it may be
- empty, caller is responsible for freeing all its entries. */
+ empty, caller is responsible for freeing all its entries.
+
+ Note that ANNEX must be NULL if the remote does not explicitly allow
+ qXfer:libraries-svr4:read packets with non-empty annexes. Support for
+ this can be checked using target_augmented_libraries_svr4_read (). */
static int
-svr4_current_sos_via_xfer_libraries (struct svr4_library_list *list)
+svr4_current_sos_via_xfer_libraries (struct svr4_library_list *list,
+ const char *annex)
{
char *svr4_library_document;
int result;
struct cleanup *back_to;
+ gdb_assert (annex == NULL || target_augmented_libraries_svr4_read ());
+
/* Fetch the list of shared libraries. */
svr4_library_document = target_read_stralloc (¤t_target,
TARGET_OBJECT_LIBRARIES_SVR4,
- NULL);
+ annex);
if (svr4_library_document == NULL)
return 0;
@@ -1136,7 +1263,8 @@ svr4_current_sos_via_xfer_libraries (struct svr4_library_list *list)
#else
static int
-svr4_current_sos_via_xfer_libraries (struct svr4_library_list *list)
+svr4_current_sos_via_xfer_libraries (struct svr4_library_list *list,
+ const char *annex)
{
return 0;
}
@@ -1170,15 +1298,19 @@ svr4_default_sos (void)
return new;
}
-/* Read the whole inferior libraries chain starting at address LM. Add the
- entries to the tail referenced by LINK_PTR_PTR. Ignore the first entry if
- IGNORE_FIRST and set global MAIN_LM_ADDR according to it. */
+/* Read the whole inferior libraries chain starting at address LM.
+ Expect the first entry in the chain's previous entry to be PREV_LM.
+ Add the entries to the tail referenced by LINK_PTR_PTR. Ignore the
+ first entry if IGNORE_FIRST and set global MAIN_LM_ADDR according
+ to it. Returns nonzero upon success. If zero is returned the
+ entries stored to LINK_PTR_PTR are still valid although they may
+ represent only part of the inferior library list. */
-static void
-svr4_read_so_list (CORE_ADDR lm, struct so_list ***link_ptr_ptr,
- int ignore_first)
+static int
+svr4_read_so_list (CORE_ADDR lm, CORE_ADDR prev_lm,
+ struct so_list ***link_ptr_ptr, int ignore_first)
{
- CORE_ADDR prev_lm = 0, next_lm;
+ CORE_ADDR next_lm;
for (; lm != 0; prev_lm = lm, lm = next_lm)
{
@@ -1194,7 +1326,7 @@ svr4_read_so_list (CORE_ADDR lm, struct so_list ***link_ptr_ptr,
if (new->lm_info == NULL)
{
do_cleanups (old_chain);
- break;
+ return 0;
}
next_lm = new->lm_info->l_next;
@@ -1205,7 +1337,7 @@ svr4_read_so_list (CORE_ADDR lm, struct so_list ***link_ptr_ptr,
paddress (target_gdbarch (), prev_lm),
paddress (target_gdbarch (), new->lm_info->l_prev));
do_cleanups (old_chain);
- break;
+ return 0;
}
/* For SVR4 versions, the first entry in the link map is for the
@@ -1251,17 +1383,21 @@ svr4_read_so_list (CORE_ADDR lm, struct so_list ***link_ptr_ptr,
**link_ptr_ptr = new;
*link_ptr_ptr = &new->next;
}
+
+ return 1;
}
-/* Implement the "current_sos" target_so_ops method. */
+/* Read the full list of currently loaded shared objects directly
+ from the inferior, without referring to any libraries read and
+ stored by the probes interface. Handle special cases relating
+ to the first elements of the list. */
static struct so_list *
-svr4_current_sos (void)
+svr4_current_sos_direct (struct svr4_info *info)
{
CORE_ADDR lm;
struct so_list *head = NULL;
struct so_list **link_ptr = &head;
- struct svr4_info *info;
struct cleanup *back_to;
int ignore_first;
struct svr4_library_list library_list;
@@ -1274,19 +1410,16 @@ svr4_current_sos (void)
Unfortunately statically linked inferiors will also fall back through this
suboptimal code path. */
- if (svr4_current_sos_via_xfer_libraries (&library_list))
+ info->using_xfer = svr4_current_sos_via_xfer_libraries (&library_list,
+ NULL);
+ if (info->using_xfer)
{
if (library_list.main_lm)
- {
- info = get_svr4_info ();
- info->main_lm_addr = library_list.main_lm;
- }
+ info->main_lm_addr = library_list.main_lm;
return library_list.head ? library_list.head : svr4_default_sos ();
}
- info = get_svr4_info ();
-
/* Always locate the debug struct, in case it has moved. */
info->debug_base = 0;
locate_base (info);
@@ -1309,7 +1442,7 @@ svr4_current_sos (void)
`struct so_list' nodes. */
lm = solib_svr4_r_map (info);
if (lm)
- svr4_read_so_list (lm, &link_ptr, ignore_first);
+ svr4_read_so_list (lm, 0, &link_ptr, ignore_first);
/* On Solaris, the dynamic linker is not in the normal list of
shared objects, so make sure we pick it up too. Having
@@ -1317,7 +1450,7 @@ svr4_current_sos (void)
for skipping dynamic linker resolver code. */
lm = solib_svr4_r_ldsomap (info);
if (lm)
- svr4_read_so_list (lm, &link_ptr, 0);
+ svr4_read_so_list (lm, 0, &link_ptr, 0);
discard_cleanups (back_to);
@@ -1327,6 +1460,22 @@ svr4_current_sos (void)
return head;
}
+/* Implement the "current_sos" target_so_ops method. */
+
+static struct so_list *
+svr4_current_sos (void)
+{
+ struct svr4_info *info = get_svr4_info ();
+
+ /* If the solib list has been read and stored by the probes
+ interface then we return a copy of the stored list. */
+ if (info->solib_list != NULL)
+ return svr4_copy_library_list (info->solib_list);
+
+ /* Otherwise obtain the solib list directly from the inferior. */
+ return svr4_current_sos_direct (info);
+}
+
/* Get the address of the link_map for a given OBJFILE. */
CORE_ADDR
@@ -1409,6 +1558,476 @@ exec_entry_point (struct bfd *abfd, struct target_ops *targ)
return gdbarch_addr_bits_remove (target_gdbarch (), addr);
}
+/* A probe and its associated action. */
+
+struct probe_and_action
+{
+ /* The probe. */
+ struct probe *probe;
+
+ /* The action. */
+ enum probe_action action;
+};
+
+/* Returns a hash code for the probe_and_action referenced by p. */
+
+static hashval_t
+hash_probe_and_action (const void *p)
+{
+ const struct probe_and_action *pa = p;
+
+ return (hashval_t) pa->probe->address;
+}
+
+/* Returns non-zero if the probe_and_actions referenced by p1 and p2
+ are equal. */
+
+static int
+equal_probe_and_action (const void *p1, const void *p2)
+{
+ const struct probe_and_action *pa1 = p1;
+ const struct probe_and_action *pa2 = p2;
+
+ return pa1->probe->address == pa2->probe->address;
+}
+
+/* Register a solib event probe and its associated action in the
+ probes table. */
+
+static void
+register_solib_event_probe (struct probe *probe, enum probe_action action)
+{
+ struct svr4_info *info = get_svr4_info ();
+ struct probe_and_action lookup, *pa;
+ void **slot;
+
+ /* Create the probes table, if necessary. */
+ if (info->probes_table == NULL)
+ info->probes_table = htab_create_alloc (1, hash_probe_and_action,
+ equal_probe_and_action,
+ xfree, xcalloc, xfree);
+
+ lookup.probe = probe;
+ slot = htab_find_slot (info->probes_table, &lookup, INSERT);
+ gdb_assert (*slot == HTAB_EMPTY_ENTRY);
+
+ pa = XCNEW (struct probe_and_action);
+ pa->probe = probe;
+ pa->action = action;
+
+ *slot = pa;
+}
+
+/* Get the solib event probe at the specified location, and the
+ action associated with it. Returns NULL if no solib event probe
+ was found. */
+
+static struct probe_and_action *
+solib_event_probe_at (struct svr4_info *info, CORE_ADDR address)
+{
+ struct probe lookup_probe;
+ struct probe_and_action lookup;
+ void **slot;
+
+ lookup_probe.address = address;
+ lookup.probe = &lookup_probe;
+ slot = htab_find_slot (info->probes_table, &lookup, NO_INSERT);
+
+ if (slot == NULL)
+ return NULL;
+
+ return (struct probe_and_action *) *slot;
+}
+
+/* Decide what action to take when the specified solib event probe is
+ hit. */
+
+static enum probe_action
+solib_event_probe_action (struct probe_and_action *pa)
+{
+ enum probe_action action;
+ unsigned probe_argc;
+
+ action = pa->action;
+ if (action == DO_NOTHING || action == PROBES_INTERFACE_FAILED)
+ return action;
+
+ gdb_assert (action == FULL_RELOAD || action == UPDATE_OR_RELOAD);
+
+ /* Check that an appropriate number of arguments has been supplied.
+ We expect:
+ arg0: Lmid_t lmid (mandatory)
+ arg1: struct r_debug *debug_base (mandatory)
+ arg2: struct link_map *new (optional, for incremental updates) */
+ probe_argc = get_probe_argument_count (pa->probe);
+ if (probe_argc == 2)
+ action = FULL_RELOAD;
+ else if (probe_argc < 2)
+ action = PROBES_INTERFACE_FAILED;
+
+ return action;
+}
+
+/* Populate the shared object list by reading the entire list of
+ shared objects from the inferior. Handle special cases relating
+ to the first elements of the list. Returns nonzero on success. */
+
+static int
+solist_update_full (struct svr4_info *info)
+{
+ free_solib_list (info);
+ info->solib_list = svr4_current_sos_direct (info);
+
+ return 1;
+}
+
+/* Update the shared object list starting from the link-map entry
+ passed by the linker in the probe's third argument. Returns
+ nonzero if the list was successfully updated, or zero to indicate
+ failure. */
+
+static int
+solist_update_incremental (struct svr4_info *info, CORE_ADDR lm)
+{
+ struct so_list *tail;
+ CORE_ADDR prev_lm;
+
+ /* svr4_current_sos_direct contains logic to handle a number of
+ special cases relating to the first elements of the list. To
+ avoid duplicating this logic we defer to solist_update_full
+ if the list is empty. */
+ if (info->solib_list == NULL)
+ return 0;
+
+ /* Fall back to a full update if we are using a remote target
+ that does not support incremental transfers. */
+ if (info->using_xfer && !target_augmented_libraries_svr4_read ())
+ return 0;
+
+ /* Walk to the end of the list. */
+ for (tail = info->solib_list; tail->next != NULL; tail = tail->next)
+ /* Nothing. */;
+ prev_lm = tail->lm_info->lm_addr;
+
+ /* Read the new objects. */
+ if (info->using_xfer)
+ {
+ struct svr4_library_list library_list;
+ char annex[64];
+
+ xsnprintf (annex, sizeof (annex), "start=%s;prev=%s",
+ phex_nz (lm, sizeof (lm)),
+ phex_nz (prev_lm, sizeof (prev_lm)));
+ if (!svr4_current_sos_via_xfer_libraries (&library_list, annex))
+ return 0;
+
+ tail->next = library_list.head;
+ }
+ else
+ {
+ struct so_list **link = &tail->next;
+
+ /* IGNORE_FIRST may safely be set to zero here because the
+ above check and deferral to solist_update_full ensures
+ that this call to svr4_read_so_list will never see the
+ first element. */
+ if (!svr4_read_so_list (lm, prev_lm, &link, 0))
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Disable the probes-based linker interface and revert to the
+ original interface. We don't reset the breakpoints as the
+ ones set up for the probes-based interface are adequate. */
+
+static void
+disable_probes_interface_cleanup (void *arg)
+{
+ struct svr4_info *info = get_svr4_info ();
+
+ warning (_("Probes-based dynamic linker interface failed.\n"
+ "Reverting to original interface.\n"));
+
+ free_probes_table (info);
+ free_solib_list (info);
+}
+
+/* Update the solib list as appropriate when using the
+ probes-based linker interface. Do nothing if using the
+ standard interface. */
+
+static void
+svr4_handle_solib_event (void)
+{
+ struct svr4_info *info = get_svr4_info ();
+ struct probe_and_action *pa;
+ enum probe_action action;
+ struct cleanup *old_chain, *usm_chain;
+ struct value *val;
+ CORE_ADDR pc, debug_base, lm = 0;
+ int is_initial_ns;
+
+ /* Do nothing if not using the probes interface. */
+ if (info->probes_table == NULL)
+ return;
+
+ /* If anything goes wrong we revert to the original linker
+ interface. */
+ old_chain = make_cleanup (disable_probes_interface_cleanup, NULL);
+
+ pc = regcache_read_pc (get_current_regcache ());
+ pa = solib_event_probe_at (info, pc);
+ if (pa == NULL)
+ {
+ do_cleanups (old_chain);
+ return;
+ }
+
+ action = solib_event_probe_action (pa);
+ if (action == PROBES_INTERFACE_FAILED)
+ {
+ do_cleanups (old_chain);
+ return;
+ }
+
+ if (action == DO_NOTHING)
+ {
+ discard_cleanups (old_chain);
+ return;
+ }
+
+ /* evaluate_probe_argument looks up symbols in the dynamic linker
+ using find_pc_section. find_pc_section is accelerated by a cache
+ called the section map. The section map is invalidated every
+ time a shared library is loaded or unloaded, and if the inferior
+ is generating a lot of shared library events then the section map
+ will be updated every time svr4_handle_solib_event is called.
+ We called find_pc_section in svr4_create_solib_event_breakpoints,
+ so we can guarantee that the dynamic linker's sections are in the
+ section map. We can therefore inhibit section map updates across
+ these calls to evaluate_probe_argument and save a lot of time. */
+ inhibit_section_map_updates (current_program_space);
+ usm_chain = make_cleanup (resume_section_map_updates_cleanup,
+ current_program_space);
+
+ val = evaluate_probe_argument (pa->probe, 1);
+ if (val == NULL)
+ {
+ do_cleanups (old_chain);
+ return;
+ }
+
+ debug_base = value_as_address (val);
+ if (debug_base == 0)
+ {
+ do_cleanups (old_chain);
+ return;
+ }
+
+ /* Always locate the debug struct, in case it moved. */
+ info->debug_base = 0;
+ if (locate_base (info) == 0)
+ {
+ do_cleanups (old_chain);
+ return;
+ }
+
+ /* GDB does not currently support libraries loaded via dlmopen
+ into namespaces other than the initial one. We must ignore
+ any namespace other than the initial namespace here until
+ support for this is added to GDB. */
+ if (debug_base != info->debug_base)
+ action = DO_NOTHING;
+
+ if (action == UPDATE_OR_RELOAD)
+ {
+ val = evaluate_probe_argument (pa->probe, 2);
+ if (val != NULL)
+ lm = value_as_address (val);
+
+ if (lm == 0)
+ action = FULL_RELOAD;
+ }
+
+ /* Resume section map updates. */
+ do_cleanups (usm_chain);
+
+ if (action == UPDATE_OR_RELOAD)
+ {
+ if (!solist_update_incremental (info, lm))
+ action = FULL_RELOAD;
+ }
+
+ if (action == FULL_RELOAD)
+ {
+ if (!solist_update_full (info))
+ {
+ do_cleanups (old_chain);
+ return;
+ }
+ }
+
+ discard_cleanups (old_chain);
+}
+
+/* Helper function for svr4_update_solib_event_breakpoints. */
+
+static int
+svr4_update_solib_event_breakpoint (struct breakpoint *b, void *arg)
+{
+ struct bp_location *loc;
+
+ if (b->type != bp_shlib_event)
+ {
+ /* Continue iterating. */
+ return 0;
+ }
+
+ for (loc = b->loc; loc != NULL; loc = loc->next)
+ {
+ struct svr4_info *info;
+ struct probe_and_action *pa;
+
+ info = program_space_data (loc->pspace, solib_svr4_pspace_data);
+ if (info == NULL || info->probes_table == NULL)
+ continue;
+
+ pa = solib_event_probe_at (info, loc->address);
+ if (pa == NULL)
+ continue;
+
+ if (pa->action == DO_NOTHING)
+ {
+ if (b->enable_state == bp_disabled && stop_on_solib_events)
+ enable_breakpoint (b);
+ else if (b->enable_state == bp_enabled && !stop_on_solib_events)
+ disable_breakpoint (b);
+ }
+
+ break;
+ }
+
+ /* Continue iterating. */
+ return 0;
+}
+
+/* Enable or disable optional solib event breakpoints as appropriate.
+ Called whenever stop_on_solib_events is changed. */
+
+static void
+svr4_update_solib_event_breakpoints (void)
+{
+ iterate_over_breakpoints (svr4_update_solib_event_breakpoint, NULL);
+}
+
+/* Create and register solib event breakpoints. PROBES is an array
+ of NUM_PROBES elements, each of which is vector of probes. A
+ solib event breakpoint will be created and registered for each
+ probe. */
+
+static void
+svr4_create_probe_breakpoints (struct gdbarch *gdbarch,
+ VEC (probe_p) **probes)
+{
+ int i;
+
+ for (i = 0; i < NUM_PROBES; i++)
+ {
+ enum probe_action action = probe_info[i].action;
+ struct probe *probe;
+ int ix;
+
+ for (ix = 0;
+ VEC_iterate (probe_p, probes[i], ix, probe);
+ ++ix)
+ {
+ create_solib_event_breakpoint (gdbarch, probe->address);
+ register_solib_event_probe (probe, action);
+ }
+ }
+
+ svr4_update_solib_event_breakpoints ();
+}
+
+/* Both the SunOS and the SVR4 dynamic linkers call a marker function
+ before and after mapping and unmapping shared libraries. The sole
+ purpose of this method is to allow debuggers to set a breakpoint so
+ they can track these changes.
+
+ Some versions of the glibc dynamic linker contain named probes
+ to allow more fine grained stopping. Given the address of the
+ original marker function, this function attempts to find these
+ probes, and if found, sets breakpoints on those instead. If the
+ probes aren't found, a single breakpoint is set on the original
+ marker function. */
+
+static void
+svr4_create_solib_event_breakpoints (struct gdbarch *gdbarch,
+ CORE_ADDR address)
+{
+ struct obj_section *os;
+
+ os = find_pc_section (address);
+ if (os != NULL)
+ {
+ int with_prefix;
+
+ for (with_prefix = 0; with_prefix <= 1; with_prefix++)
+ {
+ VEC (probe_p) *probes[NUM_PROBES];
+ int all_probes_found = 1;
+ int i;
+
+ memset (probes, 0, sizeof (probes));
+ for (i = 0; i < NUM_PROBES; i++)
+ {
+ char name[32] = { '\0' };
+
+ /* Fedora 17 and Red Hat Enterprise Linux 6.2-6.4
+ shipped with an early version of the probes code in
+ which the probes' names were prefixed with "rtld_"
+ and the "map_failed" probe did not exist. The
+ locations of the probes are otherwise the same, so
+ we check for probes with prefixed names if probes
+ with unprefixed names are not present. */
+
+ if (with_prefix)
+ strncat (name, "rtld_", sizeof (name) - strlen (name) - 1);
+
+ strncat (name, probe_info[i].name,
+ sizeof (name) - strlen (name) - 1);
+
+ probes[i] = find_probes_in_objfile (os->objfile, "rtld", name);
+
+ /* The "map_failed" probe did not exist in early
+ versions of the probes code in which the probes'
+ names were prefixed with "rtld_". */
+ if (strcmp (name, "rtld_map_failed") == 0)
+ continue;
+
+ if (VEC_empty (probe_p, probes[i]))
+ {
+ all_probes_found = 0;
+ break;
+ }
+ }
+
+ if (all_probes_found)
+ svr4_create_probe_breakpoints (gdbarch, probes);
+
+ for (i = 0; i < NUM_PROBES; i++)
+ VEC_free (probe_p, probes[i]);
+
+ if (all_probes_found)
+ return;
+ }
+ }
+
+ create_solib_event_breakpoint (gdbarch, address);
+}
+
/* Helper function for gdb_bfd_lookup_symbol. */
static int
@@ -1492,7 +2111,7 @@ enable_break (struct svr4_info *info, int from_tty)
That knowledge is encoded in the address, if it's Thumb the low bit
is 1. However, we've stripped that info above and it's not clear
what all the consequences are of passing a non-addr_bits_remove'd
- address to create_solib_event_breakpoint. The call to
+ address to svr4_create_solib_event_breakpoints. The call to
find_pc_section verifies we know about the address and have some
hope of computing the right kind of breakpoint to use (via
symbol info). It does mean that GDB needs to be pointed at a
@@ -1530,7 +2149,7 @@ enable_break (struct svr4_info *info, int from_tty)
+ bfd_section_size (tmp_bfd, interp_sect);
}
- create_solib_event_breakpoint (target_gdbarch (), sym_addr);
+ svr4_create_solib_event_breakpoints (target_gdbarch (), sym_addr);
return 1;
}
}
@@ -1688,7 +2307,8 @@ enable_break (struct svr4_info *info, int from_tty)
if (sym_addr != 0)
{
- create_solib_event_breakpoint (target_gdbarch (), load_addr + sym_addr);
+ svr4_create_solib_event_breakpoints (target_gdbarch (),
+ load_addr + sym_addr);
xfree (interp_name);
return 1;
}
@@ -1714,7 +2334,7 @@ enable_break (struct svr4_info *info, int from_tty)
sym_addr = gdbarch_convert_from_func_ptr_addr (target_gdbarch (),
sym_addr,
¤t_target);
- create_solib_event_breakpoint (target_gdbarch (), sym_addr);
+ svr4_create_solib_event_breakpoints (target_gdbarch (), sym_addr);
return 1;
}
}
@@ -1730,7 +2350,7 @@ enable_break (struct svr4_info *info, int from_tty)
sym_addr = gdbarch_convert_from_func_ptr_addr (target_gdbarch (),
sym_addr,
¤t_target);
- create_solib_event_breakpoint (target_gdbarch (), sym_addr);
+ svr4_create_solib_event_breakpoints (target_gdbarch (), sym_addr);
return 1;
}
}
@@ -2226,6 +2846,10 @@ svr4_solib_create_inferior_hook (int from_tty)
info = get_svr4_info ();
+ /* Clear the probes-based interface's state. */
+ free_probes_table (info);
+ free_solib_list (info);
+
/* Relocate the main executable if necessary. */
svr4_relocate_main_executable ();
@@ -2468,4 +3092,6 @@ _initialize_svr4_solib (void)
svr4_so_ops.lookup_lib_global_symbol = elf_lookup_lib_symbol;
svr4_so_ops.same = svr4_same;
svr4_so_ops.keep_data_in_core = svr4_keep_data_in_core;
+ svr4_so_ops.update_breakpoints = svr4_update_solib_event_breakpoints;
+ svr4_so_ops.handle_event = svr4_handle_solib_event;
}
^ permalink raw reply [flat|nested] 59+ messages in thread* Re: [RFA 5/7 take 3] Improved linker-debugger interface
2013-05-30 10:43 ` [RFA 5/7 take 3] " Gary Benson
@ 2013-05-30 17:18 ` Pedro Alves
2013-05-31 13:22 ` [RFA 5/7 take 4] " Gary Benson
0 siblings, 1 reply; 59+ messages in thread
From: Pedro Alves @ 2013-05-30 17:18 UTC (permalink / raw)
To: Jan Kratochvil, gdb-patches
On 05/30/2013 11:43 AM, Gary Benson wrote:
> Pedro Alves wrote:
>> On 05/24/2013 09:30 AM, Gary Benson wrote:
>>> +static int
>>> +svr4_update_solib_event_breakpoint (struct breakpoint *b, void *arg)
>>> +{
>>> + struct svr4_info *info = get_svr4_info ();
>>> + struct bp_location *loc;
>>> +
>> ...
>>
>>> + for (loc = b->loc; loc; loc = loc->next)
>>> + {
>>> + struct probe_and_action *pa = solib_event_probe_at (info, loc->address);
>>
>> There's no relation between INFO and the locations' inferior/program
>> space. IOW, I believe this is doing the wrong thing for multi-process.
>
> It took me a while to figure out what you meant here, but I think I
> see what you mean.
Sorry. :-/
For those following along at home, the issue is that
get_svr4_info () returns the svr4 state object corresponding
to the current program space, while here we're walking over
all locations of all breakpoints, including
breakpoints/locations of all inferiors. So in
the 'solib_event_probe_at (info, loc->address)' call, we need
to pass it the 'info' of the program space of 'loc'.
> I've attached an updated patch with this function
> reworked. Could you let me know if it looks correct?
...
+/* Helper function for svr4_update_solib_event_breakpoints. */
+
+static int
+svr4_update_solib_event_breakpoint (struct breakpoint *b, void *arg)
+{
+ struct bp_location *loc;
+
+ if (b->type != bp_shlib_event)
+ {
+ /* Continue iterating. */
+ return 0;
+ }
+
+ for (loc = b->loc; loc != NULL; loc = loc->next)
+ {
+ struct svr4_info *info;
+ struct probe_and_action *pa;
+
+ info = program_space_data (loc->pspace, solib_svr4_pspace_data);
+ if (info == NULL || info->probes_table == NULL)
+ continue;
Exactly. Excellent, looks great now.
On 05/30/2013 11:43 AM, Gary Benson wrote:> + {
> + char name[32] = { '\0' };
> +
> + /* Fedora 17 and Red Hat Enterprise Linux 6.2-6.4
> + shipped with an early version of the probes code in
> + which the probes' names were prefixed with "rtld_"
> + and the "map_failed" probe did not exist. The
> + locations of the probes are otherwise the same, so
> + we check for probes with prefixed names if probes
> + with unprefixed names are not present. */
> +
> + if (with_prefix)
> + strncat (name, "rtld_", sizeof (name) - strlen (name) - 1);
> +
> + strncat (name, probe_info[i].name,
> + sizeof (name) - strlen (name) - 1);
> +
BTW, I'd rather this was written as something like:
char name[32];
if (with_prefix)
xsnprintf (name, sizeof (name), "rtld_%s", probe_info[i].name);
else
xsnprintf (name, sizeof (name), "%s", probe_info[i].name);
strncat like that is really not future proof, as we'll just get get a silently
truncated string if a new probe appears with a name that is too big.
xsnprintf OTOH gdb_asserts the string fits in the buffer. Granted, whoever
added such a probe would probably notice this, but it's a style best avoided.
(Witness how so few strncat calls there are in gdb. There are more strcat calls,
but that only shows that whenever we _do_ care about string overruns, we tend
to use something else, not strncat.)
Plus, it looks more readable to me that way. :-)
Alternatively, we could add a xstrncat that asserts truncation never happens,
though xsnprintf in this case still looks a bit more readable to me :-)
--
Pedro Alves
^ permalink raw reply [flat|nested] 59+ messages in thread* [RFA 5/7 take 4] Improved linker-debugger interface
2013-05-30 17:18 ` Pedro Alves
@ 2013-05-31 13:22 ` Gary Benson
2013-05-31 13:27 ` Pedro Alves
` (2 more replies)
0 siblings, 3 replies; 59+ messages in thread
From: Gary Benson @ 2013-05-31 13:22 UTC (permalink / raw)
To: Pedro Alves; +Cc: Jan Kratochvil, gdb-patches
[-- Attachment #1: Type: text/plain, Size: 2327 bytes --]
Pedro Alves wrote:
> On 05/30/2013 11:43 AM, Gary Benson wrote:
> > + char name[32] = { '\0' };
> > +
> > + /* Fedora 17 and Red Hat Enterprise Linux 6.2-6.4
> > + shipped with an early version of the probes code in
> > + which the probes' names were prefixed with "rtld_"
> > + and the "map_failed" probe did not exist. The
> > + locations of the probes are otherwise the same, so
> > + we check for probes with prefixed names if probes
> > + with unprefixed names are not present. */
> > +
> > + if (with_prefix)
> > + strncat (name, "rtld_", sizeof (name) - strlen (name) - 1);
> > +
> > + strncat (name, probe_info[i].name,
> > + sizeof (name) - strlen (name) - 1);
>
> BTW, I'd rather this was written as something like:
>
> char name[32];
>
> if (with_prefix)
> xsnprintf (name, sizeof (name), "rtld_%s", probe_info[i].name);
> else
> xsnprintf (name, sizeof (name), "%s", probe_info[i].name);
>
>
> strncat like that is really not future proof, as we'll just get get
> a silently truncated string if a new probe appears with a name that
> is too big. xsnprintf OTOH gdb_asserts the string fits in the
> buffer. Granted, whoever added such a probe would probably notice
> this, but it's a style best avoided. (Witness how so few strncat
> calls there are in gdb. There are more strcat calls, but that only
> shows that whenever we _do_ care about string overruns, we tend to
> use something else, not strncat.)
> Plus, it looks more readable to me that way. :-)
> Alternatively, we could add a xstrncat that asserts truncation
> never happens, though xsnprintf in this case still looks a bit
> more readable to me :-)
How about this:
const char *name = probe_info[i].name;
char buf[32];
/* Fedora 17 and Red Hat Enterprise Linux 6.2-6.4
shipped with an early version of the probes code in
which the probes' names were prefixed with "rtld_"
and the "map_failed" probe did not exist. The
locations of the probes are otherwise the same, so
we check for probes with prefixed names if probes
with unprefixed names are not present. */
if (with_prefix)
{
xsnprintf (buf, sizeof (buf), "rtld_%s", name);
name = buf;
}
Revised patch attached.
Thanks,
Gary
--
http://gbenson.net/
[-- Attachment #2: rtld-probes-5-main-changes.patch --]
[-- Type: text/plain, Size: 33351 bytes --]
2013-05-31 Gary Benson <gbenson@redhat.com>
* breakpoint.h (handle_solib_event): Moved function declaration
to solib.h.
* breakpoint.c (handle_solib_event): Moved function to solib.c.
(bpstat_stop_status): Pass new argument to handle_solib_event.
* solib.h (update_solib_breakpoints): New function declaration.
(handle_solib_event): Moved function declaration from
breakpoint.h.
* solib.c (update_solib_breakpoints): New function.
(handle_solib_event): Moved function from breakpoint.c.
Updated to call solib_ops->handle_event if not NULL.
* solist.h (target_so_ops): New fields "update_breakpoints" and
"handle_event".
* infrun.c (set_stop_on_solib_events): New function.
(_initialize_infrun): Use the above for "set
stop-on-solib-events".
(handle_inferior_event): Pass new argument to handle_solib_event.
* solib-svr4.c (probe.h): New include.
(svr4_free_library_list): New forward declaration.
(probe_action): New enum.
(probe_info): New struct.
(probe_info): New static variable.
(NUM_PROBES): New definition.
(svr4_info): New fields "using_xfer", "probes_table" and
"solib_list".
(free_probes_table): New function.
(free_solib_list): New function.
(svr4_pspace_data_cleanup): Free probes table and solib list.
(svr4_copy_library_list): New function.
(svr4_current_sos_via_xfer_libraries): New parameter "annex".
(svr4_read_so_list): New parameter "prev_lm".
(svr4_current_sos_direct): Renamed from "svr4_current_sos".
(svr4_current_sos): New function.
(probe_and_action): New struct.
(hash_probe_and_action): New function.
(equal_probe_and_action): Likewise.
(register_solib_event_probe): Likewise.
(solib_event_probe_at): Likewise.
(solib_event_probe_action): Likewise.
(solist_update_full): Likewise.
(solist_update_incremental): Likewise.
(disable_probes_interface_cleanup): Likewise.
(svr4_handle_solib_event): Likewise.
(svr4_update_solib_event_breakpoint): Likewise.
(svr4_update_solib_event_breakpoints): Likewise.
(svr4_create_solib_event_breakpoints): Likewise.
(enable_break): Free probes table before creating breakpoints.
Use svr4_create_solib_event_breakpoints to create breakpoints.
(svr4_solib_create_inferior_hook): Free the solib list.
(_initialize_svr4_solib): Initialise
svr4_so_ops.handle_solib_event and svr4_so_ops.update_breakpoints.
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index 7df1122..e996e54 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -1553,8 +1553,6 @@ extern int user_breakpoint_p (struct breakpoint *);
/* Attempt to determine architecture of location identified by SAL. */
extern struct gdbarch *get_sal_arch (struct symtab_and_line sal);
-extern void handle_solib_event (void);
-
extern void breakpoint_free_objfile (struct objfile *objfile);
extern char *ep_parse_optional_if_clause (char **arg);
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index f4f9325..639ddae 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -5343,21 +5343,6 @@ handle_jit_event (void)
target_terminal_inferior ();
}
-/* Handle an solib event by calling solib_add. */
-
-void
-handle_solib_event (void)
-{
- clear_program_space_solib_cache (current_inferior ()->pspace);
-
- /* Check for any newly added shared libraries if we're supposed to
- be adding them automatically. Switch terminal for any messages
- produced by breakpoint_re_set. */
- target_terminal_ours_for_output ();
- solib_add (NULL, 0, ¤t_target, auto_solib_add);
- target_terminal_inferior ();
-}
-
/* Prepare WHAT final decision for infrun. */
/* Decide what infrun needs to do with this bpstat. */
diff --git a/gdb/solib.h b/gdb/solib.h
index b811866..2108429 100644
--- a/gdb/solib.h
+++ b/gdb/solib.h
@@ -90,4 +90,12 @@ extern CORE_ADDR gdb_bfd_lookup_symbol_from_symtab (bfd *abfd,
void *),
void *data);
+/* Enable or disable optional solib event breakpoints as appropriate. */
+
+extern void update_solib_breakpoints (void);
+
+/* Handle an solib event by calling solib_add. */
+
+extern void handle_solib_event (void);
+
#endif /* SOLIB_H */
diff --git a/gdb/solib.c b/gdb/solib.c
index a3479c5..763b93c 100644
--- a/gdb/solib.c
+++ b/gdb/solib.c
@@ -1208,6 +1208,37 @@ no_shared_libraries (char *ignored, int from_tty)
objfile_purge_solibs ();
}
+/* See solib.h. */
+
+void
+update_solib_breakpoints (void)
+{
+ const struct target_so_ops *ops = solib_ops (target_gdbarch ());
+
+ if (ops->update_breakpoints != NULL)
+ ops->update_breakpoints ();
+}
+
+/* See solib.h. */
+
+void
+handle_solib_event (void)
+{
+ const struct target_so_ops *ops = solib_ops (target_gdbarch ());
+
+ if (ops->handle_event != NULL)
+ ops->handle_event ();
+
+ clear_program_space_solib_cache (current_inferior ()->pspace);
+
+ /* Check for any newly added shared libraries if we're supposed to
+ be adding them automatically. Switch terminal for any messages
+ produced by breakpoint_re_set. */
+ target_terminal_ours_for_output ();
+ solib_add (NULL, 0, ¤t_target, auto_solib_add);
+ target_terminal_inferior ();
+}
+
/* Reload shared libraries, but avoid reloading the same symbol file
we already have loaded. */
diff --git a/gdb/solist.h b/gdb/solist.h
index 0495474..244484a 100644
--- a/gdb/solist.h
+++ b/gdb/solist.h
@@ -153,6 +153,19 @@ struct target_so_ops
core file (in particular, for readonly sections). */
int (*keep_data_in_core) (CORE_ADDR vaddr,
unsigned long size);
+
+ /* Enable or disable optional solib event breakpoints as
+ appropriate. This should be called whenever
+ stop_on_solib_events is changed. This pointer can be
+ NULL, in which case no enabling or disabling is necessary
+ for this target. */
+ void (*update_breakpoints) (void);
+
+ /* Target-specific processing of solib events that will be
+ performed before solib_add is called. This pointer can be
+ NULL, in which case no specific preprocessing is necessary
+ for this target. */
+ void (*handle_event) (void);
};
/* Free the memory associated with a (so_list *). */
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 54e92f2..a020dd6 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -370,6 +370,16 @@ static struct symbol *step_start_function;
/* Nonzero if we want to give control to the user when we're notified
of shared library events by the dynamic linker. */
int stop_on_solib_events;
+
+/* Enable or disable optional shared library event breakpoints
+ as appropriate when the above flag is changed. */
+
+static void
+set_stop_on_solib_events (char *args, int from_tty, struct cmd_list_element *c)
+{
+ update_solib_breakpoints ();
+}
+
static void
show_stop_on_solib_events (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
@@ -7303,7 +7313,7 @@ Show stopping for shared library events."), _("\
If nonzero, gdb will give control to the user when the dynamic linker\n\
notifies gdb of shared library events. The most common event of interest\n\
to the user would be loading/unloading of a new library."),
- NULL,
+ set_stop_on_solib_events,
show_stop_on_solib_events,
&setlist, &showlist);
diff --git a/gdb/solib-svr4.c b/gdb/solib-svr4.c
index 055fcb7..2c8d893 100644
--- a/gdb/solib-svr4.c
+++ b/gdb/solib-svr4.c
@@ -46,10 +46,12 @@
#include "auxv.h"
#include "exceptions.h"
#include "gdb_bfd.h"
+#include "probe.h"
static struct link_map_offsets *svr4_fetch_link_map_offsets (void);
static int svr4_have_link_map_offsets (void);
static void svr4_relocate_main_executable (void);
+static void svr4_free_library_list (void *p_list);
/* Link map info to include in an allocated so_list entry. */
@@ -106,6 +108,55 @@ static const char * const main_name_list[] =
NULL
};
+/* What to do when a probe stop occurs. */
+
+enum probe_action
+{
+ /* Something went seriously wrong. Stop using probes and
+ revert to using the older interface. */
+ PROBES_INTERFACE_FAILED,
+
+ /* No action is required. The shared object list is still
+ valid. */
+ DO_NOTHING,
+
+ /* The shared object list should be reloaded entirely. */
+ FULL_RELOAD,
+
+ /* Attempt to incrementally update the shared object list. If
+ the update fails or is not possible, fall back to reloading
+ the list in full. */
+ UPDATE_OR_RELOAD,
+};
+
+/* A probe's name and its associated action. */
+
+struct probe_info
+{
+ /* The name of the probe. */
+ const char *name;
+
+ /* What to do when a probe stop occurs. */
+ enum probe_action action;
+};
+
+/* A list of named probes and their associated actions. If all
+ probes are present in the dynamic linker then the probes-based
+ interface will be used. */
+
+static const struct probe_info probe_info[] =
+{
+ { "init_start", DO_NOTHING },
+ { "init_complete", FULL_RELOAD },
+ { "map_start", DO_NOTHING },
+ { "map_failed", DO_NOTHING },
+ { "reloc_complete", UPDATE_OR_RELOAD },
+ { "unmap_start", DO_NOTHING },
+ { "unmap_complete", FULL_RELOAD },
+};
+
+#define NUM_PROBES ARRAY_SIZE (probe_info)
+
/* Return non-zero if GDB_SO_NAME and INFERIOR_SO_NAME represent
the same shared library. */
@@ -313,17 +364,58 @@ struct svr4_info
CORE_ADDR interp_text_sect_high;
CORE_ADDR interp_plt_sect_low;
CORE_ADDR interp_plt_sect_high;
+
+ /* Nonzero if the list of objects was last obtained from the target
+ via qXfer:libraries-svr4:read. */
+ int using_xfer;
+
+ /* Table of struct probe_and_action instances, used by the
+ probes-based interface to map breakpoint addresses to probes
+ and their associated actions. Lookup is performed using
+ probe_and_action->probe->address. */
+ htab_t probes_table;
+
+ /* List of objects loaded into the inferior, used by the probes-
+ based interface. */
+ struct so_list *solib_list;
};
/* Per-program-space data key. */
static const struct program_space_data *solib_svr4_pspace_data;
+/* Free the probes table. */
+
+static void
+free_probes_table (struct svr4_info *info)
+{
+ if (info->probes_table == NULL)
+ return;
+
+ htab_delete (info->probes_table);
+ info->probes_table = NULL;
+}
+
+/* Free the solib list. */
+
+static void
+free_solib_list (struct svr4_info *info)
+{
+ svr4_free_library_list (&info->solib_list);
+ info->solib_list = NULL;
+}
+
static void
svr4_pspace_data_cleanup (struct program_space *pspace, void *arg)
{
struct svr4_info *info;
info = program_space_data (pspace, solib_svr4_pspace_data);
+ if (info == NULL)
+ return;
+
+ free_probes_table (info);
+ free_solib_list (info);
+
xfree (info);
}
@@ -991,6 +1083,34 @@ svr4_free_library_list (void *p_list)
}
}
+/* Copy library list. */
+
+static struct so_list *
+svr4_copy_library_list (struct so_list *src)
+{
+ struct so_list *dst = NULL;
+ struct so_list **link = &dst;
+
+ while (src != NULL)
+ {
+ struct so_list *new;
+
+ new = xmalloc (sizeof (struct so_list));
+ memcpy (new, src, sizeof (struct so_list));
+
+ new->lm_info = xmalloc (sizeof (struct lm_info));
+ memcpy (new->lm_info, src->lm_info, sizeof (struct lm_info));
+
+ new->next = NULL;
+ *link = new;
+ link = &new->next;
+
+ src = src->next;
+ }
+
+ return dst;
+}
+
#ifdef HAVE_LIBEXPAT
#include "xml-support.h"
@@ -1106,23 +1226,30 @@ svr4_parse_libraries (const char *document, struct svr4_library_list *list)
return 0;
}
-/* Attempt to get so_list from target via qXfer:libraries:read packet.
+/* Attempt to get so_list from target via qXfer:libraries-svr4:read packet.
Return 0 if packet not supported, *SO_LIST_RETURN is not modified in such
case. Return 1 if *SO_LIST_RETURN contains the library list, it may be
- empty, caller is responsible for freeing all its entries. */
+ empty, caller is responsible for freeing all its entries.
+
+ Note that ANNEX must be NULL if the remote does not explicitly allow
+ qXfer:libraries-svr4:read packets with non-empty annexes. Support for
+ this can be checked using target_augmented_libraries_svr4_read (). */
static int
-svr4_current_sos_via_xfer_libraries (struct svr4_library_list *list)
+svr4_current_sos_via_xfer_libraries (struct svr4_library_list *list,
+ const char *annex)
{
char *svr4_library_document;
int result;
struct cleanup *back_to;
+ gdb_assert (annex == NULL || target_augmented_libraries_svr4_read ());
+
/* Fetch the list of shared libraries. */
svr4_library_document = target_read_stralloc (¤t_target,
TARGET_OBJECT_LIBRARIES_SVR4,
- NULL);
+ annex);
if (svr4_library_document == NULL)
return 0;
@@ -1136,7 +1263,8 @@ svr4_current_sos_via_xfer_libraries (struct svr4_library_list *list)
#else
static int
-svr4_current_sos_via_xfer_libraries (struct svr4_library_list *list)
+svr4_current_sos_via_xfer_libraries (struct svr4_library_list *list,
+ const char *annex)
{
return 0;
}
@@ -1170,15 +1298,19 @@ svr4_default_sos (void)
return new;
}
-/* Read the whole inferior libraries chain starting at address LM. Add the
- entries to the tail referenced by LINK_PTR_PTR. Ignore the first entry if
- IGNORE_FIRST and set global MAIN_LM_ADDR according to it. */
+/* Read the whole inferior libraries chain starting at address LM.
+ Expect the first entry in the chain's previous entry to be PREV_LM.
+ Add the entries to the tail referenced by LINK_PTR_PTR. Ignore the
+ first entry if IGNORE_FIRST and set global MAIN_LM_ADDR according
+ to it. Returns nonzero upon success. If zero is returned the
+ entries stored to LINK_PTR_PTR are still valid although they may
+ represent only part of the inferior library list. */
-static void
-svr4_read_so_list (CORE_ADDR lm, struct so_list ***link_ptr_ptr,
- int ignore_first)
+static int
+svr4_read_so_list (CORE_ADDR lm, CORE_ADDR prev_lm,
+ struct so_list ***link_ptr_ptr, int ignore_first)
{
- CORE_ADDR prev_lm = 0, next_lm;
+ CORE_ADDR next_lm;
for (; lm != 0; prev_lm = lm, lm = next_lm)
{
@@ -1194,7 +1326,7 @@ svr4_read_so_list (CORE_ADDR lm, struct so_list ***link_ptr_ptr,
if (new->lm_info == NULL)
{
do_cleanups (old_chain);
- break;
+ return 0;
}
next_lm = new->lm_info->l_next;
@@ -1205,7 +1337,7 @@ svr4_read_so_list (CORE_ADDR lm, struct so_list ***link_ptr_ptr,
paddress (target_gdbarch (), prev_lm),
paddress (target_gdbarch (), new->lm_info->l_prev));
do_cleanups (old_chain);
- break;
+ return 0;
}
/* For SVR4 versions, the first entry in the link map is for the
@@ -1251,17 +1383,21 @@ svr4_read_so_list (CORE_ADDR lm, struct so_list ***link_ptr_ptr,
**link_ptr_ptr = new;
*link_ptr_ptr = &new->next;
}
+
+ return 1;
}
-/* Implement the "current_sos" target_so_ops method. */
+/* Read the full list of currently loaded shared objects directly
+ from the inferior, without referring to any libraries read and
+ stored by the probes interface. Handle special cases relating
+ to the first elements of the list. */
static struct so_list *
-svr4_current_sos (void)
+svr4_current_sos_direct (struct svr4_info *info)
{
CORE_ADDR lm;
struct so_list *head = NULL;
struct so_list **link_ptr = &head;
- struct svr4_info *info;
struct cleanup *back_to;
int ignore_first;
struct svr4_library_list library_list;
@@ -1274,19 +1410,16 @@ svr4_current_sos (void)
Unfortunately statically linked inferiors will also fall back through this
suboptimal code path. */
- if (svr4_current_sos_via_xfer_libraries (&library_list))
+ info->using_xfer = svr4_current_sos_via_xfer_libraries (&library_list,
+ NULL);
+ if (info->using_xfer)
{
if (library_list.main_lm)
- {
- info = get_svr4_info ();
- info->main_lm_addr = library_list.main_lm;
- }
+ info->main_lm_addr = library_list.main_lm;
return library_list.head ? library_list.head : svr4_default_sos ();
}
- info = get_svr4_info ();
-
/* Always locate the debug struct, in case it has moved. */
info->debug_base = 0;
locate_base (info);
@@ -1309,7 +1442,7 @@ svr4_current_sos (void)
`struct so_list' nodes. */
lm = solib_svr4_r_map (info);
if (lm)
- svr4_read_so_list (lm, &link_ptr, ignore_first);
+ svr4_read_so_list (lm, 0, &link_ptr, ignore_first);
/* On Solaris, the dynamic linker is not in the normal list of
shared objects, so make sure we pick it up too. Having
@@ -1317,7 +1450,7 @@ svr4_current_sos (void)
for skipping dynamic linker resolver code. */
lm = solib_svr4_r_ldsomap (info);
if (lm)
- svr4_read_so_list (lm, &link_ptr, 0);
+ svr4_read_so_list (lm, 0, &link_ptr, 0);
discard_cleanups (back_to);
@@ -1327,6 +1460,22 @@ svr4_current_sos (void)
return head;
}
+/* Implement the "current_sos" target_so_ops method. */
+
+static struct so_list *
+svr4_current_sos (void)
+{
+ struct svr4_info *info = get_svr4_info ();
+
+ /* If the solib list has been read and stored by the probes
+ interface then we return a copy of the stored list. */
+ if (info->solib_list != NULL)
+ return svr4_copy_library_list (info->solib_list);
+
+ /* Otherwise obtain the solib list directly from the inferior. */
+ return svr4_current_sos_direct (info);
+}
+
/* Get the address of the link_map for a given OBJFILE. */
CORE_ADDR
@@ -1409,6 +1558,476 @@ exec_entry_point (struct bfd *abfd, struct target_ops *targ)
return gdbarch_addr_bits_remove (target_gdbarch (), addr);
}
+/* A probe and its associated action. */
+
+struct probe_and_action
+{
+ /* The probe. */
+ struct probe *probe;
+
+ /* The action. */
+ enum probe_action action;
+};
+
+/* Returns a hash code for the probe_and_action referenced by p. */
+
+static hashval_t
+hash_probe_and_action (const void *p)
+{
+ const struct probe_and_action *pa = p;
+
+ return (hashval_t) pa->probe->address;
+}
+
+/* Returns non-zero if the probe_and_actions referenced by p1 and p2
+ are equal. */
+
+static int
+equal_probe_and_action (const void *p1, const void *p2)
+{
+ const struct probe_and_action *pa1 = p1;
+ const struct probe_and_action *pa2 = p2;
+
+ return pa1->probe->address == pa2->probe->address;
+}
+
+/* Register a solib event probe and its associated action in the
+ probes table. */
+
+static void
+register_solib_event_probe (struct probe *probe, enum probe_action action)
+{
+ struct svr4_info *info = get_svr4_info ();
+ struct probe_and_action lookup, *pa;
+ void **slot;
+
+ /* Create the probes table, if necessary. */
+ if (info->probes_table == NULL)
+ info->probes_table = htab_create_alloc (1, hash_probe_and_action,
+ equal_probe_and_action,
+ xfree, xcalloc, xfree);
+
+ lookup.probe = probe;
+ slot = htab_find_slot (info->probes_table, &lookup, INSERT);
+ gdb_assert (*slot == HTAB_EMPTY_ENTRY);
+
+ pa = XCNEW (struct probe_and_action);
+ pa->probe = probe;
+ pa->action = action;
+
+ *slot = pa;
+}
+
+/* Get the solib event probe at the specified location, and the
+ action associated with it. Returns NULL if no solib event probe
+ was found. */
+
+static struct probe_and_action *
+solib_event_probe_at (struct svr4_info *info, CORE_ADDR address)
+{
+ struct probe lookup_probe;
+ struct probe_and_action lookup;
+ void **slot;
+
+ lookup_probe.address = address;
+ lookup.probe = &lookup_probe;
+ slot = htab_find_slot (info->probes_table, &lookup, NO_INSERT);
+
+ if (slot == NULL)
+ return NULL;
+
+ return (struct probe_and_action *) *slot;
+}
+
+/* Decide what action to take when the specified solib event probe is
+ hit. */
+
+static enum probe_action
+solib_event_probe_action (struct probe_and_action *pa)
+{
+ enum probe_action action;
+ unsigned probe_argc;
+
+ action = pa->action;
+ if (action == DO_NOTHING || action == PROBES_INTERFACE_FAILED)
+ return action;
+
+ gdb_assert (action == FULL_RELOAD || action == UPDATE_OR_RELOAD);
+
+ /* Check that an appropriate number of arguments has been supplied.
+ We expect:
+ arg0: Lmid_t lmid (mandatory)
+ arg1: struct r_debug *debug_base (mandatory)
+ arg2: struct link_map *new (optional, for incremental updates) */
+ probe_argc = get_probe_argument_count (pa->probe);
+ if (probe_argc == 2)
+ action = FULL_RELOAD;
+ else if (probe_argc < 2)
+ action = PROBES_INTERFACE_FAILED;
+
+ return action;
+}
+
+/* Populate the shared object list by reading the entire list of
+ shared objects from the inferior. Handle special cases relating
+ to the first elements of the list. Returns nonzero on success. */
+
+static int
+solist_update_full (struct svr4_info *info)
+{
+ free_solib_list (info);
+ info->solib_list = svr4_current_sos_direct (info);
+
+ return 1;
+}
+
+/* Update the shared object list starting from the link-map entry
+ passed by the linker in the probe's third argument. Returns
+ nonzero if the list was successfully updated, or zero to indicate
+ failure. */
+
+static int
+solist_update_incremental (struct svr4_info *info, CORE_ADDR lm)
+{
+ struct so_list *tail;
+ CORE_ADDR prev_lm;
+
+ /* svr4_current_sos_direct contains logic to handle a number of
+ special cases relating to the first elements of the list. To
+ avoid duplicating this logic we defer to solist_update_full
+ if the list is empty. */
+ if (info->solib_list == NULL)
+ return 0;
+
+ /* Fall back to a full update if we are using a remote target
+ that does not support incremental transfers. */
+ if (info->using_xfer && !target_augmented_libraries_svr4_read ())
+ return 0;
+
+ /* Walk to the end of the list. */
+ for (tail = info->solib_list; tail->next != NULL; tail = tail->next)
+ /* Nothing. */;
+ prev_lm = tail->lm_info->lm_addr;
+
+ /* Read the new objects. */
+ if (info->using_xfer)
+ {
+ struct svr4_library_list library_list;
+ char annex[64];
+
+ xsnprintf (annex, sizeof (annex), "start=%s;prev=%s",
+ phex_nz (lm, sizeof (lm)),
+ phex_nz (prev_lm, sizeof (prev_lm)));
+ if (!svr4_current_sos_via_xfer_libraries (&library_list, annex))
+ return 0;
+
+ tail->next = library_list.head;
+ }
+ else
+ {
+ struct so_list **link = &tail->next;
+
+ /* IGNORE_FIRST may safely be set to zero here because the
+ above check and deferral to solist_update_full ensures
+ that this call to svr4_read_so_list will never see the
+ first element. */
+ if (!svr4_read_so_list (lm, prev_lm, &link, 0))
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Disable the probes-based linker interface and revert to the
+ original interface. We don't reset the breakpoints as the
+ ones set up for the probes-based interface are adequate. */
+
+static void
+disable_probes_interface_cleanup (void *arg)
+{
+ struct svr4_info *info = get_svr4_info ();
+
+ warning (_("Probes-based dynamic linker interface failed.\n"
+ "Reverting to original interface.\n"));
+
+ free_probes_table (info);
+ free_solib_list (info);
+}
+
+/* Update the solib list as appropriate when using the
+ probes-based linker interface. Do nothing if using the
+ standard interface. */
+
+static void
+svr4_handle_solib_event (void)
+{
+ struct svr4_info *info = get_svr4_info ();
+ struct probe_and_action *pa;
+ enum probe_action action;
+ struct cleanup *old_chain, *usm_chain;
+ struct value *val;
+ CORE_ADDR pc, debug_base, lm = 0;
+ int is_initial_ns;
+
+ /* Do nothing if not using the probes interface. */
+ if (info->probes_table == NULL)
+ return;
+
+ /* If anything goes wrong we revert to the original linker
+ interface. */
+ old_chain = make_cleanup (disable_probes_interface_cleanup, NULL);
+
+ pc = regcache_read_pc (get_current_regcache ());
+ pa = solib_event_probe_at (info, pc);
+ if (pa == NULL)
+ {
+ do_cleanups (old_chain);
+ return;
+ }
+
+ action = solib_event_probe_action (pa);
+ if (action == PROBES_INTERFACE_FAILED)
+ {
+ do_cleanups (old_chain);
+ return;
+ }
+
+ if (action == DO_NOTHING)
+ {
+ discard_cleanups (old_chain);
+ return;
+ }
+
+ /* evaluate_probe_argument looks up symbols in the dynamic linker
+ using find_pc_section. find_pc_section is accelerated by a cache
+ called the section map. The section map is invalidated every
+ time a shared library is loaded or unloaded, and if the inferior
+ is generating a lot of shared library events then the section map
+ will be updated every time svr4_handle_solib_event is called.
+ We called find_pc_section in svr4_create_solib_event_breakpoints,
+ so we can guarantee that the dynamic linker's sections are in the
+ section map. We can therefore inhibit section map updates across
+ these calls to evaluate_probe_argument and save a lot of time. */
+ inhibit_section_map_updates (current_program_space);
+ usm_chain = make_cleanup (resume_section_map_updates_cleanup,
+ current_program_space);
+
+ val = evaluate_probe_argument (pa->probe, 1);
+ if (val == NULL)
+ {
+ do_cleanups (old_chain);
+ return;
+ }
+
+ debug_base = value_as_address (val);
+ if (debug_base == 0)
+ {
+ do_cleanups (old_chain);
+ return;
+ }
+
+ /* Always locate the debug struct, in case it moved. */
+ info->debug_base = 0;
+ if (locate_base (info) == 0)
+ {
+ do_cleanups (old_chain);
+ return;
+ }
+
+ /* GDB does not currently support libraries loaded via dlmopen
+ into namespaces other than the initial one. We must ignore
+ any namespace other than the initial namespace here until
+ support for this is added to GDB. */
+ if (debug_base != info->debug_base)
+ action = DO_NOTHING;
+
+ if (action == UPDATE_OR_RELOAD)
+ {
+ val = evaluate_probe_argument (pa->probe, 2);
+ if (val != NULL)
+ lm = value_as_address (val);
+
+ if (lm == 0)
+ action = FULL_RELOAD;
+ }
+
+ /* Resume section map updates. */
+ do_cleanups (usm_chain);
+
+ if (action == UPDATE_OR_RELOAD)
+ {
+ if (!solist_update_incremental (info, lm))
+ action = FULL_RELOAD;
+ }
+
+ if (action == FULL_RELOAD)
+ {
+ if (!solist_update_full (info))
+ {
+ do_cleanups (old_chain);
+ return;
+ }
+ }
+
+ discard_cleanups (old_chain);
+}
+
+/* Helper function for svr4_update_solib_event_breakpoints. */
+
+static int
+svr4_update_solib_event_breakpoint (struct breakpoint *b, void *arg)
+{
+ struct bp_location *loc;
+
+ if (b->type != bp_shlib_event)
+ {
+ /* Continue iterating. */
+ return 0;
+ }
+
+ for (loc = b->loc; loc != NULL; loc = loc->next)
+ {
+ struct svr4_info *info;
+ struct probe_and_action *pa;
+
+ info = program_space_data (loc->pspace, solib_svr4_pspace_data);
+ if (info == NULL || info->probes_table == NULL)
+ continue;
+
+ pa = solib_event_probe_at (info, loc->address);
+ if (pa == NULL)
+ continue;
+
+ if (pa->action == DO_NOTHING)
+ {
+ if (b->enable_state == bp_disabled && stop_on_solib_events)
+ enable_breakpoint (b);
+ else if (b->enable_state == bp_enabled && !stop_on_solib_events)
+ disable_breakpoint (b);
+ }
+
+ break;
+ }
+
+ /* Continue iterating. */
+ return 0;
+}
+
+/* Enable or disable optional solib event breakpoints as appropriate.
+ Called whenever stop_on_solib_events is changed. */
+
+static void
+svr4_update_solib_event_breakpoints (void)
+{
+ iterate_over_breakpoints (svr4_update_solib_event_breakpoint, NULL);
+}
+
+/* Create and register solib event breakpoints. PROBES is an array
+ of NUM_PROBES elements, each of which is vector of probes. A
+ solib event breakpoint will be created and registered for each
+ probe. */
+
+static void
+svr4_create_probe_breakpoints (struct gdbarch *gdbarch,
+ VEC (probe_p) **probes)
+{
+ int i;
+
+ for (i = 0; i < NUM_PROBES; i++)
+ {
+ enum probe_action action = probe_info[i].action;
+ struct probe *probe;
+ int ix;
+
+ for (ix = 0;
+ VEC_iterate (probe_p, probes[i], ix, probe);
+ ++ix)
+ {
+ create_solib_event_breakpoint (gdbarch, probe->address);
+ register_solib_event_probe (probe, action);
+ }
+ }
+
+ svr4_update_solib_event_breakpoints ();
+}
+
+/* Both the SunOS and the SVR4 dynamic linkers call a marker function
+ before and after mapping and unmapping shared libraries. The sole
+ purpose of this method is to allow debuggers to set a breakpoint so
+ they can track these changes.
+
+ Some versions of the glibc dynamic linker contain named probes
+ to allow more fine grained stopping. Given the address of the
+ original marker function, this function attempts to find these
+ probes, and if found, sets breakpoints on those instead. If the
+ probes aren't found, a single breakpoint is set on the original
+ marker function. */
+
+static void
+svr4_create_solib_event_breakpoints (struct gdbarch *gdbarch,
+ CORE_ADDR address)
+{
+ struct obj_section *os;
+
+ os = find_pc_section (address);
+ if (os != NULL)
+ {
+ int with_prefix;
+
+ for (with_prefix = 0; with_prefix <= 1; with_prefix++)
+ {
+ VEC (probe_p) *probes[NUM_PROBES];
+ int all_probes_found = 1;
+ int i;
+
+ memset (probes, 0, sizeof (probes));
+ for (i = 0; i < NUM_PROBES; i++)
+ {
+ const char *name = probe_info[i].name;
+ char buf[32];
+
+ /* Fedora 17 and Red Hat Enterprise Linux 6.2-6.4
+ shipped with an early version of the probes code in
+ which the probes' names were prefixed with "rtld_"
+ and the "map_failed" probe did not exist. The
+ locations of the probes are otherwise the same, so
+ we check for probes with prefixed names if probes
+ with unprefixed names are not present. */
+ if (with_prefix)
+ {
+ xsnprintf (buf, sizeof (buf), "rtld_%s", name);
+ name = buf;
+ }
+
+ probes[i] = find_probes_in_objfile (os->objfile, "rtld", name);
+
+ /* The "map_failed" probe did not exist in early
+ versions of the probes code in which the probes'
+ names were prefixed with "rtld_". */
+ if (strcmp (name, "rtld_map_failed") == 0)
+ continue;
+
+ if (VEC_empty (probe_p, probes[i]))
+ {
+ all_probes_found = 0;
+ break;
+ }
+ }
+
+ if (all_probes_found)
+ svr4_create_probe_breakpoints (gdbarch, probes);
+
+ for (i = 0; i < NUM_PROBES; i++)
+ VEC_free (probe_p, probes[i]);
+
+ if (all_probes_found)
+ return;
+ }
+ }
+
+ create_solib_event_breakpoint (gdbarch, address);
+}
+
/* Helper function for gdb_bfd_lookup_symbol. */
static int
@@ -1492,7 +2111,7 @@ enable_break (struct svr4_info *info, int from_tty)
That knowledge is encoded in the address, if it's Thumb the low bit
is 1. However, we've stripped that info above and it's not clear
what all the consequences are of passing a non-addr_bits_remove'd
- address to create_solib_event_breakpoint. The call to
+ address to svr4_create_solib_event_breakpoints. The call to
find_pc_section verifies we know about the address and have some
hope of computing the right kind of breakpoint to use (via
symbol info). It does mean that GDB needs to be pointed at a
@@ -1530,7 +2149,7 @@ enable_break (struct svr4_info *info, int from_tty)
+ bfd_section_size (tmp_bfd, interp_sect);
}
- create_solib_event_breakpoint (target_gdbarch (), sym_addr);
+ svr4_create_solib_event_breakpoints (target_gdbarch (), sym_addr);
return 1;
}
}
@@ -1688,7 +2307,8 @@ enable_break (struct svr4_info *info, int from_tty)
if (sym_addr != 0)
{
- create_solib_event_breakpoint (target_gdbarch (), load_addr + sym_addr);
+ svr4_create_solib_event_breakpoints (target_gdbarch (),
+ load_addr + sym_addr);
xfree (interp_name);
return 1;
}
@@ -1714,7 +2334,7 @@ enable_break (struct svr4_info *info, int from_tty)
sym_addr = gdbarch_convert_from_func_ptr_addr (target_gdbarch (),
sym_addr,
¤t_target);
- create_solib_event_breakpoint (target_gdbarch (), sym_addr);
+ svr4_create_solib_event_breakpoints (target_gdbarch (), sym_addr);
return 1;
}
}
@@ -1730,7 +2350,7 @@ enable_break (struct svr4_info *info, int from_tty)
sym_addr = gdbarch_convert_from_func_ptr_addr (target_gdbarch (),
sym_addr,
¤t_target);
- create_solib_event_breakpoint (target_gdbarch (), sym_addr);
+ svr4_create_solib_event_breakpoints (target_gdbarch (), sym_addr);
return 1;
}
}
@@ -2226,6 +2846,10 @@ svr4_solib_create_inferior_hook (int from_tty)
info = get_svr4_info ();
+ /* Clear the probes-based interface's state. */
+ free_probes_table (info);
+ free_solib_list (info);
+
/* Relocate the main executable if necessary. */
svr4_relocate_main_executable ();
@@ -2468,4 +3092,6 @@ _initialize_svr4_solib (void)
svr4_so_ops.lookup_lib_global_symbol = elf_lookup_lib_symbol;
svr4_so_ops.same = svr4_same;
svr4_so_ops.keep_data_in_core = svr4_keep_data_in_core;
+ svr4_so_ops.update_breakpoints = svr4_update_solib_event_breakpoints;
+ svr4_so_ops.handle_event = svr4_handle_solib_event;
}
^ permalink raw reply [flat|nested] 59+ messages in thread* Re: [RFA 5/7 take 4] Improved linker-debugger interface
2013-05-31 13:22 ` [RFA 5/7 take 4] " Gary Benson
@ 2013-05-31 13:27 ` Pedro Alves
2013-06-03 10:31 ` Pedro Alves
2013-06-03 16:37 ` Jan Kratochvil
2 siblings, 0 replies; 59+ messages in thread
From: Pedro Alves @ 2013-05-31 13:27 UTC (permalink / raw)
To: Jan Kratochvil, gdb-patches
On 05/31/2013 02:22 PM, Gary Benson wrote:
> How about this:
>
> const char *name = probe_info[i].name;
> char buf[32];
>
> /* Fedora 17 and Red Hat Enterprise Linux 6.2-6.4
> shipped with an early version of the probes code in
> which the probes' names were prefixed with "rtld_"
> and the "map_failed" probe did not exist. The
> locations of the probes are otherwise the same, so
> we check for probes with prefixed names if probes
> with unprefixed names are not present. */
> if (with_prefix)
> {
> xsnprintf (buf, sizeof (buf), "rtld_%s", name);
> name = buf;
> }
>
Looks great. Thanks!
--
Pedro Alves
^ permalink raw reply [flat|nested] 59+ messages in thread* Re: [RFA 5/7 take 4] Improved linker-debugger interface
2013-05-31 13:22 ` [RFA 5/7 take 4] " Gary Benson
2013-05-31 13:27 ` Pedro Alves
@ 2013-06-03 10:31 ` Pedro Alves
2013-06-03 16:37 ` Jan Kratochvil
2 siblings, 0 replies; 59+ messages in thread
From: Pedro Alves @ 2013-06-03 10:31 UTC (permalink / raw)
To: Jan Kratochvil, gdb-patches
On 05/31/2013 02:22 PM, Gary Benson wrote:
> Pedro Alves wrote:
>> On 05/30/2013 11:43 AM, Gary Benson wrote:
>>> + char name[32] = { '\0' };
>>> +
>>> + /* Fedora 17 and Red Hat Enterprise Linux 6.2-6.4
>>> + shipped with an early version of the probes code in
>>> + which the probes' names were prefixed with "rtld_"
>>> + and the "map_failed" probe did not exist. The
>>> + locations of the probes are otherwise the same, so
>>> + we check for probes with prefixed names if probes
>>> + with unprefixed names are not present. */
>>> +
>>> + if (with_prefix)
>>> + strncat (name, "rtld_", sizeof (name) - strlen (name) - 1);
>>> +
>>> + strncat (name, probe_info[i].name,
>>> + sizeof (name) - strlen (name) - 1);
>>
>> BTW, I'd rather this was written as something like:
>>
>> char name[32];
>>
>> if (with_prefix)
>> xsnprintf (name, sizeof (name), "rtld_%s", probe_info[i].name);
>> else
>> xsnprintf (name, sizeof (name), "%s", probe_info[i].name);
>>
>>
>> strncat like that is really not future proof, as we'll just get get
>> a silently truncated string if a new probe appears with a name that
>> is too big. xsnprintf OTOH gdb_asserts the string fits in the
>> buffer. Granted, whoever added such a probe would probably notice
>> this, but it's a style best avoided. (Witness how so few strncat
>> calls there are in gdb. There are more strcat calls, but that only
>> shows that whenever we _do_ care about string overruns, we tend to
>> use something else, not strncat.)
>> Plus, it looks more readable to me that way. :-)
>> Alternatively, we could add a xstrncat that asserts truncation
>> never happens, though xsnprintf in this case still looks a bit
>> more readable to me :-)
>
> How about this:
>
> const char *name = probe_info[i].name;
> char buf[32];
>
> /* Fedora 17 and Red Hat Enterprise Linux 6.2-6.4
> shipped with an early version of the probes code in
> which the probes' names were prefixed with "rtld_"
> and the "map_failed" probe did not exist. The
> locations of the probes are otherwise the same, so
> we check for probes with prefixed names if probes
> with unprefixed names are not present. */
> if (with_prefix)
> {
> xsnprintf (buf, sizeof (buf), "rtld_%s", name);
> name = buf;
> }
>
> Revised patch attached.
That's great, thanks.
--
Pedro Alves
^ permalink raw reply [flat|nested] 59+ messages in thread* Re: [RFA 5/7 take 4] Improved linker-debugger interface
2013-05-31 13:22 ` [RFA 5/7 take 4] " Gary Benson
2013-05-31 13:27 ` Pedro Alves
2013-06-03 10:31 ` Pedro Alves
@ 2013-06-03 16:37 ` Jan Kratochvil
2013-06-03 17:28 ` Pedro Alves
2 siblings, 1 reply; 59+ messages in thread
From: Jan Kratochvil @ 2013-06-03 16:37 UTC (permalink / raw)
To: gdb-patches; +Cc: Pedro Alves
On Fri, 31 May 2013 15:22:06 +0200, Gary Benson wrote:
> Revised patch attached.
I am fine with check-in of your whole updated patchset.
Thanks,
Jan
^ permalink raw reply [flat|nested] 59+ messages in thread
* [RFA 6/7] Linker-debugger interface tests by Jan
2013-05-16 14:43 [RFA 0/7] Improved linker-debugger interface Gary Benson
` (5 preceding siblings ...)
2013-05-16 14:55 ` [RFA 5/7] Improved linker-debugger interface Gary Benson
@ 2013-05-16 14:55 ` Gary Benson
2013-05-29 19:06 ` Pedro Alves
2013-05-16 17:33 ` [RFA 0/7] Improved linker-debugger interface Tom Tromey
` (3 subsequent siblings)
10 siblings, 1 reply; 59+ messages in thread
From: Gary Benson @ 2013-05-16 14:55 UTC (permalink / raw)
To: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 178 bytes --]
This patch updates the testsuite to cope with some changes resulting
from the probes-based interface, and adds a new test. This patch is
principally the work of Jan Kratochvil.
[-- Attachment #2: rtld-probes-6-tests-jk.patch --]
[-- Type: text/plain, Size: 15646 bytes --]
2013-05-16 Jan Kratochvil <jan.kratochvil@redhat.com>
Gary Benson <gbenson@redhat.com>
* lib/gdb.exp (build_executable_from_specs): Use gdb_compile_pthread,
gdb_compile_shlib or gdb_compile_shlib_pthreads where appropriate.
* lib/prelink-support.exp (build_executable_own_libs): Allow INTERP
to be set to "no" to indicate that no ld.so copy should be made.
* gdb.base/break-interp.exp (solib_bp): New constant.
(reach_1): Use the above instead of "_dl_debug_state".
(test_attach): Likewise.
(test_ld): Likewise.
* gdb.threads/dlopen-libpthread.exp: New file.
* gdb.threads/dlopen-libpthread.c: Likewise.
* gdb.threads/dlopen-libpthread-lib.c: Likewise.
* gdb.base/solib-corrupted.exp: Disable test if GDB is using probes.
diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
index b8a7cf8..76ee870 100644
--- a/gdb/testsuite/lib/gdb.exp
+++ b/gdb/testsuite/lib/gdb.exp
@@ -4051,31 +4051,6 @@ proc build_executable_from_specs {testname executable options args} {
set binfile [standard_output_file $executable]
- set objects {}
- set i 0
- foreach {s local_options} $args {
- if { [gdb_compile "${srcdir}/${subdir}/${s}" "${binfile}${i}.o" object $local_options] != "" } {
- untested $testname
- return -1
- }
- lappend objects "${binfile}${i}.o"
- incr i
- }
-
- set pthreads [lsearch -exact $options "pthreads"]
- if { $pthreads >= 0 } {
- set options [lreplace $options $pthreads $pthreads]
- if { [gdb_compile_pthreads $objects "${binfile}" executable $options] != "" } {
- untested $testname
- return -1
- }
- } else {
- if { [gdb_compile $objects "${binfile}" executable $options] != "" } {
- untested $testname
- return -1
- }
- }
-
set info_options ""
if { [lsearch -exact $options "c++"] >= 0 } {
set info_options "c++"
@@ -4083,6 +4058,42 @@ proc build_executable_from_specs {testname executable options args} {
if [get_compiler_info ${info_options}] {
return -1
}
+
+ set binfile [standard_output_file $executable]
+
+ set func gdb_compile
+ set func_index [lsearch -regexp $options {^(pthreads|shlib|shlib_pthreads)$}]
+ if {$func_index != -1} {
+ set func "${func}_[lindex $options $func_index]"
+ }
+
+ # gdb_compile_shlib and gdb_compile_shlib_pthreads do not use the 3rd
+ # parameter. They also requires $sources while gdb_compile and
+ # gdb_compile_pthreads require $objects. Moreover they ignore any options.
+ if [string match gdb_compile_shlib* $func] {
+ set sources_path {}
+ foreach {s local_options} $args {
+ lappend sources_path "${srcdir}/${subdir}/${s}"
+ }
+ set ret [$func $sources_path "${binfile}" $options]
+ } else {
+ set objects {}
+ set i 0
+ foreach {s local_options} $args {
+ if { [gdb_compile "${srcdir}/${subdir}/${s}" "${binfile}${i}.o" object $local_options] != "" } {
+ untested $testname
+ return -1
+ }
+ lappend objects "${binfile}${i}.o"
+ incr i
+ }
+ set ret [$func $objects "${binfile}" executable $options]
+ }
+ if { $ret != "" } {
+ untested $testname
+ return -1
+ }
+
return 0
}
diff --git a/gdb/testsuite/lib/prelink-support.exp b/gdb/testsuite/lib/prelink-support.exp
index abb9b79..6cc8a87 100644
--- a/gdb/testsuite/lib/prelink-support.exp
+++ b/gdb/testsuite/lib/prelink-support.exp
@@ -95,8 +95,9 @@ proc file_copy {src dest} {
# Wrap function build_executable so that the resulting executable is fully
# self-sufficient (without dependencies on system libraries). Parameter
# INTERP may be used to specify a loader (ld.so) to be used that is
-# different from the default system one. Libraries on which the executable
-# depends are copied into directory DIR. Default DIR value to
+# different from the default system one. INTERP can be set to "no" if no ld.so
+# copy should be made. Libraries on which the executable depends are copied
+# into directory DIR. Default DIR value to
# `${objdir}/${subdir}/${EXECUTABLE}.d'.
#
# In case of success, return a string containing the arguments to be used
@@ -151,8 +152,15 @@ proc build_executable_own_libs {testname executable sources options {interp ""}
if {$interp == ""} {
set interp_system [section_get $binfile .interp]
- set interp ${dir}/[file tail $interp_system]
- file_copy $interp_system $interp
+ if {$interp_system == ""} {
+ fail "$test could not find .interp"
+ } else {
+ set interp ${dir}/[file tail $interp_system]
+ file_copy $interp_system $interp
+ }
+ }
+ if {$interp == "no"} {
+ set interp ""
}
set dests {}
@@ -164,13 +172,19 @@ proc build_executable_own_libs {testname executable sources options {interp ""}
# Do not lappend it so that "-rpath $dir" overrides any possible "-rpath"s
# specified by the caller to be able to link it for ldd" above.
- set options [linsert $options 0 "ldflags=-Wl,--dynamic-linker,$interp,-rpath,$dir"]
+ set options [linsert $options 0 "ldflags=-Wl,-rpath,$dir"]
+ if {$interp != ""} {
+ set options [linsert $options 0 "ldflags=-Wl,--dynamic-linker,$interp"]
+ }
if {[build_executable $testname $executable $sources $options] == -1} {
return ""
}
- set prelink_args "--dynamic-linker=$interp --ld-library-path=$dir $binfile $interp [concat $dests]"
+ set prelink_args "--ld-library-path=$dir $binfile [concat $dests]"
+ if {$interp != ""} {
+ set prelink_args "--dynamic-linker=$interp $prelink_args $interp"
+ }
return $prelink_args
}
diff --git a/gdb/testsuite/gdb.base/break-interp.exp b/gdb/testsuite/gdb.base/break-interp.exp
index 4012e66..7aa6537 100644
--- a/gdb/testsuite/gdb.base/break-interp.exp
+++ b/gdb/testsuite/gdb.base/break-interp.exp
@@ -109,12 +109,19 @@ proc strip_debug {dest} {
}
}
+# The marker function for the standard runtime linker interface is
+# _dl_debug_state. The probes-based interface has no specific marker
+# function; the probe we will stop on (init_start) is in dl_main so we
+# check for that.
+
+set solib_bp {(_dl_debug_state|dl_main)}
+
# Implementation of reach.
proc reach_1 {func command displacement} {
- global gdb_prompt expect_out
+ global gdb_prompt expect_out solib_bp
- if {$func == "_dl_debug_state"} {
+ if {$func == $solib_bp} {
# Breakpoint on _dl_debug_state can have problems due to its overlap
# with the existing internal breakpoint from GDB.
gdb_test_no_output "set stop-on-solib-events 1"
@@ -142,21 +149,21 @@ proc reach_1 {func command displacement} {
exp_continue
}
-re "Breakpoint \[0-9\]+, \\.?(__GI_)?$func \\(.*\\) at .*:\[0-9\]+\r\n.*$gdb_prompt $" {
- if {$func == "_dl_debug_state"} {
+ if {$func == $solib_bp} {
fail $test
} else {
pass $test
}
}
-re "Breakpoint \[0-9\]+, \[0-9xa-f\]+ in \\.?(__GI_)?$func \\(\\).*\r\n$gdb_prompt $" {
- if {$func == "_dl_debug_state"} {
+ if {$func == $solib_bp} {
fail $test
} else {
pass $test
}
}
-re "Stopped due to (spurious )?shared library event.*\r\n$gdb_prompt $" {
- if {$func == "_dl_debug_state"} {
+ if {$func == $solib_bp} {
if {$debug_state_count == 0} {
# First stop does not yet relocate the _start function
# descriptor on ppc64.
@@ -175,7 +182,7 @@ proc reach_1 {func command displacement} {
fail $test_displacement
}
- if {$func == "_dl_debug_state"} {
+ if {$func == $solib_bp} {
gdb_test_no_output "set stop-on-solib-events 0"
}
}
@@ -361,7 +368,7 @@ proc test_attach {file displacement {relink_args ""}} {
}
proc test_ld {file ifmain trynosym displacement} {
- global srcdir subdir gdb_prompt expect_out inferior_exited_re
+ global srcdir subdir gdb_prompt expect_out inferior_exited_re solib_bp
# First test normal `file'-command loaded $FILE with symbols.
@@ -389,9 +396,9 @@ proc test_ld {file ifmain trynosym displacement} {
gdb_test_no_output "set args ${objdir}/${subdir}/$binfile_test" "set args OBJDIR/${subdir}/$binfile_test"
}
- reach "_dl_debug_state" "run" $displacement
+ reach $solib_bp "run" $displacement
- gdb_test "bt" "#0 +\[^\r\n\]*\\m(__GI_)?_dl_debug_state\\M.*" "dl bt"
+ gdb_test "bt" "#0 +\[^\r\n\]*\\m(__GI_)?$solib_bp\\M.*" "dl bt"
if $ifmain {
reach "main" continue "NONE"
@@ -403,7 +410,7 @@ proc test_ld {file ifmain trynosym displacement} {
# Try re-run if the new PIE displacement takes effect.
gdb_test "kill" "" "kill" {Kill the program being debugged\? \(y or n\) } "y"
- reach "_dl_debug_state" "run" $displacement
+ reach $solib_bp "run" $displacement
if $ifmain {
test_core $file $displacement
@@ -435,7 +442,7 @@ proc test_ld {file ifmain trynosym displacement} {
gdb_test "exec-file $file" "exec-file $escapedfile" "load"
if $ifmain {
- reach "_dl_debug_state" run $displacement
+ reach $solib_bp run $displacement
# Use two separate gdb_test_multiple statements to avoid timeouts due
# to slow processing of wildcard capturing long output
diff --git a/gdb/testsuite/gdb.threads/dlopen-libpthread.exp b/gdb/testsuite/gdb.threads/dlopen-libpthread.exp
new file mode 100644
index 0000000..c28f7bc
--- /dev/null
+++ b/gdb/testsuite/gdb.threads/dlopen-libpthread.exp
@@ -0,0 +1,74 @@
+# Copyright 2011 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/>.
+
+if {![istarget *-linux*] || [skip_shlib_tests]} {
+ return 0
+}
+
+load_lib prelink-support.exp
+
+set testfile "dlopen-libpthread"
+set srcmainfile ${testfile}.c
+set srclibfile ${testfile}-lib.c
+set executable ${testfile}
+set binfile_lib ${objdir}/${subdir}/${executable}.so
+set binfile ${objdir}/${subdir}/${executable}
+set lib_dlopen [shlib_target_file ${executable}.so]
+
+# Use build_executable_own_libs as prelinked libpthread.so can produce false
+# PASS - it is OK if GDB processes it still before relocation.
+
+set relink_args [build_executable_own_libs ${testfile}.exp ${executable}.so $srclibfile {debug shlib_pthreads} no]
+if {$relink_args == "" || ![prelink_no $relink_args]
+ || [prepare_for_testing ${testfile}.exp ${executable} ${srcmainfile} {debug shlib_load}] } {
+ return -1
+}
+gdb_load_shlibs $binfile_lib
+
+if { ![runto_main] } {
+ return -1
+}
+
+set test "info probes all rtld rtld_map_complete"
+gdb_test_multiple $test $test {
+ -re "\[ \t\]rtld_map_complete\[ \t\]+0x\[0-9a-f\]+.*\r\n$gdb_prompt $" {
+ pass $test
+ }
+ -re "No probes matched\\.\r\n$gdb_prompt $" {
+ xfail $test
+ untested ${testfile}.exp
+ return
+ }
+}
+
+set test "libpthread.so not found"
+gdb_test_multiple "info sharedlibrary" $test {
+ -re "/libpthread\\.so.*\r\n$gdb_prompt $" {
+ fail $test
+ }
+ -re "/libc\\.so.*\r\n$gdb_prompt $" {
+ pass $test
+ }
+}
+
+gdb_test "set variable filename=\"$lib_dlopen\""
+
+gdb_breakpoint "notify"
+
+# The error was:
+# Cannot find new threads: generic error
+gdb_continue_to_breakpoint "notify" ".* notify-here .*"
+
+gdb_test "info sharedlibrary" {/libpthread\.so.*} "libpthread.so found"
diff --git a/gdb/testsuite/gdb.threads/dlopen-libpthread.c b/gdb/testsuite/gdb.threads/dlopen-libpthread.c
new file mode 100644
index 0000000..6a8b8b6
--- /dev/null
+++ b/gdb/testsuite/gdb.threads/dlopen-libpthread.c
@@ -0,0 +1,46 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2011 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/>. */
+
+#include <dlfcn.h>
+#include <stddef.h>
+#include <assert.h>
+
+static const char *volatile filename;
+
+static void
+notify (void)
+{
+ filename = NULL; /* notify-here */
+}
+
+int
+main (void)
+{
+ void *h;
+ void (*fp) (void (*) (void));
+
+ assert (filename != NULL);
+ h = dlopen (filename, RTLD_LAZY);
+ assert (h != NULL);
+
+ fp = dlsym (h, "f");
+ assert (fp != NULL);
+
+ fp (notify);
+
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.threads/dlopen-libpthread-lib.c b/gdb/testsuite/gdb.threads/dlopen-libpthread-lib.c
new file mode 100644
index 0000000..8d8c57c
--- /dev/null
+++ b/gdb/testsuite/gdb.threads/dlopen-libpthread-lib.c
@@ -0,0 +1,40 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2011 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/>. */
+
+#include <pthread.h>
+#include <assert.h>
+
+static void *
+tfunc (void *arg)
+{
+ void (*notifyp) (void) = arg;
+
+ notifyp ();
+}
+
+void
+f (void (*notifyp) (void))
+{
+ pthread_t t;
+ int i;
+
+ i = pthread_create (&t, NULL, tfunc, notifyp);
+ assert (i == 0);
+
+ i = pthread_join (t, NULL);
+ assert (i == 0);
+}
diff --git a/gdb/testsuite/gdb.base/solib-corrupted.exp b/gdb/testsuite/gdb.base/solib-corrupted.exp
index 6b703d9..4b92b8b 100644
--- a/gdb/testsuite/gdb.base/solib-corrupted.exp
+++ b/gdb/testsuite/gdb.base/solib-corrupted.exp
@@ -36,6 +36,33 @@ if ![runto_main] {
return
}
+# With probes interface GDB no longer scans the inferior library list so its
+# corruption cannot be tested. There is no way to disable the probes
+# interface.
+
+set probes { init_start init_complete map_start reloc_complete unmap_start
+ unmap_complete }
+set test "info probes"
+gdb_test_multiple $test $test {
+ -re "^rtld\[ \t\]+(?:rtld_)?(\[a-z_\]+)\[ \t\]" {
+ set idx [lsearch -exact $probes $expect_out(1,string)]
+ if { $idx >= 0 } {
+ set probes [lreplace $probes $idx $idx]
+ }
+ exp_continue
+ }
+ -re "^\[^\r\n\]*\r\n" {
+ exp_continue
+ }
+ -re "^$gdb_prompt $" {
+ }
+}
+if { [llength $probes] == 0 } {
+ xfail $test
+ untested "GDB is using probes"
+ return
+}
+
gdb_test "info sharedlibrary" "From * To .*" "normal list"
# GDB checks there for matching L_PREV.
^ permalink raw reply [flat|nested] 59+ messages in thread* Re: [RFA 6/7] Linker-debugger interface tests by Jan
2013-05-16 14:55 ` [RFA 6/7] Linker-debugger interface tests by Jan Gary Benson
@ 2013-05-29 19:06 ` Pedro Alves
2013-05-30 9:19 ` Gary Benson
0 siblings, 1 reply; 59+ messages in thread
From: Pedro Alves @ 2013-05-29 19:06 UTC (permalink / raw)
To: gdb-patches
On 05/16/2013 03:48 PM, Gary Benson wrote:
> + Copyright 2011 Free Software Foundation, Inc.
Write "2011-2013". (I haven't checked all files, but there
are more instances.)
> +# With probes interface GDB no longer scans the inferior library list so its
> +# corruption cannot be tested. There is no way to disable the probes
> +# interface.
I was wondering whether it wouldn't make sense to have such a way.
It probably would be nice to run a couple dso related tests
with the probes interface force-disabled (in addition with the probes
enabled), at least for a couple years, while distros without probes
are still relevant, so we can easily catch regressions. That could be
done as a separate work, of course.
--
Pedro Alves
^ permalink raw reply [flat|nested] 59+ messages in thread
* Re: [RFA 6/7] Linker-debugger interface tests by Jan
2013-05-29 19:06 ` Pedro Alves
@ 2013-05-30 9:19 ` Gary Benson
0 siblings, 0 replies; 59+ messages in thread
From: Gary Benson @ 2013-05-30 9:19 UTC (permalink / raw)
To: Pedro Alves; +Cc: gdb-patches
Pedro Alves wrote:
> On 05/16/2013 03:48 PM, Gary Benson wrote:
> > + Copyright 2011 Free Software Foundation, Inc.
>
> Write "2011-2013". (I haven't checked all files, but there
> are more instances.)
I have updated these, and also the files in patch 7.
> > +# With probes interface GDB no longer scans the inferior library list so its
> > +# corruption cannot be tested. There is no way to disable the probes
> > +# interface.
>
> I was wondering whether it wouldn't make sense to have such a way.
>
> It probably would be nice to run a couple dso related tests with the
> probes interface force-disabled (in addition with the probes
> enabled), at least for a couple years, while distros without probes
> are still relevant, so we can easily catch regressions. That could
> be done as a separate work, of course.
Yeah, I was thinking about this last night. I'll put together a patch
once the main series is in.
Thanks,
Gary
--
http://gbenson.net/
^ permalink raw reply [flat|nested] 59+ messages in thread
* Re: [RFA 0/7] Improved linker-debugger interface
2013-05-16 14:43 [RFA 0/7] Improved linker-debugger interface Gary Benson
` (6 preceding siblings ...)
2013-05-16 14:55 ` [RFA 6/7] Linker-debugger interface tests by Jan Gary Benson
@ 2013-05-16 17:33 ` Tom Tromey
2013-05-16 18:53 ` Gary Benson
2013-06-06 9:00 ` Gary Benson
2013-05-19 13:46 ` Jan Kratochvil
` (2 subsequent siblings)
10 siblings, 2 replies; 59+ messages in thread
From: Tom Tromey @ 2013-05-16 17:33 UTC (permalink / raw)
To: gdb-patches
>>>>> "Gary" == Gary Benson <gbenson@redhat.com> writes:
Gary> This is an updated version of a patch series I posted last year
Thanks, Gary!
Gary> (I underestimated the disruption a baby can bring to your life!)
Haha, me too.
Gary> A quick and dirty speed comparison yielded the following results:
Gary> no of solibs 128 256 512 1024 2048 4096
Gary> --------------------------------------------------------------
Gary> old interface 0 1 4 12 47 185
Gary> new interface 0 0 2 4 10 36
Gary> (time in seconds)
I know we discussed this before, but I don't recall the outcome.
It still looks like there is a non-linearity in there. Do you know why?
It would be good to have a bug for this.
Tom
^ permalink raw reply [flat|nested] 59+ messages in thread* Re: [RFA 0/7] Improved linker-debugger interface
2013-05-16 17:33 ` [RFA 0/7] Improved linker-debugger interface Tom Tromey
@ 2013-05-16 18:53 ` Gary Benson
2013-06-06 9:00 ` Gary Benson
1 sibling, 0 replies; 59+ messages in thread
From: Gary Benson @ 2013-05-16 18:53 UTC (permalink / raw)
To: gdb-patches
Tom Tromey wrote:
> >>>>> "Gary" == Gary Benson <gbenson@redhat.com> writes:
> Gary> A quick and dirty speed comparison yielded the following results:
>
> Gary> no of solibs 128 256 512 1024 2048 4096
> Gary> --------------------------------------------------------------
> Gary> old interface 0 1 4 12 47 185
> Gary> new interface 0 0 2 4 10 36
> Gary> (time in seconds)
>
> I know we discussed this before, but I don't recall the outcome.
>
> It still looks like there is a non-linearity in there. Do you know
> why?
Some of it is certainly because GDB stores solibs in linked lists.
There is a little bit of introduced quadratic behaviour in this patch
because target_so_ops->current_sos() is expected to return a freshly
allocated list of libraries to update_solib_list(), which either adds
them to its own list or frees them if it already has them. This makes
sense for the standard interface, which reads everything from the
inferior into a list and returns it. The probes interface already has
a list built by the time target_so_ops->current_sos() is called, but
it has to create a copy to return. I spent some time trying to get
around this in July or August last year but I hit a wall. I may have
another look at this tomorrow, as this latest patch is very different
in that area from what I was working with back then.
> It would be good to have a bug for this.
I will file one (tomorrow!)
Thanks,
Gary
--
http://gbenson.net/
^ permalink raw reply [flat|nested] 59+ messages in thread
* Re: [RFA 0/7] Improved linker-debugger interface
2013-05-16 17:33 ` [RFA 0/7] Improved linker-debugger interface Tom Tromey
2013-05-16 18:53 ` Gary Benson
@ 2013-06-06 9:00 ` Gary Benson
1 sibling, 0 replies; 59+ messages in thread
From: Gary Benson @ 2013-06-06 9:00 UTC (permalink / raw)
To: Tom Tromey; +Cc: gdb-patches
Tom Tromey wrote:
> >>>>> "Gary" == Gary Benson <gbenson@redhat.com> writes:
>
> Gary> A quick and dirty speed comparison yielded the following results:
>
> Gary> no of solibs 128 256 512 1024 2048 4096
> Gary> --------------------------------------------------------------
> Gary> old interface 0 1 4 12 47 185
> Gary> new interface 0 0 2 4 10 36
> Gary> (time in seconds)
>
> It still looks like there is a non-linearity in there. [...]
>
> It would be good to have a bug for this.
http://sourceware.org/bugzilla/show_bug.cgi?id=15590
Cheers,
Gary
--
http://gbenson.net/
^ permalink raw reply [flat|nested] 59+ messages in thread
* Re: [RFA 0/7] Improved linker-debugger interface
2013-05-16 14:43 [RFA 0/7] Improved linker-debugger interface Gary Benson
` (7 preceding siblings ...)
2013-05-16 17:33 ` [RFA 0/7] Improved linker-debugger interface Tom Tromey
@ 2013-05-19 13:46 ` Jan Kratochvil
2013-05-29 19:08 ` Pedro Alves
2013-06-04 13:38 ` [commit] " Gary Benson
10 siblings, 0 replies; 59+ messages in thread
From: Jan Kratochvil @ 2013-05-19 13:46 UTC (permalink / raw)
To: gdb-patches
Hi Gary,
the unreplied patch (1-4 and 6) are fine with me (+Tom's comments).
Thanks,
Jan
^ permalink raw reply [flat|nested] 59+ messages in thread* Re: [RFA 0/7] Improved linker-debugger interface
2013-05-16 14:43 [RFA 0/7] Improved linker-debugger interface Gary Benson
` (8 preceding siblings ...)
2013-05-19 13:46 ` Jan Kratochvil
@ 2013-05-29 19:08 ` Pedro Alves
2013-06-04 13:38 ` [commit] " Gary Benson
10 siblings, 0 replies; 59+ messages in thread
From: Pedro Alves @ 2013-05-29 19:08 UTC (permalink / raw)
To: gdb-patches
Very nice work.
I sent off a few comments, but I read the whole series, and
it all looked very reasonable to me.
--
Pedro Alves
^ permalink raw reply [flat|nested] 59+ messages in thread* [commit] Improved linker-debugger interface
2013-05-16 14:43 [RFA 0/7] Improved linker-debugger interface Gary Benson
` (9 preceding siblings ...)
2013-05-29 19:08 ` Pedro Alves
@ 2013-06-04 13:38 ` Gary Benson
2013-06-25 21:04 ` Joel Brobecker
10 siblings, 1 reply; 59+ messages in thread
From: Gary Benson @ 2013-06-04 13:38 UTC (permalink / raw)
To: gdb-patches; +Cc: Tom Tromey, Jan Kratochvil, Pedro Alves
[-- Attachment #1: Type: text/plain, Size: 500 bytes --]
Hi all,
I just committed the improved linker-debugger interface patch series
as attached. For those of you using the patches in distributions,
some of the attached files have different filenames than previously
posted:
a) what was rtld-probes-3-gdbserver.patch was split into
rtld-probes-3.1-gdbserver.patch and rtld-probes-3.3-news.patch.
b) rtld-probes-8-docs.patch is attached here as
rtld-probes-3.2-docs.patch.
Thank you everyone who reviewed this.
Gary
--
http://gbenson.net/
[-- Attachment #2: rtld-probes-1-convenience.patch --]
[-- Type: text/plain, Size: 3463 bytes --]
Index: gdb/ChangeLog
===================================================================
RCS file: /cvs/src/src/gdb/ChangeLog,v
retrieving revision 1.15680
diff -u -r1.15680 ChangeLog
--- gdb/ChangeLog 4 Jun 2013 02:44:34 -0000 1.15680
+++ gdb/ChangeLog 4 Jun 2013 12:49:04 -0000
@@ -1,3 +1,11 @@
+2013-06-04 Gary Benson <gbenson@redhat.com>
+
+ * probe.h (get_probe_argument_count): New declaration.
+ (evaluate_probe_argument): Likewise.
+ * probe.c (get_probe_argument_count): New function.
+ (evaluate_probe_argument): Likewise.
+ (probe_safe_evaluate_at_pc): Use the above new functions.
+
2013-06-04 Alan Modra <amodra@gmail.com>
* ppc-tdep.h (ppc_insns_match_pattern): Update prototype.
Index: gdb/probe.h
===================================================================
RCS file: /cvs/src/src/gdb/probe.h,v
retrieving revision 1.4
diff -u -r1.4 probe.h
--- gdb/probe.h 1 Jan 2013 06:32:49 -0000 1.4
+++ gdb/probe.h 4 Jun 2013 12:49:06 -0000
@@ -214,6 +214,16 @@
extern struct cmd_list_element **info_probes_cmdlist_get (void);
+/* Return the argument count of the specified probe. */
+
+extern unsigned get_probe_argument_count (struct probe *probe);
+
+/* Evaluate argument N of the specified probe. N must be between 0
+ inclusive and get_probe_argument_count exclusive. */
+
+extern struct value *evaluate_probe_argument (struct probe *probe,
+ unsigned n);
+
/* A convenience function that finds a probe at the PC in FRAME and
evaluates argument N, with 0 <= N < number_of_args. If there is no
probe at that location, or if the probe does not have enough arguments,
Index: gdb/probe.c
===================================================================
RCS file: /cvs/src/src/gdb/probe.c,v
retrieving revision 1.8
diff -u -r1.8 probe.c
--- gdb/probe.c 30 May 2013 17:39:34 -0000 1.8
+++ gdb/probe.c 4 Jun 2013 12:49:06 -0000
@@ -611,28 +611,55 @@
/* See comments in probe.h. */
+unsigned
+get_probe_argument_count (struct probe *probe)
+{
+ const struct sym_probe_fns *probe_fns;
+
+ gdb_assert (probe->objfile != NULL);
+ gdb_assert (probe->objfile->sf != NULL);
+
+ probe_fns = probe->objfile->sf->sym_probe_fns;
+
+ gdb_assert (probe_fns != NULL);
+
+ return probe_fns->sym_get_probe_argument_count (probe);
+}
+
+/* See comments in probe.h. */
+
+struct value *
+evaluate_probe_argument (struct probe *probe, unsigned n)
+{
+ const struct sym_probe_fns *probe_fns;
+
+ gdb_assert (probe->objfile != NULL);
+ gdb_assert (probe->objfile->sf != NULL);
+
+ probe_fns = probe->objfile->sf->sym_probe_fns;
+
+ gdb_assert (probe_fns != NULL);
+
+ return probe_fns->sym_evaluate_probe_argument (probe, n);
+}
+
+/* See comments in probe.h. */
+
struct value *
probe_safe_evaluate_at_pc (struct frame_info *frame, unsigned n)
{
struct probe *probe;
- const struct sym_probe_fns *probe_fns;
unsigned n_args;
probe = find_probe_by_pc (get_frame_pc (frame));
if (!probe)
return NULL;
- gdb_assert (probe->objfile != NULL);
- gdb_assert (probe->objfile->sf != NULL);
- gdb_assert (probe->objfile->sf->sym_probe_fns != NULL);
-
- probe_fns = probe->objfile->sf->sym_probe_fns;
- n_args = probe_fns->sym_get_probe_argument_count (probe);
-
+ n_args = get_probe_argument_count (probe);
if (n >= n_args)
return NULL;
- return probe_fns->sym_evaluate_probe_argument (probe, n);
+ return evaluate_probe_argument (probe, n);
}
/* See comment in probe.h. */
[-- Attachment #3: rtld-probes-2-inhibit-sm-updates.patch --]
[-- Type: text/plain, Size: 6403 bytes --]
Index: gdb/ChangeLog
===================================================================
RCS file: /cvs/src/src/gdb/ChangeLog,v
retrieving revision 1.15681
diff -u -r1.15681 ChangeLog
--- gdb/ChangeLog 4 Jun 2013 12:50:20 -0000 1.15681
+++ gdb/ChangeLog 4 Jun 2013 12:51:30 -0000
@@ -1,3 +1,22 @@
+2013-06-04 Gary Benson <gbenson@redhat.com>
+
+ * objfiles.h (inhibit_section_map_updates): New function
+ declaration.
+ (resume_section_map_updates): Likewise.
+ (resume_section_map_updates_cleanup): Likewise.
+ * objfiles.c (objfile_pspace_info): Removed field
+ "objfiles_changed_p". New fields "new_objfiles_available",
+ "section_map_dirty" and "inhibit_updates".
+ (allocate_objfile): Set new_objfiles_available.
+ (free_objfile): Set section_map_dirty.
+ (objfile_relocate1): Likewise.
+ (in_plt_section): Likewise.
+ (find_pc_section): Update the conditions under which the
+ section map will be updated.
+ (inhibit_section_map_updates): New function.
+ (resume_section_map_updates): Likewise.
+ (resume_section_map_updates_cleanup): Likewise.
+
2013-06-04 Gary Benson <gbenson@redhat.com>
* probe.h (get_probe_argument_count): New declaration.
Index: gdb/objfiles.h
===================================================================
RCS file: /cvs/src/src/gdb/objfiles.h,v
retrieving revision 1.106
diff -u -r1.106 objfiles.h
--- gdb/objfiles.h 6 May 2013 19:15:17 -0000 1.106
+++ gdb/objfiles.h 4 Jun 2013 12:51:32 -0000
@@ -501,6 +501,22 @@
modules. */
DECLARE_REGISTRY(objfile);
+/* In normal use, the section map will be rebuilt by find_pc_section
+ if objfiles have been added, removed or relocated since it was last
+ called. Calling inhibit_section_map_updates will inhibit this
+ behavior until resume_section_map_updates is called. If you call
+ inhibit_section_map_updates you must ensure that every call to
+ find_pc_section in the inhibited region relates to a section that
+ is already in the section map and has not since been removed or
+ relocated. */
+extern void inhibit_section_map_updates (struct program_space *pspace);
+
+/* Resume automatically rebuilding the section map as required. */
+extern void resume_section_map_updates (struct program_space *pspace);
+
+/* Version of the above suitable for use as a cleanup. */
+extern void resume_section_map_updates_cleanup (void *arg);
+
extern void default_iterate_over_objfiles_in_search_order
(struct gdbarch *gdbarch,
iterate_over_objfiles_in_search_order_cb_ftype *cb,
Index: gdb/objfiles.c
===================================================================
RCS file: /cvs/src/src/gdb/objfiles.c,v
retrieving revision 1.160
diff -u -r1.160 objfiles.c
--- gdb/objfiles.c 6 May 2013 19:15:17 -0000 1.160
+++ gdb/objfiles.c 4 Jun 2013 12:51:32 -0000
@@ -67,9 +67,18 @@
struct objfile_pspace_info
{
- int objfiles_changed_p;
struct obj_section **sections;
int num_sections;
+
+ /* Nonzero if object files have been added since the section map
+ was last updated. */
+ int new_objfiles_available;
+
+ /* Nonzero if the section map MUST be updated before use. */
+ int section_map_dirty;
+
+ /* Nonzero if section map updates should be inhibited if possible. */
+ int inhibit_updates;
};
/* Per-program-space data key. */
@@ -317,7 +326,7 @@
objfile->flags |= flags;
/* Rebuild section map next time we need it. */
- get_objfile_pspace_data (objfile->pspace)->objfiles_changed_p = 1;
+ get_objfile_pspace_data (objfile->pspace)->new_objfiles_available = 1;
return objfile;
}
@@ -646,7 +655,7 @@
obstack_free (&objfile->objfile_obstack, 0);
/* Rebuild section map next time we need it. */
- get_objfile_pspace_data (objfile->pspace)->objfiles_changed_p = 1;
+ get_objfile_pspace_data (objfile->pspace)->section_map_dirty = 1;
xfree (objfile);
}
@@ -826,7 +835,7 @@
}
/* Rebuild section map next time we need it. */
- get_objfile_pspace_data (objfile->pspace)->objfiles_changed_p = 1;
+ get_objfile_pspace_data (objfile->pspace)->section_map_dirty = 1;
/* Update the table in exec_ops, used to read memory. */
ALL_OBJFILE_OSECTIONS (objfile, s)
@@ -1291,11 +1300,14 @@
update_section_map (struct program_space *pspace,
struct obj_section ***pmap, int *pmap_size)
{
+ struct objfile_pspace_info *pspace_info;
int alloc_size, map_size, i;
struct obj_section *s, **map;
struct objfile *objfile;
- gdb_assert (get_objfile_pspace_data (pspace)->objfiles_changed_p != 0);
+ pspace_info = get_objfile_pspace_data (pspace);
+ gdb_assert (pspace_info->section_map_dirty != 0
+ || pspace_info->new_objfiles_available != 0);
map = *pmap;
xfree (map);
@@ -1365,7 +1377,9 @@
return s;
pspace_info = get_objfile_pspace_data (current_program_space);
- if (pspace_info->objfiles_changed_p != 0)
+ if (pspace_info->section_map_dirty
+ || (pspace_info->new_objfiles_available
+ && !pspace_info->inhibit_updates))
{
update_section_map (current_program_space,
&pspace_info->sections,
@@ -1373,7 +1387,8 @@
/* Don't need updates to section map until objfiles are added,
removed or relocated. */
- pspace_info->objfiles_changed_p = 0;
+ pspace_info->new_objfiles_available = 0;
+ pspace_info->section_map_dirty = 0;
}
/* The C standard (ISO/IEC 9899:TC2) requires the BASE argument to
@@ -1414,14 +1429,38 @@
}
\f
-/* Set objfiles_changed_p so section map will be rebuilt next time it
+/* Set section_map_dirty so section map will be rebuilt next time it
is used. Called by reread_symbols. */
void
objfiles_changed (void)
{
/* Rebuild section map next time we need it. */
- get_objfile_pspace_data (current_program_space)->objfiles_changed_p = 1;
+ get_objfile_pspace_data (current_program_space)->section_map_dirty = 1;
+}
+
+/* See comments in objfiles.h. */
+
+void
+inhibit_section_map_updates (struct program_space *pspace)
+{
+ get_objfile_pspace_data (pspace)->inhibit_updates = 1;
+}
+
+/* See comments in objfiles.h. */
+
+void
+resume_section_map_updates (struct program_space *pspace)
+{
+ get_objfile_pspace_data (pspace)->inhibit_updates = 0;
+}
+
+/* See comments in objfiles.h. */
+
+void
+resume_section_map_updates_cleanup (void *arg)
+{
+ resume_section_map_updates (arg);
}
/* The default implementation for the "iterate_over_objfiles_in_search_order"
[-- Attachment #4: rtld-probes-3.1-gdbserver.patch --]
[-- Type: text/plain, Size: 9682 bytes --]
Index: gdb/gdbserver/ChangeLog
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/ChangeLog,v
retrieving revision 1.720
diff -u -r1.720 ChangeLog
--- gdb/gdbserver/ChangeLog 31 May 2013 19:14:33 -0000 1.720
+++ gdb/gdbserver/ChangeLog 4 Jun 2013 12:58:04 -0000
@@ -1,3 +1,12 @@
+2013-06-04 Gary Benson <gbenson@redhat.com>
+
+ * server.c (handle_query): Add "augmented-libraries-svr4-read+"
+ to qSupported response when appropriate.
+ (handle_qxfer_libraries_svr4): Allow qXfer:libraries-svr4:read
+ with nonzero-length annex.
+ * linux-low.c (linux_qxfer_libraries_svr4): Parse and handle
+ arguments supplied in annex.
+
2013-05-31 Doug Evans <dje@google.com>
* linux-x86-low.c (ps_get_thread_area): Properly extend address to
Index: gdb/gdbserver/server.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/server.c,v
retrieving revision 1.191
diff -u -r1.191 server.c
--- gdb/gdbserver/server.c 24 May 2013 11:28:06 -0000 1.191
+++ gdb/gdbserver/server.c 4 Jun 2013 12:58:08 -0000
@@ -1115,8 +1115,7 @@
if (writebuf != NULL)
return -2;
- if (annex[0] != '\0' || !target_running ()
- || the_target->qxfer_libraries_svr4 == NULL)
+ if (!target_running () || the_target->qxfer_libraries_svr4 == NULL)
return -1;
return the_target->qxfer_libraries_svr4 (annex, readbuf, writebuf, offset, len);
@@ -1743,7 +1742,8 @@
PBUFSIZ - 1);
if (the_target->qxfer_libraries_svr4 != NULL)
- strcat (own_buf, ";qXfer:libraries-svr4:read+");
+ strcat (own_buf, ";qXfer:libraries-svr4:read+"
+ ";augmented-libraries-svr4-read+");
else
{
/* We do not have any hook to indicate whether the non-SVR4 target
Index: gdb/gdbserver/linux-low.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/linux-low.c,v
retrieving revision 1.237
diff -u -r1.237 linux-low.c
--- gdb/gdbserver/linux-low.c 23 May 2013 17:17:50 -0000 1.237
+++ gdb/gdbserver/linux-low.c 4 Jun 2013 12:58:06 -0000
@@ -5728,6 +5728,12 @@
};
const struct link_map_offsets *lmo;
unsigned int machine;
+ int ptr_size;
+ CORE_ADDR lm_addr = 0, lm_prev = 0;
+ int allocated = 1024;
+ char *p;
+ CORE_ADDR l_name, l_addr, l_ld, l_next, l_prev;
+ int header_done = 0;
if (writebuf != NULL)
return -2;
@@ -5738,128 +5744,144 @@
xsnprintf (filename, sizeof filename, "/proc/%d/exe", pid);
is_elf64 = elf_64_file_p (filename, &machine);
lmo = is_elf64 ? &lmo_64bit_offsets : &lmo_32bit_offsets;
+ ptr_size = is_elf64 ? 8 : 4;
- if (priv->r_debug == 0)
- priv->r_debug = get_r_debug (pid, is_elf64);
-
- /* We failed to find DT_DEBUG. Such situation will not change for this
- inferior - do not retry it. Report it to GDB as E01, see for the reasons
- at the GDB solib-svr4.c side. */
- if (priv->r_debug == (CORE_ADDR) -1)
- return -1;
-
- if (priv->r_debug == 0)
+ while (annex[0] != '\0')
{
- document = xstrdup ("<library-list-svr4 version=\"1.0\"/>\n");
+ const char *sep;
+ CORE_ADDR *addrp;
+ int len;
+
+ sep = strchr (annex, '=');
+ if (sep == NULL)
+ break;
+
+ len = sep - annex;
+ if (len == 5 && strncmp (annex, "start", 5) == 0)
+ addrp = &lm_addr;
+ else if (len == 4 && strncmp (annex, "prev", 4) == 0)
+ addrp = &lm_prev;
+ else
+ {
+ annex = strchr (sep, ';');
+ if (annex == NULL)
+ break;
+ annex++;
+ continue;
+ }
+
+ annex = decode_address_to_semicolon (addrp, sep + 1);
}
- else
+
+ if (lm_addr == 0)
{
- int allocated = 1024;
- char *p;
- const int ptr_size = is_elf64 ? 8 : 4;
- CORE_ADDR lm_addr, lm_prev, l_name, l_addr, l_ld, l_next, l_prev;
- int r_version, header_done = 0;
-
- document = xmalloc (allocated);
- strcpy (document, "<library-list-svr4 version=\"1.0\"");
- p = document + strlen (document);
-
- r_version = 0;
- if (linux_read_memory (priv->r_debug + lmo->r_version_offset,
- (unsigned char *) &r_version,
- sizeof (r_version)) != 0
- || r_version != 1)
+ int r_version = 0;
+
+ if (priv->r_debug == 0)
+ priv->r_debug = get_r_debug (pid, is_elf64);
+
+ /* We failed to find DT_DEBUG. Such situation will not change
+ for this inferior - do not retry it. Report it to GDB as
+ E01, see for the reasons at the GDB solib-svr4.c side. */
+ if (priv->r_debug == (CORE_ADDR) -1)
+ return -1;
+
+ if (priv->r_debug != 0)
{
- warning ("unexpected r_debug version %d", r_version);
- goto done;
+ if (linux_read_memory (priv->r_debug + lmo->r_version_offset,
+ (unsigned char *) &r_version,
+ sizeof (r_version)) != 0
+ || r_version != 1)
+ {
+ warning ("unexpected r_debug version %d", r_version);
+ }
+ else if (read_one_ptr (priv->r_debug + lmo->r_map_offset,
+ &lm_addr, ptr_size) != 0)
+ {
+ warning ("unable to read r_map from 0x%lx",
+ (long) priv->r_debug + lmo->r_map_offset);
+ }
}
+ }
+
+ document = xmalloc (allocated);
+ strcpy (document, "<library-list-svr4 version=\"1.0\"");
+ p = document + strlen (document);
+
+ while (lm_addr
+ && read_one_ptr (lm_addr + lmo->l_name_offset,
+ &l_name, ptr_size) == 0
+ && read_one_ptr (lm_addr + lmo->l_addr_offset,
+ &l_addr, ptr_size) == 0
+ && read_one_ptr (lm_addr + lmo->l_ld_offset,
+ &l_ld, ptr_size) == 0
+ && read_one_ptr (lm_addr + lmo->l_prev_offset,
+ &l_prev, ptr_size) == 0
+ && read_one_ptr (lm_addr + lmo->l_next_offset,
+ &l_next, ptr_size) == 0)
+ {
+ unsigned char libname[PATH_MAX];
- if (read_one_ptr (priv->r_debug + lmo->r_map_offset,
- &lm_addr, ptr_size) != 0)
+ if (lm_prev != l_prev)
{
- warning ("unable to read r_map from 0x%lx",
- (long) priv->r_debug + lmo->r_map_offset);
- goto done;
+ warning ("Corrupted shared library list: 0x%lx != 0x%lx",
+ (long) lm_prev, (long) l_prev);
+ break;
}
- lm_prev = 0;
- while (read_one_ptr (lm_addr + lmo->l_name_offset,
- &l_name, ptr_size) == 0
- && read_one_ptr (lm_addr + lmo->l_addr_offset,
- &l_addr, ptr_size) == 0
- && read_one_ptr (lm_addr + lmo->l_ld_offset,
- &l_ld, ptr_size) == 0
- && read_one_ptr (lm_addr + lmo->l_prev_offset,
- &l_prev, ptr_size) == 0
- && read_one_ptr (lm_addr + lmo->l_next_offset,
- &l_next, ptr_size) == 0)
+ /* Not checking for error because reading may stop before
+ we've got PATH_MAX worth of characters. */
+ libname[0] = '\0';
+ linux_read_memory (l_name, libname, sizeof (libname) - 1);
+ libname[sizeof (libname) - 1] = '\0';
+ if (libname[0] != '\0')
{
- unsigned char libname[PATH_MAX];
+ /* 6x the size for xml_escape_text below. */
+ size_t len = 6 * strlen ((char *) libname);
+ char *name;
- if (lm_prev != l_prev)
+ if (!header_done)
{
- warning ("Corrupted shared library list: 0x%lx != 0x%lx",
- (long) lm_prev, (long) l_prev);
- break;
+ /* Terminate `<library-list-svr4'. */
+ *p++ = '>';
+ header_done = 1;
}
- /* Not checking for error because reading may stop before
- we've got PATH_MAX worth of characters. */
- libname[0] = '\0';
- linux_read_memory (l_name, libname, sizeof (libname) - 1);
- libname[sizeof (libname) - 1] = '\0';
- if (libname[0] != '\0')
+ while (allocated < p - document + len + 200)
{
- /* 6x the size for xml_escape_text below. */
- size_t len = 6 * strlen ((char *) libname);
- char *name;
-
- if (!header_done)
- {
- /* Terminate `<library-list-svr4'. */
- *p++ = '>';
- header_done = 1;
- }
-
- while (allocated < p - document + len + 200)
- {
- /* Expand to guarantee sufficient storage. */
- uintptr_t document_len = p - document;
-
- document = xrealloc (document, 2 * allocated);
- allocated *= 2;
- p = document + document_len;
- }
-
- name = xml_escape_text ((char *) libname);
- p += sprintf (p, "<library name=\"%s\" lm=\"0x%lx\" "
- "l_addr=\"0x%lx\" l_ld=\"0x%lx\"/>",
- name, (unsigned long) lm_addr,
- (unsigned long) l_addr, (unsigned long) l_ld);
- free (name);
- }
- else if (lm_prev == 0)
- {
- sprintf (p, " main-lm=\"0x%lx\"", (unsigned long) lm_addr);
- p = p + strlen (p);
- }
+ /* Expand to guarantee sufficient storage. */
+ uintptr_t document_len = p - document;
- if (l_next == 0)
- break;
+ document = xrealloc (document, 2 * allocated);
+ allocated *= 2;
+ p = document + document_len;
+ }
- lm_prev = lm_addr;
- lm_addr = l_next;
+ name = xml_escape_text ((char *) libname);
+ p += sprintf (p, "<library name=\"%s\" lm=\"0x%lx\" "
+ "l_addr=\"0x%lx\" l_ld=\"0x%lx\"/>",
+ name, (unsigned long) lm_addr,
+ (unsigned long) l_addr, (unsigned long) l_ld);
+ free (name);
}
- done:
- if (!header_done)
+ else if (lm_prev == 0)
{
- /* Empty list; terminate `<library-list-svr4'. */
- strcpy (p, "/>");
+ sprintf (p, " main-lm=\"0x%lx\"", (unsigned long) lm_addr);
+ p = p + strlen (p);
}
- else
- strcpy (p, "</library-list-svr4>");
+
+ lm_prev = lm_addr;
+ lm_addr = l_next;
}
+ if (!header_done)
+ {
+ /* Empty list; terminate `<library-list-svr4'. */
+ strcpy (p, "/>");
+ }
+ else
+ strcpy (p, "</library-list-svr4>");
+
document_len = strlen (document);
if (offset < document_len)
document_len -= offset;
[-- Attachment #5: rtld-probes-3.2-docs.patch --]
[-- Type: text/plain, Size: 3780 bytes --]
Index: gdb/doc/ChangeLog
===================================================================
RCS file: /cvs/src/src/gdb/doc/ChangeLog,v
retrieving revision 1.1463
diff -u -r1.1463 ChangeLog
--- gdb/doc/ChangeLog 24 May 2013 04:50:26 -0000 1.1463
+++ gdb/doc/ChangeLog 4 Jun 2013 13:05:24 -0000
@@ -1,3 +1,12 @@
+2013-06-04 Gary Benson <gbenson@redhat.com>
+
+ * gdb.texinfo (General Query Packets/qSupported): Added
+ "qXfer:libraries-svr4:read" and "augmented-libraries-svr4-read".
+ to the table of currently defined stub features.
+ Added a more detailed entry for "augmented-libraries-svr4-read".
+ (General Query Packets/qXfer:libraries-svr4:read): Documented
+ the augmented form of this packet.
+
2013-05-23 Joel Brobecker <brobecker@adacore.com>
* gdb.texinfo (System-wide Configuration Scripts): Renames
Index: gdb/doc/gdb.texinfo
===================================================================
RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v
retrieving revision 1.1093
diff -u -r1.1093 gdb.texinfo
--- gdb/doc/gdb.texinfo 24 May 2013 04:50:26 -0000 1.1093
+++ gdb/doc/gdb.texinfo 4 Jun 2013 13:05:58 -0000
@@ -38594,6 +38594,16 @@
@tab @samp{-}
@tab Yes
+@item @samp{qXfer:libraries-svr4:read}
+@tab No
+@tab @samp{-}
+@tab Yes
+
+@item @samp{augmented-libraries-svr4-read}
+@tab No
+@tab @samp{-}
+@tab No
+
@item @samp{qXfer:memory-map:read}
@tab No
@tab @samp{-}
@@ -38770,6 +38780,11 @@
The remote stub understands the @samp{qXfer:libraries-svr4:read} packet
(@pxref{qXfer svr4 library list read}).
+@item augmented-libraries-svr4-read
+The remote stub understands the augmented form of the
+@samp{qXfer:libraries-svr4:read} packet
+(@pxref{qXfer svr4 library list read}).
+
@item qXfer:memory-map:read
The remote stub understands the @samp{qXfer:memory-map:read} packet
(@pxref{qXfer memory map read}).
@@ -39065,7 +39080,10 @@
@anchor{qXfer svr4 library list read}
Access the target's list of loaded libraries when the target is an SVR4
platform. @xref{Library List Format for SVR4 Targets}. The annex part
-of the generic @samp{qXfer} packet must be empty (@pxref{qXfer read}).
+of the generic @samp{qXfer} packet must be empty unless the remote
+stub indicated it supports the augmented form of this packet
+by supplying an appropriate @samp{qSupported} response
+(@pxref{qXfer read}, @ref{qSupported}).
This packet is optional for better performance on SVR4 targets.
@value{GDBN} uses memory read packets to read the SVR4 library list otherwise.
@@ -39073,6 +39091,30 @@
This packet is not probed by default; the remote stub must request it,
by supplying an appropriate @samp{qSupported} response (@pxref{qSupported}).
+If the remote stub indicates it supports the augmented form of this
+packet then the annex part of the generic @samp{qXfer} packet may
+contain a semicolon-separated list of @samp{@var{name}=@var{value}}
+arguments. The currently supported arguments are:
+
+@table @code
+@item start=@var{address}
+A hexadecimal number specifying the address of the @samp{struct
+link_map} to start reading the library list from. If unset or zero
+then the first @samp{struct link_map} in the library list will be
+chosen as the starting point.
+
+@item prev=@var{address}
+A hexadecimal number specifying the address of the @samp{struct
+link_map} immediately preceding the @samp{struct link_map}
+specified by the @samp{start} argument. If unset or zero then
+the remote stub will expect that no @samp{struct link_map}
+exists prior to the starting point.
+
+@end table
+
+Arguments that are not understood by the remote stub will be silently
+ignored.
+
@item qXfer:memory-map:read::@var{offset},@var{length}
@anchor{qXfer memory map read}
Access the target's @dfn{memory-map}. @xref{Memory Map Format}. The
[-- Attachment #6: rtld-probes-3.3-news.patch --]
[-- Type: text/plain, Size: 1359 bytes --]
Index: gdb/ChangeLog
===================================================================
RCS file: /cvs/src/src/gdb/ChangeLog,v
retrieving revision 1.15682
diff -u -r1.15682 ChangeLog
--- gdb/ChangeLog 4 Jun 2013 12:53:33 -0000 1.15682
+++ gdb/ChangeLog 4 Jun 2013 13:00:08 -0000
@@ -1,3 +1,7 @@
+2013-06-04 Gary Benson <gbenson@redhat.com>
+
+ * NEWS: Update.
+
2013-06-04 Gary Benson <gbenson@redhat.com>
* objfiles.h (inhibit_section_map_updates): New function
Index: gdb/NEWS
===================================================================
RCS file: /cvs/src/src/gdb/NEWS,v
retrieving revision 1.600
diff -u -r1.600 NEWS
--- gdb/NEWS 23 May 2013 17:17:50 -0000 1.600
+++ gdb/NEWS 4 Jun 2013 13:00:12 -0000
@@ -95,6 +95,14 @@
stub to step through an address range itself, without GDB
involvemement at each single-step.
+qXfer:libraries-svr4:read's annex
+ The previously unused annex of the qXfer:libraries-svr4:read packet
+ is now used to support passing an argument list. The remote stub
+ reports support for this argument list to GDB's qSupported query.
+ The defined arguments are "start" and "prev", used to reduce work
+ necessary for library list updating, resulting in significant
+ speedup.
+
* New features in the GDB remote stub, GDBserver
** GDBserver now supports target-assisted range stepping. Currently
[-- Attachment #7: rtld-probes-4-remote.patch --]
[-- Type: text/plain, Size: 5060 bytes --]
Index: gdb/ChangeLog
===================================================================
RCS file: /cvs/src/src/gdb/ChangeLog,v
retrieving revision 1.15683
diff -u -r1.15683 ChangeLog
--- gdb/ChangeLog 4 Jun 2013 13:02:15 -0000 1.15683
+++ gdb/ChangeLog 4 Jun 2013 13:08:43 -0000
@@ -1,3 +1,19 @@
+2013-06-04 Gary Benson <gbenson@redhat.com>
+
+ * target.h (target_ops): New field
+ "to_augmented_libraries_svr4_read".
+ (target_augmented_libraries_svr4_read): New macro.
+ * target.c (update_current_target): Handle
+ to_augmented_libraries_svr4_read.
+ * remote.c (remote_state): New field
+ "augmented_libraries_svr4_read".
+ (remote_augmented_libraries_svr4_read_feature): New function.
+ (remote_protocol_features): Add entry for
+ "augmented-libraries-svr4-read".
+ (remote_augmented_libraries_svr4_read): New function.
+ (init_remote_ops): Initialize
+ remote_ops.to_augmented_libraries_svr4_read.
+
2013-06-04 Gary Benson <gbenson@redhat.com>
* NEWS: Update.
Index: gdb/target.h
===================================================================
RCS file: /cvs/src/src/gdb/target.h,v
retrieving revision 1.262
diff -u -r1.262 target.h
--- gdb/target.h 14 May 2013 20:33:36 -0000 1.262
+++ gdb/target.h 4 Jun 2013 13:08:55 -0000
@@ -941,6 +941,10 @@
(inclusive) to function END (exclusive). */
void (*to_call_history_range) (ULONGEST begin, ULONGEST end, int flags);
+ /* Nonzero if TARGET_OBJECT_LIBRARIES_SVR4 may be read with a
+ non-empty annex. */
+ int (*to_augmented_libraries_svr4_read) (void);
+
int to_magic;
/* Need sub-structure for target machine related rather than comm related?
*/
@@ -1809,6 +1813,9 @@
#define target_can_use_agent() \
(*current_target.to_can_use_agent) ()
+#define target_augmented_libraries_svr4_read() \
+ (*current_target.to_augmented_libraries_svr4_read) ()
+
/* Command logging facility. */
#define target_log_command(p) \
Index: gdb/target.c
===================================================================
RCS file: /cvs/src/src/gdb/target.c,v
retrieving revision 1.335
diff -u -r1.335 target.c
--- gdb/target.c 14 May 2013 20:33:36 -0000 1.335
+++ gdb/target.c 4 Jun 2013 13:08:54 -0000
@@ -731,6 +731,7 @@
INHERIT (to_traceframe_info, t);
INHERIT (to_use_agent, t);
INHERIT (to_can_use_agent, t);
+ INHERIT (to_augmented_libraries_svr4_read, t);
INHERIT (to_magic, t);
INHERIT (to_supports_evaluation_of_breakpoint_conditions, t);
INHERIT (to_can_run_breakpoint_commands, t);
@@ -975,6 +976,9 @@
de_fault (to_can_use_agent,
(int (*) (void))
return_zero);
+ de_fault (to_augmented_libraries_svr4_read,
+ (int (*) (void))
+ return_zero);
de_fault (to_execution_direction, default_execution_direction);
#undef de_fault
Index: gdb/remote.c
===================================================================
RCS file: /cvs/src/src/gdb/remote.c,v
retrieving revision 1.552
diff -u -r1.552 remote.c
--- gdb/remote.c 30 May 2013 09:29:18 -0000 1.552
+++ gdb/remote.c 4 Jun 2013 13:08:50 -0000
@@ -361,6 +361,10 @@
/* True if the stub can collect strings using tracenz bytecode. */
int string_tracing;
+ /* True if the stub supports qXfer:libraries-svr4:read with a
+ non-empty annex. */
+ int augmented_libraries_svr4_read;
+
/* Nonzero if the user has pressed Ctrl-C, but the target hasn't
responded to that. */
int ctrlc_pending_p;
@@ -3949,6 +3953,16 @@
rs->string_tracing = (support == PACKET_ENABLE);
}
+static void
+remote_augmented_libraries_svr4_read_feature
+ (const struct protocol_feature *feature,
+ enum packet_support support, const char *value)
+{
+ struct remote_state *rs = get_remote_state ();
+
+ rs->augmented_libraries_svr4_read = (support == PACKET_ENABLE);
+}
+
static struct protocol_feature remote_protocol_features[] = {
{ "PacketSize", PACKET_DISABLE, remote_packet_size, -1 },
{ "qXfer:auxv:read", PACKET_DISABLE, remote_supported_packet,
@@ -3959,6 +3973,8 @@
PACKET_qXfer_libraries },
{ "qXfer:libraries-svr4:read", PACKET_DISABLE, remote_supported_packet,
PACKET_qXfer_libraries_svr4 },
+ { "augmented-libraries-svr4-read", PACKET_DISABLE,
+ remote_augmented_libraries_svr4_read_feature, -1 },
{ "qXfer:memory-map:read", PACKET_DISABLE, remote_supported_packet,
PACKET_qXfer_memory_map },
{ "qXfer:spu:read", PACKET_DISABLE, remote_supported_packet,
@@ -11439,6 +11455,14 @@
return btrace;
}
+static int
+remote_augmented_libraries_svr4_read (void)
+{
+ struct remote_state *rs = get_remote_state ();
+
+ return rs->augmented_libraries_svr4_read;
+}
+
static void
init_remote_ops (void)
{
@@ -11561,6 +11585,8 @@
remote_ops.to_disable_btrace = remote_disable_btrace;
remote_ops.to_teardown_btrace = remote_teardown_btrace;
remote_ops.to_read_btrace = remote_read_btrace;
+ remote_ops.to_augmented_libraries_svr4_read =
+ remote_augmented_libraries_svr4_read;
}
/* Set up the extended remote vector by making a copy of the standard
[-- Attachment #8: rtld-probes-5-main-changes.patch --]
[-- Type: text/plain, Size: 33655 bytes --]
Index: gdb/ChangeLog
===================================================================
RCS file: /cvs/src/src/gdb/ChangeLog,v
retrieving revision 1.15684
diff -u -r1.15684 ChangeLog
--- gdb/ChangeLog 4 Jun 2013 13:10:53 -0000 1.15684
+++ gdb/ChangeLog 4 Jun 2013 13:14:01 -0000
@@ -1,3 +1,56 @@
+2013-06-04 Gary Benson <gbenson@redhat.com>
+
+ * breakpoint.h (handle_solib_event): Moved function declaration
+ to solib.h.
+ * breakpoint.c (handle_solib_event): Moved function to solib.c.
+ (bpstat_stop_status): Pass new argument to handle_solib_event.
+ * solib.h (update_solib_breakpoints): New function declaration.
+ (handle_solib_event): Moved function declaration from
+ breakpoint.h.
+ * solib.c (update_solib_breakpoints): New function.
+ (handle_solib_event): Moved function from breakpoint.c.
+ Updated to call solib_ops->handle_event if not NULL.
+ * solist.h (target_so_ops): New fields "update_breakpoints" and
+ "handle_event".
+ * infrun.c (set_stop_on_solib_events): New function.
+ (_initialize_infrun): Use the above for "set
+ stop-on-solib-events".
+ (handle_inferior_event): Pass new argument to handle_solib_event.
+ * solib-svr4.c (probe.h): New include.
+ (svr4_free_library_list): New forward declaration.
+ (probe_action): New enum.
+ (probe_info): New struct.
+ (probe_info): New static variable.
+ (NUM_PROBES): New definition.
+ (svr4_info): New fields "using_xfer", "probes_table" and
+ "solib_list".
+ (free_probes_table): New function.
+ (free_solib_list): New function.
+ (svr4_pspace_data_cleanup): Free probes table and solib list.
+ (svr4_copy_library_list): New function.
+ (svr4_current_sos_via_xfer_libraries): New parameter "annex".
+ (svr4_read_so_list): New parameter "prev_lm".
+ (svr4_current_sos_direct): Renamed from "svr4_current_sos".
+ (svr4_current_sos): New function.
+ (probe_and_action): New struct.
+ (hash_probe_and_action): New function.
+ (equal_probe_and_action): Likewise.
+ (register_solib_event_probe): Likewise.
+ (solib_event_probe_at): Likewise.
+ (solib_event_probe_action): Likewise.
+ (solist_update_full): Likewise.
+ (solist_update_incremental): Likewise.
+ (disable_probes_interface_cleanup): Likewise.
+ (svr4_handle_solib_event): Likewise.
+ (svr4_update_solib_event_breakpoint): Likewise.
+ (svr4_update_solib_event_breakpoints): Likewise.
+ (svr4_create_solib_event_breakpoints): Likewise.
+ (enable_break): Free probes table before creating breakpoints.
+ Use svr4_create_solib_event_breakpoints to create breakpoints.
+ (svr4_solib_create_inferior_hook): Free the solib list.
+ (_initialize_svr4_solib): Initialise
+ svr4_so_ops.handle_solib_event and svr4_so_ops.update_breakpoints.
+
2013-06-04 Gary Benson <gbenson@redhat.com>
* target.h (target_ops): New field
Index: gdb/breakpoint.h
===================================================================
RCS file: /cvs/src/src/gdb/breakpoint.h,v
retrieving revision 1.197
diff -u -r1.197 breakpoint.h
--- gdb/breakpoint.h 21 May 2013 04:18:54 -0000 1.197
+++ gdb/breakpoint.h 4 Jun 2013 13:14:13 -0000
@@ -1554,8 +1554,6 @@
/* Attempt to determine architecture of location identified by SAL. */
extern struct gdbarch *get_sal_arch (struct symtab_and_line sal);
-extern void handle_solib_event (void);
-
extern void breakpoint_free_objfile (struct objfile *objfile);
extern char *ep_parse_optional_if_clause (char **arg);
Index: gdb/breakpoint.c
===================================================================
RCS file: /cvs/src/src/gdb/breakpoint.c,v
retrieving revision 1.764
diff -u -r1.764 breakpoint.c
--- gdb/breakpoint.c 30 May 2013 17:09:02 -0000 1.764
+++ gdb/breakpoint.c 4 Jun 2013 13:14:12 -0000
@@ -5352,21 +5352,6 @@
target_terminal_inferior ();
}
-/* Handle an solib event by calling solib_add. */
-
-void
-handle_solib_event (void)
-{
- clear_program_space_solib_cache (current_inferior ()->pspace);
-
- /* Check for any newly added shared libraries if we're supposed to
- be adding them automatically. Switch terminal for any messages
- produced by breakpoint_re_set. */
- target_terminal_ours_for_output ();
- solib_add (NULL, 0, ¤t_target, auto_solib_add);
- target_terminal_inferior ();
-}
-
/* Prepare WHAT final decision for infrun. */
/* Decide what infrun needs to do with this bpstat. */
Index: gdb/solib.h
===================================================================
RCS file: /cvs/src/src/gdb/solib.h,v
retrieving revision 1.35
diff -u -r1.35 solib.h
--- gdb/solib.h 21 May 2013 08:16:10 -0000 1.35
+++ gdb/solib.h 4 Jun 2013 13:14:22 -0000
@@ -90,4 +90,12 @@
void *),
void *data);
+/* Enable or disable optional solib event breakpoints as appropriate. */
+
+extern void update_solib_breakpoints (void);
+
+/* Handle an solib event by calling solib_add. */
+
+extern void handle_solib_event (void);
+
#endif /* SOLIB_H */
Index: gdb/solib.c
===================================================================
RCS file: /cvs/src/src/gdb/solib.c,v
retrieving revision 1.175
diff -u -r1.175 solib.c
--- gdb/solib.c 4 Jun 2013 01:33:31 -0000 1.175
+++ gdb/solib.c 4 Jun 2013 13:14:22 -0000
@@ -1209,6 +1209,37 @@
objfile_purge_solibs ();
}
+/* See solib.h. */
+
+void
+update_solib_breakpoints (void)
+{
+ const struct target_so_ops *ops = solib_ops (target_gdbarch ());
+
+ if (ops->update_breakpoints != NULL)
+ ops->update_breakpoints ();
+}
+
+/* See solib.h. */
+
+void
+handle_solib_event (void)
+{
+ const struct target_so_ops *ops = solib_ops (target_gdbarch ());
+
+ if (ops->handle_event != NULL)
+ ops->handle_event ();
+
+ clear_program_space_solib_cache (current_inferior ()->pspace);
+
+ /* Check for any newly added shared libraries if we're supposed to
+ be adding them automatically. Switch terminal for any messages
+ produced by breakpoint_re_set. */
+ target_terminal_ours_for_output ();
+ solib_add (NULL, 0, ¤t_target, auto_solib_add);
+ target_terminal_inferior ();
+}
+
/* Reload shared libraries, but avoid reloading the same symbol file
we already have loaded. */
Index: gdb/solist.h
===================================================================
RCS file: /cvs/src/src/gdb/solist.h,v
retrieving revision 1.39
diff -u -r1.39 solist.h
--- gdb/solist.h 6 May 2013 22:18:38 -0000 1.39
+++ gdb/solist.h 4 Jun 2013 13:14:22 -0000
@@ -153,6 +153,19 @@
core file (in particular, for readonly sections). */
int (*keep_data_in_core) (CORE_ADDR vaddr,
unsigned long size);
+
+ /* Enable or disable optional solib event breakpoints as
+ appropriate. This should be called whenever
+ stop_on_solib_events is changed. This pointer can be
+ NULL, in which case no enabling or disabling is necessary
+ for this target. */
+ void (*update_breakpoints) (void);
+
+ /* Target-specific processing of solib events that will be
+ performed before solib_add is called. This pointer can be
+ NULL, in which case no specific preprocessing is necessary
+ for this target. */
+ void (*handle_event) (void);
};
/* Free the memory associated with a (so_list *). */
Index: gdb/infrun.c
===================================================================
RCS file: /cvs/src/src/gdb/infrun.c,v
retrieving revision 1.582
diff -u -r1.582 infrun.c
--- gdb/infrun.c 30 May 2013 17:37:50 -0000 1.582
+++ gdb/infrun.c 4 Jun 2013 13:14:18 -0000
@@ -370,6 +370,16 @@
/* Nonzero if we want to give control to the user when we're notified
of shared library events by the dynamic linker. */
int stop_on_solib_events;
+
+/* Enable or disable optional shared library event breakpoints
+ as appropriate when the above flag is changed. */
+
+static void
+set_stop_on_solib_events (char *args, int from_tty, struct cmd_list_element *c)
+{
+ update_solib_breakpoints ();
+}
+
static void
show_stop_on_solib_events (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
@@ -7333,7 +7343,7 @@
If nonzero, gdb will give control to the user when the dynamic linker\n\
notifies gdb of shared library events. The most common event of interest\n\
to the user would be loading/unloading of a new library."),
- NULL,
+ set_stop_on_solib_events,
show_stop_on_solib_events,
&setlist, &showlist);
Index: gdb/solib-svr4.c
===================================================================
RCS file: /cvs/src/src/gdb/solib-svr4.c,v
retrieving revision 1.178
diff -u -r1.178 solib-svr4.c
--- gdb/solib-svr4.c 21 May 2013 23:41:29 -0000 1.178
+++ gdb/solib-svr4.c 4 Jun 2013 13:14:20 -0000
@@ -46,10 +46,12 @@
#include "auxv.h"
#include "exceptions.h"
#include "gdb_bfd.h"
+#include "probe.h"
static struct link_map_offsets *svr4_fetch_link_map_offsets (void);
static int svr4_have_link_map_offsets (void);
static void svr4_relocate_main_executable (void);
+static void svr4_free_library_list (void *p_list);
/* Link map info to include in an allocated so_list entry. */
@@ -106,6 +108,55 @@
NULL
};
+/* What to do when a probe stop occurs. */
+
+enum probe_action
+{
+ /* Something went seriously wrong. Stop using probes and
+ revert to using the older interface. */
+ PROBES_INTERFACE_FAILED,
+
+ /* No action is required. The shared object list is still
+ valid. */
+ DO_NOTHING,
+
+ /* The shared object list should be reloaded entirely. */
+ FULL_RELOAD,
+
+ /* Attempt to incrementally update the shared object list. If
+ the update fails or is not possible, fall back to reloading
+ the list in full. */
+ UPDATE_OR_RELOAD,
+};
+
+/* A probe's name and its associated action. */
+
+struct probe_info
+{
+ /* The name of the probe. */
+ const char *name;
+
+ /* What to do when a probe stop occurs. */
+ enum probe_action action;
+};
+
+/* A list of named probes and their associated actions. If all
+ probes are present in the dynamic linker then the probes-based
+ interface will be used. */
+
+static const struct probe_info probe_info[] =
+{
+ { "init_start", DO_NOTHING },
+ { "init_complete", FULL_RELOAD },
+ { "map_start", DO_NOTHING },
+ { "map_failed", DO_NOTHING },
+ { "reloc_complete", UPDATE_OR_RELOAD },
+ { "unmap_start", DO_NOTHING },
+ { "unmap_complete", FULL_RELOAD },
+};
+
+#define NUM_PROBES ARRAY_SIZE (probe_info)
+
/* Return non-zero if GDB_SO_NAME and INFERIOR_SO_NAME represent
the same shared library. */
@@ -313,17 +364,58 @@
CORE_ADDR interp_text_sect_high;
CORE_ADDR interp_plt_sect_low;
CORE_ADDR interp_plt_sect_high;
+
+ /* Nonzero if the list of objects was last obtained from the target
+ via qXfer:libraries-svr4:read. */
+ int using_xfer;
+
+ /* Table of struct probe_and_action instances, used by the
+ probes-based interface to map breakpoint addresses to probes
+ and their associated actions. Lookup is performed using
+ probe_and_action->probe->address. */
+ htab_t probes_table;
+
+ /* List of objects loaded into the inferior, used by the probes-
+ based interface. */
+ struct so_list *solib_list;
};
/* Per-program-space data key. */
static const struct program_space_data *solib_svr4_pspace_data;
+/* Free the probes table. */
+
+static void
+free_probes_table (struct svr4_info *info)
+{
+ if (info->probes_table == NULL)
+ return;
+
+ htab_delete (info->probes_table);
+ info->probes_table = NULL;
+}
+
+/* Free the solib list. */
+
+static void
+free_solib_list (struct svr4_info *info)
+{
+ svr4_free_library_list (&info->solib_list);
+ info->solib_list = NULL;
+}
+
static void
svr4_pspace_data_cleanup (struct program_space *pspace, void *arg)
{
struct svr4_info *info;
info = program_space_data (pspace, solib_svr4_pspace_data);
+ if (info == NULL)
+ return;
+
+ free_probes_table (info);
+ free_solib_list (info);
+
xfree (info);
}
@@ -991,6 +1083,34 @@
}
}
+/* Copy library list. */
+
+static struct so_list *
+svr4_copy_library_list (struct so_list *src)
+{
+ struct so_list *dst = NULL;
+ struct so_list **link = &dst;
+
+ while (src != NULL)
+ {
+ struct so_list *new;
+
+ new = xmalloc (sizeof (struct so_list));
+ memcpy (new, src, sizeof (struct so_list));
+
+ new->lm_info = xmalloc (sizeof (struct lm_info));
+ memcpy (new->lm_info, src->lm_info, sizeof (struct lm_info));
+
+ new->next = NULL;
+ *link = new;
+ link = &new->next;
+
+ src = src->next;
+ }
+
+ return dst;
+}
+
#ifdef HAVE_LIBEXPAT
#include "xml-support.h"
@@ -1106,23 +1226,30 @@
return 0;
}
-/* Attempt to get so_list from target via qXfer:libraries:read packet.
+/* Attempt to get so_list from target via qXfer:libraries-svr4:read packet.
Return 0 if packet not supported, *SO_LIST_RETURN is not modified in such
case. Return 1 if *SO_LIST_RETURN contains the library list, it may be
- empty, caller is responsible for freeing all its entries. */
+ empty, caller is responsible for freeing all its entries.
+
+ Note that ANNEX must be NULL if the remote does not explicitly allow
+ qXfer:libraries-svr4:read packets with non-empty annexes. Support for
+ this can be checked using target_augmented_libraries_svr4_read (). */
static int
-svr4_current_sos_via_xfer_libraries (struct svr4_library_list *list)
+svr4_current_sos_via_xfer_libraries (struct svr4_library_list *list,
+ const char *annex)
{
char *svr4_library_document;
int result;
struct cleanup *back_to;
+ gdb_assert (annex == NULL || target_augmented_libraries_svr4_read ());
+
/* Fetch the list of shared libraries. */
svr4_library_document = target_read_stralloc (¤t_target,
TARGET_OBJECT_LIBRARIES_SVR4,
- NULL);
+ annex);
if (svr4_library_document == NULL)
return 0;
@@ -1136,7 +1263,8 @@
#else
static int
-svr4_current_sos_via_xfer_libraries (struct svr4_library_list *list)
+svr4_current_sos_via_xfer_libraries (struct svr4_library_list *list,
+ const char *annex)
{
return 0;
}
@@ -1170,15 +1298,19 @@
return new;
}
-/* Read the whole inferior libraries chain starting at address LM. Add the
- entries to the tail referenced by LINK_PTR_PTR. Ignore the first entry if
- IGNORE_FIRST and set global MAIN_LM_ADDR according to it. */
+/* Read the whole inferior libraries chain starting at address LM.
+ Expect the first entry in the chain's previous entry to be PREV_LM.
+ Add the entries to the tail referenced by LINK_PTR_PTR. Ignore the
+ first entry if IGNORE_FIRST and set global MAIN_LM_ADDR according
+ to it. Returns nonzero upon success. If zero is returned the
+ entries stored to LINK_PTR_PTR are still valid although they may
+ represent only part of the inferior library list. */
-static void
-svr4_read_so_list (CORE_ADDR lm, struct so_list ***link_ptr_ptr,
- int ignore_first)
+static int
+svr4_read_so_list (CORE_ADDR lm, CORE_ADDR prev_lm,
+ struct so_list ***link_ptr_ptr, int ignore_first)
{
- CORE_ADDR prev_lm = 0, next_lm;
+ CORE_ADDR next_lm;
for (; lm != 0; prev_lm = lm, lm = next_lm)
{
@@ -1194,7 +1326,7 @@
if (new->lm_info == NULL)
{
do_cleanups (old_chain);
- break;
+ return 0;
}
next_lm = new->lm_info->l_next;
@@ -1205,7 +1337,7 @@
paddress (target_gdbarch (), prev_lm),
paddress (target_gdbarch (), new->lm_info->l_prev));
do_cleanups (old_chain);
- break;
+ return 0;
}
/* For SVR4 versions, the first entry in the link map is for the
@@ -1251,17 +1383,21 @@
**link_ptr_ptr = new;
*link_ptr_ptr = &new->next;
}
+
+ return 1;
}
-/* Implement the "current_sos" target_so_ops method. */
+/* Read the full list of currently loaded shared objects directly
+ from the inferior, without referring to any libraries read and
+ stored by the probes interface. Handle special cases relating
+ to the first elements of the list. */
static struct so_list *
-svr4_current_sos (void)
+svr4_current_sos_direct (struct svr4_info *info)
{
CORE_ADDR lm;
struct so_list *head = NULL;
struct so_list **link_ptr = &head;
- struct svr4_info *info;
struct cleanup *back_to;
int ignore_first;
struct svr4_library_list library_list;
@@ -1274,19 +1410,16 @@
Unfortunately statically linked inferiors will also fall back through this
suboptimal code path. */
- if (svr4_current_sos_via_xfer_libraries (&library_list))
+ info->using_xfer = svr4_current_sos_via_xfer_libraries (&library_list,
+ NULL);
+ if (info->using_xfer)
{
if (library_list.main_lm)
- {
- info = get_svr4_info ();
- info->main_lm_addr = library_list.main_lm;
- }
+ info->main_lm_addr = library_list.main_lm;
return library_list.head ? library_list.head : svr4_default_sos ();
}
- info = get_svr4_info ();
-
/* Always locate the debug struct, in case it has moved. */
info->debug_base = 0;
locate_base (info);
@@ -1309,7 +1442,7 @@
`struct so_list' nodes. */
lm = solib_svr4_r_map (info);
if (lm)
- svr4_read_so_list (lm, &link_ptr, ignore_first);
+ svr4_read_so_list (lm, 0, &link_ptr, ignore_first);
/* On Solaris, the dynamic linker is not in the normal list of
shared objects, so make sure we pick it up too. Having
@@ -1317,7 +1450,7 @@
for skipping dynamic linker resolver code. */
lm = solib_svr4_r_ldsomap (info);
if (lm)
- svr4_read_so_list (lm, &link_ptr, 0);
+ svr4_read_so_list (lm, 0, &link_ptr, 0);
discard_cleanups (back_to);
@@ -1327,6 +1460,22 @@
return head;
}
+/* Implement the "current_sos" target_so_ops method. */
+
+static struct so_list *
+svr4_current_sos (void)
+{
+ struct svr4_info *info = get_svr4_info ();
+
+ /* If the solib list has been read and stored by the probes
+ interface then we return a copy of the stored list. */
+ if (info->solib_list != NULL)
+ return svr4_copy_library_list (info->solib_list);
+
+ /* Otherwise obtain the solib list directly from the inferior. */
+ return svr4_current_sos_direct (info);
+}
+
/* Get the address of the link_map for a given OBJFILE. */
CORE_ADDR
@@ -1409,6 +1558,476 @@
return gdbarch_addr_bits_remove (target_gdbarch (), addr);
}
+/* A probe and its associated action. */
+
+struct probe_and_action
+{
+ /* The probe. */
+ struct probe *probe;
+
+ /* The action. */
+ enum probe_action action;
+};
+
+/* Returns a hash code for the probe_and_action referenced by p. */
+
+static hashval_t
+hash_probe_and_action (const void *p)
+{
+ const struct probe_and_action *pa = p;
+
+ return (hashval_t) pa->probe->address;
+}
+
+/* Returns non-zero if the probe_and_actions referenced by p1 and p2
+ are equal. */
+
+static int
+equal_probe_and_action (const void *p1, const void *p2)
+{
+ const struct probe_and_action *pa1 = p1;
+ const struct probe_and_action *pa2 = p2;
+
+ return pa1->probe->address == pa2->probe->address;
+}
+
+/* Register a solib event probe and its associated action in the
+ probes table. */
+
+static void
+register_solib_event_probe (struct probe *probe, enum probe_action action)
+{
+ struct svr4_info *info = get_svr4_info ();
+ struct probe_and_action lookup, *pa;
+ void **slot;
+
+ /* Create the probes table, if necessary. */
+ if (info->probes_table == NULL)
+ info->probes_table = htab_create_alloc (1, hash_probe_and_action,
+ equal_probe_and_action,
+ xfree, xcalloc, xfree);
+
+ lookup.probe = probe;
+ slot = htab_find_slot (info->probes_table, &lookup, INSERT);
+ gdb_assert (*slot == HTAB_EMPTY_ENTRY);
+
+ pa = XCNEW (struct probe_and_action);
+ pa->probe = probe;
+ pa->action = action;
+
+ *slot = pa;
+}
+
+/* Get the solib event probe at the specified location, and the
+ action associated with it. Returns NULL if no solib event probe
+ was found. */
+
+static struct probe_and_action *
+solib_event_probe_at (struct svr4_info *info, CORE_ADDR address)
+{
+ struct probe lookup_probe;
+ struct probe_and_action lookup;
+ void **slot;
+
+ lookup_probe.address = address;
+ lookup.probe = &lookup_probe;
+ slot = htab_find_slot (info->probes_table, &lookup, NO_INSERT);
+
+ if (slot == NULL)
+ return NULL;
+
+ return (struct probe_and_action *) *slot;
+}
+
+/* Decide what action to take when the specified solib event probe is
+ hit. */
+
+static enum probe_action
+solib_event_probe_action (struct probe_and_action *pa)
+{
+ enum probe_action action;
+ unsigned probe_argc;
+
+ action = pa->action;
+ if (action == DO_NOTHING || action == PROBES_INTERFACE_FAILED)
+ return action;
+
+ gdb_assert (action == FULL_RELOAD || action == UPDATE_OR_RELOAD);
+
+ /* Check that an appropriate number of arguments has been supplied.
+ We expect:
+ arg0: Lmid_t lmid (mandatory)
+ arg1: struct r_debug *debug_base (mandatory)
+ arg2: struct link_map *new (optional, for incremental updates) */
+ probe_argc = get_probe_argument_count (pa->probe);
+ if (probe_argc == 2)
+ action = FULL_RELOAD;
+ else if (probe_argc < 2)
+ action = PROBES_INTERFACE_FAILED;
+
+ return action;
+}
+
+/* Populate the shared object list by reading the entire list of
+ shared objects from the inferior. Handle special cases relating
+ to the first elements of the list. Returns nonzero on success. */
+
+static int
+solist_update_full (struct svr4_info *info)
+{
+ free_solib_list (info);
+ info->solib_list = svr4_current_sos_direct (info);
+
+ return 1;
+}
+
+/* Update the shared object list starting from the link-map entry
+ passed by the linker in the probe's third argument. Returns
+ nonzero if the list was successfully updated, or zero to indicate
+ failure. */
+
+static int
+solist_update_incremental (struct svr4_info *info, CORE_ADDR lm)
+{
+ struct so_list *tail;
+ CORE_ADDR prev_lm;
+
+ /* svr4_current_sos_direct contains logic to handle a number of
+ special cases relating to the first elements of the list. To
+ avoid duplicating this logic we defer to solist_update_full
+ if the list is empty. */
+ if (info->solib_list == NULL)
+ return 0;
+
+ /* Fall back to a full update if we are using a remote target
+ that does not support incremental transfers. */
+ if (info->using_xfer && !target_augmented_libraries_svr4_read ())
+ return 0;
+
+ /* Walk to the end of the list. */
+ for (tail = info->solib_list; tail->next != NULL; tail = tail->next)
+ /* Nothing. */;
+ prev_lm = tail->lm_info->lm_addr;
+
+ /* Read the new objects. */
+ if (info->using_xfer)
+ {
+ struct svr4_library_list library_list;
+ char annex[64];
+
+ xsnprintf (annex, sizeof (annex), "start=%s;prev=%s",
+ phex_nz (lm, sizeof (lm)),
+ phex_nz (prev_lm, sizeof (prev_lm)));
+ if (!svr4_current_sos_via_xfer_libraries (&library_list, annex))
+ return 0;
+
+ tail->next = library_list.head;
+ }
+ else
+ {
+ struct so_list **link = &tail->next;
+
+ /* IGNORE_FIRST may safely be set to zero here because the
+ above check and deferral to solist_update_full ensures
+ that this call to svr4_read_so_list will never see the
+ first element. */
+ if (!svr4_read_so_list (lm, prev_lm, &link, 0))
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Disable the probes-based linker interface and revert to the
+ original interface. We don't reset the breakpoints as the
+ ones set up for the probes-based interface are adequate. */
+
+static void
+disable_probes_interface_cleanup (void *arg)
+{
+ struct svr4_info *info = get_svr4_info ();
+
+ warning (_("Probes-based dynamic linker interface failed.\n"
+ "Reverting to original interface.\n"));
+
+ free_probes_table (info);
+ free_solib_list (info);
+}
+
+/* Update the solib list as appropriate when using the
+ probes-based linker interface. Do nothing if using the
+ standard interface. */
+
+static void
+svr4_handle_solib_event (void)
+{
+ struct svr4_info *info = get_svr4_info ();
+ struct probe_and_action *pa;
+ enum probe_action action;
+ struct cleanup *old_chain, *usm_chain;
+ struct value *val;
+ CORE_ADDR pc, debug_base, lm = 0;
+ int is_initial_ns;
+
+ /* Do nothing if not using the probes interface. */
+ if (info->probes_table == NULL)
+ return;
+
+ /* If anything goes wrong we revert to the original linker
+ interface. */
+ old_chain = make_cleanup (disable_probes_interface_cleanup, NULL);
+
+ pc = regcache_read_pc (get_current_regcache ());
+ pa = solib_event_probe_at (info, pc);
+ if (pa == NULL)
+ {
+ do_cleanups (old_chain);
+ return;
+ }
+
+ action = solib_event_probe_action (pa);
+ if (action == PROBES_INTERFACE_FAILED)
+ {
+ do_cleanups (old_chain);
+ return;
+ }
+
+ if (action == DO_NOTHING)
+ {
+ discard_cleanups (old_chain);
+ return;
+ }
+
+ /* evaluate_probe_argument looks up symbols in the dynamic linker
+ using find_pc_section. find_pc_section is accelerated by a cache
+ called the section map. The section map is invalidated every
+ time a shared library is loaded or unloaded, and if the inferior
+ is generating a lot of shared library events then the section map
+ will be updated every time svr4_handle_solib_event is called.
+ We called find_pc_section in svr4_create_solib_event_breakpoints,
+ so we can guarantee that the dynamic linker's sections are in the
+ section map. We can therefore inhibit section map updates across
+ these calls to evaluate_probe_argument and save a lot of time. */
+ inhibit_section_map_updates (current_program_space);
+ usm_chain = make_cleanup (resume_section_map_updates_cleanup,
+ current_program_space);
+
+ val = evaluate_probe_argument (pa->probe, 1);
+ if (val == NULL)
+ {
+ do_cleanups (old_chain);
+ return;
+ }
+
+ debug_base = value_as_address (val);
+ if (debug_base == 0)
+ {
+ do_cleanups (old_chain);
+ return;
+ }
+
+ /* Always locate the debug struct, in case it moved. */
+ info->debug_base = 0;
+ if (locate_base (info) == 0)
+ {
+ do_cleanups (old_chain);
+ return;
+ }
+
+ /* GDB does not currently support libraries loaded via dlmopen
+ into namespaces other than the initial one. We must ignore
+ any namespace other than the initial namespace here until
+ support for this is added to GDB. */
+ if (debug_base != info->debug_base)
+ action = DO_NOTHING;
+
+ if (action == UPDATE_OR_RELOAD)
+ {
+ val = evaluate_probe_argument (pa->probe, 2);
+ if (val != NULL)
+ lm = value_as_address (val);
+
+ if (lm == 0)
+ action = FULL_RELOAD;
+ }
+
+ /* Resume section map updates. */
+ do_cleanups (usm_chain);
+
+ if (action == UPDATE_OR_RELOAD)
+ {
+ if (!solist_update_incremental (info, lm))
+ action = FULL_RELOAD;
+ }
+
+ if (action == FULL_RELOAD)
+ {
+ if (!solist_update_full (info))
+ {
+ do_cleanups (old_chain);
+ return;
+ }
+ }
+
+ discard_cleanups (old_chain);
+}
+
+/* Helper function for svr4_update_solib_event_breakpoints. */
+
+static int
+svr4_update_solib_event_breakpoint (struct breakpoint *b, void *arg)
+{
+ struct bp_location *loc;
+
+ if (b->type != bp_shlib_event)
+ {
+ /* Continue iterating. */
+ return 0;
+ }
+
+ for (loc = b->loc; loc != NULL; loc = loc->next)
+ {
+ struct svr4_info *info;
+ struct probe_and_action *pa;
+
+ info = program_space_data (loc->pspace, solib_svr4_pspace_data);
+ if (info == NULL || info->probes_table == NULL)
+ continue;
+
+ pa = solib_event_probe_at (info, loc->address);
+ if (pa == NULL)
+ continue;
+
+ if (pa->action == DO_NOTHING)
+ {
+ if (b->enable_state == bp_disabled && stop_on_solib_events)
+ enable_breakpoint (b);
+ else if (b->enable_state == bp_enabled && !stop_on_solib_events)
+ disable_breakpoint (b);
+ }
+
+ break;
+ }
+
+ /* Continue iterating. */
+ return 0;
+}
+
+/* Enable or disable optional solib event breakpoints as appropriate.
+ Called whenever stop_on_solib_events is changed. */
+
+static void
+svr4_update_solib_event_breakpoints (void)
+{
+ iterate_over_breakpoints (svr4_update_solib_event_breakpoint, NULL);
+}
+
+/* Create and register solib event breakpoints. PROBES is an array
+ of NUM_PROBES elements, each of which is vector of probes. A
+ solib event breakpoint will be created and registered for each
+ probe. */
+
+static void
+svr4_create_probe_breakpoints (struct gdbarch *gdbarch,
+ VEC (probe_p) **probes)
+{
+ int i;
+
+ for (i = 0; i < NUM_PROBES; i++)
+ {
+ enum probe_action action = probe_info[i].action;
+ struct probe *probe;
+ int ix;
+
+ for (ix = 0;
+ VEC_iterate (probe_p, probes[i], ix, probe);
+ ++ix)
+ {
+ create_solib_event_breakpoint (gdbarch, probe->address);
+ register_solib_event_probe (probe, action);
+ }
+ }
+
+ svr4_update_solib_event_breakpoints ();
+}
+
+/* Both the SunOS and the SVR4 dynamic linkers call a marker function
+ before and after mapping and unmapping shared libraries. The sole
+ purpose of this method is to allow debuggers to set a breakpoint so
+ they can track these changes.
+
+ Some versions of the glibc dynamic linker contain named probes
+ to allow more fine grained stopping. Given the address of the
+ original marker function, this function attempts to find these
+ probes, and if found, sets breakpoints on those instead. If the
+ probes aren't found, a single breakpoint is set on the original
+ marker function. */
+
+static void
+svr4_create_solib_event_breakpoints (struct gdbarch *gdbarch,
+ CORE_ADDR address)
+{
+ struct obj_section *os;
+
+ os = find_pc_section (address);
+ if (os != NULL)
+ {
+ int with_prefix;
+
+ for (with_prefix = 0; with_prefix <= 1; with_prefix++)
+ {
+ VEC (probe_p) *probes[NUM_PROBES];
+ int all_probes_found = 1;
+ int i;
+
+ memset (probes, 0, sizeof (probes));
+ for (i = 0; i < NUM_PROBES; i++)
+ {
+ const char *name = probe_info[i].name;
+ char buf[32];
+
+ /* Fedora 17 and Red Hat Enterprise Linux 6.2-6.4
+ shipped with an early version of the probes code in
+ which the probes' names were prefixed with "rtld_"
+ and the "map_failed" probe did not exist. The
+ locations of the probes are otherwise the same, so
+ we check for probes with prefixed names if probes
+ with unprefixed names are not present. */
+ if (with_prefix)
+ {
+ xsnprintf (buf, sizeof (buf), "rtld_%s", name);
+ name = buf;
+ }
+
+ probes[i] = find_probes_in_objfile (os->objfile, "rtld", name);
+
+ /* The "map_failed" probe did not exist in early
+ versions of the probes code in which the probes'
+ names were prefixed with "rtld_". */
+ if (strcmp (name, "rtld_map_failed") == 0)
+ continue;
+
+ if (VEC_empty (probe_p, probes[i]))
+ {
+ all_probes_found = 0;
+ break;
+ }
+ }
+
+ if (all_probes_found)
+ svr4_create_probe_breakpoints (gdbarch, probes);
+
+ for (i = 0; i < NUM_PROBES; i++)
+ VEC_free (probe_p, probes[i]);
+
+ if (all_probes_found)
+ return;
+ }
+ }
+
+ create_solib_event_breakpoint (gdbarch, address);
+}
+
/* Helper function for gdb_bfd_lookup_symbol. */
static int
@@ -1492,7 +2111,7 @@
That knowledge is encoded in the address, if it's Thumb the low bit
is 1. However, we've stripped that info above and it's not clear
what all the consequences are of passing a non-addr_bits_remove'd
- address to create_solib_event_breakpoint. The call to
+ address to svr4_create_solib_event_breakpoints. The call to
find_pc_section verifies we know about the address and have some
hope of computing the right kind of breakpoint to use (via
symbol info). It does mean that GDB needs to be pointed at a
@@ -1530,7 +2149,7 @@
+ bfd_section_size (tmp_bfd, interp_sect);
}
- create_solib_event_breakpoint (target_gdbarch (), sym_addr);
+ svr4_create_solib_event_breakpoints (target_gdbarch (), sym_addr);
return 1;
}
}
@@ -1688,7 +2307,8 @@
if (sym_addr != 0)
{
- create_solib_event_breakpoint (target_gdbarch (), load_addr + sym_addr);
+ svr4_create_solib_event_breakpoints (target_gdbarch (),
+ load_addr + sym_addr);
xfree (interp_name);
return 1;
}
@@ -1714,7 +2334,7 @@
sym_addr = gdbarch_convert_from_func_ptr_addr (target_gdbarch (),
sym_addr,
¤t_target);
- create_solib_event_breakpoint (target_gdbarch (), sym_addr);
+ svr4_create_solib_event_breakpoints (target_gdbarch (), sym_addr);
return 1;
}
}
@@ -1730,7 +2350,7 @@
sym_addr = gdbarch_convert_from_func_ptr_addr (target_gdbarch (),
sym_addr,
¤t_target);
- create_solib_event_breakpoint (target_gdbarch (), sym_addr);
+ svr4_create_solib_event_breakpoints (target_gdbarch (), sym_addr);
return 1;
}
}
@@ -2226,6 +2846,10 @@
info = get_svr4_info ();
+ /* Clear the probes-based interface's state. */
+ free_probes_table (info);
+ free_solib_list (info);
+
/* Relocate the main executable if necessary. */
svr4_relocate_main_executable ();
@@ -2468,4 +3092,6 @@
svr4_so_ops.lookup_lib_global_symbol = elf_lookup_lib_symbol;
svr4_so_ops.same = svr4_same;
svr4_so_ops.keep_data_in_core = svr4_keep_data_in_core;
+ svr4_so_ops.update_breakpoints = svr4_update_solib_event_breakpoints;
+ svr4_so_ops.handle_event = svr4_handle_solib_event;
}
[-- Attachment #9: rtld-probes-6-tests-jk.patch --]
[-- Type: text/plain, Size: 16507 bytes --]
Index: gdb/testsuite/ChangeLog
===================================================================
RCS file: /cvs/src/src/gdb/testsuite/ChangeLog,v
retrieving revision 1.3682
diff -u -r1.3682 ChangeLog
--- gdb/testsuite/ChangeLog 30 May 2013 00:25:16 -0000 1.3682
+++ gdb/testsuite/ChangeLog 4 Jun 2013 13:20:02 -0000
@@ -1,3 +1,19 @@
+2013-06-04 Jan Kratochvil <jan.kratochvil@redhat.com>
+ Gary Benson <gbenson@redhat.com>
+
+ * lib/gdb.exp (build_executable_from_specs): Use gdb_compile_pthread,
+ gdb_compile_shlib or gdb_compile_shlib_pthreads where appropriate.
+ * lib/prelink-support.exp (build_executable_own_libs): Allow INTERP
+ to be set to "no" to indicate that no ld.so copy should be made.
+ * gdb.base/break-interp.exp (solib_bp): New constant.
+ (reach_1): Use the above instead of "_dl_debug_state".
+ (test_attach): Likewise.
+ (test_ld): Likewise.
+ * gdb.threads/dlopen-libpthread.exp: New file.
+ * gdb.threads/dlopen-libpthread.c: Likewise.
+ * gdb.threads/dlopen-libpthread-lib.c: Likewise.
+ * gdb.base/solib-corrupted.exp: Disable test if GDB is using probes.
+
2013-05-30 Yao Qi <yao@codesourcery.com>
* gdb.mi/mi-cmd-param-changed.exp (test_command_param_changed):
Index: gdb/testsuite/lib/gdb.exp
===================================================================
RCS file: /cvs/src/src/gdb/testsuite/lib/gdb.exp,v
retrieving revision 1.231
diff -u -r1.231 gdb.exp
--- gdb/testsuite/lib/gdb.exp 6 May 2013 22:11:15 -0000 1.231
+++ gdb/testsuite/lib/gdb.exp 4 Jun 2013 13:20:08 -0000
@@ -4051,31 +4051,6 @@
set binfile [standard_output_file $executable]
- set objects {}
- set i 0
- foreach {s local_options} $args {
- if { [gdb_compile "${srcdir}/${subdir}/${s}" "${binfile}${i}.o" object $local_options] != "" } {
- untested $testname
- return -1
- }
- lappend objects "${binfile}${i}.o"
- incr i
- }
-
- set pthreads [lsearch -exact $options "pthreads"]
- if { $pthreads >= 0 } {
- set options [lreplace $options $pthreads $pthreads]
- if { [gdb_compile_pthreads $objects "${binfile}" executable $options] != "" } {
- untested $testname
- return -1
- }
- } else {
- if { [gdb_compile $objects "${binfile}" executable $options] != "" } {
- untested $testname
- return -1
- }
- }
-
set info_options ""
if { [lsearch -exact $options "c++"] >= 0 } {
set info_options "c++"
@@ -4083,6 +4058,42 @@
if [get_compiler_info ${info_options}] {
return -1
}
+
+ set binfile [standard_output_file $executable]
+
+ set func gdb_compile
+ set func_index [lsearch -regexp $options {^(pthreads|shlib|shlib_pthreads)$}]
+ if {$func_index != -1} {
+ set func "${func}_[lindex $options $func_index]"
+ }
+
+ # gdb_compile_shlib and gdb_compile_shlib_pthreads do not use the 3rd
+ # parameter. They also requires $sources while gdb_compile and
+ # gdb_compile_pthreads require $objects. Moreover they ignore any options.
+ if [string match gdb_compile_shlib* $func] {
+ set sources_path {}
+ foreach {s local_options} $args {
+ lappend sources_path "${srcdir}/${subdir}/${s}"
+ }
+ set ret [$func $sources_path "${binfile}" $options]
+ } else {
+ set objects {}
+ set i 0
+ foreach {s local_options} $args {
+ if { [gdb_compile "${srcdir}/${subdir}/${s}" "${binfile}${i}.o" object $local_options] != "" } {
+ untested $testname
+ return -1
+ }
+ lappend objects "${binfile}${i}.o"
+ incr i
+ }
+ set ret [$func $objects "${binfile}" executable $options]
+ }
+ if { $ret != "" } {
+ untested $testname
+ return -1
+ }
+
return 0
}
Index: gdb/testsuite/lib/prelink-support.exp
===================================================================
RCS file: /cvs/src/src/gdb/testsuite/lib/prelink-support.exp,v
retrieving revision 1.6
diff -u -r1.6 prelink-support.exp
--- gdb/testsuite/lib/prelink-support.exp 1 Jan 2013 06:41:28 -0000 1.6
+++ gdb/testsuite/lib/prelink-support.exp 4 Jun 2013 13:20:08 -0000
@@ -95,8 +95,9 @@
# Wrap function build_executable so that the resulting executable is fully
# self-sufficient (without dependencies on system libraries). Parameter
# INTERP may be used to specify a loader (ld.so) to be used that is
-# different from the default system one. Libraries on which the executable
-# depends are copied into directory DIR. Default DIR value to
+# different from the default system one. INTERP can be set to "no" if no ld.so
+# copy should be made. Libraries on which the executable depends are copied
+# into directory DIR. Default DIR value to
# `${objdir}/${subdir}/${EXECUTABLE}.d'.
#
# In case of success, return a string containing the arguments to be used
@@ -151,8 +152,15 @@
if {$interp == ""} {
set interp_system [section_get $binfile .interp]
- set interp ${dir}/[file tail $interp_system]
- file_copy $interp_system $interp
+ if {$interp_system == ""} {
+ fail "$test could not find .interp"
+ } else {
+ set interp ${dir}/[file tail $interp_system]
+ file_copy $interp_system $interp
+ }
+ }
+ if {$interp == "no"} {
+ set interp ""
}
set dests {}
@@ -164,13 +172,19 @@
# Do not lappend it so that "-rpath $dir" overrides any possible "-rpath"s
# specified by the caller to be able to link it for ldd" above.
- set options [linsert $options 0 "ldflags=-Wl,--dynamic-linker,$interp,-rpath,$dir"]
+ set options [linsert $options 0 "ldflags=-Wl,-rpath,$dir"]
+ if {$interp != ""} {
+ set options [linsert $options 0 "ldflags=-Wl,--dynamic-linker,$interp"]
+ }
if {[build_executable $testname $executable $sources $options] == -1} {
return ""
}
- set prelink_args "--dynamic-linker=$interp --ld-library-path=$dir $binfile $interp [concat $dests]"
+ set prelink_args "--ld-library-path=$dir $binfile [concat $dests]"
+ if {$interp != ""} {
+ set prelink_args "--dynamic-linker=$interp $prelink_args $interp"
+ }
return $prelink_args
}
Index: gdb/testsuite/gdb.base/break-interp.exp
===================================================================
RCS file: /cvs/src/src/gdb/testsuite/gdb.base/break-interp.exp,v
retrieving revision 1.40
diff -u -r1.40 break-interp.exp
--- gdb/testsuite/gdb.base/break-interp.exp 15 Mar 2013 01:41:28 -0000 1.40
+++ gdb/testsuite/gdb.base/break-interp.exp 4 Jun 2013 13:20:03 -0000
@@ -109,12 +109,19 @@
}
}
+# The marker function for the standard runtime linker interface is
+# _dl_debug_state. The probes-based interface has no specific marker
+# function; the probe we will stop on (init_start) is in dl_main so we
+# check for that.
+
+set solib_bp {(_dl_debug_state|dl_main)}
+
# Implementation of reach.
proc reach_1 {func command displacement} {
- global gdb_prompt expect_out
+ global gdb_prompt expect_out solib_bp
- if {$func == "_dl_debug_state"} {
+ if {$func == $solib_bp} {
# Breakpoint on _dl_debug_state can have problems due to its overlap
# with the existing internal breakpoint from GDB.
gdb_test_no_output "set stop-on-solib-events 1"
@@ -142,21 +149,21 @@
exp_continue
}
-re "Breakpoint \[0-9\]+, \\.?(__GI_)?$func \\(.*\\) at .*:\[0-9\]+\r\n.*$gdb_prompt $" {
- if {$func == "_dl_debug_state"} {
+ if {$func == $solib_bp} {
fail $test
} else {
pass $test
}
}
-re "Breakpoint \[0-9\]+, \[0-9xa-f\]+ in \\.?(__GI_)?$func \\(\\).*\r\n$gdb_prompt $" {
- if {$func == "_dl_debug_state"} {
+ if {$func == $solib_bp} {
fail $test
} else {
pass $test
}
}
-re "Stopped due to (spurious )?shared library event.*\r\n$gdb_prompt $" {
- if {$func == "_dl_debug_state"} {
+ if {$func == $solib_bp} {
if {$debug_state_count == 0} {
# First stop does not yet relocate the _start function
# descriptor on ppc64.
@@ -175,7 +182,7 @@
fail $test_displacement
}
- if {$func == "_dl_debug_state"} {
+ if {$func == $solib_bp} {
gdb_test_no_output "set stop-on-solib-events 0"
}
}
@@ -361,7 +368,7 @@
}
proc test_ld {file ifmain trynosym displacement} {
- global srcdir subdir gdb_prompt expect_out inferior_exited_re
+ global srcdir subdir gdb_prompt expect_out inferior_exited_re solib_bp
# First test normal `file'-command loaded $FILE with symbols.
@@ -389,9 +396,9 @@
gdb_test_no_output "set args ${objdir}/${subdir}/$binfile_test" "set args OBJDIR/${subdir}/$binfile_test"
}
- reach "_dl_debug_state" "run" $displacement
+ reach $solib_bp "run" $displacement
- gdb_test "bt" "#0 +\[^\r\n\]*\\m(__GI_)?_dl_debug_state\\M.*" "dl bt"
+ gdb_test "bt" "#0 +\[^\r\n\]*\\m(__GI_)?$solib_bp\\M.*" "dl bt"
if $ifmain {
reach "main" continue "NONE"
@@ -403,7 +410,7 @@
# Try re-run if the new PIE displacement takes effect.
gdb_test "kill" "" "kill" {Kill the program being debugged\? \(y or n\) } "y"
- reach "_dl_debug_state" "run" $displacement
+ reach $solib_bp "run" $displacement
if $ifmain {
test_core $file $displacement
@@ -435,7 +442,7 @@
gdb_test "exec-file $file" "exec-file $escapedfile" "load"
if $ifmain {
- reach "_dl_debug_state" run $displacement
+ reach $solib_bp run $displacement
# Use two separate gdb_test_multiple statements to avoid timeouts due
# to slow processing of wildcard capturing long output
Index: gdb/testsuite/gdb.threads/dlopen-libpthread.exp
===================================================================
RCS file: gdb/testsuite/gdb.threads/dlopen-libpthread.exp
diff -N gdb/testsuite/gdb.threads/dlopen-libpthread.exp
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gdb/testsuite/gdb.threads/dlopen-libpthread.exp 4 Jun 2013 13:20:05 -0000
@@ -0,0 +1,74 @@
+# Copyright 2011-2013 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/>.
+
+if {![istarget *-linux*] || [skip_shlib_tests]} {
+ return 0
+}
+
+load_lib prelink-support.exp
+
+set testfile "dlopen-libpthread"
+set srcmainfile ${testfile}.c
+set srclibfile ${testfile}-lib.c
+set executable ${testfile}
+set binfile_lib ${objdir}/${subdir}/${executable}.so
+set binfile ${objdir}/${subdir}/${executable}
+set lib_dlopen [shlib_target_file ${executable}.so]
+
+# Use build_executable_own_libs as prelinked libpthread.so can produce false
+# PASS - it is OK if GDB processes it still before relocation.
+
+set relink_args [build_executable_own_libs ${testfile}.exp ${executable}.so $srclibfile {debug shlib_pthreads} no]
+if {$relink_args == "" || ![prelink_no $relink_args]
+ || [prepare_for_testing ${testfile}.exp ${executable} ${srcmainfile} {debug shlib_load}] } {
+ return -1
+}
+gdb_load_shlibs $binfile_lib
+
+if { ![runto_main] } {
+ return -1
+}
+
+set test "info probes all rtld rtld_map_complete"
+gdb_test_multiple $test $test {
+ -re "\[ \t\]rtld_map_complete\[ \t\]+0x\[0-9a-f\]+.*\r\n$gdb_prompt $" {
+ pass $test
+ }
+ -re "No probes matched\\.\r\n$gdb_prompt $" {
+ xfail $test
+ untested ${testfile}.exp
+ return
+ }
+}
+
+set test "libpthread.so not found"
+gdb_test_multiple "info sharedlibrary" $test {
+ -re "/libpthread\\.so.*\r\n$gdb_prompt $" {
+ fail $test
+ }
+ -re "/libc\\.so.*\r\n$gdb_prompt $" {
+ pass $test
+ }
+}
+
+gdb_test "set variable filename=\"$lib_dlopen\""
+
+gdb_breakpoint "notify"
+
+# The error was:
+# Cannot find new threads: generic error
+gdb_continue_to_breakpoint "notify" ".* notify-here .*"
+
+gdb_test "info sharedlibrary" {/libpthread\.so.*} "libpthread.so found"
Index: gdb/testsuite/gdb.threads/dlopen-libpthread.c
===================================================================
RCS file: gdb/testsuite/gdb.threads/dlopen-libpthread.c
diff -N gdb/testsuite/gdb.threads/dlopen-libpthread.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gdb/testsuite/gdb.threads/dlopen-libpthread.c 4 Jun 2013 13:20:05 -0000
@@ -0,0 +1,46 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2011-2013 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/>. */
+
+#include <dlfcn.h>
+#include <stddef.h>
+#include <assert.h>
+
+static const char *volatile filename;
+
+static void
+notify (void)
+{
+ filename = NULL; /* notify-here */
+}
+
+int
+main (void)
+{
+ void *h;
+ void (*fp) (void (*) (void));
+
+ assert (filename != NULL);
+ h = dlopen (filename, RTLD_LAZY);
+ assert (h != NULL);
+
+ fp = dlsym (h, "f");
+ assert (fp != NULL);
+
+ fp (notify);
+
+ return 0;
+}
Index: gdb/testsuite/gdb.threads/dlopen-libpthread-lib.c
===================================================================
RCS file: gdb/testsuite/gdb.threads/dlopen-libpthread-lib.c
diff -N gdb/testsuite/gdb.threads/dlopen-libpthread-lib.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gdb/testsuite/gdb.threads/dlopen-libpthread-lib.c 4 Jun 2013 13:20:05 -0000
@@ -0,0 +1,40 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2011-2013 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/>. */
+
+#include <pthread.h>
+#include <assert.h>
+
+static void *
+tfunc (void *arg)
+{
+ void (*notifyp) (void) = arg;
+
+ notifyp ();
+}
+
+void
+f (void (*notifyp) (void))
+{
+ pthread_t t;
+ int i;
+
+ i = pthread_create (&t, NULL, tfunc, notifyp);
+ assert (i == 0);
+
+ i = pthread_join (t, NULL);
+ assert (i == 0);
+}
Index: gdb/testsuite/gdb.base/solib-corrupted.exp
===================================================================
RCS file: /cvs/src/src/gdb/testsuite/gdb.base/solib-corrupted.exp,v
retrieving revision 1.8
diff -u -r1.8 solib-corrupted.exp
--- gdb/testsuite/gdb.base/solib-corrupted.exp 1 Jan 2013 06:33:26 -0000 1.8
+++ gdb/testsuite/gdb.base/solib-corrupted.exp 4 Jun 2013 13:20:04 -0000
@@ -36,6 +36,33 @@
return
}
+# With probes interface GDB no longer scans the inferior library list so its
+# corruption cannot be tested. There is no way to disable the probes
+# interface.
+
+set probes { init_start init_complete map_start reloc_complete unmap_start
+ unmap_complete }
+set test "info probes"
+gdb_test_multiple $test $test {
+ -re "^rtld\[ \t\]+(?:rtld_)?(\[a-z_\]+)\[ \t\]" {
+ set idx [lsearch -exact $probes $expect_out(1,string)]
+ if { $idx >= 0 } {
+ set probes [lreplace $probes $idx $idx]
+ }
+ exp_continue
+ }
+ -re "^\[^\r\n\]*\r\n" {
+ exp_continue
+ }
+ -re "^$gdb_prompt $" {
+ }
+}
+if { [llength $probes] == 0 } {
+ xfail $test
+ untested "GDB is using probes"
+ return
+}
+
gdb_test "info sharedlibrary" "From * To .*" "normal list"
# GDB checks there for matching L_PREV.
[-- Attachment #10: rtld-probes-7-tests-gb.patch --]
[-- Type: text/plain, Size: 14659 bytes --]
Index: gdb/testsuite/ChangeLog
===================================================================
RCS file: /cvs/src/src/gdb/testsuite/ChangeLog,v
retrieving revision 1.3683
diff -u -r1.3683 ChangeLog
--- gdb/testsuite/ChangeLog 4 Jun 2013 13:23:31 -0000 1.3683
+++ gdb/testsuite/ChangeLog 4 Jun 2013 13:28:03 -0000
@@ -1,3 +1,13 @@
+2013-06-04 Gary Benson <gbenson@redhat.com>
+
+ * gdb.base/break-probes.exp: New file.
+ * gdb.base/break-probes.c: Likewise.
+ * gdb.base/break-probes-solib.c: Likewise.
+ * gdb.base/info-shared.exp: New file.
+ * gdb.base/info-shared.c: Likewise.
+ * gdb.base/info-shared-solib1.c: Likewise.
+ * gdb.base/info-shared-solib2.c: Likewise.
+
2013-06-04 Jan Kratochvil <jan.kratochvil@redhat.com>
Gary Benson <gbenson@redhat.com>
Index: gdb/testsuite/gdb.base/break-probes.exp
===================================================================
RCS file: gdb/testsuite/gdb.base/break-probes.exp
diff -N gdb/testsuite/gdb.base/break-probes.exp
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gdb/testsuite/gdb.base/break-probes.exp 4 Jun 2013 13:28:04 -0000
@@ -0,0 +1,78 @@
+# Copyright 2012-2013 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/>.
+
+if { [skip_shlib_tests] } {
+ return 0
+}
+
+standard_testfile
+
+set libname $testfile-solib
+set srcfile_lib $srcdir/$subdir/$libname.c
+set binfile_lib [standard_output_file $libname.so]
+
+set normal_bp "_dl_debug_state"
+set probes_bp "dl_main"
+
+if { [gdb_compile_shlib $srcfile_lib $binfile_lib \
+ [list additional_flags=-fPIC]] != "" } {
+ untested "Could not compile $binfile_lib."
+ return -1
+}
+
+if { [prepare_for_testing $testfile.exp $testfile $srcfile \
+ [list additional_flags=-DSHLIB_NAME=\"$binfile_lib\" libs=-ldl]] } {
+ return -1
+}
+
+# Enable stop-on-solib-events
+gdb_test_no_output "set stop-on-solib-events 1"
+
+# Start the inferior and run to the first stop
+gdb_run_cmd
+gdb_test "" ".*Stopped due to shared library event.*"
+
+# XFAIL if we are not using probes
+set test "ensure using probes"
+set using_probes 0
+gdb_test_multiple "bt" $test {
+ -re "#0 +\[^\r\n\]*\\m(__GI_)?$normal_bp\\M.*$gdb_prompt $" {
+ untested "probes not present on this system"
+ }
+ -re "#0 +\[^\r\n\]*\\m(__GI_)?$probes_bp\\M.*$gdb_prompt $" {
+ pass $test
+ set using_probes 1
+ }
+}
+
+if { $using_probes } {
+ # Run til it loads our library
+ set test "run til our library loads"
+ set not_loaded_library 1
+ while { $not_loaded_library } {
+ set not_loaded_library 0
+ gdb_test_multiple "c" $test {
+ -re "Inferior loaded $binfile_lib\\M.*$gdb_prompt $" {
+ pass $test
+ }
+ -re "Stopped due to shared library event\\M.*$gdb_prompt $" {
+ set not_loaded_library 1
+ }
+ }
+ }
+
+ # Call something to ensure that relocation occurred
+ gdb_test "call foo(23)" "\\\$.* = 31.*\\\M.*"
+}
Index: gdb/testsuite/gdb.base/break-probes.c
===================================================================
RCS file: gdb/testsuite/gdb.base/break-probes.c
diff -N gdb/testsuite/gdb.base/break-probes.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gdb/testsuite/gdb.base/break-probes.c 4 Jun 2013 13:28:04 -0000
@@ -0,0 +1,30 @@
+/* Copyright 2012-2013 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/>. */
+
+#include <dlfcn.h>
+#include <assert.h>
+#include <stddef.h>
+
+int
+main (void)
+{
+ void *handle = dlopen (SHLIB_NAME, RTLD_LAZY);
+
+ assert (handle != NULL);
+
+ dlclose (handle);
+
+ return 0;
+}
Index: gdb/testsuite/gdb.base/break-probes-solib.c
===================================================================
RCS file: gdb/testsuite/gdb.base/break-probes-solib.c
diff -N gdb/testsuite/gdb.base/break-probes-solib.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gdb/testsuite/gdb.base/break-probes-solib.c 4 Jun 2013 13:28:04 -0000
@@ -0,0 +1,22 @@
+/* Copyright 2012-2013 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/>. */
+
+#include <stdio.h>
+
+int
+foo (int n)
+{
+ return n * n / 17;
+}
Index: gdb/testsuite/gdb.base/info-shared.exp
===================================================================
RCS file: gdb/testsuite/gdb.base/info-shared.exp
diff -N gdb/testsuite/gdb.base/info-shared.exp
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gdb/testsuite/gdb.base/info-shared.exp 4 Jun 2013 13:28:05 -0000
@@ -0,0 +1,146 @@
+# Copyright 2012-2013 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/>.
+
+if { [skip_shlib_tests] } {
+ return 0
+}
+
+standard_testfile
+
+set lib1name $testfile-solib1
+set srcfile_lib1 $srcdir/$subdir/$lib1name.c
+set binfile_lib1 [standard_output_file $lib1name.so]
+set define1 -DSHLIB1_NAME=\"$binfile_lib1\"
+
+set lib2name $testfile-solib2
+set srcfile_lib2 $srcdir/$subdir/$lib2name.c
+set binfile_lib2 [standard_output_file $lib2name.so]
+set define2 -DSHLIB2_NAME=\"$binfile_lib2\"
+
+if { [gdb_compile_shlib $srcfile_lib1 $binfile_lib1 \
+ [list additional_flags=-fPIC]] != "" } {
+ untested "Could not compile $binfile_lib1."
+ return -1
+}
+
+if { [gdb_compile_shlib $srcfile_lib2 $binfile_lib2 \
+ [list additional_flags=-fPIC]] != "" } {
+ untested "Could not compile $binfile_lib2."
+ return -1
+}
+
+set cflags "$define1 $define2"
+if { [prepare_for_testing $testfile.exp $testfile $srcfile \
+ [list additional_flags=$cflags libs=-ldl]] } {
+ return -1
+}
+
+# Run "info sharedlibrary" and check for the presence or absence of
+# our libraries.
+proc check_info_shared { test expect1 expect2 } {
+ global lib1name
+ global lib2name
+ global gdb_prompt
+
+ set actual1 0
+ set actual2 0
+
+ gdb_test_multiple "info sharedlibrary" $test {
+ -re $lib1name {
+ set actual1 1
+ exp_continue
+ }
+ -re $lib2name {
+ set actual2 1
+ exp_continue
+ }
+ -re "\r\n$gdb_prompt $" {
+ if { $actual1 == $expect1 && $actual2 == $expect2 } {
+ pass $test
+ } else {
+ fail $test
+ }
+ }
+ }
+}
+
+# Start the inferior, and check neither of the libraries are loaded at
+# the start.
+if ![runto_main] {
+ return 0
+}
+check_info_shared "info sharedlibrary #1" 0 0
+
+# Set up breakpoints.
+gdb_breakpoint "stop"
+gdb_breakpoint "foo" allow-pending
+gdb_breakpoint "bar" allow-pending
+
+# Run to the first stop and check that only the first library is loaded.
+gdb_continue_to_breakpoint "library load #1" "stop .*"
+check_info_shared "info sharedlibrary #2" 1 0
+
+# Run to the second stop and check that both libraries are loaded.
+gdb_continue_to_breakpoint "library load #2" "stop .*"
+check_info_shared "info sharedlibrary #3" 1 1
+
+# Check that the next stop is in foo.
+gdb_continue_to_breakpoint "library function #1" "foo .*"
+
+# Check that the next stop is in bar.
+gdb_continue_to_breakpoint "library function #2" "bar .*"
+
+# Restart the inferior and make sure there are no breakpoint reset
+# errors. These can happen with the probes-based runtime linker
+# interface if the cache is not cleared correctly.
+set test "restart"
+gdb_run_cmd
+gdb_test_multiple "" $test {
+ -re {Start it from the beginning\? \(y or n\) $} {
+ send_gdb "y\n"
+ exp_continue
+ }
+ -re {Error in re-setting breakpoint} {
+ fail $test
+ }
+ -re "\r\n$gdb_prompt $" {
+ pass $test
+ }
+}
+
+# Check that neither library is loaded.
+check_info_shared "info sharedlibrary #4" 0 0
+
+# Run to the first stop and check that only the first library is loaded.
+gdb_continue_to_breakpoint "library load #3" "stop .*"
+check_info_shared "info sharedlibrary #5" 1 0
+
+# Run to the second stop and check that both libraries are loaded.
+gdb_continue_to_breakpoint "library load #4" "stop .*"
+check_info_shared "info sharedlibrary #6" 1 1
+
+# Check that the next stop is in foo.
+gdb_continue_to_breakpoint "library function #3" "foo .*"
+
+# Check that the next stop is in bar.
+gdb_continue_to_breakpoint "library function #4" "bar .*"
+
+# Run to the next stop and check that the first library has been unloaded.
+gdb_continue_to_breakpoint "library unload #1" "stop .*"
+check_info_shared "info sharedlibrary #7" 0 1
+
+# Run to the last stop and check that both libraries are gone.
+gdb_continue_to_breakpoint "library unload #2" "stop .*"
+check_info_shared "info sharedlibrary #8" 0 0
Index: gdb/testsuite/gdb.base/info-shared.c
===================================================================
RCS file: gdb/testsuite/gdb.base/info-shared.c
diff -N gdb/testsuite/gdb.base/info-shared.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gdb/testsuite/gdb.base/info-shared.c 4 Jun 2013 13:28:05 -0000
@@ -0,0 +1,52 @@
+/* Copyright 2012-2013 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/>. */
+
+#include <dlfcn.h>
+#include <assert.h>
+#include <stddef.h>
+
+void
+stop (void)
+{
+}
+
+int
+main (void)
+{
+ void *handle1, *handle2;
+ void (*func)(int);
+
+ handle1 = dlopen (SHLIB1_NAME, RTLD_LAZY);
+ assert (handle1 != NULL);
+ stop ();
+
+ handle2 = dlopen (SHLIB2_NAME, RTLD_LAZY);
+ assert (handle2 != NULL);
+ stop ();
+
+ func = (void (*)(int)) dlsym (handle1, "foo");
+ func (1);
+
+ func = (void (*)(int)) dlsym (handle2, "bar");
+ func (2);
+
+ dlclose (handle1);
+ stop ();
+
+ dlclose (handle2);
+ stop ();
+
+ return 0;
+}
Index: gdb/testsuite/gdb.base/info-shared-solib1.c
===================================================================
RCS file: gdb/testsuite/gdb.base/info-shared-solib1.c
diff -N gdb/testsuite/gdb.base/info-shared-solib1.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gdb/testsuite/gdb.base/info-shared-solib1.c 4 Jun 2013 13:28:05 -0000
@@ -0,0 +1,24 @@
+/* Copyright 2012-2013 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/>. */
+
+#include <stdio.h>
+
+int
+foo (int n)
+{
+ printf ("foo %d\n", n);
+
+ return 0;
+}
Index: gdb/testsuite/gdb.base/info-shared-solib2.c
===================================================================
RCS file: gdb/testsuite/gdb.base/info-shared-solib2.c
diff -N gdb/testsuite/gdb.base/info-shared-solib2.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gdb/testsuite/gdb.base/info-shared-solib2.c 4 Jun 2013 13:28:05 -0000
@@ -0,0 +1,24 @@
+/* Copyright 2012-2013 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/>. */
+
+#include <stdio.h>
+
+int
+bar (int n)
+{
+ printf ("bar %d\n", n);
+
+ return 0;
+}
^ permalink raw reply [flat|nested] 59+ messages in thread* Re: [commit] Improved linker-debugger interface
2013-06-04 13:38 ` [commit] " Gary Benson
@ 2013-06-25 21:04 ` Joel Brobecker
2013-06-25 22:03 ` Sergio Durigan Junior
0 siblings, 1 reply; 59+ messages in thread
From: Joel Brobecker @ 2013-06-25 21:04 UTC (permalink / raw)
To: gdb-patches, Tom Tromey, Jan Kratochvil, Pedro Alves
Hi Gary,
> I just committed the improved linker-debugger interface patch series
> as attached. For those of you using the patches in distributions,
> some of the attached files have different filenames than previously
> posted:
I am seeing some issues on ia64-linux (rhES5):
| (gdb) start
| Temporary breakpoint 1 at 0x40000000000005a1: file bar.c, line 4.
| Starting program: /saco.a/users/brobecke/ex/simple/bar
| warning: Probes-based dynamic linker interface failed.
| Reverting to original interface.
|
| Unknown numeric token on expression `0 8@r35'.
I will investigate the problem with the unknown numeric token, but
any recommendation before I start?
Also, I am wondering we really want a warning in this case -
I think this is going to make the average user think that there
is something wrong and therefore that needs to be fixed. What
do people think?
--
Joel
^ permalink raw reply [flat|nested] 59+ messages in thread
* Re: [commit] Improved linker-debugger interface
2013-06-25 21:04 ` Joel Brobecker
@ 2013-06-25 22:03 ` Sergio Durigan Junior
2013-06-26 0:49 ` Joel Brobecker
2013-06-26 15:38 ` Tom Tromey
0 siblings, 2 replies; 59+ messages in thread
From: Sergio Durigan Junior @ 2013-06-25 22:03 UTC (permalink / raw)
To: Joel Brobecker; +Cc: gdb-patches, Tom Tromey, Jan Kratochvil, Pedro Alves
On Tuesday, June 25 2013, Joel Brobecker wrote:
>> I just committed the improved linker-debugger interface patch series
>> as attached. For those of you using the patches in distributions,
>> some of the attached files have different filenames than previously
>> posted:
>
> I am seeing some issues on ia64-linux (rhES5):
>
> | (gdb) start
> | Temporary breakpoint 1 at 0x40000000000005a1: file bar.c, line 4.
> | Starting program: /saco.a/users/brobecke/ex/simple/bar
> | warning: Probes-based dynamic linker interface failed.
> | Reverting to original interface.
> |
> | Unknown numeric token on expression `0 8@r35'.
>
> I will investigate the problem with the unknown numeric token, but
> any recommendation before I start?
Hi Joel,
Thanks for the report. There are two kinds of things happening here.
First, the current SDT parser (implemented on stap-probe.c) is not
recognizing one of the probe's arguments. This is where the "Unknown
numeric token" comes from. The initial "0" is making the parser
confused, and to be honest it is also making me confused :-). I did not
implement the support for IA-64, FWIW.
I am looking into this issue right away.
> Also, I am wondering we really want a warning in this case -
> I think this is going to make the average user think that there
> is something wrong and therefore that needs to be fixed. What
> do people think?
The second thing is the warning. It is issues by Gary's patch, and I
agree that it could confuse users. However, I think it is still a good
thing to have. Maybe one could create a debug flag that would enable
printing such warnings? Just an idea.
I will get back to you when I have more news about what's going on with
the SDT parser.
Thanks,
--
Sergio
^ permalink raw reply [flat|nested] 59+ messages in thread
* Re: [commit] Improved linker-debugger interface
2013-06-25 22:03 ` Sergio Durigan Junior
@ 2013-06-26 0:49 ` Joel Brobecker
2013-07-09 8:41 ` Gary Benson
[not found] ` <20130708104719.GA11176@blade.nx>
2013-06-26 15:38 ` Tom Tromey
1 sibling, 2 replies; 59+ messages in thread
From: Joel Brobecker @ 2013-06-26 0:49 UTC (permalink / raw)
To: Sergio Durigan Junior
Cc: gdb-patches, Tom Tromey, Jan Kratochvil, Pedro Alves
Hi Sergio,
> I am looking into this issue right away.
Wow, thanks! Don't feel compeled to look at it. It would take me more
time to investigate as I'm not familiar with this area, but I'm still
happy to do it.
> The second thing is the warning. It is issues by Gary's patch, and I
> agree that it could confuse users. However, I think it is still a good
> thing to have. Maybe one could create a debug flag that would enable
> printing such warnings? Just an idea.
I agree that an informative message on the command line would be useful,
and the first thing that came to my mind when I saw the warning is that
we should be mimicking what we're doing for libthread_db.
But also, I think what we will be doing will also depend on how we see
the future. I get the impression with this warning that we eventually
expect all GNU/Linux systems to all provide whatever feature is needed
for the improved method to work. But solib-svr4 is used on other
platforms too - do we expect it to be the default on those as well?
> I will get back to you when I have more news about what's going on with
> the SDT parser.
Thanks again, I really appreciate that!
--
Joel
^ permalink raw reply [flat|nested] 59+ messages in thread* Re: [commit] Improved linker-debugger interface
2013-06-26 0:49 ` Joel Brobecker
@ 2013-07-09 8:41 ` Gary Benson
[not found] ` <20130708104719.GA11176@blade.nx>
1 sibling, 0 replies; 59+ messages in thread
From: Gary Benson @ 2013-07-09 8:41 UTC (permalink / raw)
To: Joel Brobecker
Cc: Sergio Durigan Junior, gdb-patches, Tom Tromey, Jan Kratochvil,
Pedro Alves
Joel Brobecker wrote:
> Also, I am wondering we really want a warning in this case - I think
> this is going to make the average user think that there is something
> wrong and therefore that needs to be fixed. What do people think?
I think this may have been resolved by other messages in this thread,
but for the avoidance of doubt the warning does mean that something is
wrong and needs to be fixed. If solib-svr4 finds the probes it needs
in the runtime linker it uses them. If it doesn't find the probes--
either because they aren't there, or because GDB has no probes
support--then solib-svr4 will silently fall back to the original
(non-probes) interface. The warning is only displayed if solib-svr4
started out using the probes and something unexpected happened, so if
you see the warning it means either the linker or GDB has a bug.
> But also, I think what we will be doing will also depend on how we
> see the future. I get the impression with this warning that we
> eventually expect all GNU/Linux systems to all provide whatever
> feature is needed for the improved method to work. But solib-svr4 is
> used on other platforms too - do we expect it to be the default on
> those as well?
The original (non-probes) interface is still there, and if solib-svr4
can't use the probes interface for whatever reason the original
interface will be used as before. I don't see this changing any time
soon. Having said that, nothing in the probes-based linker interface
is SystemTap-specific so it should be possible to implement the
interface on other platforms without touching solib-svr4.c.
Thanks,
Gary
^ permalink raw reply [flat|nested] 59+ messages in thread[parent not found: <20130708104719.GA11176@blade.nx>]
* Re: [commit] Improved linker-debugger interface
[not found] ` <20130708104719.GA11176@blade.nx>
@ 2013-07-09 14:45 ` Joel Brobecker
0 siblings, 0 replies; 59+ messages in thread
From: Joel Brobecker @ 2013-07-09 14:45 UTC (permalink / raw)
To: Sergio Durigan Junior, gdb-patches, Tom Tromey, Jan Kratochvil,
Pedro Alves
> I think this may have been resolved by other messages in this thread,
> but for the avoidance of doubt the warning does mean that something is
> wrong and needs to be fixed. If solib-svr4 finds the probes it needs
> in the runtime linker it uses them. If it doesn't find the probes--
> either because they aren't there, or because GDB has no probes
> support--then solib-svr4 will silently fall back to the original
> (non-probes) interface. The warning is only displayed if solib-svr4
> started out using the probes and something unexpected happened, so if
> you see the warning it means either the linker or GDB has a bug.
OK, thanks for clarifying. I agree with the warning, now.
--
Joel
^ permalink raw reply [flat|nested] 59+ messages in thread
* Re: [commit] Improved linker-debugger interface
2013-06-25 22:03 ` Sergio Durigan Junior
2013-06-26 0:49 ` Joel Brobecker
@ 2013-06-26 15:38 ` Tom Tromey
2013-06-26 17:23 ` Sergio Durigan Junior
1 sibling, 1 reply; 59+ messages in thread
From: Tom Tromey @ 2013-06-26 15:38 UTC (permalink / raw)
To: Sergio Durigan Junior
Cc: Joel Brobecker, gdb-patches, Jan Kratochvil, Pedro Alves
Joel> Also, I am wondering we really want a warning in this case -
Joel> I think this is going to make the average user think that there
Joel> is something wrong and therefore that needs to be fixed. What
Joel> do people think?
Sergio> The second thing is the warning. It is issues by Gary's patch, and I
Sergio> agree that it could confuse users. However, I think it is still a good
Sergio> thing to have. Maybe one could create a debug flag that would enable
Sergio> printing such warnings? Just an idea.
It seems to me that we could make the warning more verbose and have it
request that users file a bug report; and it could include a little
explanation, plus some text to report. Like:
warning: Probes-based dynamic linker interface failed:
Unknown numeric token ...
This means there is a bug, either in gdb or elsewhere in the
toolchain. Please report it to the gdb bugzilla, along with
this information:
Arch: Whatever
Probe name: ...
Argument number: ...
Argument text: ...
Being extra wordy is a bit of a pain, maybe, since presumably users will
see it often. OTOH, it's a "shouldn't happen" scenario where gdb has
lots of information already...
Also, I wonder why we're trying to use the probes on a platform to which
the gdb side hasn't been ported. Are we just optimistically trying to
parse the assembly operands here?
Tom
^ permalink raw reply [flat|nested] 59+ messages in thread* Re: [commit] Improved linker-debugger interface
2013-06-26 15:38 ` Tom Tromey
@ 2013-06-26 17:23 ` Sergio Durigan Junior
2013-06-26 19:15 ` Joel Brobecker
2013-06-27 23:33 ` Tom Tromey
0 siblings, 2 replies; 59+ messages in thread
From: Sergio Durigan Junior @ 2013-06-26 17:23 UTC (permalink / raw)
To: Tom Tromey; +Cc: Joel Brobecker, gdb-patches, Jan Kratochvil, Pedro Alves
On Wednesday, June 26 2013, Tom Tromey wrote:
> It seems to me that we could make the warning more verbose and have it
> request that users file a bug report; and it could include a little
> explanation, plus some text to report. Like:
>
> warning: Probes-based dynamic linker interface failed:
> Unknown numeric token ...
> This means there is a bug, either in gdb or elsewhere in the
> toolchain. Please report it to the gdb bugzilla, along with
> this information:
> Arch: Whatever
> Probe name: ...
> Argument number: ...
> Argument text: ...
>
> Being extra wordy is a bit of a pain, maybe, since presumably users will
> see it often. OTOH, it's a "shouldn't happen" scenario where gdb has
> lots of information already...
Sounds good to me, but...
> Also, I wonder why we're trying to use the probes on a platform to which
> the gdb side hasn't been ported. Are we just optimistically trying to
> parse the assembly operands here?
That's a relevant question. GDB has a generic asm parser (implemented
in stap-probe.c), which makes use of specific target-dep
functions/variables to correctly handle the idiosyncrasies of each type
of asm.
So far, we have support for x86, x86_64, PPC, PPC64, ARM, and a pending
patch for IA-64. However, there must be more architectures where we
will need to implement it. The pre-requisite I am/was using is: if
systemtap-sdt-devel is installable on the system, then GDB needs to
support SDT probes. Unfortunately I failed to check IA-64, but that is
hopefully fixed now.
OTOH, if the user successfuly installs <sys/sdt.h> on her system, then
GDB should at least be prepared to avoid trying to parse something it
doesn't fully understand.
What could be done is to check gdbarch_stap_is_single_operand_p. This
is a mandatory function that needs to be set by the target. If it
doesn't exist, then we know that the target lacks SDT support.
Before I work on a patch, I'd like to know what you think.
Thanks,
--
Sergio
^ permalink raw reply [flat|nested] 59+ messages in thread
* Re: [commit] Improved linker-debugger interface
2013-06-26 17:23 ` Sergio Durigan Junior
@ 2013-06-26 19:15 ` Joel Brobecker
2013-06-27 23:33 ` Tom Tromey
1 sibling, 0 replies; 59+ messages in thread
From: Joel Brobecker @ 2013-06-26 19:15 UTC (permalink / raw)
To: Sergio Durigan Junior
Cc: Tom Tromey, gdb-patches, Jan Kratochvil, Pedro Alves
> What could be done is to check gdbarch_stap_is_single_operand_p. This
> is a mandatory function that needs to be set by the target. If it
> doesn't exist, then we know that the target lacks SDT support.
>
> Before I work on a patch, I'd like to know what you think.
I agree that it would be friendlier to make sure stap-support is
activated before trying to use it. If the warning is then only
possible when stap support is in, and denotes a bug in either GDB
or the executable, then I'm all for keeping it.
I also like Tom's suggestion of expanding the warning to contain
the pieces of information he suggested. I had a recent experience
where the warning was missing a critical piece of information and
that prevented me from diagnosing the problem remotely.
--
Joel
^ permalink raw reply [flat|nested] 59+ messages in thread
* Re: [commit] Improved linker-debugger interface
2013-06-26 17:23 ` Sergio Durigan Junior
2013-06-26 19:15 ` Joel Brobecker
@ 2013-06-27 23:33 ` Tom Tromey
2013-06-30 3:12 ` Sergio Durigan Junior
1 sibling, 1 reply; 59+ messages in thread
From: Tom Tromey @ 2013-06-27 23:33 UTC (permalink / raw)
To: Sergio Durigan Junior
Cc: Joel Brobecker, gdb-patches, Jan Kratochvil, Pedro Alves
>>>>> "Sergio" == Sergio Durigan Junior <sergiodj@redhat.com> writes:
Sergio> What could be done is to check gdbarch_stap_is_single_operand_p. This
Sergio> is a mandatory function that needs to be set by the target. If it
Sergio> doesn't exist, then we know that the target lacks SDT support.
Sergio> Before I work on a patch, I'd like to know what you think.
I think this would be good. The error could ask the user to report a
different kind of bug -- "please do this port" :)
Tom
^ permalink raw reply [flat|nested] 59+ messages in thread
* Re: [commit] Improved linker-debugger interface
2013-06-27 23:33 ` Tom Tromey
@ 2013-06-30 3:12 ` Sergio Durigan Junior
0 siblings, 0 replies; 59+ messages in thread
From: Sergio Durigan Junior @ 2013-06-30 3:12 UTC (permalink / raw)
To: Tom Tromey; +Cc: Joel Brobecker, gdb-patches, Jan Kratochvil, Pedro Alves
On Thursday, June 27 2013, Tom Tromey wrote:
>>>>>> "Sergio" == Sergio Durigan Junior <sergiodj@redhat.com> writes:
>
> Sergio> What could be done is to check gdbarch_stap_is_single_operand_p. This
> Sergio> is a mandatory function that needs to be set by the target. If it
> Sergio> doesn't exist, then we know that the target lacks SDT support.
>
> Sergio> Before I work on a patch, I'd like to know what you think.
>
> I think this would be good. The error could ask the user to report a
> different kind of bug -- "please do this port" :)
Sounds fine by me :-). I will work on a patch and submit it ASAP.
Thanks,
--
Sergio
^ permalink raw reply [flat|nested] 59+ messages in thread