This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
[RFC] solib for darwin
- From: Tristan Gingold <gingold at adacore dot com>
- To: gdb-patches at sourceware dot org
- Date: Wed, 3 Dec 2008 13:53:58 +0100
- Subject: [RFC] solib for darwin
Hi,
I just have added support for Darwin shared libraries and it fixes
about 80 failures.
However I was unable to add this support without slightly changing
common files.
This root issue is Darwin fat (or universal) binaries. Fat binaries
are binaries for more than one
architecture. From a BFD point of view, it's a kind of archive with
one member for each architecture.
(On Darwin the same fat executable can run on ppc or x86 provided it
has the right component).
As system libraries are fat binaries, we can't avoid this issue.
solib.c:solib_bfd_open explicitly checked that the format is a
bfd_object. As this might not be true
on Darwin, I added a new solib target which does the check. On
Darwin, it may also extract the right
binary from the fat binary.
As it is not easy to retrieve the right member from a filename,
solib.c:symbol_add_stub calls
symbol_file_add_from_bfd instead of symbol_file_add. I think this is
still a good idea not to have
2 bfd for the same file. But this also implies that the bfd must be
closed only once. So I added a new
flag, OBJF_KEEPBFD that prevent objfile.c from bfd_close-ing the bfd
of an objfile.
I still have to write ChangeLog entries and to clean-up a little bit
solib-darwin.c. But I'd like to heard
about my approach.
See below solib-darwin.[ch] and the patch against existing files.
Comments are *very* welcome.
Tristan.
Index: i386-darwin-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/i386-darwin-tdep.c,v
retrieving revision 1.1
diff -c -p -r1.1 i386-darwin-tdep.c
*** i386-darwin-tdep.c 27 Nov 2008 09:23:01 -0000 1.1
--- i386-darwin-tdep.c 3 Dec 2008 12:47:43 -0000
***************
*** 29,34 ****
--- 29,36 ----
#include "regcache.h"
#include "libbfd.h"
#include "objfiles.h"
+ #include "solib.h"
+ #include "solib-darwin.h"
#include "i387-tdep.h"
#include "i386-tdep.h"
*************** i386_darwin_init_abi (struct gdbarch_inf
*** 114,119 ****
--- 116,123 ----
tdep->sc_num_regs = 16;
tdep->jb_pc_offset = 20;
+
+ set_solib_ops (gdbarch, &darwin_so_ops);
}
static void
*************** x86_darwin_init_abi_64 (struct gdbarch_i
*** 131,136 ****
--- 135,142 ----
tdep->sc_num_regs = ARRAY_SIZE
(amd64_darwin_thread_state_reg_offset);
tdep->jb_pc_offset = 148;
+
+ set_solib_ops (gdbarch, &darwin_so_ops);
}
static enum gdb_osabi
Index: machoread.c
===================================================================
RCS file: /cvs/src/src/gdb/machoread.c,v
retrieving revision 1.1
diff -c -p -r1.1 machoread.c
*** machoread.c 27 Nov 2008 09:23:01 -0000 1.1
--- machoread.c 3 Dec 2008 12:47:43 -0000
*************** macho_symfile_read (struct objfile *objf
*** 538,544 ****
/* Get symbols from the symbol table only if the file is an
executable.
The symbol table of object files is not relocated and is
expected to
be in the executable. */
! if (bfd_get_file_flags (abfd) & EXEC_P)
{
/* Process the normal symbol table first. */
storage_needed = bfd_get_symtab_upper_bound (objfile->obfd);
--- 538,544 ----
/* Get symbols from the symbol table only if the file is an
executable.
The symbol table of object files is not relocated and is
expected to
be in the executable. */
! if (bfd_get_file_flags (abfd) & (EXEC_P | DYNAMIC))
{
/* Process the normal symbol table first. */
storage_needed = bfd_get_symtab_upper_bound (objfile->obfd);
Index: objfiles.c
===================================================================
RCS file: /cvs/src/src/gdb/objfiles.c,v
retrieving revision 1.79
diff -c -p -r1.79 objfiles.c
*** objfiles.c 5 Sep 2008 11:37:17 -0000 1.79
--- objfiles.c 3 Dec 2008 12:47:43 -0000
*************** free_objfile (struct objfile *objfile)
*** 424,430 ****
/* We always close the bfd. */
! if (objfile->obfd != NULL)
{
char *name = bfd_get_filename (objfile->obfd);
if (!bfd_close (objfile->obfd))
--- 424,430 ----
/* We always close the bfd. */
! if (objfile->obfd != NULL && !(objfile->flags & OBJF_KEEPBFD))
{
char *name = bfd_get_filename (objfile->obfd);
if (!bfd_close (objfile->obfd))
Index: objfiles.h
===================================================================
RCS file: /cvs/src/src/gdb/objfiles.h,v
retrieving revision 1.57
diff -c -p -r1.57 objfiles.h
*** objfiles.h 18 Nov 2008 21:31:26 -0000 1.57
--- objfiles.h 3 Dec 2008 12:47:43 -0000
*************** struct objfile
*** 414,419 ****
--- 414,424 ----
#define OBJF_USERLOADED (1 << 3) /* User loaded */
+ /* The bfd of this objfile is used outside of the objfile (eg by
solib).
+ Do not try to free it. */
+
+ #define OBJF_KEEPBFD (1 << 4) /* Do not delete bfd. */
+
/* The object file that the main symbol table was loaded from (e.g.
the
argument to the "symbol-file" or "file" command). */
Index: solib-frv.c
===================================================================
RCS file: /cvs/src/src/gdb/solib-frv.c,v
retrieving revision 1.23
diff -c -p -r1.23 solib-frv.c
*** solib-frv.c 19 Nov 2008 21:17:07 -0000 1.23
--- solib-frv.c 3 Dec 2008 12:47:43 -0000
*************** _initialize_frv_solib (void)
*** 1280,1285 ****
--- 1280,1286 ----
frv_so_ops.current_sos = frv_current_sos;
frv_so_ops.open_symbol_file_object = open_symbol_file_object;
frv_so_ops.in_dynsym_resolve_code = frv_in_dynsym_resolve_code;
+ frv_so_ops.check_bfd_format = solib_default_check_bfd_format;
/* Debug this file's internals. */
add_setshow_zinteger_cmd ("solib-frv", class_maintenance,
Index: solib-irix.c
===================================================================
RCS file: /cvs/src/src/gdb/solib-irix.c,v
retrieving revision 1.21
diff -c -p -r1.21 solib-irix.c
*** solib-irix.c 22 Sep 2008 15:20:08 -0000 1.21
--- solib-irix.c 3 Dec 2008 12:47:43 -0000
*************** _initialize_irix_solib (void)
*** 730,733 ****
--- 730,734 ----
irix_so_ops.current_sos = irix_current_sos;
irix_so_ops.open_symbol_file_object = irix_open_symbol_file_object;
irix_so_ops.in_dynsym_resolve_code = irix_in_dynsym_resolve_code;
+ irix_so_ops.check_bfd_format = solib_default_check_bfd_format;
}
Index: solib-null.c
===================================================================
RCS file: /cvs/src/src/gdb/solib-null.c,v
retrieving revision 1.5
diff -c -p -r1.5 solib-null.c
*** solib-null.c 1 Jan 2008 22:53:13 -0000 1.5
--- solib-null.c 3 Dec 2008 12:47:43 -0000
*************** _initialize_null_solib (void)
*** 81,86 ****
--- 81,87 ----
null_so_ops.current_sos = null_current_sos;
null_so_ops.open_symbol_file_object = null_open_symbol_file_object;
null_so_ops.in_dynsym_resolve_code = null_in_dynsym_resolve_code;
+ null_so_ops.check_bfd_format = solib_default_check_bfd_format;
/* Set current_target_so_ops to null_so_ops if not already set. */
if (current_target_so_ops == 0)
Index: solib-pa64.c
===================================================================
RCS file: /cvs/src/src/gdb/solib-pa64.c,v
retrieving revision 1.13
diff -c -p -r1.13 solib-pa64.c
*** solib-pa64.c 9 Aug 2008 18:21:59 -0000 1.13
--- solib-pa64.c 3 Dec 2008 12:47:44 -0000
*************** _initialize_pa64_solib (void)
*** 658,663 ****
--- 658,664 ----
pa64_so_ops.current_sos = pa64_current_sos;
pa64_so_ops.open_symbol_file_object = pa64_open_symbol_file_object;
pa64_so_ops.in_dynsym_resolve_code = pa64_in_dynsym_resolve_code;
+ pa64_so_ops.check_bfd_format = solib_default_check_bfd_format;
memset (&dld_cache, 0, sizeof (dld_cache));
}
Index: solib-som.c
===================================================================
RCS file: /cvs/src/src/gdb/solib-som.c,v
retrieving revision 1.17
diff -c -p -r1.17 solib-som.c
*** solib-som.c 1 Oct 2008 16:56:52 -0000 1.17
--- solib-som.c 3 Dec 2008 12:47:44 -0000
*************** _initialize_som_solib (void)
*** 804,809 ****
--- 804,810 ----
som_so_ops.current_sos = som_current_sos;
som_so_ops.open_symbol_file_object = som_open_symbol_file_object;
som_so_ops.in_dynsym_resolve_code = som_in_dynsym_resolve_code;
+ som_so_ops.check_bfd_format = solib_default_check_bfd_format;
}
void som_solib_select (struct gdbarch *gdbarch)
Index: solib-svr4.c
===================================================================
RCS file: /cvs/src/src/gdb/solib-svr4.c,v
retrieving revision 1.94
diff -c -p -r1.94 solib-svr4.c
*** solib-svr4.c 22 Sep 2008 15:20:08 -0000 1.94
--- solib-svr4.c 3 Dec 2008 12:47:44 -0000
*************** _initialize_svr4_solib (void)
*** 1826,1829 ****
--- 1826,1830 ----
svr4_so_ops.in_dynsym_resolve_code = svr4_in_dynsym_resolve_code;
svr4_so_ops.lookup_lib_global_symbol = elf_lookup_lib_symbol;
svr4_so_ops.same = svr4_same;
+ svr4_so_ops.check_bfd_format = solib_default_check_bfd_format;
}
Index: solib-target.c
===================================================================
RCS file: /cvs/src/src/gdb/solib-target.c,v
retrieving revision 1.9
diff -c -p -r1.9 solib-target.c
*** solib-target.c 14 Mar 2008 22:30:07 -0000 1.9
--- solib-target.c 3 Dec 2008 12:47:44 -0000
*************** _initialize_solib_target (void)
*** 492,495 ****
--- 492,496 ----
= solib_target_open_symbol_file_object;
solib_target_so_ops.in_dynsym_resolve_code
= solib_target_in_dynsym_resolve_code;
+ solib_target_so_ops.check_bfd_format =
solib_default_check_bfd_format;
}
Index: solib.c
===================================================================
RCS file: /cvs/src/src/gdb/solib.c,v
retrieving revision 1.107
diff -c -p -r1.107 solib.c
*** solib.c 3 Nov 2008 14:01:27 -0000 1.107
--- solib.c 3 Dec 2008 12:47:44 -0000
*************** solib_bfd_open (char *in_pathname)
*** 182,190 ****
temp_pathname, bfd_errmsg (bfd_get_error ()));
}
! if (!bfd_check_format (abfd, bfd_object))
{
- bfd_close (abfd);
make_cleanup (xfree, temp_pathname);
error (_("`%s': not in executable format: %s"),
temp_pathname, bfd_errmsg (bfd_get_error ()));
--- 182,190 ----
temp_pathname, bfd_errmsg (bfd_get_error ()));
}
! abfd = ops->check_bfd_format (abfd);
! if (abfd)
{
make_cleanup (xfree, temp_pathname);
error (_("`%s': not in executable format: %s"),
temp_pathname, bfd_errmsg (bfd_get_error ()));
*************** solib_bfd_open (char *in_pathname)
*** 267,275 ****
temp_pathname, bfd_errmsg (bfd_get_error ()));
}
! if (!bfd_check_format (abfd, bfd_object))
{
- bfd_close (abfd);
make_cleanup (xfree, temp_pathname);
error (_("`%s': not in executable format: %s"),
temp_pathname, bfd_errmsg (bfd_get_error ()));
--- 267,275 ----
temp_pathname, bfd_errmsg (bfd_get_error ()));
}
! abfd = ops->check_bfd_format (abfd);
! if (!abfd)
{
make_cleanup (xfree, temp_pathname);
error (_("`%s': not in executable format: %s"),
temp_pathname, bfd_errmsg (bfd_get_error ()));
*************** symbol_add_stub (void *arg)
*** 432,439 ****
sap = build_section_addr_info_from_section_table (so->sections,
so-
>sections_end);
! so->objfile = symbol_file_add (so->so_name, so->from_tty,
! sap, 0, OBJF_SHARED);
free_section_addr_info (sap);
return (1);
--- 432,439 ----
sap = build_section_addr_info_from_section_table (so->sections,
so-
>sections_end);
! so->objfile = symbol_file_add_from_bfd (so->abfd, so->from_tty,
! sap, 0, OBJF_SHARED | OBJF_KEEPBFD);
free_section_addr_info (sap);
return (1);
*************** solib_global_lookup (const struct objfil
*** 1000,1005 ****
--- 1000,1015 ----
return NULL;
}
+ bfd *
+ solib_default_check_bfd_format (bfd *abfd)
+ {
+ if (!bfd_check_format (abfd, bfd_object))
+ {
+ bfd_close (abfd);
+ return NULL;
+ }
+ return abfd;
+ }
extern initialize_file_ftype _initialize_solib; /* -Wmissing-
prototypes */
Index: solist.h
===================================================================
RCS file: /cvs/src/src/gdb/solist.h,v
retrieving revision 1.21
diff -c -p -r1.21 solist.h
*** solist.h 26 Aug 2008 17:30:35 -0000 1.21
--- solist.h 3 Dec 2008 12:47:44 -0000
*************** struct target_so_ops
*** 118,123 ****
--- 118,130 ----
and another from the list returned by current_sos, return 1
if they represent the same library. */
int (*same) (struct so_list *gdb, struct so_list *inferior);
+
+ /* Return a bfd for the shared library if ABFD is valid.
+ If ABFD is not valid, it is freed and NULL is returned.
+ On most system, this is just a format check.
+ On some systems (eg Darwin), this can extract a shared
library from
+ a fat image. */
+ bfd * (*check_bfd_format)(bfd *abfd);
};
/* Free the memory associated with a (so_list *). */
*************** struct so_list *master_so_list (void);
*** 129,134 ****
--- 136,144 ----
/* Find solib binary file and open it. */
extern bfd *solib_bfd_open (char *in_pathname);
+ /* Default implementation of check_bfd_format op. */
+ extern bfd *solib_default_check_bfd_format (bfd *abfd);
+
/* FIXME: gdbarch needs to control this variable */
extern struct target_so_ops *current_target_so_ops;
solib-darwin.h:
/* Handle shared libraries for GDB, the GNU Debugger.
Copyright (C) 2008 Free Software Foundation, Inc.
This file is part of GDB.
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/
>. */
#ifndef SOLIB_DARWIN_H
#define SOLIB_DARWIN_H
struct objfile;
struct target_so_ops;
extern struct target_so_ops darwin_so_ops;
#endif /* solib-darwin.h */
solib-darwin.c:
/* Handle Darwin shared libraries for GDB, the GNU Debugger.
Copyright (C) 2008 Free Software Foundation, Inc.
This file is part of GDB.
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 "defs.h"
#include "symtab.h"
#include "bfd.h"
#include "symfile.h"
#include "objfiles.h"
#include "gdbcore.h"
#include "target.h"
#include "inferior.h"
#include "gdbthread.h"
#include "gdb_assert.h"
#include "solist.h"
#include "solib.h"
#include "solib-svr4.h"
#include "bfd-target.h"
#include "elf-bfd.h"
#include "exec.h"
#include "auxv.h"
#include "exceptions.h"
#include "mach-o.h"
struct gdb_dyld_image_info
{
/* Base address (which corresponds to the Mach-O header). */
CORE_ADDR mach_header;
/* Image file path. */
CORE_ADDR file_path;
/* st.m_time of image file. */
unsigned long mtime;
};
/* Content of inferior dyld_all_image_infos structure. */
struct gdb_dyld_all_image_infos
{
/* Version (1). */
unsigned long version;
/* Number of images. */
unsigned long count;
/* Image description. */
CORE_ADDR info;
/* Notifier (function called when a library is added or removed). */
CORE_ADDR notifier;
};
/* Current all_image_infos version. */
#define DYLD_VERSION 1
/* Address of structure dyld_all_image_infos in inferior. */
static CORE_ADDR dyld_all_image_addr;
/* Gdb copy of dyld_all_info_infos. */
static struct gdb_dyld_all_image_infos dyld_all_image;
/* Read dyld_all_image from inferior. */
static void
darwin_load_image_infos (void)
{
gdb_byte buf[24];
struct type *ptr_type = builtin_type (target_gdbarch)-
>builtin_data_ptr;
int len;
len = 4 + 4 + 2 * ptr_type->length;
memset (&dyld_all_image, 0, sizeof (dyld_all_image));
if (dyld_all_image_addr == 0)
return;
if (target_read_memory (dyld_all_image_addr, buf, len))
return;
dyld_all_image.version = extract_unsigned_integer (buf, 4);
if (dyld_all_image.version != DYLD_VERSION)
return;
dyld_all_image.count = extract_unsigned_integer (buf + 4, 4);
dyld_all_image.info = extract_typed_address (buf + 8, ptr_type);
dyld_all_image.notifier = extract_typed_address
(buf + 8 + ptr_type->length, ptr_type);
}
/* Link map info to include in an allocated so_list entry */
struct lm_info
{
/* The target location of lm. */
CORE_ADDR lm_addr;
};
struct darwin_so_list
{
struct so_list sl;
struct lm_info li;
};
/* Local function prototypes */
static int match_main (char *);
static CORE_ADDR bfd_lookup_symbol (bfd *, char *);
/* Return non-zero if GDB_SO_NAME and INFERIOR_SO_NAME represent
the same shared library. */
static int
darwin_same (struct so_list *gdb, struct so_list *inferior)
{
return strcmp (gdb->so_original_name, inferior->so_original_name)
== 0;
}
/*
LOCAL FUNCTION
bfd_lookup_symbol -- lookup the value for a specific symbol
SYNOPSIS
CORE_ADDR bfd_lookup_symbol (bfd *abfd, char *symname)
DESCRIPTION
An expensive way to lookup the value of a single symbol for
bfd's that are only temporary anyway. This is used by the
shared library support to find the address of the debugger
notification routine in the shared library.
The returned symbol may be in a code or data section; functions
will normally be in a code section, but may be in a data section
if this architecture uses function descriptors.
Note that 0 is specifically allowed as an error return (no
such symbol).
*/
static CORE_ADDR
bfd_lookup_symbol (bfd *abfd, char *symname)
{
long storage_needed;
asymbol **symbol_table;
unsigned int number_of_symbols;
unsigned int i;
CORE_ADDR symaddr = 0;
storage_needed = bfd_get_symtab_upper_bound (abfd);
if (storage_needed > 0)
{
symbol_table = (asymbol **) xmalloc (storage_needed);
number_of_symbols = bfd_canonicalize_symtab (abfd, symbol_table);
for (i = 0; i < number_of_symbols; i++)
{
asymbol *sym = symbol_table[i];
if (strcmp (sym->name, symname) == 0
&& (sym->section->flags & (SEC_CODE | SEC_DATA)) != 0)
{
/* BFD symbols are section relative. */
symaddr = sym->value + sym->section->vma;
break;
}
}
xfree (symbol_table);
}
return symaddr;
}
/* Return program interpreter string. */
static gdb_byte *
find_program_interpreter (void)
{
gdb_byte *buf = NULL;
/* If we have an exec_bfd, use its section table. */
if (exec_bfd)
{
struct bfd_section *dylinker_sect;
dylinker_sect = bfd_get_section_by_name (exec_bfd,
"LC_LOAD_DYLINKER");
if (dylinker_sect != NULL)
{
int sect_size = bfd_section_size (exec_bfd, dylinker_sect);
buf = xmalloc (sect_size);
if (bfd_get_section_contents (exec_bfd, dylinker_sect,
buf, 0, sect_size))
return buf;
xfree (buf);
}
}
/* If we didn't find it, read from memory.
FIXME: todo. */
return buf;
}
/*
LOCAL FUNCTION
open_symbol_file_object
SYNOPSIS
void open_symbol_file_object (void *from_tty)
DESCRIPTION
If no open symbol file, attempt to locate and open the main symbol
file. On SVR4 systems, this is the first link map entry. If its
name is here, we can open it. Useful when attaching to a process
without first loading its symbol file.
If FROM_TTYP dereferences to a non-zero integer, allow messages to
be printed. This parameter is a pointer rather than an int because
open_symbol_file_object() is called via catch_errors() and
catch_errors() requires a pointer argument. */
static int
open_symbol_file_object (void *from_ttyp)
{
return 0;
}
/* LOCAL FUNCTION
current_sos -- build a list of currently loaded shared objects
SYNOPSIS
struct so_list *current_sos ()
DESCRIPTION
Build a list of `struct so_list' objects describing the shared
objects currently loaded in the inferior. This list does not
include an entry for the main executable file.
Note that we only gather information directly available from the
inferior --- we don't examine any of the shared library files
themselves. The declaration of `struct so_list' says which fields
we provide values for. */
static struct so_list *
darwin_current_sos (void)
{
struct type *ptr_type = builtin_type (target_gdbarch)-
>builtin_data_ptr;
int ptr_len = TYPE_LENGTH (ptr_type);
unsigned int image_info_size;
CORE_ADDR lm;
struct so_list *head = NULL;
struct so_list *tail = NULL;
int i;
darwin_load_image_infos ();
if (dyld_all_image.version != DYLD_VERSION)
return NULL;
image_info_size = ptr_len * 3;
for (i = 0; i < dyld_all_image.count; i++)
{
CORE_ADDR info = dyld_all_image.info + i * image_info_size;
char buf[image_info_size];
CORE_ADDR load_addr;
CORE_ADDR path_addr;
char *file_path;
int errcode;
struct darwin_so_list *dnew = XZALLOC (struct darwin_so_list);
struct so_list *new = &dnew->sl;
struct cleanup *old_chain = make_cleanup (xfree, dnew);
new->lm_info = &dnew->li;
if (target_read_memory (info, buf, image_info_size))
break;
load_addr = extract_typed_address (buf, ptr_type);
path_addr = extract_typed_address (buf + ptr_len, ptr_type);
target_read_string (path_addr, &file_path,
SO_NAME_MAX_PATH_SIZE - 1, &errcode);
if (errcode)
break;
/* Ignore first entry as this is the executable itself. */
if (i == 0)
continue;
dnew = XZALLOC (struct darwin_so_list);
new = &dnew->sl;
old_chain = make_cleanup (xfree, dnew);
new->lm_info = &dnew->li;
strncpy (new->so_name, file_path, SO_NAME_MAX_PATH_SIZE - 1);
new->so_name[SO_NAME_MAX_PATH_SIZE - 1] = '\0';
strcpy (new->so_original_name, new->so_name);
xfree (file_path);
new->lm_info->lm_addr = load_addr;
if (head == NULL)
head = new;
else
tail->next = new;
tail = new;
discard_cleanups (old_chain);
}
return head;
}
/* Return 1 if PC lies in the dynamic symbol resolution code of the
SVR4 run time loader. */
static CORE_ADDR interp_text_sect_low;
static CORE_ADDR interp_text_sect_high;
int
darwin_in_dynsym_resolve_code (CORE_ADDR pc)
{
return (pc >= interp_text_sect_low && pc < interp_text_sect_high);
}
/*
LOCAL FUNCTION
special_symbol_handling -- additional shared library symbol handling
SYNOPSIS
void special_symbol_handling ()
DESCRIPTION
Once the symbols from a shared object have been loaded in the usual
way, we are called to do any system specific symbol handling that
is needed.
For SunOS4, this consisted of grunging around in the dynamic
linkers structures to find symbol definitions for "common" symbols
and adding them to the minimal symbol table for the runtime common
objfile.
However, for SVR4, there's nothing to do.
*/
static void
darwin_special_symbol_handling (void)
{
}
/*
GLOBAL FUNCTION
darwin_solib_create_inferior_hook -- shared library startup support
SYNOPSIS
void darwin_solib_create_inferior_hook ()
DESCRIPTION
When gdb starts up the inferior, it nurses it along (through the
shell) until it is ready to execute it's first instruction. At this
point, this function gets called via expansion of the macro
SOLIB_CREATE_INFERIOR_HOOK.
For SunOS executables, this first instruction is typically the
one at "_start", or a similar text label, regardless of whether
the executable is statically or dynamically linked. The runtime
startup code takes care of dynamically linking in any shared
libraries, once gdb allows the inferior to continue.
For SVR4 executables, this first instruction is either the first
instruction in the dynamic linker (for dynamically linked
executables) or the instruction at "start" for statically linked
executables. For dynamically linked executables, the system
first exec's /lib/libc.so.N, which contains the dynamic linker,
and starts it running. The dynamic linker maps in any needed
shared libraries, maps in the actual user executable, and then
jumps to "start" in the user executable.
For both SunOS shared libraries, and SVR4 shared libraries, we
can arrange to cooperate with the dynamic linker to discover the
names of shared libraries that are dynamically linked, and the
base addresses to which they are linked.
This function is responsible for discovering those names and
addresses, and saving sufficient information about them to allow
their symbols to be read at a later time.
FIXME
Between enable_break() and disable_break(), this code does not
properly handle hitting breakpoints which the user might have
set in the startup code or in the dynamic linker itself. Proper
handling will probably have to wait until the implementation is
changed to use the "breakpoint handler function" method.
Also, what if child has exit()ed? Must exit loop somehow.
*/
static void
darwin_solib_create_inferior_hook (void)
{
struct minimal_symbol *msymbol;
char **bkpt_namep;
asection *interp_sect;
gdb_byte *interp_name;
CORE_ADDR sym_addr;
CORE_ADDR load_addr = 0;
int load_addr_found = 0;
int loader_found_in_list = 0;
struct so_list *so;
bfd *dyld_bfd = NULL;
/* First, remove all the solib event breakpoints. Their addresses
may have changed since the last time we ran the program. */
remove_solib_event_breakpoints ();
interp_text_sect_low = interp_text_sect_high = 0;
/* Find the program interpreter; if not found, warn the user and drop
into the old breakpoint at symbol code. */
interp_name = find_program_interpreter ();
if (!interp_name)
return;
sym_addr = 0;
/* Now we need to figure out where the dynamic linker was
loaded so that we can load its symbols and place a breakpoint
in the dynamic linker itself.
This address is stored on the stack. However, I've been unable
to find any magic formula to find it for Solaris (appears to
be trivial on GNU/Linux). Therefore, we have to try an alternate
mechanism to find the dynamic linker's base address. */
dyld_bfd = bfd_openr (interp_name, gnutarget);
if (dyld_bfd)
{
bfd *sub;
sub = bfd_mach_o_fat_extract (dyld_bfd, bfd_object,
gdbarch_bfd_arch_info (current_gdbarch));
if (sub)
dyld_bfd = sub;
else
{
bfd_close (dyld_bfd);
dyld_bfd = NULL;
}
}
if (!dyld_bfd)
{
xfree (interp_name);
return;
}
/* Otherwise we find the dynamic linker's base address by examining
the current pc (which should point at the entry point for the
dynamic linker) and subtracting the offset of the entry point.
This is more fragile than the previous approaches, but is a good
fallback method because it has actually been working well in
most cases. */
load_addr = (read_pc () - bfd_get_start_address (dyld_bfd));
#if 0
/* Record the relocated start and end address of the dynamic linker
text and plt section for svr4_in_dynsym_resolve_code. */
interp_sect = bfd_get_section_by_name (tmp_bfd, ".text");
if (interp_sect)
{
interp_text_sect_low =
bfd_section_vma (tmp_bfd, interp_sect) + load_addr;
interp_text_sect_high =
interp_text_sect_low + bfd_section_size (tmp_bfd, interp_sect);
}
#endif
/* Now try to set a breakpoint in the dynamic linker. */
dyld_all_image_addr =
bfd_lookup_symbol (dyld_bfd, "_dyld_all_image_infos");
bfd_close (dyld_bfd);
xfree (interp_name);
if (dyld_all_image_addr == 0)
return;
dyld_all_image_addr += load_addr;
darwin_load_image_infos ();
if (dyld_all_image.version == DYLD_VERSION)
create_solib_event_breakpoint (dyld_all_image.notifier);
}
static void
darwin_clear_solib (void)
{
dyld_all_image_addr = 0;
dyld_all_image.version = 0;
}
static void
darwin_free_so (struct so_list *so)
{
}
static void
darwin_relocate_section_addresses (struct so_list *so,
struct section_table *sec)
{
sec->addr += so->lm_info->lm_addr;
sec->endaddr += so->lm_info->lm_addr;
/* Best effort to set addr_high/addr_low. */
if (so->addr_high == 0)
{
so->addr_low = sec->addr;
so->addr_high = sec->endaddr;
}
if (sec->endaddr > so->addr_high)
so->addr_high = sec->endaddr;
if (sec->addr < so->addr_low)
so->addr_low = sec->addr;
}
static struct symbol *
darwin_lookup_lib_symbol (const struct objfile *objfile,
const char *name,
const char *linkage_name,
const domain_enum domain)
{
return NULL;
}
bfd *
darwin_check_bfd_format (bfd *abfd)
{
bfd *res;
res = bfd_mach_o_fat_extract (abfd, bfd_object,
gdbarch_bfd_arch_info (current_gdbarch));
if (res)
return res;
bfd_close (abfd);
return NULL;
}
extern initialize_file_ftype _initialize_svr4_solib; /* -Wmissing-
prototypes */
struct target_so_ops darwin_so_ops;
void
_initialize_darwin_solib (void)
{
darwin_so_ops.relocate_section_addresses =
darwin_relocate_section_addresses;
darwin_so_ops.free_so = darwin_free_so;
darwin_so_ops.clear_solib = darwin_clear_solib;
darwin_so_ops.solib_create_inferior_hook =
darwin_solib_create_inferior_hook;
darwin_so_ops.special_symbol_handling =
darwin_special_symbol_handling;
darwin_so_ops.current_sos = darwin_current_sos;
darwin_so_ops.open_symbol_file_object = open_symbol_file_object;
darwin_so_ops.in_dynsym_resolve_code = darwin_in_dynsym_resolve_code;
darwin_so_ops.lookup_lib_global_symbol = darwin_lookup_lib_symbol;
darwin_so_ops.same = darwin_same;
darwin_so_ops.check_bfd_format = darwin_check_bfd_format;
}