From: Paul Pluzhnikov <ppluzhnikov@google.com>
To: Jan Kratochvil <jan.kratochvil@redhat.com>
Cc: gdb-patches@sourceware.org
Subject: [patch] Implement qXfer:libraries for Linux/gdbserver [Was: Re: [RFC] Make target_read_string faster over high-latency links.]
Date: Fri, 05 Aug 2011 18:11:00 -0000 [thread overview]
Message-ID: <CALoOobM_nZ+Xkv7tqjq-JLOaPSQabOTKnXx29HADOtfQk_Jgrg@mail.gmail.com> (raw)
[-- Attachment #1: Type: text/plain, Size: 1929 bytes --]
On Tue, Jul 26, 2011 at 1:36 AM, Jan Kratochvil
<jan.kratochvil@redhat.com> wrote:
> On Fri, 15 Jul 2011 20:07:48 +0200, Paul Pluzhnikov wrote:
>> This is GDB walking through the shared library list, and reading shared
>> library names from gdbserver via target_read_string 4 bytes at a time ;-(
>
> Just that you do not mention supporting qXfer:libraries:read also on GNU/Linux
> platforms (currently used only on MS-Windows)
That sounds like an excellent idea: it reduces many many packets with
just one.
> that is to move solib-svr4.c to gdb/common/ etc.
Moving solib-svr4.c to gdb/common doesn't appear necessary: the parts
that I would have used in gdbserver/linux-low.c are quite small, and not
easily re-usable.
Tested on Linux/x86_64 native, and with gdbserver (x86_64) against x86_64
and i686 inferiors. No regressions.
Thanks,
--
Paul Pluzhnikov
2011-08-05 Paul Pluzhnikov <ppluzhnikov@google.com>
* solib-svr4.c (library_list_start_segment): New function.
(library_list_start_library, library_list_end_library): Likewise.
(library_list_start_list): Likewise.
(segment_attributes, library_children): New variables.
(library_attributes, library_list_children): Likewise.
(library_list_attributes, library_list_elements): Likewise.
(svr4_free_so): Moved to here.
(svr4_free_library_list, svr4_parse_libraries): New functions.
(svr4_current_sos_via_xfer_libraries): Likewise.
(svr4_current_sos): Adjust.
gdbserver/ChangeLog:
2011-08-05 Paul Pluzhnikov <ppluzhnikov@google.com>
* linux-low.c (linux_add_process): Adjust.
(get_phdr_phnum_from_proc_auxv, get_dynamic): New functions.
(get_r_debug, read_one_ptr): Likewise.
(struct link_map_offsets): New struct decl.
(linux_qxfer_libraries): New function.
(struct linux_target_ops): Adjust.
* linux-low.h (struct process_info_private): New member.
* server.c (handle_qxfer_libraries): Adjust.
* target.h (struct target_ops): New member.
[-- Attachment #2: gdb-solib-list-20110805-2.txt --]
[-- Type: text/plain, Size: 17973 bytes --]
Index: solib-svr4.c
===================================================================
RCS file: /cvs/src/src/gdb/solib-svr4.c,v
retrieving revision 1.152
diff -u -p -r1.152 solib-svr4.c
--- solib-svr4.c 5 Aug 2011 15:17:23 -0000 1.152
+++ solib-svr4.c 5 Aug 2011 17:56:24 -0000
@@ -106,6 +106,201 @@ static const char * const main_name_lis
NULL
};
+
+#if defined(HAVE_LIBEXPAT)
+
+#include "xml-support.h"
+
+/* Handle the start of a <segment> element. */
+
+static void
+library_list_start_segment (struct gdb_xml_parser *parser,
+ const struct gdb_xml_element *element,
+ void *user_data, VEC(gdb_xml_value_s) *attributes)
+{
+ ULONGEST *address_p = xml_find_attribute (attributes, "address")->value;
+ CORE_ADDR address = (CORE_ADDR) *address_p;
+ struct so_list **so_list = user_data;
+
+ (*so_list)->lm_info->l_addr = address;
+}
+
+/* Handle the start of a <library> element. Note: new elements are added
+ at the head of the list (i.e. the list is built in reverse order). */
+
+static void
+library_list_start_library (struct gdb_xml_parser *parser,
+ const struct gdb_xml_element *element,
+ void *user_data, VEC(gdb_xml_value_s) *attributes)
+{
+ const char *name = xml_find_attribute (attributes, "name")->value;
+ struct so_list *new_elem, **so_list = user_data;
+
+ new_elem = XZALLOC (struct so_list);
+ new_elem->next = *so_list;
+ new_elem->lm_info = XZALLOC (struct lm_info);
+ strcpy (new_elem->so_original_name, name);
+ strcpy (new_elem->so_name, name);
+
+ *so_list = new_elem;
+}
+
+static void
+library_list_end_library (struct gdb_xml_parser *parser,
+ const struct gdb_xml_element *element,
+ void *user_data, const char *body_text)
+{
+ struct so_list **so_list = user_data;
+
+ if ((*so_list)->lm_info->l_addr == 0)
+ gdb_xml_error (parser, _("No segment defined for %s"),
+ (*so_list)->so_name);
+}
+
+
+/* Handle the start of a <library-list> element. */
+
+static void
+library_list_start_list (struct gdb_xml_parser *parser,
+ const struct gdb_xml_element *element,
+ void *user_data, VEC(gdb_xml_value_s) *attributes)
+{
+ char *version = xml_find_attribute (attributes, "version")->value;
+
+ if (strcmp (version, "1.0") != 0)
+ gdb_xml_error (parser,
+ _("Library list has unsupported version \"%s\""),
+ version);
+}
+
+
+/* The allowed elements and attributes for an XML library list.
+ The root element is a <library-list>. */
+
+static const struct gdb_xml_attribute segment_attributes[] = {
+ { "address", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
+ { NULL, GDB_XML_AF_NONE, NULL, NULL }
+};
+
+static const struct gdb_xml_element library_children[] = {
+ { "segment", segment_attributes, NULL,
+ GDB_XML_EF_NONE, library_list_start_segment, NULL },
+ { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
+};
+
+static const struct gdb_xml_attribute library_attributes[] = {
+ { "name", GDB_XML_AF_NONE, NULL, NULL },
+ { NULL, GDB_XML_AF_NONE, NULL, NULL }
+};
+
+static const struct gdb_xml_element library_list_children[] = {
+ { "library", library_attributes, library_children,
+ GDB_XML_EF_REPEATABLE | GDB_XML_EF_OPTIONAL,
+ library_list_start_library, library_list_end_library },
+ { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
+};
+
+static const struct gdb_xml_attribute library_list_attributes[] = {
+ { "version", GDB_XML_AF_NONE, NULL, NULL },
+ { NULL, GDB_XML_AF_NONE, NULL, NULL }
+};
+
+static const struct gdb_xml_element library_list_elements[] = {
+ { "library-list", library_list_attributes, library_list_children,
+ GDB_XML_EF_NONE, library_list_start_list, NULL },
+ { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
+};
+
+static void
+svr4_free_so (struct so_list *so)
+{
+ xfree (so->lm_info->lm);
+ xfree (so->lm_info);
+}
+
+/* Free so_list built so far (called via cleanup). */
+
+static void
+svr4_free_library_list (void *p_list)
+{
+ struct so_list *list = *(struct so_list **) p_list;
+ while (list != NULL)
+ {
+ struct so_list *next = list->next;
+
+ svr4_free_so (list);
+ list = next;
+ }
+}
+
+/* Parse qXfer:libraries:read packet into so_list. */
+
+static struct so_list *
+svr4_parse_libraries (const char *document)
+{
+ struct so_list *result = NULL;
+ struct cleanup *back_to = make_cleanup (svr4_free_library_list,
+ &result);
+
+ if (gdb_xml_parse_quick (_("target library list"), "library-list.dtd",
+ library_list_elements, document, &result) == 0)
+ {
+ struct so_list *prev;
+
+ /* Parsed successfully, keep the result. */
+ discard_cleanups (back_to);
+
+ /* Reverse the list -- it was built in reverse order. */
+ prev = NULL;
+ while (result)
+ {
+ struct so_list *next = result->next;
+
+ result->next = prev;
+ prev = result;
+ result = next;
+ }
+ return prev;
+ }
+
+ do_cleanups (back_to);
+ return NULL;
+}
+
+/* Attempt to get so_list from target via qXfer:libraries:read packet.
+ Return NULL if packet not supported, or contains no libraries. */
+
+static struct so_list *
+svr4_current_sos_via_xfer_libraries ()
+{
+ char *library_document;
+ struct so_list *result;
+ struct cleanup *back_to;
+
+ /* Fetch the list of shared libraries. */
+ library_document = target_read_stralloc (¤t_target,
+ TARGET_OBJECT_LIBRARIES,
+ NULL);
+ if (library_document == NULL)
+ return NULL;
+
+ back_to = make_cleanup (xfree, library_document);
+ result = svr4_parse_libraries (library_document);
+ do_cleanups (back_to);
+
+ return result;
+}
+
+#else
+
+static struct so_list *
+svr4_current_sos_via_xfer_libraries ()
+{
+ return NULL;
+}
+
+#endif
+
/* Return non-zero if GDB_SO_NAME and INFERIOR_SO_NAME represent
the same shared library. */
@@ -1136,6 +1331,10 @@ svr4_current_sos (void)
CORE_ADDR ldsomap = 0;
struct svr4_info *info;
+ head = svr4_current_sos_via_xfer_libraries ();
+ if (head != NULL)
+ return head;
+
info = get_svr4_info ();
/* Always locate the debug struct, in case it has moved. */
@@ -2249,13 +2448,6 @@ svr4_clear_solib (void)
info->debug_loader_name = NULL;
}
-static void
-svr4_free_so (struct so_list *so)
-{
- xfree (so->lm_info->lm);
- xfree (so->lm_info);
-}
-
/* Clear any bits of ADDR that wouldn't fit in a target-format
data pointer. "Data pointer" here refers to whatever sort of
Index: gdbserver/linux-low.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/linux-low.c,v
retrieving revision 1.173
diff -u -p -r1.173 linux-low.c
--- gdbserver/linux-low.c 21 Jul 2011 23:46:12 -0000 1.173
+++ gdbserver/linux-low.c 5 Aug 2011 17:56:24 -0000
@@ -264,6 +264,7 @@ linux_add_process (int pid, int attached
proc = add_process (pid, attached);
proc->private = xcalloc (1, sizeof (*proc->private));
+ proc->private->r_debug = (CORE_ADDR) -1;
if (the_low_target.new_process != NULL)
proc->private->arch_private = the_low_target.new_process ();
@@ -4755,6 +4756,343 @@ linux_emit_ops (void)
return NULL;
}
+/* Extract &phdr and num_phdr in the inferior. Return 0 on success. */
+
+static int
+get_phdr_phnum_from_proc_auxv (const int pid, const int is_elf64,
+ CORE_ADDR *phdr_memaddr, int *num_phdr)
+{
+ char filename[PATH_MAX];
+ int fd;
+ const int auxv_size = is_elf64
+ ? sizeof (Elf64_auxv_t) : sizeof (Elf32_auxv_t);
+ char buf[sizeof (Elf64_auxv_t)]; /* The larger of the two. */
+
+ xsnprintf (filename, sizeof filename, "/proc/%d/auxv", pid);
+
+ fd = open (filename, O_RDONLY);
+ if (fd < 0)
+ return 1;
+
+ *phdr_memaddr = 0;
+ *num_phdr = 0;
+ while (read (fd, buf, auxv_size) == auxv_size
+ && (*phdr_memaddr == 0 || *num_phdr == 0))
+ {
+ if (is_elf64)
+ {
+ Elf64_auxv_t *const aux = (Elf64_auxv_t *) buf;
+
+ switch (aux->a_type)
+ {
+ case AT_PHDR:
+ *phdr_memaddr = aux->a_un.a_val;
+ break;
+ case AT_PHNUM:
+ *num_phdr = aux->a_un.a_val;
+ break;
+ }
+ }
+ else
+ {
+ Elf32_auxv_t *const aux = (Elf32_auxv_t *) buf;
+
+ switch (aux->a_type)
+ {
+ case AT_PHDR:
+ *phdr_memaddr = aux->a_un.a_val;
+ break;
+ case AT_PHNUM:
+ *num_phdr = aux->a_un.a_val;
+ break;
+ }
+ }
+ }
+
+ close (fd);
+
+ if (*phdr_memaddr == 0 || *num_phdr == 0)
+ {
+ warning ("Unexpected missing AT_PHDR and/or AT_PHNUM: "
+ "phdr_memaddr = %ld, phdr_num = %d",
+ (long) *phdr_memaddr, *num_phdr);
+ return 2;
+ }
+
+ return 0;
+}
+
+/* Return &_DYNAMIC (via PT_DYNAMIC) in the inferior, or 0 if not present. */
+
+static CORE_ADDR
+get_dynamic (const int pid, const int is_elf64)
+{
+ CORE_ADDR phdr_memaddr;
+ int num_phdr, i;
+ unsigned char *phdr_buf;
+ const int phdr_size = is_elf64 ? sizeof (Elf64_Phdr) : sizeof (Elf32_Phdr);
+
+
+ if (get_phdr_phnum_from_proc_auxv (pid, is_elf64, &phdr_memaddr, &num_phdr))
+ return 0;
+
+ gdb_assert (num_phdr < 100); /* Basic sanity check. */
+ phdr_buf = alloca (num_phdr * phdr_size);
+
+ if (linux_read_memory (phdr_memaddr, phdr_buf, num_phdr * phdr_size))
+ return 0;
+
+ for (i = 0; i < num_phdr; i++)
+ {
+ if (is_elf64)
+ {
+ Elf64_Phdr *const p = (Elf64_Phdr *) (phdr_buf + i * phdr_size);
+
+ if (p->p_type == PT_DYNAMIC)
+ return p->p_vaddr;
+ }
+ else
+ {
+ Elf32_Phdr *const p = (Elf32_Phdr *) (phdr_buf + i * phdr_size);
+
+ if (p->p_type == PT_DYNAMIC)
+ return p->p_vaddr;
+ }
+ }
+
+ return 0;
+}
+
+/* Return &_r_debug in the inferior, or 0 if not present. */
+
+static CORE_ADDR
+get_r_debug (const int pid, const int is_elf64)
+{
+ CORE_ADDR dynamic_memaddr;
+ const int dyn_size = is_elf64 ? sizeof (Elf64_Dyn) : sizeof (Elf32_Dyn);
+ unsigned char buf[sizeof (Elf64_Dyn)]; /* The larger of the two. */
+
+ dynamic_memaddr = get_dynamic (pid, is_elf64);
+ if (dynamic_memaddr == 0)
+ return 0;
+
+ while (linux_read_memory (dynamic_memaddr, buf, dyn_size) == 0)
+ {
+ if (is_elf64)
+ {
+ Elf64_Dyn *const dyn = (Elf64_Dyn *) buf;
+
+ if (dyn->d_tag == DT_DEBUG)
+ return dyn->d_un.d_val;
+
+ if (dyn->d_tag == DT_NULL)
+ break;
+ }
+ else
+ {
+ Elf32_Dyn *const dyn = (Elf32_Dyn *) buf;
+
+ if (dyn->d_tag == DT_DEBUG)
+ return dyn->d_un.d_val;
+
+ if (dyn->d_tag == DT_NULL)
+ break;
+ }
+
+ dynamic_memaddr += dyn_size;
+ }
+
+ return 0;
+}
+
+/* Read one pointer from MEMADDR in the inferior. */
+
+static int
+read_one_ptr (CORE_ADDR memaddr, CORE_ADDR *ptr, int ptr_size)
+{
+ *ptr = 0;
+ return linux_read_memory (memaddr, (unsigned char *) ptr, ptr_size);
+}
+
+
+struct link_map_offsets
+ {
+ /* Offset and size of r_debug.r_version. */
+ int r_version_offset;
+
+ /* Offset and size of r_debug.r_map. */
+ int r_map_offset;
+
+ /* Offset to l_addr field in struct link_map. */
+ int l_addr_offset;
+
+ /* Offset to l_name field in struct link_map. */
+ int l_name_offset;
+
+ /* Offset to l_next field in struct link_map. */
+ int l_next_offset;
+
+ /* Offset to l_prev field in struct link_map. */
+ int l_prev_offset;
+
+ };
+
+/* Construct qXfer:libraries:read reply. */
+
+static int
+linux_qxfer_libraries (const char *annex, unsigned char *readbuf,
+ unsigned const char *writebuf,
+ CORE_ADDR offset, int len)
+{
+ char *document;
+ unsigned document_len;
+ struct process_info_private *const priv = current_process ()->private;
+ char filename[PATH_MAX];
+ int pid, is_elf64;
+
+ static const struct link_map_offsets lmo_32bit_offsets =
+ {
+ 0, /* r_version offset. */
+ 4, /* r_debug.r_map offset. */
+ 0, /* l_addr offset in link_map. */
+ 4, /* l_name offset in link_map. */
+ 12, /* l_next offset in link_map. */
+ 16 /* l_prev offset in link_map. */
+ };
+
+ static const struct link_map_offsets lmo_64bit_offsets =
+ {
+ 0, /* r_version offset. */
+ 8, /* r_debug.r_map offset. */
+ 0, /* l_addr offset in link_map. */
+ 8, /* l_name offset in link_map. */
+ 24, /* l_next offset in link_map. */
+ 32 /* l_prev offset in link_map. */
+ };
+ const struct link_map_offsets *lmo;
+
+ if (writebuf != NULL)
+ return -2;
+ if (readbuf == NULL)
+ return -1;
+
+ pid = lwpid_of (get_thread_lwp (current_inferior));
+ xsnprintf (filename, sizeof filename, "/proc/%d/exe", pid);
+ is_elf64 = elf_64_file_p (filename);
+ lmo = is_elf64 ? &lmo_64bit_offsets : &lmo_32bit_offsets;
+
+ if (priv->r_debug == (CORE_ADDR) -1)
+ priv->r_debug = get_r_debug (pid, is_elf64);
+
+ gdb_assert (priv->r_debug != (CORE_ADDR) -1);
+
+ if (priv->r_debug == 0)
+ {
+ document = xstrdup ("<library-list/>\n");
+ }
+ 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_next, l_prev;
+ int r_version;
+
+ document = xmalloc (allocated);
+ strcpy (document, "<library-list>");
+ 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)
+ {
+ warning ("unexpected r_debug version %d", r_version);
+ goto done;
+ }
+
+ 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);
+ goto done;
+ }
+
+ 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_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 ("corrupt solib chain: 0x%lx != 0x%lx",
+ (long) lm_prev, (long) l_prev);
+ break;
+ }
+
+ /* 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));
+ if (libname[0] != '\0')
+ {
+ size_t len = strlen ((char *) libname);
+ char *name;
+
+ while (allocated < p - document + len + 100)
+ {
+ /* Expand to guarantee sufficient storage. */
+ uintptr_t document_len = p - document;
+
+ document = xrealloc (document, 2 * allocated);
+ allocated *= 2;
+ p = document + document_len;
+ }
+
+ strcpy (p, "<library name=\"");
+ p = p + strlen (p);
+ name = xml_escape_text ((char *) libname);
+ strcpy (p, name);
+ free (name);
+ p = p + strlen (p);
+ strcpy (p, "\"><segment address=\"");
+ p = p + strlen (p);
+ sprintf (p, "0x%lx", (long) l_addr);
+ p = p + strlen (p);
+ strcpy (p, "\"/></library>");
+ p = p + strlen (p);
+ }
+
+ if (l_next == 0)
+ break;
+
+ lm_prev = lm_addr;
+ lm_addr = l_next;
+ }
+ done:
+ strcpy (p, "</library-list>");
+ }
+
+ document_len = strlen (document + offset);
+ if (len > document_len)
+ len = document_len;
+
+ memcpy (readbuf, document + offset, len);
+ xfree (document);
+
+ return len;
+}
+
+
static struct target_ops linux_target_ops = {
linux_create_inferior,
linux_attach,
@@ -4813,7 +5151,8 @@ static struct target_ops linux_target_op
linux_cancel_breakpoints,
linux_stabilize_threads,
linux_install_fast_tracepoint_jump_pad,
- linux_emit_ops
+ linux_emit_ops,
+ linux_qxfer_libraries
};
static void
Index: gdbserver/linux-low.h
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/linux-low.h,v
retrieving revision 1.47
diff -u -p -r1.47 linux-low.h
--- gdbserver/linux-low.h 1 Jan 2011 15:33:24 -0000 1.47
+++ gdbserver/linux-low.h 5 Aug 2011 17:56:24 -0000
@@ -56,6 +56,9 @@ struct process_info_private
/* libthread_db-specific additions. Not NULL if this process has loaded
thread_db, and it is active. */
struct thread_db *thread_db;
+
+ /* &_r_debug. -1 if not yet determined. 0 if no PT_DYNAMIC in Phdrs. */
+ CORE_ADDR r_debug;
};
struct lwp_info;
Index: gdbserver/server.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/server.c,v
retrieving revision 1.146
diff -u -p -r1.146 server.c
--- gdbserver/server.c 21 Jul 2011 23:46:12 -0000 1.146
+++ gdbserver/server.c 5 Aug 2011 17:56:24 -0000
@@ -918,6 +918,9 @@ handle_qxfer_libraries (const char *anne
if (annex[0] != '\0' || !target_running ())
return -1;
+ if (the_target->qxfer_libraries != NULL)
+ return the_target->qxfer_libraries (annex, readbuf, writebuf, offset, len);
+
/* Over-estimate the necessary memory. Assume that every character
in the library name must be escaped. */
total_len = 64;
Index: gdbserver/target.h
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/target.h,v
retrieving revision 1.54
diff -u -p -r1.54 target.h
--- gdbserver/target.h 1 Jan 2011 15:33:24 -0000 1.54
+++ gdbserver/target.h 5 Aug 2011 17:56:24 -0000
@@ -373,6 +373,11 @@ struct target_ops
/* Return the bytecode operations vector for the current inferior.
Returns NULL if bytecode compilation is not supported. */
struct emit_ops *(*emit_ops) (void);
+
+ /* Read solib info. */
+ int (*qxfer_libraries) (const char *annex, unsigned char *readbuf,
+ unsigned const char *writebuf,
+ CORE_ADDR offset, int len);
};
extern struct target_ops *the_target;
next reply other threads:[~2011-08-05 18:11 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-08-05 18:11 Paul Pluzhnikov [this message]
2011-08-08 18:36 ` Jan Kratochvil
2011-08-08 18:56 ` Paul Pluzhnikov
2011-08-08 21:24 ` [patch] Implement qXfer:libraries for Linux/gdbserver Jan Kratochvil
2011-08-09 18:25 ` Daniel Jacobowitz
2011-08-08 21:10 ` Jan Kratochvil
2011-08-08 21:31 ` Paul Pluzhnikov
2011-08-08 21:38 ` Jan Kratochvil
2011-08-08 23:50 ` Paul Pluzhnikov
2011-08-09 9:07 ` Jan Kratochvil
2011-08-09 16:57 ` Paul Pluzhnikov
2011-08-14 16:36 ` Jan Kratochvil
2011-10-03 21:57 ` IMO-obsolste: " Jan Kratochvil
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=CALoOobM_nZ+Xkv7tqjq-JLOaPSQabOTKnXx29HADOtfQk_Jgrg@mail.gmail.com \
--to=ppluzhnikov@google.com \
--cc=gdb-patches@sourceware.org \
--cc=jan.kratochvil@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox