#endif
#include "target.h"
#include "gdb/fileio.h"
+#include "inferior.h"
typedef bfd *bfdp;
DEF_VEC_P (bfdp);
/* The mtime of the BFD at the point the cache entry was made. */
time_t mtime;
+ /* The file size (in bytes) at the point the cache entry was made. */
+ off_t size;
+
+ /* The inode of the file at the point the cache entry was made. */
+ ino_t inode;
+
+ /* The device id of the file at the point the cache entry was made. */
+ dev_t device_id;
+
/* This is true if we have determined whether this BFD has any
sections requiring relocation. */
unsigned int relocation_computed : 1;
static htab_t gdb_bfd_cache;
+/* When true gdb will reuse an existing bfd object if the filename,
+ modification time, and file size all match. */
+
+static int bfd_sharing = 1;
+static void
+show_bfd_sharing (struct ui_file *file, int from_tty,
+ struct cmd_list_element *c, const char *value)
+{
+ fprintf_filtered (file, _("BFD sharing is %s.\n"), value);
+}
+
+/* When non-zero debugging of the bfd caches is enabled. */
+
+static unsigned int debug_bfd_cache;
+static void
+show_bfd_cache_debug (struct ui_file *file, int from_tty,
+ struct cmd_list_element *c, const char *value)
+{
+ fprintf_filtered (file, _("BFD cache debugging is %s.\n"), value);
+}
+
/* The type of an object being looked up in gdb_bfd_cache. We use
htab's capability of storing one kind of object (BFD in this case)
and using a different sort of object for searching. */
const char *filename;
/* The mtime. */
time_t mtime;
+ /* The file size (in bytes). */
+ off_t size;
+ /* The inode of the file. */
+ ino_t inode;
+ /* The device id of the file. */
+ dev_t device_id;
};
/* A hash function for BFDs. */
struct gdb_bfd_data *gdata = bfd_usrdata (abfd);
return (gdata->mtime == s->mtime
+ && gdata->size == s->size
+ && gdata->inode == s->inode
+ && gdata->device_id == s->device_id
&& strcmp (bfd_get_filename (abfd), s->filename) == 0);
}
OPEN_CLOSURE is unused. */
static void *
-gdb_bfd_iovec_fileio_open (struct bfd *abfd, void *open_closure)
+gdb_bfd_iovec_fileio_open (struct bfd *abfd, void *inferior)
{
const char *filename = bfd_get_filename (abfd);
int fd, target_errno;
gdb_assert (is_target_filename (filename));
- fd = target_fileio_open (filename + strlen (TARGET_SYSROOT_PREFIX),
- FILEIO_O_RDONLY, 0,
- &target_errno);
+ fd = target_fileio_open_warn_if_slow ((struct inferior *) inferior,
+ filename
+ + strlen (TARGET_SYSROOT_PREFIX),
+ FILEIO_O_RDONLY, 0,
+ &target_errno);
if (fd == -1)
{
errno = fileio_errno_to_host (target_errno);
pos = 0;
while (nbytes > pos)
{
+ QUIT;
+
bytes = target_fileio_pread (fd, (gdb_byte *) buf + pos,
nbytes - pos, offset + pos,
&target_errno);
{
gdb_assert (fd == -1);
- abfd = gdb_bfd_openr_iovec (name, target,
- gdb_bfd_iovec_fileio_open, NULL,
+ return gdb_bfd_openr_iovec (name, target,
+ gdb_bfd_iovec_fileio_open,
+ current_inferior (),
gdb_bfd_iovec_fileio_pread,
gdb_bfd_iovec_fileio_close,
gdb_bfd_iovec_fileio_fstat);
-
- if (abfd != NULL || errno != ENOSYS)
- return abfd;
-
- /* gdb_bfd_iovec_fileio_open failed with ENOSYS. This can
- happen, for example, with vgdb (Valgrind GDB), which
- presents itself as a remote target but works on the local
- filesystem: it does not implement remote get and users
- are not expected to set gdb_sysroot. To handle this case
- we fall back to trying the local filesystem iff
- gdb_sysroot is exactly TARGET_SYSROOT_PREFIX. */
- if (gdb_sysroot == NULL
- || strcmp (gdb_sysroot, TARGET_SYSROOT_PREFIX) != 0)
- return NULL;
}
name += strlen (TARGET_SYSROOT_PREFIX);
{
/* Weird situation here. */
search.mtime = 0;
+ search.size = 0;
+ search.inode = 0;
+ search.device_id = 0;
}
else
- search.mtime = st.st_mtime;
+ {
+ search.mtime = st.st_mtime;
+ search.size = st.st_size;
+ search.inode = st.st_ino;
+ search.device_id = st.st_dev;
+ }
/* Note that this must compute the same result as hash_bfd. */
hash = htab_hash_string (name);
opening the BFD may fail; and this would violate hashtab
invariants. */
abfd = htab_find_with_hash (gdb_bfd_cache, &search, hash);
- if (abfd != NULL)
+ if (bfd_sharing && abfd != NULL)
{
+ if (debug_bfd_cache)
+ fprintf_unfiltered (gdb_stdlog,
+ "Reusing cached bfd %s for %s\n",
+ host_address_to_string (abfd),
+ bfd_get_filename (abfd));
close (fd);
gdb_bfd_ref (abfd);
return abfd;
if (abfd == NULL)
return NULL;
- slot = htab_find_slot_with_hash (gdb_bfd_cache, &search, hash, INSERT);
- gdb_assert (!*slot);
- *slot = abfd;
+ if (debug_bfd_cache)
+ fprintf_unfiltered (gdb_stdlog,
+ "Creating new bfd %s for %s\n",
+ host_address_to_string (abfd),
+ bfd_get_filename (abfd));
+
+ if (bfd_sharing)
+ {
+ slot = htab_find_slot_with_hash (gdb_bfd_cache, &search, hash, INSERT);
+ gdb_assert (!*slot);
+ *slot = abfd;
+ }
gdb_bfd_ref (abfd);
return abfd;
void
gdb_bfd_ref (struct bfd *abfd)
{
+ struct stat buf;
struct gdb_bfd_data *gdata;
void **slot;
gdata = bfd_usrdata (abfd);
+ if (debug_bfd_cache)
+ fprintf_unfiltered (gdb_stdlog,
+ "Increase reference count on bfd %s (%s)\n",
+ host_address_to_string (abfd),
+ bfd_get_filename (abfd));
+
if (gdata != NULL)
{
gdata->refc += 1;
gdata = bfd_zalloc (abfd, sizeof (struct gdb_bfd_data));
gdata->refc = 1;
gdata->mtime = bfd_get_mtime (abfd);
+ gdata->size = bfd_get_size (abfd);
gdata->archive_bfd = NULL;
+ if (bfd_stat (abfd, &buf) == 0)
+ {
+ gdata->inode = buf.st_ino;
+ gdata->device_id = buf.st_dev;
+ }
+ else
+ {
+ /* The stat failed. */
+ gdata->inode = 0;
+ gdata->device_id = 0;
+ }
bfd_usrdata (abfd) = gdata;
bfd_alloc_data (abfd);
gdata->refc -= 1;
if (gdata->refc > 0)
- return;
+ {
+ if (debug_bfd_cache)
+ fprintf_unfiltered (gdb_stdlog,
+ "Decrease reference count on bfd %s (%s)\n",
+ host_address_to_string (abfd),
+ bfd_get_filename (abfd));
+ return;
+ }
+
+ if (debug_bfd_cache)
+ fprintf_unfiltered (gdb_stdlog,
+ "Delete final reference count on bfd %s (%s)\n",
+ host_address_to_string (abfd),
+ bfd_get_filename (abfd));
archive_bfd = gdata->archive_bfd;
search.filename = bfd_get_filename (abfd);
void **slot;
search.mtime = gdata->mtime;
+ search.size = gdata->size;
+ search.inode = gdata->inode;
+ search.device_id = gdata->device_id;
slot = htab_find_slot_with_hash (gdb_bfd_cache, &search, hash,
NO_INSERT);
add_cmd ("bfds", class_maintenance, maintenance_info_bfds, _("\
List the BFDs that are currently open."),
&maintenanceinfolist);
+
+ add_setshow_boolean_cmd ("bfd-sharing", no_class,
+ &bfd_sharing, _("\
+Set whether gdb will share bfds that appear to be the same file."), _("\
+Show whether gdb will share bfds that appear to be the same file."), _("\
+When enabled gdb will reuse existing bfds rather than reopening the\n\
+same file. To decide if two files are the same then gdb compares the\n\
+filename, file size, file modification time, and file inode."),
+ NULL,
+ &show_bfd_sharing,
+ &maintenance_set_cmdlist,
+ &maintenance_show_cmdlist);
+
+ add_setshow_zuinteger_cmd ("bfd-cache", class_maintenance,
+ &debug_bfd_cache, _("\
+Set bfd cache debugging."), _("\
+Show bfd cache debugging."), _("\
+When non-zero, bfd cache specific debugging is enabled."),
+ NULL,
+ &show_bfd_cache_debug,
+ &setdebuglist, &showdebuglist);
}