+static char *
+get_debug_link_info (struct objfile *objfile, unsigned long *crc32_out)
+{
+ asection *sect;
+ bfd_size_type debuglink_size;
+ unsigned long crc32;
+ char *contents;
+ int crc_offset;
+ unsigned char *p;
+
+ sect = bfd_get_section_by_name (objfile->obfd, ".gnu_debuglink");
+
+ if (sect == NULL)
+ return NULL;
+
+ debuglink_size = bfd_section_size (objfile->obfd, sect);
+
+ contents = xmalloc (debuglink_size);
+ bfd_get_section_contents (objfile->obfd, sect, contents,
+ (file_ptr)0, (bfd_size_type)debuglink_size);
+
+ /* Crc value is stored after the filename, aligned up to 4 bytes. */
+ crc_offset = strlen (contents) + 1;
+ crc_offset = (crc_offset + 3) & ~3;
+
+ crc32 = bfd_get_32 (objfile->obfd, (bfd_byte *) (contents + crc_offset));
+
+ *crc32_out = crc32;
+ return contents;
+}
+
+static int
+separate_debug_file_exists (const char *name, unsigned long crc)
+{
+ unsigned long file_crc = 0;
+ int fd;
+ char buffer[8*1024];
+ int count;
+
+ fd = open (name, O_RDONLY | O_BINARY);
+ if (fd < 0)
+ return 0;
+
+ while ((count = read (fd, buffer, sizeof (buffer))) > 0)
+ file_crc = gnu_debuglink_crc32 (file_crc, buffer, count);
+
+ close (fd);
+
+ return crc == file_crc;
+}
+
+static char *debug_file_directory = NULL;
+
+#if ! defined (DEBUG_SUBDIRECTORY)
+#define DEBUG_SUBDIRECTORY ".debug"
+#endif
+
+static char *
+find_separate_debug_file (struct objfile *objfile)
+{
+ asection *sect;
+ char *basename;
+ char *dir;
+ char *debugfile;
+ char *name_copy;
+ bfd_size_type debuglink_size;
+ unsigned long crc32;
+ int i;
+
+ basename = get_debug_link_info (objfile, &crc32);
+
+ if (basename == NULL)
+ return NULL;
+
+ dir = xstrdup (objfile->name);
+
+ /* Strip off the final filename part, leaving the directory name,
+ followed by a slash. Objfile names should always be absolute and
+ tilde-expanded, so there should always be a slash in there
+ somewhere. */
+ for (i = strlen(dir) - 1; i >= 0; i--)
+ {
+ if (IS_DIR_SEPARATOR (dir[i]))
+ break;
+ }
+ gdb_assert (i >= 0 && IS_DIR_SEPARATOR (dir[i]));
+ dir[i+1] = '\0';
+
+ debugfile = alloca (strlen (debug_file_directory) + 1
+ + strlen (dir)
+ + strlen (DEBUG_SUBDIRECTORY)
+ + strlen ("/")
+ + strlen (basename)
+ + 1);
+
+ /* First try in the same directory as the original file. */
+ strcpy (debugfile, dir);
+ strcat (debugfile, basename);
+
+ if (separate_debug_file_exists (debugfile, crc32))
+ {
+ xfree (basename);
+ xfree (dir);
+ return xstrdup (debugfile);
+ }
+
+ /* Then try in the subdirectory named DEBUG_SUBDIRECTORY. */
+ strcpy (debugfile, dir);
+ strcat (debugfile, DEBUG_SUBDIRECTORY);
+ strcat (debugfile, "/");
+ strcat (debugfile, basename);
+
+ if (separate_debug_file_exists (debugfile, crc32))
+ {
+ xfree (basename);
+ xfree (dir);
+ return xstrdup (debugfile);
+ }
+
+ /* Then try in the global debugfile directory. */
+ strcpy (debugfile, debug_file_directory);
+ strcat (debugfile, "/");
+ strcat (debugfile, dir);
+ strcat (debugfile, basename);
+
+ if (separate_debug_file_exists (debugfile, crc32))
+ {
+ xfree (basename);
+ xfree (dir);
+ return xstrdup (debugfile);
+ }
+
+ xfree (basename);
+ xfree (dir);
+ return NULL;
+}
+
+