* [patch v6 0/3] remove-symbol-file
@ 2013-06-05 19:08 Nicolas Blanc
2013-06-05 19:08 ` [patch v6 3/3] Documentation for the remove-symbol-file command Nicolas Blanc
` (2 more replies)
0 siblings, 3 replies; 8+ messages in thread
From: Nicolas Blanc @ 2013-06-05 19:08 UTC (permalink / raw)
To: gdb-patches, palves, tromey, eliz, yao, lgustavo, dje; +Cc: nicolas.blanc
Hi,
Please see the new command syntax, which was changed according to the feedback
from Doug and Luis (http://sourceware.org/ml/gdb-patches/2013-06/msg00027.html).
Thank you,
Nicolas
Changes between v5 and v6:
* Changed syntax of the command according to feedback:
remove-symbol-file FILENAME
remove-symbol-file -a ADDRESS
* Updated the documentation for the new syntax.
* Updated the test for the new syntax.
* Added check to only remove objfiles from the current program space.
Changes between v4 and v5:
* The address parameter can now be any address mapping into one of the sections
of the file to remove. This is more flexible and more judicious because the symbol
file may have no text section, as pointed out in some reviews.
* Move is_addr_in_objfile from breakpoint.c to objfiles.c. This new function
is now used in both symfile.c and breakpoint.c.
* is_addr_in_objfile returns now 0 if OBJFILE is NULL.
* Updated the documentation to reflect the command change.
* Removed double blank lines.
* Reworded the log entries in the commit messages, as suggested.
* The test was simplified using prepare_for_testing, as suggested.
Changes between v3 and v4:
* gdb/symfile.c: add missing space character in output string.
* gdb/doc/gdb.texinfo: add usage example.
Changes between v2 and v3:
* gdb/breakpoints.c (disable_breakpoints_in_freed_objfile):
Changed name of disable_breakpoints_in_free_objfile to disable_breakpoints_in_freed_objfile.
Call observer_breakpoint_modified at most one time per breakpoint.
* gdb/objfiles.h (struct objfile): Add comment for low_addr.
* gdb/solib.c (remove_user_added_objfile): Don't check OBJF_SHARED anymore to avoid leaving dangling pointers.
* gdb/symfile.c (add_symbol_file_command): Parse and evaluate the address parameter only once.
* gdb/symfile.c (remove_symbol_file_command): Don't use gdb_buildargv anymore. Ask the user for confirmation before removing a file.
* gdb/doc/gdb.texinfo: The parameter of the command is now referred to as "the address of the text section".
* gdb/NEWS: Move the entry for remove-symbol-file to "Changes since GDB 7.6". The address parameter is now referred to as "the beginning of the text section".
* Fixed letter case of variables in comments.
* Fixed indentation typos.
Nicolas Blanc (3):
New remove-symbol-file command.
Test adding and removing a symbol file at runtime.
Documentation for the remove-symbol-file command.
gdb/NEWS | 6 +
gdb/breakpoint.c | 66 ++++++-
gdb/doc/gdb.texinfo | 26 ++-
gdb/doc/observer.texi | 4 +
gdb/objfiles.c | 23 ++
gdb/objfiles.h | 2 +
gdb/printcmd.c | 15 +-
gdb/solib.c | 22 ++
gdb/symfile.c | 84 ++++++++
gdb/testsuite/gdb.base/sym-file-lib.c | 19 ++
gdb/testsuite/gdb.base/sym-file-main.c | 365 ++++++++++++++++++++++++++++++++
gdb/testsuite/gdb.base/sym-file.exp | 143 +++++++++++++
12 files changed, 764 insertions(+), 11 deletions(-)
create mode 100644 gdb/testsuite/gdb.base/sym-file-lib.c
create mode 100644 gdb/testsuite/gdb.base/sym-file-main.c
create mode 100644 gdb/testsuite/gdb.base/sym-file.exp
--
1.7.6.5
^ permalink raw reply [flat|nested] 8+ messages in thread
* [patch v6 2/3] Test adding and removing a symbol file at runtime.
2013-06-05 19:08 [patch v6 0/3] remove-symbol-file Nicolas Blanc
2013-06-05 19:08 ` [patch v6 3/3] Documentation for the remove-symbol-file command Nicolas Blanc
2013-06-05 19:08 ` [patch v6 1/3] New " Nicolas Blanc
@ 2013-06-05 19:08 ` Nicolas Blanc
2013-06-06 15:47 ` Luis Machado
2 siblings, 1 reply; 8+ messages in thread
From: Nicolas Blanc @ 2013-06-05 19:08 UTC (permalink / raw)
To: gdb-patches, palves, tromey, eliz, yao, lgustavo, dje; +Cc: nicolas.blanc
This test exercises the commands 'add-symbol-file'
and 'remove-symbol-file'.
2013-04-04 Nicolas Blanc <nicolas.blanc@intel.com>
gdb/testsuite
* gdb.base/sym-file-lib.c: New file.
* gdb.base/sym-file-lib.c: New file.
* gdb.base/sym-file.exp: New file.
Signed-off-by: Nicolas Blanc <nicolas.blanc@intel.com>
---
gdb/testsuite/gdb.base/sym-file-lib.c | 19 ++
gdb/testsuite/gdb.base/sym-file-main.c | 365 ++++++++++++++++++++++++++++++++
gdb/testsuite/gdb.base/sym-file.exp | 143 +++++++++++++
3 files changed, 527 insertions(+), 0 deletions(-)
create mode 100644 gdb/testsuite/gdb.base/sym-file-lib.c
create mode 100644 gdb/testsuite/gdb.base/sym-file-main.c
create mode 100644 gdb/testsuite/gdb.base/sym-file.exp
diff --git a/gdb/testsuite/gdb.base/sym-file-lib.c b/gdb/testsuite/gdb.base/sym-file-lib.c
new file mode 100644
index 0000000..f9faf8a
--- /dev/null
+++ b/gdb/testsuite/gdb.base/sym-file-lib.c
@@ -0,0 +1,19 @@
+/* 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/>.
+*/
+
+extern int bar () { return 1; } /* gdb break at bar */
+
+extern int foo (int a) { return a; } /* gdb break at foo */
+
diff --git a/gdb/testsuite/gdb.base/sym-file-main.c b/gdb/testsuite/gdb.base/sym-file-main.c
new file mode 100644
index 0000000..f692ec5
--- /dev/null
+++ b/gdb/testsuite/gdb.base/sym-file-main.c
@@ -0,0 +1,365 @@
+/* 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 <fcntl.h>
+#include </usr/include/elf.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+
+#ifdef TARGET_LP64
+typedef Elf64_Phdr Elf_Phdr;
+typedef Elf64_Ehdr Elf_Ehdr;
+typedef Elf64_Shdr Elf_Shdr;
+typedef Elf64_Sym Elf_Sym;
+typedef Elf64_Word Elf_Word;
+
+unsigned char inline elf_st_type (unsigned char st_info)
+{
+ return ELF64_ST_TYPE (st_info);
+}
+#elif defined TARGET_ILP32
+typedef Elf32_Phdr Elf_Phdr;
+typedef Elf32_Ehdr Elf_Ehdr;
+typedef Elf32_Shdr Elf_Shdr;
+typedef Elf32_Sym Elf_Sym;
+typedef Elf32_Word Elf_Word;
+
+unsigned char inline elf_st_type (unsigned char st_info)
+{
+ return ELF32_ST_TYPE (st_info);
+}
+#endif
+
+void gdb_add_symbol_file (void* addr, const char* file)
+{
+ return;
+}
+
+void gdb_remove_symbol_file (void* addr)
+{
+ return;
+}
+
+struct segment
+{
+ char* mapped_addr;
+ Elf_Phdr* phdr;
+ struct segment* next;
+};
+
+/* Load a program segment. */
+
+struct segment* load (char * addr, Elf_Phdr* phdr, struct segment* tail_seg)
+{
+ /* For the sake of simplicity all operations are permitted. */
+ unsigned perm = PROT_READ | PROT_WRITE | PROT_EXEC;
+
+ char* mapped_addr = (char*) mmap ((void*) phdr->p_vaddr,
+ phdr->p_memsz, perm,
+ MAP_ANONYMOUS | MAP_PRIVATE,
+ -1, 0);
+
+ void * from = (void*) (addr + phdr->p_offset);
+ void * to = (void*) mapped_addr;
+
+ memcpy (to, from, phdr->p_filesz);
+
+ struct segment* seg = (struct segment*) malloc (sizeof (struct segment));
+
+ if (seg == 0)
+ return 0;
+
+ seg->mapped_addr = mapped_addr;
+ seg->phdr = phdr;
+ seg->next = 0;
+
+ if (tail_seg != 0)
+ tail_seg->next = seg;
+
+ return seg;
+}
+
+/* Load a shared library without calling the standard loader. */
+
+int load_shlib (const char *file, Elf_Ehdr **ehdr_out, struct segment **seg_out)
+{
+ unsigned i = 0;
+
+ /* Map the lib in memory for reading. */
+ int fd = open (file, O_RDONLY);
+ if (fd < 0)
+ {
+ perror ("fopen failed.");
+ return -1;
+ }
+
+ off_t fsize = lseek (fd, 0, SEEK_END);
+
+ if (fsize < 0)
+ {
+ perror ("lseek failed.");
+ return -1;
+ }
+
+ char* addr = (char*) mmap (NULL, fsize, PROT_READ, MAP_PRIVATE, fd, 0);
+ if (addr == (char*) -1)
+ {
+ perror ("mmap failed.");
+ return -1;
+ }
+
+ /* Check if the lib is an ELF file. */
+ Elf_Ehdr* ehdr = (Elf_Ehdr*) addr;
+ if (ehdr->e_ident[EI_MAG0] != ELFMAG0
+ || ehdr->e_ident[EI_MAG1] != ELFMAG1
+ || ehdr->e_ident[EI_MAG2] != ELFMAG2
+ || ehdr->e_ident[EI_MAG3] != ELFMAG3)
+ {
+ printf ("Not an ELF file: %x\n", ehdr->e_ident[EI_MAG0]);
+ return -1;
+ }
+
+ if (ehdr->e_ident[EI_CLASS] == ELFCLASS32)
+ {
+ if (sizeof (int*) != 4)
+ {
+ printf ("Architecture mismatch.");
+ return -1;
+ }
+ }
+ else if (ehdr->e_ident[EI_CLASS] == ELFCLASS64)
+ {
+ if (sizeof (int*) != 8)
+ {
+ printf ("Architecture mismatch.");
+ return -1;
+ }
+ }
+
+ /* Load the program segments. For the sake of simplicity
+ assume that no reallocation is needed. */
+ Elf_Phdr* phdr = (Elf_Phdr*) (addr + ehdr->e_phoff);
+ struct segment* head_seg = 0;
+ struct segment* tail_seg = 0;
+ for (i=0; i < ehdr->e_phnum; i++, phdr++)
+ {
+ if (phdr->p_type == PT_LOAD)
+ {
+ struct segment* next_seg = load (addr, phdr, tail_seg);
+ if (next_seg == 0)
+ continue;
+ tail_seg = next_seg;
+ if (head_seg == 0)
+ head_seg = next_seg;
+ }
+ }
+ *ehdr_out = ehdr;
+ *seg_out = head_seg;
+ return 0;
+}
+
+/* Return the section-header table. */
+
+Elf_Shdr* find_shdrtab (Elf_Ehdr *ehdr)
+{
+ return (Elf_Shdr*) (((char*) ehdr) + ehdr->e_shoff);
+}
+
+/* Return the string table of the section headers. */
+
+const char* find_shstrtab (Elf_Ehdr *ehdr, unsigned *size)
+{
+ const Elf_Shdr *shdr = find_shdrtab (ehdr);
+
+ if (ehdr->e_shnum <= ehdr->e_shstrndx)
+ {
+ printf ("The index of the string table is corrupt.");
+ return NULL;
+ }
+ const Elf_Shdr* shstr = &shdr[ehdr->e_shstrndx];
+ *size = shstr->sh_size;
+ return ((const char*) ehdr) + shstr->sh_offset;
+}
+
+/* Return the string table named SECTION. */
+
+const char* find_strtab (Elf_Ehdr *ehdr,
+ const char* shstrtab, unsigned shstrtab_size,
+ const char* section, unsigned *strtab_size)
+{
+ const Elf_Shdr* shdr = find_shdrtab (ehdr);
+ unsigned i = 0;
+ for (i=0; i < ehdr->e_shnum; i++)
+ {
+ Elf_Word name = shdr[i].sh_name;
+ if (shdr[i].sh_type == SHT_STRTAB && name <= shstrtab_size
+ && strcmp ((const char*) &shstrtab[name], section) == 0)
+ {
+ *strtab_size = shdr[i].sh_size;
+ return ((const char*) ehdr) + shdr[i].sh_offset;
+ }
+
+ }
+ return NULL;
+}
+
+/* Return the section header named SECTION. */
+
+Elf_Shdr* find_shdr (Elf_Ehdr* ehdr, const char *section,
+ const char *shstrtab, unsigned shstrtab_size)
+{
+ Elf_Shdr *shdr = find_shdrtab (ehdr);
+ unsigned i = 0;
+ for (i=0; i < ehdr->e_shnum; i++)
+ {
+ Elf_Word name = shdr[i].sh_name;
+ if (name <= shstrtab_size)
+ {
+ if (strcmp ((const char*) &shstrtab[name], section) == 0)
+ return &shdr[i];
+ }
+
+ }
+ return NULL;
+}
+
+/* Return the symbol table. */
+
+Elf_Sym* find_symtab (Elf_Ehdr* ehdr, unsigned *symtab_size)
+{
+ unsigned i = 0;
+ const Elf_Shdr *shdr = find_shdrtab (ehdr);
+ for (i=0; i < ehdr->e_shnum; i++)
+ {
+ if (shdr[i].sh_type == SHT_SYMTAB)
+ {
+ *symtab_size = shdr[i].sh_size / sizeof (Elf_Sym);
+ return (Elf_Sym*) (((const char*) ehdr) + shdr[i].sh_offset);
+ }
+ }
+ return NULL;
+}
+
+/* Lookup the offset of FUNC. */
+
+int lookup_function (const char *func,
+ Elf_Sym *symtab, unsigned symtab_size,
+ const char *strtab, unsigned strtab_size,
+ unsigned *offset)
+{
+ unsigned i = 0;
+ for (i=0; i < symtab_size; i++)
+ {
+ Elf_Sym* sym = &symtab[i];
+
+ if (elf_st_type (sym->st_info) != STT_FUNC)
+ continue;
+
+ if (sym->st_name < strtab_size)
+ {
+ const char* name = &strtab[sym->st_name];
+ if (strcmp (name, func) == 0)
+ {
+ *offset = (unsigned) sym->st_value;
+ return 0;
+ }
+ }
+ }
+
+ return -1;
+}
+
+/* Load a shared library without relying on the standard
+ loader to test GDB's commands for adding and removing
+ symbol files at runtime. */
+
+int main (int argc, const char* argv[])
+{
+ const char *file = SHLIB_NAME;
+
+ Elf_Ehdr *ehdr = 0;
+ struct segment *head_seg = 0;
+
+ if (load_shlib (file, &ehdr, &head_seg) != 0)
+ return -1;
+
+ /* Get the string table for the section headers. */
+ unsigned shstrtab_size = 0;
+ const char* shstrtab = find_shstrtab (ehdr, &shstrtab_size);
+
+ if (shstrtab == NULL)
+ return -1;
+
+ /* Get the text section. */
+ Elf_Shdr* text = find_shdr (ehdr, ".text", shstrtab, shstrtab_size);
+ if (text == NULL)
+ return -1;
+
+ char* base_addr = head_seg->mapped_addr + text->sh_offset;
+
+ /* Notify GDB to add the symbol file. */
+ gdb_add_symbol_file (base_addr, file);
+
+ /* Get the string table for the symbols. */
+ unsigned strtab_size = 0;
+ const char* strtab = find_strtab (ehdr, shstrtab, shstrtab_size,
+ ".strtab", &strtab_size);
+ if (strtab == NULL)
+ {
+ printf (".strtab not found.");
+ return -1;
+ }
+
+ /* Get the symbol table. */
+ unsigned symtab_size = 0;
+ Elf_Sym* symtab = find_symtab (ehdr, &symtab_size);
+ if (symtab == NULL)
+ {
+ printf ("symtab not found.");
+ return -1;
+ }
+
+ /* Call bar from SHLIB_NAME. */
+ unsigned bar_offset = 0;
+ if (lookup_function ("bar",
+ symtab, symtab_size,
+ strtab, strtab_size,
+ &bar_offset) != 0)
+ return -1;
+
+ int (*pbar) () = (int (*) ()) (head_seg->mapped_addr + bar_offset);
+
+ int value1 = (*pbar) ();
+
+ /* Call foo from SHLIB_NAME. */
+ unsigned foo_offset = 0;
+ if (lookup_function ("foo",
+ symtab, symtab_size,
+ strtab, strtab_size,
+ &foo_offset) != 0)
+ return -1;
+
+ int (*pfoo) (int) = (int (*) (int)) (head_seg->mapped_addr + foo_offset);
+
+ int value2 = (*pfoo) (2);
+
+ /* Notify GDB to remove the symbol file. */
+ gdb_remove_symbol_file (base_addr);
+
+ return 0;
+}
+
diff --git a/gdb/testsuite/gdb.base/sym-file.exp b/gdb/testsuite/gdb.base/sym-file.exp
new file mode 100644
index 0000000..567eb97
--- /dev/null
+++ b/gdb/testsuite/gdb.base/sym-file.exp
@@ -0,0 +1,143 @@
+# 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/>. */
+
+# Test adding and removing a symbol file dynamically:
+# 1) Run to gdb_add_symbol_file in $srcfile.
+# 2) Set a pending breakpoint at bar in $libsrc.
+# 3) Load $shlib_name using 'add-symbol-file'.
+# 4) Continue to bar in $libsrc.
+# 5) Set a breakpiont at foo in $librc.
+# 6) Continue to foo in $libsrc.
+# 7) Set a breakpoint at gdb_remove_symbol_file.
+# 8) Continue to gdb_remove_symbol_file in $srcfile.
+# 9) Remove $shlib_name using 'remove-symbol-file'.
+# 10) Check that the breakpoints at foo and bar are pending.
+# 11) Check that the execution can continue without error.
+
+if [skip_shlib_tests] {
+ return 0
+}
+
+if [is_remote target] {
+ return 0
+}
+
+set target_size TARGET_UNKNOWN
+if [is_lp64_target] {
+ set target_size TARGET_LP64
+} elseif [is_ilp32_target] {
+ set target_size TARGET_ILP32
+} else {
+ return 0
+}
+
+set testfile sym-file.exp
+set mainfile sym-file-main
+set libfile sym-file-lib
+set srcfile ${mainfile}.c
+set libsrc "${srcdir}/${subdir}/${libfile}.c"
+set libname "${libfile}.so"
+set shlib_name "${objdir}/${subdir}/${libname}"
+set libobj "${objdir}/${subdir}/${libname}"
+set exec_opts [list debug "additional_flags=-D$target_size\
+ -DSHLIB_NAME\\=\"$shlib_name\""]
+
+if [get_compiler_info] {
+ return -1
+}
+
+if { [gdb_compile_shlib $libsrc $libobj {debug}] != "" } {
+ untested ${testfile}
+ return
+}
+
+if { [prepare_for_testing ${testfile} ${mainfile} ${srcfile} $exec_opts] } {
+ return
+}
+
+# 1) Run to GDB_ADD_SYMBOl_FILE in $srcfile for adding
+# $shlib_name.
+set result [runto gdb_add_symbol_file]
+if { !$result } then {
+ return
+}
+
+# 2) Set a pending breakpoint at bar in $libsrc.
+set result [gdb_breakpoint bar allow-pending]
+if { !$result } then {
+ return
+}
+
+# 3) Add $shlib_name using 'add-symbol-file'.
+set result [gdb_test "add-symbol-file ${shlib_name} addr" \
+ "Reading symbols from .*${shlib_name}\\.\\.\\.done\\." \
+ "add-symbol-file ${shlib_name}.*" \
+ "add symbol table from file \".*${shlib_name}\"\
+ at.*\\(y or n\\) " \
+ "y"]
+if { $result != 0 } then {
+ return
+}
+
+# 4) Continue to bar in $libsrc to ensure that the breakpoint
+# was bound correctly after adding $shilb_name.
+set lnum_bar [gdb_get_line_number "break at bar" $libsrc]
+gdb_continue_to_breakpoint bar ".*$libfile\\.c:$lnum_bar.*"
+
+# 5) Set a breakpoint at foo in $libsrc.
+set result [gdb_breakpoint foo]
+if { !$result } then {
+ return
+}
+
+# 6) Continue to foo in $libsrc to ensure that the breakpoint
+# was bound correctly.
+set lnum_foo [gdb_get_line_number "break at foo" $libsrc]
+gdb_continue_to_breakpoint foo ".*$libfile\\.c:$lnum_foo.*"
+
+# 7) Set a breakpint at gdb_remove_symbol_file in $srcfile for
+# removing $shlib_name.
+set result [gdb_breakpoint gdb_remove_symbol_file]
+if { !$result } then {
+ return
+}
+
+# 8) Continue to gdb_remove_symbol_file in $srcfile.
+gdb_continue_to_breakpoint gdb_remove_symbol_file
+
+# 9) Remove $shlib_name using 'remove-symbol-file'.
+set result [gdb_test "remove-symbol-file -a addr" \
+ ""\
+ "remove-symbol-file -a addr" \
+ "Remove symbol table from file \".*${shlib_name}\"\\?\
+.*\\(y or n\\) " \
+ "y"]
+if { $result != 0 } then {
+ return
+}
+
+# 10) Check that the breakpoints at foo and bar are pending after removing
+# $shlib_name.
+gdb_test "info breakpoints 2" \
+ ".*PENDING.*" \
+ "check if Breakpoint 2 is pending."
+
+gdb_test "info breakpoints 3" \
+ ".*PENDING.*" \
+ "check if Breakpoint 3 is pending."
+
+# 11) Check that the execution can continue without error.
+gdb_continue_to_end
+
--
1.7.6.5
^ permalink raw reply [flat|nested] 8+ messages in thread
* [patch v6 1/3] New remove-symbol-file command.
2013-06-05 19:08 [patch v6 0/3] remove-symbol-file Nicolas Blanc
2013-06-05 19:08 ` [patch v6 3/3] Documentation for the remove-symbol-file command Nicolas Blanc
@ 2013-06-05 19:08 ` Nicolas Blanc
2013-06-06 15:44 ` Luis Machado
2013-06-05 19:08 ` [patch v6 2/3] Test adding and removing a symbol file at runtime Nicolas Blanc
2 siblings, 1 reply; 8+ messages in thread
From: Nicolas Blanc @ 2013-06-05 19:08 UTC (permalink / raw)
To: gdb-patches, palves, tromey, eliz, yao, lgustavo, dje; +Cc: nicolas.blanc
New command for removing symbol files added via
the add-symbol-file command.
2013-18-03 Nicolas Blanc <nicolas.blanc@intel.com>
* breakpoint.c (disable_breakpoints_in_freed_objfile): New function for
disabling breakpoints in objfiles upon free_objfile notifications.
* objfiles.c (free_objfile): Notify free_objfile.
(is_addr_in_objfile): New query function.
* objfiles.h (is_addr_in_objfile): New declaration.
* printcmd.c (clear_dangling_display_expressions): Act upon free_objfile
events instead of solib_unloaded events.
(_initialize_printcmd): Register observer for free_objfile instead
of solib_unloaded notifications.
* solib.c (remove_user_added_objfile): New function for removing
dangling references upon notification of free_objfile.
* symfile.c (remove_symbol_file_command): New command for removing symbol
files.
(_initialize_symfile): Add remove-symbol-file.
gdb/doc
* observer.texi: New free_objfile event.
Signed-off-by: Nicolas Blanc <nicolas.blanc@intel.com>
---
gdb/breakpoint.c | 66 ++++++++++++++++++++++++++++++++++++--
gdb/doc/observer.texi | 4 ++
gdb/objfiles.c | 23 +++++++++++++
gdb/objfiles.h | 2 +
gdb/printcmd.c | 15 +++++---
gdb/solib.c | 22 +++++++++++++
gdb/symfile.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++++
7 files changed, 207 insertions(+), 9 deletions(-)
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index d4ccc81..9446918 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -7403,9 +7403,9 @@ disable_breakpoints_in_shlibs (void)
}
}
-/* Disable any breakpoints and tracepoints that are in an unloaded shared
- library. Only apply to enabled breakpoints, disabled ones can just stay
- disabled. */
+/* Disable any breakpoints and tracepoints that are in SOLIB upon
+ notification of unloaded_shlib. Only apply to enabled breakpoints,
+ disabled ones can just stay disabled. */
static void
disable_breakpoints_in_unloaded_shlib (struct so_list *solib)
@@ -7457,6 +7457,65 @@ disable_breakpoints_in_unloaded_shlib (struct so_list *solib)
}
}
+/* Disable any breakpoints and tracepoints in OBJFILE upon
+ notification of free_objfile. Only apply to enabled breakpoints,
+ disabled ones can just stay disabled. */
+
+static void
+disable_breakpoints_in_freed_objfile (struct objfile * objfile)
+{
+ struct breakpoint *b;
+
+ if (objfile == NULL)
+ return;
+
+ /* If the file is a shared library not loaded by the user then
+ solib_unloaded was notified and disable_breakpoints_in_unloaded_shlib
+ was called. In that case there is no need to take action again. */
+ if ((objfile->flags & OBJF_SHARED) && !(objfile->flags & OBJF_USERLOADED))
+ return;
+
+ ALL_BREAKPOINTS (b)
+ {
+ struct bp_location *loc;
+ int bp_modified = 0;
+ int is_no_tracepoint = !is_tracepoint (b);
+
+ if (is_no_tracepoint
+ && b->type != bp_breakpoint
+ && b->type != bp_jit_event
+ && b->type != bp_hardware_breakpoint)
+ continue;
+
+ for (loc = b->loc; loc != NULL; loc = loc->next)
+ {
+ CORE_ADDR loc_addr = loc->address;
+
+ if (is_no_tracepoint
+ && loc->loc_type != bp_loc_hardware_breakpoint
+ && loc->loc_type != bp_loc_software_breakpoint)
+ continue;
+
+ if (loc->shlib_disabled != 0)
+ continue;
+
+ if (objfile->pspace != loc->pspace)
+ continue;
+
+ if (is_addr_in_objfile (loc_addr, objfile))
+ {
+ loc->shlib_disabled = 1;
+ loc->inserted = 0;
+ bp_modified = 1;
+ }
+ }
+
+ if (bp_modified)
+ observer_notify_breakpoint_modified (b);
+ }
+
+}
+
/* FORK & VFORK catchpoints. */
/* An instance of this type is used to represent a fork or vfork
@@ -15861,6 +15920,7 @@ _initialize_breakpoint (void)
initialize_breakpoint_ops ();
observer_attach_solib_unloaded (disable_breakpoints_in_unloaded_shlib);
+ observer_attach_free_objfile (disable_breakpoints_in_freed_objfile);
observer_attach_inferior_exit (clear_syscall_counts);
observer_attach_memory_changed (invalidate_bp_value_on_memory_change);
diff --git a/gdb/doc/observer.texi b/gdb/doc/observer.texi
index adb7085..f753965 100644
--- a/gdb/doc/observer.texi
+++ b/gdb/doc/observer.texi
@@ -138,6 +138,10 @@ Called with @var{objfile} equal to @code{NULL} to indicate
previously loaded symbol table data has now been invalidated.
@end deftypefun
+@deftypefun void free_objfile (struct objfile *@var{objfile})
+The object file specified by @var{objfile} is about to be freed.
+@end deftypefun
+
@deftypefun void new_thread (struct thread_info *@var{t})
The thread specified by @var{t} has been created.
@end deftypefun
diff --git a/gdb/objfiles.c b/gdb/objfiles.c
index 1e1b7bc..6411380 100644
--- a/gdb/objfiles.c
+++ b/gdb/objfiles.c
@@ -539,6 +539,9 @@ free_objfile_separate_debug (struct objfile *objfile)
void
free_objfile (struct objfile *objfile)
{
+ /* First notify observers that this objfile is about to be freed. */
+ observer_notify_free_objfile (objfile);
+
/* Free all separate debug objfiles. */
free_objfile_separate_debug (objfile);
@@ -1463,6 +1466,26 @@ resume_section_map_updates_cleanup (void *arg)
resume_section_map_updates (arg);
}
+/* Return 1 if ADDR maps into one of the sections of OBJFILE and 0
+ otherwise. */
+
+int
+is_addr_in_objfile (CORE_ADDR addr, const struct objfile * objfile)
+{
+ struct obj_section *osect;
+
+ if (objfile == NULL)
+ return 0;
+
+ ALL_OBJFILE_OSECTIONS (objfile, osect)
+ {
+ if (obj_section_addr (osect) <= addr
+ && addr < obj_section_endaddr (osect))
+ return 1;
+ }
+ return 0;
+}
+
/* The default implementation for the "iterate_over_objfiles_in_search_order"
gdbarch method. It is equivalent to use the ALL_OBJFILES macro,
searching the objfiles in the order they are stored internally,
diff --git a/gdb/objfiles.h b/gdb/objfiles.h
index adb1ef8..b25afb1 100644
--- a/gdb/objfiles.h
+++ b/gdb/objfiles.h
@@ -482,6 +482,8 @@ extern int have_full_symbols (void);
extern void objfiles_changed (void);
+extern int is_addr_in_objfile (CORE_ADDR, const struct objfile *);
+
/* This operation deletes all objfile entries that represent solibs that
weren't explicitly loaded by the user, via e.g., the add-symbol-file
command. */
diff --git a/gdb/printcmd.c b/gdb/printcmd.c
index 7beb334..f155522 100644
--- a/gdb/printcmd.c
+++ b/gdb/printcmd.c
@@ -1925,21 +1925,24 @@ disable_display_command (char *args, int from_tty)
an item by re-parsing .exp_string field in the new execution context. */
static void
-clear_dangling_display_expressions (struct so_list *solib)
+clear_dangling_display_expressions (struct objfile *objfile)
{
- struct objfile *objfile = solib->objfile;
struct display *d;
+ struct program_space *pspace;
/* With no symbol file we cannot have a block or expression from it. */
if (objfile == NULL)
return;
+ pspace = objfile->pspace;
if (objfile->separate_debug_objfile_backlink)
- objfile = objfile->separate_debug_objfile_backlink;
- gdb_assert (objfile->pspace == solib->pspace);
+ {
+ objfile = objfile->separate_debug_objfile_backlink;
+ gdb_assert (objfile->pspace == pspace);
+ }
for (d = display_chain; d != NULL; d = d->next)
{
- if (d->pspace != solib->pspace)
+ if (d->pspace != pspace)
continue;
if (lookup_objfile_from_block (d->block) == objfile
@@ -2471,7 +2474,7 @@ _initialize_printcmd (void)
current_display_number = -1;
- observer_attach_solib_unloaded (clear_dangling_display_expressions);
+ observer_attach_free_objfile (clear_dangling_display_expressions);
add_info ("address", address_info,
_("Describe where symbol SYM is stored."));
diff --git a/gdb/solib.c b/gdb/solib.c
index c987fe5..987d510 100644
--- a/gdb/solib.c
+++ b/gdb/solib.c
@@ -1478,6 +1478,26 @@ gdb_bfd_lookup_symbol (bfd *abfd,
return symaddr;
}
+/* SO_LIST_HEAD may contain user-loaded object files that can be removed
+ out-of-band by the user. So upon notification of free_objfile remove
+ any reference to any user-loaded file that is about to be freed. */
+
+static void
+remove_user_added_objfile (struct objfile *objfile)
+{
+ struct so_list *so;
+
+ if (!objfile)
+ return;
+
+ if (objfile->flags & OBJF_USERLOADED)
+ {
+ for (so = so_list_head; so != NULL; so = so->next)
+ if (so->objfile == objfile)
+ so->objfile = NULL;
+ }
+}
+
extern initialize_file_ftype _initialize_solib; /* -Wmissing-prototypes */
void
@@ -1485,6 +1505,8 @@ _initialize_solib (void)
{
solib_data = gdbarch_data_register_pre_init (solib_init);
+ observer_attach_free_objfile (remove_user_added_objfile);
+
add_com ("sharedlibrary", class_files, sharedlibrary_command,
_("Load shared object library symbols for files matching REGEXP."));
add_info ("sharedlibrary", info_sharedlibrary_command,
diff --git a/gdb/symfile.c b/gdb/symfile.c
index c2ad797..bb1a6d5 100644
--- a/gdb/symfile.c
+++ b/gdb/symfile.c
@@ -2330,6 +2330,81 @@ add_symbol_file_command (char *args, int from_tty)
}
\f
+/* This function removes a symbol file that was added via add-symbol-file. */
+
+static void
+remove_symbol_file_command (char *args, int from_tty)
+{
+ char **argv;
+ struct objfile* objf = NULL;
+ struct cleanup *my_cleanups;
+ struct program_space *pspace = current_program_space;
+ struct gdbarch *gdbarch = get_current_arch ();
+
+ dont_repeat ();
+
+ if (args == NULL)
+ error (_("USAGE: remove-symbol-file FILENAME\n\
+ remove-symbol-file -a ADDRESS"));
+
+ my_cleanups = make_cleanup (null_cleanup, NULL);
+
+ argv = gdb_buildargv (args);
+
+ if (strcmp (argv[0], "-a") == 0)
+ {
+ /* Interpret the next argument as an address. */
+ CORE_ADDR addr;
+
+ if (argv[1] == NULL)
+ error (_("Missing address argument"));
+
+ if (argv[2] != NULL)
+ error (_("Junk after %s"), argv[1]);
+
+ addr = parse_and_eval_address (argv[1]);
+
+ ALL_OBJFILES (objf)
+ {
+ if (objf->flags & OBJF_USERLOADED
+ && objf->pspace == pspace
+ && is_addr_in_objfile (addr, objf))
+ break;
+ }
+ }
+ else if (argv[0] != NULL)
+ {
+ /* Interpret the current argument as a file name. */
+ char *filename;
+
+ if (argv[1] != NULL)
+ error (_("Junk after %s"), argv[0]);
+
+ filename = tilde_expand (argv[0]);
+ make_cleanup (xfree, filename);
+
+ ALL_OBJFILES (objf)
+ {
+ if (objf->flags & OBJF_USERLOADED
+ && objf->pspace == pspace
+ && filename_cmp (filename, objf->name) == 0)
+ break;
+ }
+ }
+
+ if (objf == NULL)
+ error (_("No symbol file found"));
+
+ if (from_tty
+ && !query (_("Remove symbol table from file \"%s\"? "), objf->name))
+ error (_("Not confirmed."));
+
+ free_objfile (objf);
+ clear_symtab_users (0);
+
+ do_cleanups (my_cleanups);
+}
+
typedef struct objfile *objfilep;
DEF_VEC_P (objfilep);
@@ -3744,6 +3819,15 @@ with the text. SECT is a section name to be loaded at SECT_ADDR."),
&cmdlist);
set_cmd_completer (c, filename_completer);
+ c = add_cmd ("remove-symbol-file", class_files,
+ remove_symbol_file_command, _("\
+Remove a symbol file added via the add-symbol-file command.\n\
+Usage: remove-symbol-file FILENAME\n\
+ remove-symbol-file -a ADDRESS\n\
+The file to remove can be identified by its filename or by an address\n\
+pointing inside one of its sections."),
+ &cmdlist);
+
c = add_cmd ("load", class_files, load_command, _("\
Dynamically load FILE into the running program, and record its symbols\n\
for access from GDB.\n\
--
1.7.6.5
^ permalink raw reply [flat|nested] 8+ messages in thread
* [patch v6 3/3] Documentation for the remove-symbol-file command.
2013-06-05 19:08 [patch v6 0/3] remove-symbol-file Nicolas Blanc
@ 2013-06-05 19:08 ` Nicolas Blanc
2013-06-06 15:49 ` Luis Machado
2013-06-05 19:08 ` [patch v6 1/3] New " Nicolas Blanc
2013-06-05 19:08 ` [patch v6 2/3] Test adding and removing a symbol file at runtime Nicolas Blanc
2 siblings, 1 reply; 8+ messages in thread
From: Nicolas Blanc @ 2013-06-05 19:08 UTC (permalink / raw)
To: gdb-patches, palves, tromey, eliz, yao, lgustavo, dje; +Cc: nicolas.blanc
2013-04-05 Nicolas Blanc <nicolas.blanc@intel.com>
* NEWS: Add description of the remove-symbol-file command.
gdb/doc
* gdb.texinfo (Commands to Specify Files): Add description
of the remove-symbol-file command.
Signed-off-by: Nicolas Blanc <nicolas.blanc@intel.com>
---
gdb/NEWS | 6 ++++++
gdb/doc/gdb.texinfo | 26 ++++++++++++++++++++++++--
2 files changed, 30 insertions(+), 2 deletions(-)
diff --git a/gdb/NEWS b/gdb/NEWS
index eea9917..311a164 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -31,6 +31,12 @@ maint set|show per-command time
maint set|show per-command symtab
Enable display of per-command gdb resource usage.
+remove-symbol-file FILENAME
+remove-symbol-file -a ADDRESS
+ Remove a symbol file added via add-symbol-file. The file to remove
+ can be identified by its filename or by an address pointing inside
+ one of its sections.
+
* New options
set remote trace-status-packet
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index e9b6eae..222d4bd 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -16511,8 +16511,9 @@ section name and base address for that section. You can specify any
The symbol table of the file @var{filename} is added to the symbol table
originally read with the @code{symbol-file} command. You can use the
@code{add-symbol-file} command any number of times; the new symbol data
-thus read keeps adding to the old. To discard all old symbol data
-instead, use the @code{symbol-file} command without any arguments.
+thus read keeps adding to the old.
+
+Changes can be reverted using the command @code{remove-symbol-file}.
@cindex relocatable object files, reading symbols from
@cindex object files, relocatable, reading symbols from
@@ -16550,6 +16551,27 @@ way.
@code{add-symbol-file} does not repeat if you press @key{RET} after using it.
+@kindex remove-symbol-file
+@item remove-symbol-file @var{filename}
+@item remove-symbol-file -a @var{address}
+Remove a symbol file added via the @code{add-symbol-file} command. The
+file to remove can be identified by its filename or by an address pointing
+inside one of its sections. Example:
+
+@smallexample
+(gdb) add-symbol-file /home/user/gdb/mylib.so 0x7ffff7ff9480
+add symbol table from file "/home/user/gdb/mylib.so" at
+ .text_addr = 0x7ffff7ff9480
+(y or n) y
+Reading symbols from /home/user/gdb/mylib.so...done.
+(gdb) remove-symbol-file -a 0x7ffff7ff9480
+Remove symbol table from file "/home/user/gdb/mylib.so"? (y or n) y
+(gdb)
+@end smallexample
+
+
+@code{remove-symbol-file} does not repeat if you press @key{RET} after using it.
+
@kindex add-symbol-file-from-memory
@cindex @code{syscall DSO}
@cindex load symbols from memory
--
1.7.6.5
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [patch v6 1/3] New remove-symbol-file command.
2013-06-05 19:08 ` [patch v6 1/3] New " Nicolas Blanc
@ 2013-06-06 15:44 ` Luis Machado
0 siblings, 0 replies; 8+ messages in thread
From: Luis Machado @ 2013-06-06 15:44 UTC (permalink / raw)
To: Nicolas Blanc; +Cc: gdb-patches, palves, tromey, eliz, yao, lgustavo, dje
Thanks.
It is looking good. A few more comments below.
On 06/05/2013 09:07 PM, Nicolas Blanc wrote:
> New command for removing symbol files added via
> the add-symbol-file command.
>
> 2013-18-03 Nicolas Blanc <nicolas.blanc@intel.com>
>
> * breakpoint.c (disable_breakpoints_in_freed_objfile): New function for
> disabling breakpoints in objfiles upon free_objfile notifications.
> * objfiles.c (free_objfile): Notify free_objfile.
> (is_addr_in_objfile): New query function.
> * objfiles.h (is_addr_in_objfile): New declaration.
> * printcmd.c (clear_dangling_display_expressions): Act upon free_objfile
> events instead of solib_unloaded events.
> (_initialize_printcmd): Register observer for free_objfile instead
> of solib_unloaded notifications.
> * solib.c (remove_user_added_objfile): New function for removing
> dangling references upon notification of free_objfile.
> * symfile.c (remove_symbol_file_command): New command for removing symbol
> files.
> (_initialize_symfile): Add remove-symbol-file.
> gdb/doc
> * observer.texi: New free_objfile event.
For new functions, "New function" should do. No need to explain the
functions in the ChangeLog entry.
>
> Signed-off-by: Nicolas Blanc <nicolas.blanc@intel.com>
> ---
> gdb/breakpoint.c | 66 ++++++++++++++++++++++++++++++++++++--
> gdb/doc/observer.texi | 4 ++
> gdb/objfiles.c | 23 +++++++++++++
> gdb/objfiles.h | 2 +
> gdb/printcmd.c | 15 +++++---
> gdb/solib.c | 22 +++++++++++++
> gdb/symfile.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++++
> 7 files changed, 207 insertions(+), 9 deletions(-)
>
> diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
> index d4ccc81..9446918 100644
> --- a/gdb/breakpoint.c
> +++ b/gdb/breakpoint.c
> @@ -7403,9 +7403,9 @@ disable_breakpoints_in_shlibs (void)
> }
> }
>
> -/* Disable any breakpoints and tracepoints that are in an unloaded shared
> - library. Only apply to enabled breakpoints, disabled ones can just stay
> - disabled. */
> +/* Disable any breakpoints and tracepoints that are in SOLIB upon
> + notification of unloaded_shlib. Only apply to enabled breakpoints,
> + disabled ones can just stay disabled. */
>
> static void
> disable_breakpoints_in_unloaded_shlib (struct so_list *solib)
> @@ -7457,6 +7457,65 @@ disable_breakpoints_in_unloaded_shlib (struct so_list *solib)
> }
> }
>
> +/* Disable any breakpoints and tracepoints in OBJFILE upon
> + notification of free_objfile. Only apply to enabled breakpoints,
> + disabled ones can just stay disabled. */
> +
> +static void
> +disable_breakpoints_in_freed_objfile (struct objfile * objfile)
> +{
> + struct breakpoint *b;
> +
> + if (objfile == NULL)
> + return;
> +
> + /* If the file is a shared library not loaded by the user then
> + solib_unloaded was notified and disable_breakpoints_in_unloaded_shlib
> + was called. In that case there is no need to take action again. */
> + if ((objfile->flags & OBJF_SHARED) && !(objfile->flags & OBJF_USERLOADED))
> + return;
> +
> + ALL_BREAKPOINTS (b)
> + {
> + struct bp_location *loc;
> + int bp_modified = 0;
> + int is_no_tracepoint = !is_tracepoint (b);
> +
> + if (is_no_tracepoint
> + && b->type != bp_breakpoint
> + && b->type != bp_jit_event
> + && b->type != bp_hardware_breakpoint)
> + continue;
Sorry i didn't notice this, but, does it make sense to use the
is_breakpoint function here? It checks for bp_breakpoint,
bp_hardware_breakpoint and bp_dprintf.
> +
> + for (loc = b->loc; loc != NULL; loc = loc->next)
> + {
> + CORE_ADDR loc_addr = loc->address;
> +
> + if (is_no_tracepoint
> + && loc->loc_type != bp_loc_hardware_breakpoint
> + && loc->loc_type != bp_loc_software_breakpoint)
> + continue;
> +
> + if (loc->shlib_disabled != 0)
> + continue;
> +
> + if (objfile->pspace != loc->pspace)
> + continue;
> +
> + if (is_addr_in_objfile (loc_addr, objfile))
> + {
> + loc->shlib_disabled = 1;
> + loc->inserted = 0;
> + bp_modified = 1;
> + }
> + }
> +
> + if (bp_modified)
> + observer_notify_breakpoint_modified (b);
> + }
> +
> +}
> +
Since we are disabling breakpoints that are related to a specific
objfile or shared library, i think we should call either
mark_breakpoint_modified or mark_breakpoint_location_modified to make
sure things still work OK in case any of these breakpoints are carrying
conditions and the evaluation of these conditions is taking place on the
target's side.
In fact, i think we may be missing calls to these functions in a couple
other places, but you don't need to address those.
> diff --git a/gdb/solib.c b/gdb/solib.c
> index c987fe5..987d510 100644
> --- a/gdb/solib.c
> +++ b/gdb/solib.c
> @@ -1478,6 +1478,26 @@ gdb_bfd_lookup_symbol (bfd *abfd,
> return symaddr;
> }
>
> +/* SO_LIST_HEAD may contain user-loaded object files that can be removed
> + out-of-band by the user. So upon notification of free_objfile remove
> + any reference to any user-loaded file that is about to be freed. */
> +
> +static void
> +remove_user_added_objfile (struct objfile *objfile)
> +{
> + struct so_list *so;
> +
> + if (!objfile)
> + return;
> +
Just a nit. Keep everything consistent in the code. Above you used
"objfile == NULL" instead of "!objfile".
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [patch v6 2/3] Test adding and removing a symbol file at runtime.
2013-06-05 19:08 ` [patch v6 2/3] Test adding and removing a symbol file at runtime Nicolas Blanc
@ 2013-06-06 15:47 ` Luis Machado
0 siblings, 0 replies; 8+ messages in thread
From: Luis Machado @ 2013-06-06 15:47 UTC (permalink / raw)
To: Nicolas Blanc; +Cc: gdb-patches, palves, tromey, eliz, yao, lgustavo, dje
Thanks.
On 06/05/2013 09:07 PM, Nicolas Blanc wrote:
> This test exercises the commands 'add-symbol-file'
> and 'remove-symbol-file'.
>
> 2013-04-04 Nicolas Blanc <nicolas.blanc@intel.com>
>
> gdb/testsuite
> * gdb.base/sym-file-lib.c: New file.
> * gdb.base/sym-file-lib.c: New file.
> * gdb.base/sym-file.exp: New file.
>
> Signed-off-by: Nicolas Blanc <nicolas.blanc@intel.com>
> ---
> gdb/testsuite/gdb.base/sym-file-lib.c | 19 ++
> gdb/testsuite/gdb.base/sym-file-main.c | 365 ++++++++++++++++++++++++++++++++
> gdb/testsuite/gdb.base/sym-file.exp | 143 +++++++++++++
> 3 files changed, 527 insertions(+), 0 deletions(-)
> create mode 100644 gdb/testsuite/gdb.base/sym-file-lib.c
> create mode 100644 gdb/testsuite/gdb.base/sym-file-main.c
> create mode 100644 gdb/testsuite/gdb.base/sym-file.exp
>
> diff --git a/gdb/testsuite/gdb.base/sym-file-lib.c b/gdb/testsuite/gdb.base/sym-file-lib.c
> new file mode 100644
> index 0000000..f9faf8a
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/sym-file-lib.c
> @@ -0,0 +1,19 @@
> +/* 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/>.
> +*/
> +
> +extern int bar () { return 1; } /* gdb break at bar */
> +
> +extern int foo (int a) { return a; } /* gdb break at foo */
> +
> diff --git a/gdb/testsuite/gdb.base/sym-file-main.c b/gdb/testsuite/gdb.base/sym-file-main.c
> new file mode 100644
> index 0000000..f692ec5
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/sym-file-main.c
> @@ -0,0 +1,365 @@
> +/* 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 <fcntl.h>
> +#include </usr/include/elf.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <sys/mman.h>
> +
> +#ifdef TARGET_LP64
> +typedef Elf64_Phdr Elf_Phdr;
> +typedef Elf64_Ehdr Elf_Ehdr;
> +typedef Elf64_Shdr Elf_Shdr;
> +typedef Elf64_Sym Elf_Sym;
> +typedef Elf64_Word Elf_Word;
> +
> +unsigned char inline elf_st_type (unsigned char st_info)
> +{
> + return ELF64_ST_TYPE (st_info);
> +}
> +#elif defined TARGET_ILP32
> +typedef Elf32_Phdr Elf_Phdr;
> +typedef Elf32_Ehdr Elf_Ehdr;
> +typedef Elf32_Shdr Elf_Shdr;
> +typedef Elf32_Sym Elf_Sym;
> +typedef Elf32_Word Elf_Word;
> +
> +unsigned char inline elf_st_type (unsigned char st_info)
> +{
> + return ELF32_ST_TYPE (st_info);
> +}
> +#endif
> +
> +void gdb_add_symbol_file (void* addr, const char* file)
> +{
> + return;
> +}
> +
> +void gdb_remove_symbol_file (void* addr)
> +{
> + return;
> +}
> +
> +struct segment
> +{
> + char* mapped_addr;
> + Elf_Phdr* phdr;
> + struct segment* next;
> +};
> +
> +/* Load a program segment. */
> +
> +struct segment* load (char * addr, Elf_Phdr* phdr, struct segment* tail_seg)
> +{
> + /* For the sake of simplicity all operations are permitted. */
> + unsigned perm = PROT_READ | PROT_WRITE | PROT_EXEC;
> +
> + char* mapped_addr = (char*) mmap ((void*) phdr->p_vaddr,
> + phdr->p_memsz, perm,
> + MAP_ANONYMOUS | MAP_PRIVATE,
> + -1, 0);
> +
> + void * from = (void*) (addr + phdr->p_offset);
> + void * to = (void*) mapped_addr;
> +
> + memcpy (to, from, phdr->p_filesz);
> +
> + struct segment* seg = (struct segment*) malloc (sizeof (struct segment));
> +
> + if (seg == 0)
> + return 0;
> +
> + seg->mapped_addr = mapped_addr;
> + seg->phdr = phdr;
> + seg->next = 0;
> +
> + if (tail_seg != 0)
> + tail_seg->next = seg;
> +
> + return seg;
> +}
> +
> +/* Load a shared library without calling the standard loader. */
> +
> +int load_shlib (const char *file, Elf_Ehdr **ehdr_out, struct segment **seg_out)
> +{
> + unsigned i = 0;
> +
> + /* Map the lib in memory for reading. */
> + int fd = open (file, O_RDONLY);
> + if (fd < 0)
> + {
> + perror ("fopen failed.");
> + return -1;
> + }
> +
> + off_t fsize = lseek (fd, 0, SEEK_END);
> +
> + if (fsize < 0)
> + {
> + perror ("lseek failed.");
> + return -1;
> + }
> +
> + char* addr = (char*) mmap (NULL, fsize, PROT_READ, MAP_PRIVATE, fd, 0);
> + if (addr == (char*) -1)
> + {
> + perror ("mmap failed.");
> + return -1;
> + }
> +
> + /* Check if the lib is an ELF file. */
> + Elf_Ehdr* ehdr = (Elf_Ehdr*) addr;
> + if (ehdr->e_ident[EI_MAG0] != ELFMAG0
> + || ehdr->e_ident[EI_MAG1] != ELFMAG1
> + || ehdr->e_ident[EI_MAG2] != ELFMAG2
> + || ehdr->e_ident[EI_MAG3] != ELFMAG3)
> + {
> + printf ("Not an ELF file: %x\n", ehdr->e_ident[EI_MAG0]);
> + return -1;
> + }
> +
> + if (ehdr->e_ident[EI_CLASS] == ELFCLASS32)
> + {
> + if (sizeof (int*) != 4)
> + {
> + printf ("Architecture mismatch.");
> + return -1;
> + }
> + }
> + else if (ehdr->e_ident[EI_CLASS] == ELFCLASS64)
> + {
> + if (sizeof (int*) != 8)
> + {
> + printf ("Architecture mismatch.");
> + return -1;
> + }
> + }
> +
> + /* Load the program segments. For the sake of simplicity
> + assume that no reallocation is needed. */
> + Elf_Phdr* phdr = (Elf_Phdr*) (addr + ehdr->e_phoff);
> + struct segment* head_seg = 0;
> + struct segment* tail_seg = 0;
> + for (i=0; i < ehdr->e_phnum; i++, phdr++)
> + {
> + if (phdr->p_type == PT_LOAD)
> + {
> + struct segment* next_seg = load (addr, phdr, tail_seg);
> + if (next_seg == 0)
> + continue;
> + tail_seg = next_seg;
> + if (head_seg == 0)
> + head_seg = next_seg;
> + }
> + }
> + *ehdr_out = ehdr;
> + *seg_out = head_seg;
> + return 0;
> +}
> +
> +/* Return the section-header table. */
> +
> +Elf_Shdr* find_shdrtab (Elf_Ehdr *ehdr)
> +{
> + return (Elf_Shdr*) (((char*) ehdr) + ehdr->e_shoff);
> +}
> +
> +/* Return the string table of the section headers. */
> +
> +const char* find_shstrtab (Elf_Ehdr *ehdr, unsigned *size)
> +{
> + const Elf_Shdr *shdr = find_shdrtab (ehdr);
> +
> + if (ehdr->e_shnum <= ehdr->e_shstrndx)
> + {
> + printf ("The index of the string table is corrupt.");
> + return NULL;
> + }
> + const Elf_Shdr* shstr = &shdr[ehdr->e_shstrndx];
> + *size = shstr->sh_size;
> + return ((const char*) ehdr) + shstr->sh_offset;
> +}
> +
> +/* Return the string table named SECTION. */
> +
> +const char* find_strtab (Elf_Ehdr *ehdr,
> + const char* shstrtab, unsigned shstrtab_size,
> + const char* section, unsigned *strtab_size)
> +{
> + const Elf_Shdr* shdr = find_shdrtab (ehdr);
> + unsigned i = 0;
> + for (i=0; i < ehdr->e_shnum; i++)
> + {
> + Elf_Word name = shdr[i].sh_name;
> + if (shdr[i].sh_type == SHT_STRTAB && name <= shstrtab_size
> + && strcmp ((const char*) &shstrtab[name], section) == 0)
> + {
> + *strtab_size = shdr[i].sh_size;
> + return ((const char*) ehdr) + shdr[i].sh_offset;
> + }
> +
> + }
> + return NULL;
> +}
> +
> +/* Return the section header named SECTION. */
> +
> +Elf_Shdr* find_shdr (Elf_Ehdr* ehdr, const char *section,
> + const char *shstrtab, unsigned shstrtab_size)
> +{
> + Elf_Shdr *shdr = find_shdrtab (ehdr);
> + unsigned i = 0;
> + for (i=0; i < ehdr->e_shnum; i++)
> + {
> + Elf_Word name = shdr[i].sh_name;
> + if (name <= shstrtab_size)
> + {
> + if (strcmp ((const char*) &shstrtab[name], section) == 0)
> + return &shdr[i];
> + }
> +
> + }
> + return NULL;
> +}
> +
> +/* Return the symbol table. */
> +
> +Elf_Sym* find_symtab (Elf_Ehdr* ehdr, unsigned *symtab_size)
> +{
> + unsigned i = 0;
> + const Elf_Shdr *shdr = find_shdrtab (ehdr);
> + for (i=0; i < ehdr->e_shnum; i++)
> + {
> + if (shdr[i].sh_type == SHT_SYMTAB)
> + {
> + *symtab_size = shdr[i].sh_size / sizeof (Elf_Sym);
> + return (Elf_Sym*) (((const char*) ehdr) + shdr[i].sh_offset);
> + }
> + }
> + return NULL;
> +}
> +
> +/* Lookup the offset of FUNC. */
> +
> +int lookup_function (const char *func,
> + Elf_Sym *symtab, unsigned symtab_size,
> + const char *strtab, unsigned strtab_size,
> + unsigned *offset)
> +{
> + unsigned i = 0;
> + for (i=0; i < symtab_size; i++)
> + {
> + Elf_Sym* sym = &symtab[i];
> +
> + if (elf_st_type (sym->st_info) != STT_FUNC)
> + continue;
> +
> + if (sym->st_name < strtab_size)
> + {
> + const char* name = &strtab[sym->st_name];
> + if (strcmp (name, func) == 0)
> + {
> + *offset = (unsigned) sym->st_value;
> + return 0;
> + }
> + }
> + }
> +
> + return -1;
> +}
> +
> +/* Load a shared library without relying on the standard
> + loader to test GDB's commands for adding and removing
> + symbol files at runtime. */
> +
> +int main (int argc, const char* argv[])
> +{
> + const char *file = SHLIB_NAME;
> +
> + Elf_Ehdr *ehdr = 0;
> + struct segment *head_seg = 0;
> +
> + if (load_shlib (file, &ehdr, &head_seg) != 0)
> + return -1;
> +
> + /* Get the string table for the section headers. */
> + unsigned shstrtab_size = 0;
> + const char* shstrtab = find_shstrtab (ehdr, &shstrtab_size);
> +
> + if (shstrtab == NULL)
> + return -1;
> +
> + /* Get the text section. */
> + Elf_Shdr* text = find_shdr (ehdr, ".text", shstrtab, shstrtab_size);
> + if (text == NULL)
> + return -1;
> +
> + char* base_addr = head_seg->mapped_addr + text->sh_offset;
> +
> + /* Notify GDB to add the symbol file. */
> + gdb_add_symbol_file (base_addr, file);
> +
> + /* Get the string table for the symbols. */
> + unsigned strtab_size = 0;
> + const char* strtab = find_strtab (ehdr, shstrtab, shstrtab_size,
> + ".strtab", &strtab_size);
> + if (strtab == NULL)
> + {
> + printf (".strtab not found.");
> + return -1;
> + }
> +
> + /* Get the symbol table. */
> + unsigned symtab_size = 0;
> + Elf_Sym* symtab = find_symtab (ehdr, &symtab_size);
> + if (symtab == NULL)
> + {
> + printf ("symtab not found.");
> + return -1;
> + }
> +
> + /* Call bar from SHLIB_NAME. */
> + unsigned bar_offset = 0;
> + if (lookup_function ("bar",
> + symtab, symtab_size,
> + strtab, strtab_size,
> + &bar_offset) != 0)
> + return -1;
> +
> + int (*pbar) () = (int (*) ()) (head_seg->mapped_addr + bar_offset);
> +
> + int value1 = (*pbar) ();
> +
> + /* Call foo from SHLIB_NAME. */
> + unsigned foo_offset = 0;
> + if (lookup_function ("foo",
> + symtab, symtab_size,
> + strtab, strtab_size,
> + &foo_offset) != 0)
> + return -1;
> +
> + int (*pfoo) (int) = (int (*) (int)) (head_seg->mapped_addr + foo_offset);
> +
> + int value2 = (*pfoo) (2);
> +
> + /* Notify GDB to remove the symbol file. */
> + gdb_remove_symbol_file (base_addr);
> +
> + return 0;
> +}
> +
> diff --git a/gdb/testsuite/gdb.base/sym-file.exp b/gdb/testsuite/gdb.base/sym-file.exp
> new file mode 100644
> index 0000000..567eb97
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/sym-file.exp
> @@ -0,0 +1,143 @@
> +# 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/>. */
> +
> +# Test adding and removing a symbol file dynamically:
> +# 1) Run to gdb_add_symbol_file in $srcfile.
> +# 2) Set a pending breakpoint at bar in $libsrc.
> +# 3) Load $shlib_name using 'add-symbol-file'.
> +# 4) Continue to bar in $libsrc.
> +# 5) Set a breakpiont at foo in $librc.
> +# 6) Continue to foo in $libsrc.
> +# 7) Set a breakpoint at gdb_remove_symbol_file.
> +# 8) Continue to gdb_remove_symbol_file in $srcfile.
> +# 9) Remove $shlib_name using 'remove-symbol-file'.
> +# 10) Check that the breakpoints at foo and bar are pending.
> +# 11) Check that the execution can continue without error.
> +
> +if [skip_shlib_tests] {
> + return 0
> +}
> +
> +if [is_remote target] {
> + return 0
> +}
> +
> +set target_size TARGET_UNKNOWN
> +if [is_lp64_target] {
> + set target_size TARGET_LP64
> +} elseif [is_ilp32_target] {
> + set target_size TARGET_ILP32
> +} else {
> + return 0
> +}
> +
> +set testfile sym-file.exp
> +set mainfile sym-file-main
> +set libfile sym-file-lib
> +set srcfile ${mainfile}.c
> +set libsrc "${srcdir}/${subdir}/${libfile}.c"
> +set libname "${libfile}.so"
> +set shlib_name "${objdir}/${subdir}/${libname}"
> +set libobj "${objdir}/${subdir}/${libname}"
> +set exec_opts [list debug "additional_flags=-D$target_size\
> + -DSHLIB_NAME\\=\"$shlib_name\""]
> +
> +if [get_compiler_info] {
> + return -1
> +}
> +
> +if { [gdb_compile_shlib $libsrc $libobj {debug}] != "" } {
> + untested ${testfile}
> + return
> +}
> +
> +if { [prepare_for_testing ${testfile} ${mainfile} ${srcfile} $exec_opts] } {
> + return
> +}
> +
> +# 1) Run to GDB_ADD_SYMBOl_FILE in $srcfile for adding
> +# $shlib_name.
> +set result [runto gdb_add_symbol_file]
> +if { !$result } then {
> + return
> +}
> +
> +# 2) Set a pending breakpoint at bar in $libsrc.
> +set result [gdb_breakpoint bar allow-pending]
> +if { !$result } then {
> + return
> +}
> +
> +# 3) Add $shlib_name using 'add-symbol-file'.
> +set result [gdb_test "add-symbol-file ${shlib_name} addr" \
> + "Reading symbols from .*${shlib_name}\\.\\.\\.done\\." \
> + "add-symbol-file ${shlib_name}.*" \
> + "add symbol table from file \".*${shlib_name}\"\
> + at.*\\(y or n\\) " \
> + "y"]
> +if { $result != 0 } then {
> + return
> +}
> +
> +# 4) Continue to bar in $libsrc to ensure that the breakpoint
> +# was bound correctly after adding $shilb_name.
> +set lnum_bar [gdb_get_line_number "break at bar" $libsrc]
> +gdb_continue_to_breakpoint bar ".*$libfile\\.c:$lnum_bar.*"
> +
> +# 5) Set a breakpoint at foo in $libsrc.
> +set result [gdb_breakpoint foo]
> +if { !$result } then {
> + return
> +}
> +
> +# 6) Continue to foo in $libsrc to ensure that the breakpoint
> +# was bound correctly.
> +set lnum_foo [gdb_get_line_number "break at foo" $libsrc]
> +gdb_continue_to_breakpoint foo ".*$libfile\\.c:$lnum_foo.*"
> +
> +# 7) Set a breakpint at gdb_remove_symbol_file in $srcfile for
> +# removing $shlib_name.
> +set result [gdb_breakpoint gdb_remove_symbol_file]
> +if { !$result } then {
> + return
> +}
> +
> +# 8) Continue to gdb_remove_symbol_file in $srcfile.
> +gdb_continue_to_breakpoint gdb_remove_symbol_file
> +
> +# 9) Remove $shlib_name using 'remove-symbol-file'.
> +set result [gdb_test "remove-symbol-file -a addr" \
> + ""\
> + "remove-symbol-file -a addr" \
> + "Remove symbol table from file \".*${shlib_name}\"\\?\
> +.*\\(y or n\\) " \
> + "y"]
> +if { $result != 0 } then {
> + return
> +}
> +
> +# 10) Check that the breakpoints at foo and bar are pending after removing
> +# $shlib_name.
> +gdb_test "info breakpoints 2" \
> + ".*PENDING.*" \
> + "check if Breakpoint 2 is pending."
> +
> +gdb_test "info breakpoints 3" \
> + ".*PENDING.*" \
> + "check if Breakpoint 3 is pending."
> +
> +# 11) Check that the execution can continue without error.
> +gdb_continue_to_end
> +
>
I don't have comment on this one.
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [patch v6 3/3] Documentation for the remove-symbol-file command.
2013-06-05 19:08 ` [patch v6 3/3] Documentation for the remove-symbol-file command Nicolas Blanc
@ 2013-06-06 15:49 ` Luis Machado
2013-06-06 16:17 ` Eli Zaretskii
0 siblings, 1 reply; 8+ messages in thread
From: Luis Machado @ 2013-06-06 15:49 UTC (permalink / raw)
To: Nicolas Blanc; +Cc: gdb-patches, palves, tromey, eliz, yao, dje
Thanks.
On 06/05/2013 09:07 PM, Nicolas Blanc wrote:
> 2013-04-05 Nicolas Blanc <nicolas.blanc@intel.com>
>
> * NEWS: Add description of the remove-symbol-file command.
> gdb/doc
> * gdb.texinfo (Commands to Specify Files): Add description
> of the remove-symbol-file command.
>
> Signed-off-by: Nicolas Blanc <nicolas.blanc@intel.com>
> ---
> gdb/NEWS | 6 ++++++
> gdb/doc/gdb.texinfo | 26 ++++++++++++++++++++++++--
> 2 files changed, 30 insertions(+), 2 deletions(-)
>
> diff --git a/gdb/NEWS b/gdb/NEWS
> index eea9917..311a164 100644
> --- a/gdb/NEWS
> +++ b/gdb/NEWS
> @@ -31,6 +31,12 @@ maint set|show per-command time
> maint set|show per-command symtab
> Enable display of per-command gdb resource usage.
>
> +remove-symbol-file FILENAME
> +remove-symbol-file -a ADDRESS
> + Remove a symbol file added via add-symbol-file. The file to remove
> + can be identified by its filename or by an address pointing inside
> + one of its sections.
> +
I'd rewrite this one to read a little better. Eli may have a better
suggestion.
Something like this?
Remove a symbol file added via add-symbol-file. The symbol file to
remove can be identified by its filename or by an address that lies
within the boundaries of this symbol file in memory.
> * New options
>
> set remote trace-status-packet
> diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
> index e9b6eae..222d4bd 100644
> --- a/gdb/doc/gdb.texinfo
> +++ b/gdb/doc/gdb.texinfo
> @@ -16511,8 +16511,9 @@ section name and base address for that section. You can specify any
> The symbol table of the file @var{filename} is added to the symbol table
> originally read with the @code{symbol-file} command. You can use the
> @code{add-symbol-file} command any number of times; the new symbol data
> -thus read keeps adding to the old. To discard all old symbol data
> -instead, use the @code{symbol-file} command without any arguments.
> +thus read keeps adding to the old.
> +
> +Changes can be reverted using the command @code{remove-symbol-file}.
>
> @cindex relocatable object files, reading symbols from
> @cindex object files, relocatable, reading symbols from
> @@ -16550,6 +16551,27 @@ way.
>
> @code{add-symbol-file} does not repeat if you press @key{RET} after using it.
>
> +@kindex remove-symbol-file
> +@item remove-symbol-file @var{filename}
> +@item remove-symbol-file -a @var{address}
> +Remove a symbol file added via the @code{add-symbol-file} command. The
> +file to remove can be identified by its filename or by an address pointing
> +inside one of its sections. Example:
Same as above?
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [patch v6 3/3] Documentation for the remove-symbol-file command.
2013-06-06 15:49 ` Luis Machado
@ 2013-06-06 16:17 ` Eli Zaretskii
0 siblings, 0 replies; 8+ messages in thread
From: Eli Zaretskii @ 2013-06-06 16:17 UTC (permalink / raw)
To: lgustavo; +Cc: nicolas.blanc, gdb-patches, palves, tromey, yao, dje
> Date: Thu, 06 Jun 2013 17:49:28 +0200
> From: Luis Machado <lgustavo@codesourcery.com>
> CC: gdb-patches@sourceware.org, palves@redhat.com, tromey@redhat.com,
> eliz@gnu.org, yao@codesourcery.com, dje@google.com
>
> > +remove-symbol-file FILENAME
> > +remove-symbol-file -a ADDRESS
> > + Remove a symbol file added via add-symbol-file. The file to remove
> > + can be identified by its filename or by an address pointing inside
> > + one of its sections.
> > +
>
> I'd rewrite this one to read a little better. Eli may have a better
> suggestion.
>
> Something like this?
>
> Remove a symbol file added via add-symbol-file. The symbol file to
> remove can be identified by its filename or by an address that lies
> within the boundaries of this symbol file in memory.
These two variants seem to have different semantics.
> > +@kindex remove-symbol-file
> > +@item remove-symbol-file @var{filename}
> > +@item remove-symbol-file -a @var{address}
> > +Remove a symbol file added via the @code{add-symbol-file} command. The
> > +file to remove can be identified by its filename or by an address pointing
> > +inside one of its sections. Example:
>
> Same as above?
"filename" and "address" should be in @var.
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2013-06-06 16:17 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-06-05 19:08 [patch v6 0/3] remove-symbol-file Nicolas Blanc
2013-06-05 19:08 ` [patch v6 3/3] Documentation for the remove-symbol-file command Nicolas Blanc
2013-06-06 15:49 ` Luis Machado
2013-06-06 16:17 ` Eli Zaretskii
2013-06-05 19:08 ` [patch v6 1/3] New " Nicolas Blanc
2013-06-06 15:44 ` Luis Machado
2013-06-05 19:08 ` [patch v6 2/3] Test adding and removing a symbol file at runtime Nicolas Blanc
2013-06-06 15:47 ` Luis Machado
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox