#include <sys/mman.h>
#endif
+#ifdef HAVE_LIBDEBUGINFOD
+#include <elfutils/debuginfod.h>
+#endif
+
/* Internal headers for the ELF .stab-dump code - sorry. */
#define BYTES_IN_WORD 32
#include "aout/aout64.h"
#define SHOW_PRECEDING_CONTEXT_LINES (5)
-/* Read a complete file into memory. */
+#if HAVE_LIBDEBUGINFOD
+/* Return a hex string represention of the build-id. */
+
+unsigned char *
+get_build_id (void * data)
+{
+ unsigned i;
+ char * build_id_str;
+ bfd * abfd = (bfd *) data;
+ const struct bfd_build_id * build_id;
+
+ build_id = abfd->build_id;
+ if (build_id == NULL)
+ return NULL;
+
+ build_id_str = malloc (build_id->size * 2 + 1);
+ if (build_id_str == NULL)
+ return NULL;
+
+ for (i = 0; i < build_id->size; i++)
+ sprintf (build_id_str + (i * 2), "%02x", build_id->data[i]);
+ build_id_str[build_id->size * 2] = '\0';
+
+ return (unsigned char *) build_id_str;
+}
+
+/* Search for a separate debug file matching ABFD's build-id. */
+
+static bfd *
+find_separate_debug (const bfd * abfd)
+{
+ const struct bfd_build_id * build_id = abfd->build_id;
+ separate_info * i = first_separate_info;
+
+ if (build_id == NULL || i == NULL)
+ return NULL;
+
+ while (i != NULL)
+ {
+ const bfd * i_bfd = (bfd *) i->handle;
+
+ if (abfd != NULL && i_bfd->build_id != NULL)
+ {
+ const unsigned char * data = i_bfd->build_id->data;
+ size_t size = i_bfd->build_id->size;
+
+ if (size == build_id->size
+ && memcmp (data, build_id->data, size) == 0)
+ return (bfd *) i->handle;
+ }
+
+ i = i->next;
+ }
+
+ return NULL;
+}
+
+/* Search for a separate debug file matching ABFD's .gnu_debugaltlink
+ build-id. */
+
+static bfd *
+find_alt_debug (const bfd * abfd)
+{
+ size_t namelen;
+ size_t id_len;
+ const char * name;
+ struct dwarf_section * section;
+ const struct bfd_build_id * build_id = abfd->build_id;
+ separate_info * i = first_separate_info;
+
+ if (i == NULL
+ || build_id == NULL
+ || !load_debug_section (gnu_debugaltlink, (void *) abfd))
+ return NULL;
+
+ section = &debug_displays[gnu_debugaltlink].section;
+ if (section == NULL)
+ return NULL;
+
+ name = (const char *) section->start;
+ namelen = strnlen (name, section->size) + 1;
+ if (namelen == 1)
+ return NULL;
+ if (namelen >= section->size)
+ return NULL;
+
+ id_len = section->size - namelen;
+ if (id_len < 0x14)
+ return NULL;
+
+ /* Compare the .gnu_debugaltlink build-id with the build-ids of the
+ known separate_info files. */
+ while (i != NULL)
+ {
+ const bfd * i_bfd = (bfd *) i->handle;
+
+ if (i_bfd != NULL && i_bfd->build_id != NULL)
+ {
+ const unsigned char * data = i_bfd->build_id->data;
+ size_t size = i_bfd->build_id->size;
+
+ if (id_len == size
+ && memcmp (section->start + namelen, data, size) == 0)
+ return (bfd *) i->handle;
+ }
+
+ i = i->next;
+ }
+
+ return NULL;
+}
+
+#endif /* HAVE_LIBDEBUGINFOD */
+
+/* Reads the contents of file FN into memory. Returns a pointer to the buffer.
+ Also returns the size of the buffer in SIZE_RETURN and a filled out
+ stat structure in FST_RETURN. Returns NULL upon failure. */
static const char *
-slurp_file (const char *fn, size_t *size, struct stat *fst)
+slurp_file (const char * fn,
+ size_t * size_return,
+ struct stat * fst_return,
+ bfd * abfd ATTRIBUTE_UNUSED)
{
#ifdef HAVE_MMAP
- int ps = getpagesize ();
+ int ps;
size_t msize;
#endif
const char *map;
- int fd = open (fn, O_RDONLY | O_BINARY);
+ int fd;
+
+ /* Paranoia. */
+ if (fn == NULL || * fn == 0 || size_return == NULL || fst_return == NULL)
+ return NULL;
+
+ fd = open (fn, O_RDONLY | O_BINARY);
+
+#if HAVE_LIBDEBUGINFOD
+ if (fd < 0 && use_debuginfod && fn[0] == '/' && abfd != NULL)
+ {
+ unsigned char * build_id;
+ debuginfod_client * client;
+
+ client = debuginfod_begin ();
+ if (client == NULL)
+ return NULL;
+
+ build_id = get_build_id (abfd);
+ fd = debuginfod_find_source (client, build_id, 0, fn, NULL);
+ free (build_id);
+ debuginfod_end (client);
+ }
+#endif
if (fd < 0)
return NULL;
- if (fstat (fd, fst) < 0)
+
+ if (fstat (fd, fst_return) < 0)
{
close (fd);
return NULL;
}
- *size = fst->st_size;
+
+ *size_return = fst_return->st_size;
+
#ifdef HAVE_MMAP
- msize = (*size + ps - 1) & ~(ps - 1);
+ ps = getpagesize ();
+ msize = (*size_return + ps - 1) & ~(ps - 1);
map = mmap (NULL, msize, PROT_READ, MAP_SHARED, fd, 0);
if (map != (char *) -1L)
{
return map;
}
#endif
- map = (const char *) malloc (*size);
- if (!map || (size_t) read (fd, (char *) map, *size) != *size)
+
+ map = (const char *) malloc (*size_return);
+ if (!map || (size_t) read (fd, (char *) map, *size_return) != *size_return)
{
free ((void *) map);
map = NULL;
}
/* Tries to open MODNAME, and if successful adds a node to print_files
- linked list and returns that node. Returns NULL on failure. */
+ linked list and returns that node. Also fills in the stat structure
+ pointed to by FST_RETURN. Returns NULL on failure. */
static struct print_file_list *
-try_print_file_open (const char *origname, const char *modname, struct stat *fst)
+try_print_file_open (const char * origname,
+ const char * modname,
+ struct stat * fst_return,
+ bfd * abfd)
{
struct print_file_list *p;
p = (struct print_file_list *) xmalloc (sizeof (struct print_file_list));
- p->map = slurp_file (modname, &p->mapsize, fst);
+ p->map = slurp_file (modname, &p->mapsize, fst_return, abfd);
if (p->map == NULL)
{
free (p);
struct stat fst;
int i;
- p = try_print_file_open (filename, filename, &fst);
+ p = try_print_file_open (filename, filename, &fst, abfd);
if (p == NULL)
{
if (include_path_count == 0)
char *modname = concat (include_paths[i], "/", fname,
(const char *) 0);
- p = try_print_file_open (filename, modname, &fst);
+ p = try_print_file_open (filename, modname, &fst, abfd);
if (p)
break;
if (! with_line_numbers && ! with_source_code)
return;
+#ifdef HAVE_LIBDEBUGINFOD
+ {
+ bfd *debug_bfd;
+ const char *alt_filename = NULL;
+
+ if (use_debuginfod)
+ {
+ bfd *alt_bfd;
+
+ /* PR 29075: Check for separate debuginfo and .gnu_debugaltlink files.
+ They need to be passed to bfd_find_nearest_line_with_alt in case they
+ were downloaded from debuginfod. Otherwise libbfd will attempt to
+ search for them and fail to locate them. */
+ debug_bfd = find_separate_debug (abfd);
+ if (debug_bfd == NULL)
+ debug_bfd = abfd;
+
+ alt_bfd = find_alt_debug (debug_bfd);
+ if (alt_bfd != NULL)
+ alt_filename = bfd_get_filename (alt_bfd);
+ }
+ else
+ debug_bfd = abfd;
+
+ bfd_set_error (bfd_error_no_error);
+ if (! bfd_find_nearest_line_with_alt (debug_bfd, alt_filename,
+ section, syms,
+ addr_offset, &filename,
+ &functionname, &linenumber,
+ &discriminator))
+ {
+ if (bfd_get_error () == bfd_error_no_error)
+ return;
+ if (! bfd_find_nearest_line_discriminator (abfd, section, syms,
+ addr_offset, &filename,
+ &functionname, &linenumber,
+ &discriminator))
+ return;
+ }
+ }
+#else
if (! bfd_find_nearest_line_discriminator (abfd, section, syms, addr_offset,
&filename, &functionname,
&linenumber, &discriminator))
return;
+#endif
if (filename != NULL && *filename == '\0')
filename = NULL;
return data;
}
-#if HAVE_LIBDEBUGINFOD
-/* Return a hex string represention of the build-id. */
-
-unsigned char *
-get_build_id (void * data)
-{
- unsigned i;
- char * build_id_str;
- bfd * abfd = (bfd *) data;
- const struct bfd_build_id * build_id;
-
- build_id = abfd->build_id;
- if (build_id == NULL)
- return NULL;
-
- build_id_str = malloc (build_id->size * 2 + 1);
- if (build_id_str == NULL)
- return NULL;
-
- for (i = 0; i < build_id->size; i++)
- sprintf (build_id_str + (i * 2), "%02x", build_id->data[i]);
- build_id_str[build_id->size * 2] = '\0';
-
- return (unsigned char *)build_id_str;
-}
-#endif /* HAVE_LIBDEBUGINFOD */
-
static void
dump_dwarf_section (bfd *abfd, asection *section,
void *arg)