From patchwork Thu Oct 17 10:03:12 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Raza, Saqlain" X-Patchwork-Id: 35087 Received: (qmail 7059 invoked by alias); 17 Oct 2019 10:03:28 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 6999 invoked by uid 89); 17 Oct 2019 10:03:27 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-21.1 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_SHORT, KAM_STOCKGEN autolearn=ham version=3.3.1 spammy=sk:interpr, 1101, sake, Architecture X-HELO: esa3.mentor.iphmx.com Received: from esa3.mentor.iphmx.com (HELO esa3.mentor.iphmx.com) (68.232.137.180) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Thu, 17 Oct 2019 10:03:23 +0000 IronPort-SDR: g3HYBJBv4NBq80gcFblQ4Kp15EF3AJEvyooXU6XrDeBv4a732YXpolX2HOP6u4ghjtJJlmr0/i iw1Kg9sJcp2NrrEYoWodpz2wS19hMrovU5njsjpl05FyBPC4QuVRiseYqeXnHWQj66VG+rLzOK 67NmdYVa+NueOD/AGxReFvwm7L/MRsLh8FbTf5mZA3hPIwon/7KDCJ4e/uKVuHxKUJB6r3LtYK gq59Rh6AusO1uH6Nd0zFLuV+gsNre23bBYjDvnZvrK/p/676bKgL9xvT7ENX8qEU0ggSHO+/Uk AEo= Received: from orw-gwy-01-in.mentorg.com ([192.94.38.165]) by esa3.mentor.iphmx.com with ESMTP; 17 Oct 2019 02:03:22 -0800 IronPort-SDR: 5oRhRm6NR1AGREyuJRDFQV/aBex/4B2+JfWTonX3RM+Fprva++BkrJMrX4TXhLq+ENdm+9bNEY 0H7j5t1oNotHf53oqluXsX0ntav9dAc9JLCFCqP5dWGVcfrOmHEtmcg/gP7Xwi1D7Tn7ieHnyq DJ2xc0JnSG3QZHD2THGaDsQDhOzenVYdIRuIwWbbDOP+bxEDOZi54rska2GwlIHkfiBxbUQ9Ja 1AEXOaMD/F6Fjk7GfFuJdytDCxTpFUbgsFO7l8Qy0M/fUMOp2HY2k6bO0oAdPUns3nrjzhFhrJ eYw= From: "Raza, Saqlain" To: CC: , "Raza, Saqlain" , Subject: [PATCH 2/2] Testsuite for varobj updation after symbol removal Date: Thu, 17 Oct 2019 03:03:12 -0700 Message-ID: <1571306592-24472-3-git-send-email-Saqlain_Raza@mentor.com> In-Reply-To: <1571306592-24472-1-git-send-email-Saqlain_Raza@mentor.com> References: <1571306592-24472-1-git-send-email-Saqlain_Raza@mentor.com> Return-Path: sraza@mentor.com MIME-Version: 1.0 This patch provides testcases for variable object updation after removing symbols. Test programs are same as used for testing remove-symbol-file command in gdb.base. sym-file-main.c is modified to just add a global variable for which varible object is created in testsuite. Testing: ======= This is tested for x86 and arm-none-linux-gnueabi targets using both simulator and real boards. 2019-10-17 Saqlain Raza Taimoor Mirza * gdb.mi/mi-var-invalidate.exp: Add tests to check global variable object change list is correct when its value is updated before removing symbols. * gdb.mi/sym-file-loader.c: New file. * gdb.mi/sym-file-loader.h: New file. * gdb.mi/sym-file-main.c: New file. * gdb.mi/sym-file-lib.c: New file. Signed-off-by: Raza, Saqlain --- gdb/testsuite/ChangeLog | 11 + gdb/testsuite/gdb.mi/mi-var-invalidate.exp | 68 ++++++ gdb/testsuite/gdb.mi/sym-file-lib.c | 28 +++ gdb/testsuite/gdb.mi/sym-file-loader.c | 355 +++++++++++++++++++++++++++++ gdb/testsuite/gdb.mi/sym-file-loader.h | 101 ++++++++ gdb/testsuite/gdb.mi/sym-file-main.c | 86 +++++++ 6 files changed, 649 insertions(+) create mode 100644 gdb/testsuite/gdb.mi/sym-file-lib.c create mode 100644 gdb/testsuite/gdb.mi/sym-file-loader.c create mode 100644 gdb/testsuite/gdb.mi/sym-file-loader.h create mode 100644 gdb/testsuite/gdb.mi/sym-file-main.c diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 395a3cc..82c3a57 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,14 @@ +2019-10-17 Saqlain Raza + Taimoor Mirza + + * gdb.mi/mi-var-invalidate.exp: Add tests to check global + variable object change list is correct when its value is + updated before removing symbols. + * gdb.mi/sym-file-loader.c: New file. + * gdb.mi/sym-file-loader.h: New file. + * gdb.mi/sym-file-main.c: New file. + * gdb.mi/sym-file-lib.c: New file. + 2019-10-16 Andrew Burgess * gdb.fortran/module.exp: Extend with 'info variables' test. diff --git a/gdb/testsuite/gdb.mi/mi-var-invalidate.exp b/gdb/testsuite/gdb.mi/mi-var-invalidate.exp index e390968..b06e713 100644 --- a/gdb/testsuite/gdb.mi/mi-var-invalidate.exp +++ b/gdb/testsuite/gdb.mi/mi-var-invalidate.exp @@ -120,6 +120,74 @@ mi_gdb_test "-var-update global_simple" \ mi_gdb_test "-var-info-type global_simple" \ "\\^done,type=\"\"" \ "no type for invalid variable global_simple" +# Test varobj updation after removing symbols. + +#if {[skip_shlib_tests]} { +# 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 main_basename sym-file-main +set loader_basename sym-file-loader +set lib_basename sym-file-lib + +standard_testfile $main_basename.c $loader_basename.c $lib_basename.c + +set libsrc "${srcdir}/${subdir}/${srcfile3}" +set test_bin_name "sym-test-file" +set test_bin [standard_output_file ${test_bin_name}] +set shlib_name [standard_output_file ${lib_basename}.so] +set exec_opts [list debug "additional_flags= -I$srcdir/../../include/ \ +-D$target_size -DSHLIB_NAME\\=\"$shlib_name\""] + +if [get_compiler_info] { + return -1 +} + +if {[gdb_compile_shlib $libsrc $shlib_name {debug}] != ""} { + untested ${testfile} + return -1 +} + +if {[build_executable $testfile $test_bin "$srcfile $srcfile2" $exec_opts]} { + return -1 +} + +mi_delete_breakpoints +mi_gdb_load ${test_bin} + +# Create varobj for count variable. +mi_create_varobj var_count count "Create global varobj for count" + +# Run to GDB_ADD_SYMBOl_FILE in $srcfile for adding +# $shlib_name. +mi_runto gdb_add_symbol_file + +# Add $shlib_name using 'add-symbol-file'. +mi_gdb_test "-interpreter-exec console \"add-symbol-file ${shlib_name} addr\"" \ + "~\"add symbol table from file .*so.*at.*= $hex.*\\^done" \ + "add-symbol-file ${shlib_name}" + +# Continue to gdb_remove_symbol_file in $srcfile. +mi_runto gdb_remove_symbol_file + +# Remove $shlib_name using 'remove-symbol-file'. +mi_gdb_test "-interpreter-exec console \"remove-symbol-file -a addr\"" \ + ".*\\^done"\ + "remove-symbol-file test" + +# Check var_count varobj changelist is not empty. +mi_varobj_update var_count {var_count} "Update var_count" + mi_gdb_exit + return 0 mi_gdb_exit return 0 diff --git a/gdb/testsuite/gdb.mi/sym-file-lib.c b/gdb/testsuite/gdb.mi/sym-file-lib.c new file mode 100644 index 0000000..86c719c --- /dev/null +++ b/gdb/testsuite/gdb.mi/sym-file-lib.c @@ -0,0 +1,28 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2019 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.mi/sym-file-loader.c b/gdb/testsuite/gdb.mi/sym-file-loader.c new file mode 100644 index 0000000..0a3cd32 --- /dev/null +++ b/gdb/testsuite/gdb.mi/sym-file-loader.c @@ -0,0 +1,355 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2019 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 + +#include "sym-file-loader.h" + +#ifdef TARGET_LP64 + +uint8_t +elf_st_type (uint8_t st_info) +{ + return ELF64_ST_TYPE (st_info); +} + +#elif defined TARGET_ILP32 + +uint8_t +elf_st_type (uint8_t st_info) +{ + return ELF32_ST_TYPE (st_info); +} + +#endif + +/* Load a program segment. */ + +static struct segment * +load (uint8_t *addr, Elf_External_Phdr *phdr, struct segment *tail_seg) +{ + struct segment *seg = NULL; + uint8_t *mapped_addr = NULL; + void *from = NULL; + void *to = NULL; + + /* For the sake of simplicity all operations are permitted. */ + unsigned perm = PROT_READ | PROT_WRITE | PROT_EXEC; + + mapped_addr = (uint8_t *) mmap ((void *) GETADDR (phdr, p_vaddr), + GET (phdr, p_memsz), perm, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + + from = (void *) (addr + GET (phdr, p_offset)); + to = (void *) mapped_addr; + + memcpy (to, from, GET (phdr, p_filesz)); + + 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; +} + +/* Mini shared library loader. No reallocation + is performed for the sake of simplicity. */ + +int +load_shlib (const char *file, Elf_External_Ehdr **ehdr_out, + struct segment **seg_out) +{ + uint64_t i; + int fd; + off_t fsize; + uint8_t *addr; + Elf_External_Ehdr *ehdr; + Elf_External_Phdr *phdr; + struct segment *head_seg = NULL; + struct segment *tail_seg = NULL; + + /* Map the lib in memory for reading. */ + fd = open (file, O_RDONLY); + if (fd < 0) + { + perror ("fopen failed."); + return -1; + } + + fsize = lseek (fd, 0, SEEK_END); + + if (fsize < 0) + { + perror ("lseek failed."); + return -1; + } + + addr = (uint8_t *) mmap (NULL, fsize, PROT_READ, MAP_PRIVATE, fd, 0); + if (addr == (uint8_t *) -1) + { + perror ("mmap failed."); + return -1; + } + + /* Check if the lib is an ELF file. */ + ehdr = (Elf_External_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 (void *) != 4) + { + printf ("Architecture mismatch."); + return -1; + } + } + else if (ehdr->e_ident[EI_CLASS] == ELFCLASS64) + { + if (sizeof (void *) != 8) + { + printf ("Architecture mismatch."); + return -1; + } + } + + /* Load the program segments. For the sake of simplicity + assume that no reallocation is needed. */ + phdr = (Elf_External_Phdr *) (addr + GET (ehdr, e_phoff)); + for (i = 0; i < GET (ehdr, e_phnum); i++, phdr++) + { + if (GET (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_External_Shdr * +find_shdrtab (Elf_External_Ehdr *ehdr) +{ + return (Elf_External_Shdr *) (((uint8_t *) ehdr) + GET (ehdr, e_shoff)); +} + +/* Return the string table of the section headers. */ + +const char * +find_shstrtab (Elf_External_Ehdr *ehdr, uint64_t *size) +{ + const Elf_External_Shdr *shdr; + const Elf_External_Shdr *shstr; + + if (GET (ehdr, e_shnum) <= GET (ehdr, e_shstrndx)) + { + printf ("The index of the string table is corrupt."); + return NULL; + } + + shdr = find_shdrtab (ehdr); + + shstr = &shdr[GET (ehdr, e_shstrndx)]; + *size = GET (shstr, sh_size); + return ((const char *) ehdr) + GET (shstr, sh_offset); +} + +/* Return the string table named SECTION. */ + +const char * +find_strtab (Elf_External_Ehdr *ehdr, + const char *section, uint64_t *strtab_size) +{ + uint64_t shstrtab_size = 0; + const char *shstrtab; + uint64_t i; + const Elf_External_Shdr *shdr = find_shdrtab (ehdr); + + /* Get the string table of the section headers. */ + shstrtab = find_shstrtab (ehdr, &shstrtab_size); + if (shstrtab == NULL) + return NULL; + + for (i = 0; i < GET (ehdr, e_shnum); i++) + { + uint64_t name = GET (shdr + i, sh_name); + if (GET (shdr + i, sh_type) == SHT_STRTAB && name <= shstrtab_size + && strcmp ((const char *) &shstrtab[name], section) == 0) + { + *strtab_size = GET (shdr + i, sh_size); + return ((const char *) ehdr) + GET (shdr + i, sh_offset); + } + + } + return NULL; +} + +/* Return the section header named SECTION. */ + +Elf_External_Shdr * +find_shdr (Elf_External_Ehdr *ehdr, const char *section) +{ + uint64_t shstrtab_size = 0; + const char *shstrtab; + uint64_t i; + + /* Get the string table of the section headers. */ + shstrtab = find_shstrtab (ehdr, &shstrtab_size); + if (shstrtab == NULL) + return NULL; + + Elf_External_Shdr *shdr = find_shdrtab (ehdr); + for (i = 0; i < GET (ehdr, e_shnum); i++) + { + uint64_t name = GET (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_External_Sym * +find_symtab (Elf_External_Ehdr *ehdr, uint64_t *symtab_size) +{ + uint64_t i; + const Elf_External_Shdr *shdr = find_shdrtab (ehdr); + + for (i = 0; i < GET (ehdr, e_shnum); i++) + { + if (GET (shdr + i, sh_type) == SHT_SYMTAB) + { + *symtab_size = GET (shdr + i, sh_size) / sizeof (Elf_External_Sym); + return (Elf_External_Sym *) (((const char *) ehdr) + + GET (shdr + i, sh_offset)); + } + } + return NULL; +} + +/* Translate a file offset to an address in a loaded segment. */ + +int +translate_offset (uint64_t file_offset, struct segment *seg, void **addr) +{ + while (seg) + { + uint64_t p_from, p_to; + + Elf_External_Phdr *phdr = seg->phdr; + + if (phdr == NULL) + { + seg = seg->next; + continue; + } + + p_from = GET (phdr, p_offset); + p_to = p_from + GET (phdr, p_filesz); + + if (p_from <= file_offset && file_offset < p_to) + { + *addr = (void *) (seg->mapped_addr + (file_offset - p_from)); + return 0; + } + seg = seg->next; + } + + return -1; +} + +/* Lookup the address of FUNC. */ + +int +lookup_function (const char *func, + Elf_External_Ehdr *ehdr, struct segment *seg, void **addr) +{ + const char *strtab; + uint64_t strtab_size = 0; + Elf_External_Sym *symtab; + uint64_t symtab_size = 0; + uint64_t i; + + /* Get the string table for the symbols. */ + strtab = find_strtab (ehdr, ".strtab", &strtab_size); + if (strtab == NULL) + { + printf (".strtab not found."); + return -1; + } + + /* Get the symbol table. */ + symtab = find_symtab (ehdr, &symtab_size); + if (symtab == NULL) + { + printf ("symbol table not found."); + return -1; + } + + for (i = 0; i < symtab_size; i++) + { + Elf_External_Sym *sym = &symtab[i]; + + if (elf_st_type (GET (sym, st_info)) != STT_FUNC) + continue; + + if (GET (sym, st_name) < strtab_size) + { + const char *name = &strtab[GET (sym, st_name)]; + if (strcmp (name, func) == 0) + { + + uint64_t offset = GET (sym, st_value); + return translate_offset (offset, seg, addr); + } + } + } + + return -1; +} diff --git a/gdb/testsuite/gdb.mi/sym-file-loader.h b/gdb/testsuite/gdb.mi/sym-file-loader.h new file mode 100644 index 0000000..d6ebb39 --- /dev/null +++ b/gdb/testsuite/gdb.mi/sym-file-loader.h @@ -0,0 +1,101 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2019 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 . */ + +#ifndef __SYM_FILE_LOADER__ +#define __SYM_FILE_LOADER__ + +#include +#include +#include +#include + +#ifdef TARGET_LP64 + +typedef Elf64_External_Phdr Elf_External_Phdr; +typedef Elf64_External_Ehdr Elf_External_Ehdr; +typedef Elf64_External_Shdr Elf_External_Shdr; +typedef Elf64_External_Sym Elf_External_Sym; +typedef uint64_t Elf_Addr; + +#elif defined TARGET_ILP32 + +typedef Elf32_External_Phdr Elf_External_Phdr; +typedef Elf32_External_Ehdr Elf_External_Ehdr; +typedef Elf32_External_Shdr Elf_External_Shdr; +typedef Elf32_External_Sym Elf_External_Sym; +typedef uint32_t Elf_Addr; + +#endif + +#define GET(hdr, field) (\ +sizeof ((hdr)->field) == 1 ? (uint64_t) (hdr)->field[0] : \ +sizeof ((hdr)->field) == 2 ? (uint64_t) *(uint16_t *) (hdr)->field : \ +sizeof ((hdr)->field) == 4 ? (uint64_t) *(uint32_t *) (hdr)->field : \ +sizeof ((hdr)->field) == 8 ? *(uint64_t *) (hdr)->field : \ +*(uint64_t *) NULL) + +#define GETADDR(hdr, field) (\ +sizeof ((hdr)->field) == sizeof (Elf_Addr) ? *(Elf_Addr *) (hdr)->field : \ +*(Elf_Addr *) NULL) + +struct segment +{ + uint8_t *mapped_addr; + Elf_External_Phdr *phdr; + struct segment *next; +}; + +/* Mini shared library loader. No reallocation is performed + for the sake of simplicity. */ + +int +load_shlib (const char *file, Elf_External_Ehdr **ehdr_out, + struct segment **seg_out); + +/* Return the section-header table. */ + +Elf_External_Shdr *find_shdrtab (Elf_External_Ehdr *ehdr); + +/* Return the string table of the section headers. */ + +const char *find_shstrtab (Elf_External_Ehdr *ehdr, uint64_t *size); + +/* Return the string table named SECTION. */ + +const char *find_strtab (Elf_External_Ehdr *ehdr, + const char *section, uint64_t *strtab_size); + +/* Return the section header named SECTION. */ + +Elf_External_Shdr *find_shdr (Elf_External_Ehdr *ehdr, const char *section); + +/* Return the symbol table. */ + +Elf_External_Sym *find_symtab (Elf_External_Ehdr *ehdr, + uint64_t *symtab_size); + +/* Translate a file offset to an address in a loaded segment. */ + +int translate_offset (uint64_t file_offset, struct segment *seg, void **addr); + +/* Lookup the address of FUNC. */ + +int +lookup_function (const char *func, Elf_External_Ehdr* ehdr, + struct segment *seg, void **addr); + +#endif diff --git a/gdb/testsuite/gdb.mi/sym-file-main.c b/gdb/testsuite/gdb.mi/sym-file-main.c new file mode 100644 index 0000000..ecdef4e --- /dev/null +++ b/gdb/testsuite/gdb.mi/sym-file-main.c @@ -0,0 +1,86 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2019 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 "sym-file-loader.h" + +// Global variable +int count = 0; + +void +gdb_add_symbol_file (void *addr, const char *file) +{ + return; +} + +void +gdb_remove_symbol_file (void *addr) +{ + return; +} + +/* 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_External_Ehdr *ehdr = NULL; + struct segment *head_seg = NULL; + Elf_External_Shdr *text; + char *text_addr = NULL; + int (*pbar) () = NULL; + int (*pfoo) (int) = NULL; + + if (load_shlib (file, &ehdr, &head_seg) != 0) + return -1; + + /* Get the text section. */ + text = find_shdr (ehdr, ".text"); + if (text == NULL) + return -1; + + /* Notify GDB to add the symbol file. */ + if (translate_offset (GET (text, sh_offset), head_seg, (void **) &text_addr) + != 0) + return -1; + + gdb_add_symbol_file (text_addr, file); + + /* Call bar from SHLIB_NAME. */ + if (lookup_function ("bar", ehdr, head_seg, (void *) &pbar) != 0) + return -1; + + (*pbar) (); + + /* Call foo from SHLIB_NAME. */ + if (lookup_function ("foo", ehdr, head_seg, (void *) &pfoo) != 0) + return -1; + + (*pfoo) (2); + + count++; + + /* Notify GDB to remove the symbol file. */ + gdb_remove_symbol_file (text_addr); + + return 0; +}