+
+/* Process a symbol file, as either the main file or as a dynamically
+ loaded file. See symbol_file_add_with_addrs_or_offsets's comments
+ for details. */
+struct objfile *
+symbol_file_add (char *name, int from_tty, struct section_addr_info *addrs,
+ int mainline, int flags)
+{
+ return symbol_file_add_with_addrs_or_offsets (name, from_tty, addrs, 0, 0,
+ mainline, flags);
+}
+
+
+/* Call symbol_file_add() with default values and update whatever is
+ affected by the loading of a new main().
+ Used when the file is supplied in the gdb command line
+ and by some targets with special loading requirements.
+ The auxiliary function, symbol_file_add_main_1(), has the flags
+ argument for the switches that can only be specified in the symbol_file
+ command itself. */
+
+void
+symbol_file_add_main (char *args, int from_tty)
+{
+ symbol_file_add_main_1 (args, from_tty, 0);
+}
+
+static void
+symbol_file_add_main_1 (char *args, int from_tty, int flags)
+{
+ symbol_file_add (args, from_tty, NULL, 1, flags);
+
+#ifdef HPUXHPPA
+ RESET_HP_UX_GLOBALS ();
+#endif
+
+ /* Getting new symbols may change our opinion about
+ what is frameless. */
+ reinit_frame_cache ();
+
+ set_initial_language ();
+}
+
+void
+symbol_file_clear (int from_tty)
+{
+ if ((have_full_symbols () || have_partial_symbols ())
+ && from_tty
+ && !query ("Discard symbol table from `%s'? ",
+ symfile_objfile->name))
+ error ("Not confirmed.");
+ free_all_objfiles ();
+
+ /* solib descriptors may have handles to objfiles. Since their
+ storage has just been released, we'd better wipe the solib
+ descriptors as well.
+ */
+#if defined(SOLIB_RESTART)
+ SOLIB_RESTART ();
+#endif
+
+ symfile_objfile = NULL;
+ if (from_tty)
+ printf_unfiltered ("No symbol file now.\n");
+#ifdef HPUXHPPA
+ RESET_HP_UX_GLOBALS ();
+#endif
+}
+
+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;
+}
+
+