From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 7392 invoked by alias); 29 May 2013 09:13:47 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Received: (qmail 7293 invoked by uid 89); 29 May 2013 09:13:46 -0000 X-Spam-SWARE-Status: No, score=-5.6 required=5.0 tests=AWL,BAYES_00,KAM_STOCKGEN,KHOP_RCVD_UNTRUST,KHOP_THREADED,RCVD_IN_HOSTKARMA_W,RCVD_IN_HOSTKARMA_WL,RP_MATCHES_RCVD,TW_CP,TW_DR autolearn=ham version=3.3.1 Received: from mga03.intel.com (HELO mga03.intel.com) (143.182.124.21) by sourceware.org (qpsmtpd/0.84/v0.84-167-ge50287c) with ESMTP; Wed, 29 May 2013 09:13:43 +0000 Received: from azsmga002.ch.intel.com ([10.2.17.35]) by azsmga101.ch.intel.com with ESMTP; 29 May 2013 02:13:39 -0700 X-ExtLoop1: 1 Received: from irvmail001.ir.intel.com ([163.33.26.43]) by AZSMGA002.ch.intel.com with ESMTP; 29 May 2013 02:13:37 -0700 Received: from ulslx001.iul.intel.com (ulslx001.iul.intel.com [172.28.207.63]) by irvmail001.ir.intel.com (8.14.3/8.13.6/MailSET/Hub) with ESMTP id r4T9Da4E011439; Wed, 29 May 2013 10:13:36 +0100 Received: from ulslx001.iul.intel.com (localhost [127.0.0.1]) by ulslx001.iul.intel.com with ESMTP id r4T9DZmL014342; Wed, 29 May 2013 11:13:35 +0200 Received: (from nblanc@localhost) by ulslx001.iul.intel.com with id r4T9DZEW014338; Wed, 29 May 2013 11:13:35 +0200 From: Nicolas Blanc To: gdb-patches@sourceware.org, palves@redhat.com, tromey@redhat.com, eliz@gnu.org, yao@codesourcery.com Cc: nicolas.blanc@intel.com Subject: [patch v4 2/3] Test adding and removing a symbol file at runtime. Date: Wed, 29 May 2013 09:13:00 -0000 Message-Id: <1369818805-14288-3-git-send-email-nicolas.blanc@intel.com> In-Reply-To: <1369818805-14288-1-git-send-email-nicolas.blanc@intel.com> References: <1369818805-14288-1-git-send-email-nicolas.blanc@intel.com> X-SW-Source: 2013-05/txt/msg00980.txt.bz2 This test exercises the commands 'add-symbol-file' and 'remove-symbol-file'. 2013-04-04 Nicolas Blanc 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 --- gdb/testsuite/gdb.base/sym-file-lib.c | 21 ++ gdb/testsuite/gdb.base/sym-file-main.c | 377 ++++++++++++++++++++++++++++++++ gdb/testsuite/gdb.base/sym-file.exp | 160 ++++++++++++++ 3 files changed, 558 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..32426b9 --- /dev/null +++ b/gdb/testsuite/gdb.base/sym-file-lib.c @@ -0,0 +1,21 @@ +/* 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 . +*/ + + +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..01adf2c --- /dev/null +++ b/gdb/testsuite/gdb.base/sym-file-main.c @@ -0,0 +1,377 @@ +/* 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 . +*/ + +#include +#include +#include +#include +#include +#include + +#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; +} + + +int main (int argc, const char* argv[]) +{ + /* Load a shared library without relying on the standard + loader to test GDB's commands for adding and removing + symbol files at runtime. */ + + 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..88392c6 --- /dev/null +++ b/gdb/testsuite/gdb.base/sym-file.exp @@ -0,0 +1,160 @@ +# 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 . */ + + +# Test adding and removing a symbol file dynamically: +# 1) Load the main executable. +# 2) Run to GDB_ADD_SYMBOl_FILE in $srcfile. +# 3) Set a pending breakpoint at BAR in $libsrc. +# 4) Load $shlib_name using 'add-symbol-file'. +# 5) Continue to BAR in $libsrc. +# 6) Set a breakpiont at FOO in $librc. +# 7) Continue to FOO in $libsrc. +# 8) Set a breakpoint at GDB_REMOVE_SYMBOL_FILE. +# 9) Continue to GDB_REMOVE_SYMBOL_FILE in $srcfile. +# 10) Remove $shlib_name using 'remove-symbol-file'. +# 11) Check that the breakpoints at FOO and BAR are pending. +# 12) 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-main +set libfile sym-file-lib +set srcfile ${testfile}.c +set binfile ${objdir}/${subdir}/${testfile} + +set libsrc "${srcdir}/${subdir}/${libfile}.c" +set libname "${libfile}.so" +set shlib_name "${objdir}/${subdir}/${libname}" +set libobj "${objdir}/${subdir}/${libname}" +set execsrc "${srcdir}/${subdir}/${srcfile}" +set exec_opts [list debug "additional_flags=-D$target_size -DSHLIB_NAME\\=\"$shlib_name\""] + +remote_exec build "rm -f ${binfile}" + +if [get_compiler_info] { + return -1 +} + + +if { [gdb_compile_shlib $libsrc $libobj {debug}] != "" + || [gdb_compile $execsrc ${binfile} executable $exec_opts] != "" } { + untested ${testfile} + return +} + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir + +# 1) Load the main executable. +set result [gdb_load ${binfile}] +if { $result != 0 } then { + return +} + +# 2) Run to GDB_ADD_SYMBOl_FILE in $srcfile for adding +# $shlib_name. +set result [runto gdb_add_symbol_file] +if { !$result } then { + return +} + +# 3) Set a pending breakpoint at BAR in $libsrc. +set result [gdb_breakpoint bar allow-pending] +if { !$result } then { + return +} + +# 4) 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 +} + +# 5) 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.*" + +# 6) Set a breakpoint at FOO in $libsrc. +set result [gdb_breakpoint foo] +if { !$result } then { + return +} + +# 7) 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.*" + + +# 8) 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 +} + +# 9) Continue to GDB_REMOVE_SYMBOL_FILE in $srcfile. +gdb_continue_to_breakpoint gdb_remove_symbol_file + +# 10) Remove $shlib_name using 'remove-symbol-file'. +set result [gdb_test "remove-symbol-file addr" \ + "" \ + "remove-symbol-file addr" \ + "Remove symbol table from file \".*${shlib_name}\"\ + at.*\\(y or n\\) " \ + "y"] +if { $result != 0 } then { + return +} + +# 11) 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." + +# 12) Check that the execution can continue without error. +gdb_continue_to_end + + -- 1.7.6.5