+https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=207644
+
+
+diff -u -rup -x testsuite gdb-6.3-orig/gdb/corelow.c gdb-6.3/gdb/corelow.c
+--- gdb-6.3-orig/gdb/corelow.c 2004-10-08 22:29:46.000000000 +0200
++++ gdb-6.3/gdb/corelow.c 2006-12-29 18:51:19.000000000 +0100
+@@ -30,6 +30,8 @@
+ #ifdef HAVE_SYS_FILE_H
+ #include <sys/file.h> /* needed for F_OK and friends */
+ #endif
++#include <dirent.h>
++#include <asm/page.h> /* FIXME: `PAGE_SIZE'! */
+ #include "frame.h" /* required by inferior.h */
+ #include "inferior.h"
+ #include "symtab.h"
+@@ -45,6 +47,13 @@
+ #include "readline/readline.h"
+ #include "observer.h"
+ #include "gdb_assert.h"
++#include "gdbcmd.h"
++#include "completer.h"
++#include "elf-bfd.h"
++#include "libbfd.h"
++#include "solist.h"
++
++#include <objid.h>
+
+ #ifndef O_BINARY
+ #define O_BINARY 0
+@@ -272,6 +281,369 @@ add_to_thread_list (bfd *abfd, asection
+ inferior_ptid = pid_to_ptid (thread_id); /* Yes, make it current */
+ }
+
++static char *object_path;
++
++static void
++show_objectdirectories (char *ignore, int from_tty)
++{
++ puts_filtered ("Object directories searched: ");
++ puts_filtered (object_path);
++ puts_filtered ("\n");
++}
++
++static void
++init_object_path (void)
++{
++ object_path = xstrdup ("");
++}
++
++/* Add zero or more directories to the front of the object path. */
++
++void
++objectdirectory_command (char *dirname, int from_tty)
++{
++ dont_repeat ();
++ /* FIXME, this goes to "delete dir"... */
++ if (dirname == 0)
++ {
++ if (from_tty && query ("Reinitialize object path to empty? "))
++ {
++ xfree (object_path);
++ init_object_path ();
++ }
++ }
++ else
++ {
++ mod_path (dirname, &object_path);
++ }
++ if (from_tty)
++ show_objectdirectories ((char *) 0, from_tty);
++}
++
++struct objid_cache
++ {
++ struct objid_cache *next;
++ char *filename;
++ ElfW(Word) sum;
++ };
++static struct objid_cache *objid_cache;
++
++static const char *
++objid_cache_find (ElfW(Word) sum)
++{
++ struct objid_cache *item;
++
++ for (item = objid_cache; item != NULL; item = item->next)
++ if (item->sum == sum)
++ return item->filename;
++
++ return NULL;
++}
++
++static void
++objid_cache_add (const char *filename, ElfW(Word) sum)
++{
++ const char *filename_old;
++ struct objid_cache *objid_cache_new;
++
++ filename_old = objid_cache_find (sum);
++ if (filename_old != NULL && strcmp (filename, filename_old) != 0)
++ warning ("Duplicite checksum of `%s' vs. `%s'", filename_old, filename);
++ if (filename_old != NULL)
++ return;
++
++ objid_cache_new = xmalloc (sizeof (*objid_cache_new));
++ objid_cache_new->next = objid_cache;
++ objid_cache_new->filename = xstrdup (filename);
++ objid_cache_new->sum = sum;
++ objid_cache = objid_cache_new;
++}
++
++static void
++objid_cache_clear (void)
++{
++ while (objid_cache)
++ {
++ struct objid_cache *freeing;
++
++ freeing = objid_cache;
++ objid_cache = freeing->next;
++ xfree (freeing->filename);
++ xfree (freeing);
++ }
++}
++
++static void
++objid_locate_file_bfd (bfd *abfd)
++{
++ unsigned phi;
++ FILE *f;
++ Elf_Internal_Ehdr *ehdr;
++ ElfW(Word) sum = 0;
++
++ if (bfd_check_format (abfd, bfd_object) == FALSE)
++ {
++ if (bfd_get_error () != bfd_error_file_not_recognized)
++ warning ("Error checking binary `%s' (%s)", bfd_get_filename (abfd),
++ bfd_errmsg (bfd_get_error ()));
++ return;
++ }
++ /* Non-executable files? Such as the `.o' files. */
++ if ((bfd_get_file_flags (abfd) & (EXEC_P | DYNAMIC)) == 0)
++ return;
++
++ /* `bfd_target_elf_flavour' is required for elf_tdata(). */
++ if (bfd_get_flavour (abfd) != bfd_target_elf_flavour)
++ return;
++
++ ehdr = elf_tdata (abfd)->elf_header;
++
++ for (phi = 0; phi < ehdr->e_phnum; phi++)
++ {
++ Elf_Internal_Phdr *phdr = &elf_tdata (abfd)->phdr[phi];
++ bfd_size_type remains;
++
++ /* Match the same conditions as in libobjid `phdr_callback'! */
++ /* FIXME: Unify the code. */
++ if (phdr->p_type != PT_LOAD)
++ continue;
++ if (!(phdr->p_flags & PF_R))
++ continue;
++ /* Present? We probably could not checksum such one. */
++ if (phdr->p_flags & PF_W)
++ continue;
++
++ if (bfd_seek (abfd, phdr->p_offset, SEEK_SET) != 0)
++ {
++ warning ("Error seeking binary `%s' to program header #%u (%s)",
++ bfd_get_filename (abfd), phi, bfd_errmsg (bfd_get_error ()));
++ return;
++ }
++ remains = phdr->p_filesz;
++ while (remains > 0)
++ {
++ unsigned char buf[0x10000];
++ bfd_size_type count;
++ unsigned char *ptr;
++
++ count = min (remains, sizeof (buf));
++ if (bfd_bread (buf, count, abfd) != count)
++ {
++ warning ("Error reading binary `%s' of program header #%u (%s)",
++ bfd_get_filename (abfd), phi,
++ bfd_errmsg (bfd_get_error ()));
++ return;
++ }
++
++ for (ptr = buf; ptr < buf + count; ptr++)
++ sum = sum * 31 + *ptr;
++
++ remains -= count;
++ }
++ }
++
++ objid_cache_add (bfd_get_filename (abfd), sum);
++}
++
++static void
++objid_locate_file (const char *filename)
++{
++ bfd *abfd;
++
++ /* FIXME: Persistent storage - `core_bfd'! */
++ abfd = bfd_openr (filename, bfd_get_target (core_bfd));
++ if (abfd == NULL)
++ {
++ warning ("Error opening binary `%s' (%s)", filename,
++ bfd_errmsg (bfd_get_error ()));
++ return;
++ }
++
++ objid_locate_file_bfd (abfd);
++
++ if (!bfd_close (abfd))
++ {
++ warning ("Error closing binary `%s' (%s)", filename,
++ bfd_errmsg (bfd_get_error ()));
++ return;
++ }
++}
++
++static void
++objid_locate_dir (const char *dirname)
++{
++ DIR *dir;
++ struct dirent *dirent;
++
++ dir = opendir (dirname);
++ if (dir == NULL)
++ {
++ warning ("Error scanning object directory `%s' (%s)", dirname,
++ safe_strerror (errno));
++ return;
++ }
++ while (errno = 0, dirent = readdir (dir))
++ {
++ char *targetname;
++
++ if (strcmp (dirent->d_name, ".") == 0)
++ continue;
++ if (strcmp (dirent->d_name, "..") == 0)
++ continue;
++ targetname = xstrprintf ("%s/%s", dirname, dirent->d_name);
++ if (dirent->d_type == DT_DIR)
++ objid_locate_dir (targetname);
++ if (dirent->d_type == DT_REG)
++ objid_locate_file (targetname);
++ xfree (targetname);
++ }
++ if (errno != 0)
++ warning ("Error reading object directory `%s' (%s)", dirname,
++ safe_strerror (errno));
++ if (closedir (dir))
++ {
++ warning ("Error closing object directory `%s' (%s)", dirname,
++ safe_strerror (errno));
++ return;
++ }
++}
++
++static void
++objid_cache_reload (void)
++{
++ char *p, *p1;
++
++ objid_cache_clear ();
++
++ if (strcmp (object_path, "") == 0)
++ return;
++
++ for (p = object_path; p; p = p1 ? p1 + 1 : 0)
++ {
++ char *dirname;
++ DIR *dir;
++
++ p1 = strchr (p, DIRNAME_SEPARATOR);
++ if (p1 == NULL)
++ dirname = xstrdup (p);
++ else
++ {
++ dirname = xmalloc (p1 + 1 - p);
++ memcpy (dirname, p, p1 - p);
++ dirname[p1 - p] = 0;
++ }
++ objid_locate_dir (dirname);
++ xfree (dirname);
++ }
++}
++
++/* HEADER_POINTER is at the place of user data OBJ. */
++/* Return TRUE of allocated header has been read to `*header_pointer'. */
++static bfd_boolean
++objid_locate_scan (bfd *abfd, asection *sect,
++ ElfW(LibobjidHdr) **header_pointer)
++{
++ file_ptr offset;
++ bfd_size_type size = bfd_section_size (abfd, sect);
++ ElfW(LibobjidHdr) header_local, *header;
++
++ if (size < sizeof (header_local))
++ return FALSE;
++
++ /* FIXME: `PAGE_SIZE' should be from `auxv'. */
++ for (offset = 0; offset <= size - sizeof (header_local); offset += PAGE_SIZE)
++ {
++ if (bfd_get_section_contents (abfd, sect, &header_local, offset,
++ sizeof (header_local)) == FALSE)
++ continue;
++ if (header_local.magic != ElfW(Magic))
++ continue;
++ if (header_local.self != bfd_section_vma (abfd, sect) + offset)
++ continue;
++ if (header_local.self_not != ~header_local.self)
++ continue;
++ /* Sanity check to avoid loading xmalloc() crashes. */
++ if (header_local.size > 0x10000)
++ continue;
++ if (header_local.size < sizeof (*header)
++ + header_local.obj_count * sizeof (*header->obj))
++ continue;
++
++ header = xmalloc (header_local.size);
++ if (bfd_get_section_contents (abfd, sect, header, offset,
++ header_local.size) == TRUE)
++ {
++ *header_pointer = header;
++ return TRUE;
++ }
++ xfree (header);
++ }
++ return FALSE;
++}
++
++static void
++objid_exec_load (char *exec_file, int from_tty)
++{
++ if (exec_bfd == NULL
++ || query (_("Load the matching executable/symbols \"%s\"? "),
++ exec_file))
++ {
++ if (catch_command_errors (exec_file_attach,
++ exec_file, from_tty, RETURN_MASK_ALL))
++ catch_command_errors (symbol_file_add_main_userloaded,
++ exec_file, from_tty, RETURN_MASK_ALL);
++ }
++}
++
++static void
++objid_locate (bfd *core_bfd, int from_tty)
++{
++ asection *sect;
++ ElfW(LibobjidHdr) *header;
++ unsigned obji;
++
++ if (bfd_sections_find_if (core_bfd,
++ (bfd_boolean (*) (bfd *abfd, asection *sect, void *obj))
++ objid_locate_scan, &header) == NULL)
++ return;
++
++ /* FIXME: Keep the cache more persistent. */
++ objid_cache_reload ();
++
++ for (obji = 0; obji < header->obj_count; obji++)
++ {
++ ElfW(LibobjidObj) *obj = &header->obj[obji];
++ CORE_ADDR filename_addr = obj->filename;
++ char *filename;
++ int filename_errno;
++
++ /* Return value 0 is OK - empty strings. */
++ if (target_read_string (filename_addr, &filename, FILENAME_MAX,
++ &filename_errno) <= 0 || filename_errno != 0)
++ warning ("Error reading objid object #%u filename (%s)", obji,
++ safe_strerror (filename_errno));
++ else
++ {
++ const char *filename_found;
++
++ filename_found = objid_cache_find (obj->checksum);
++ if (filename_found != NULL)
++ {
++ /* Main executable? It is the first entry with empty name. */
++ if (obji == 0 && strcmp (filename, "") == 0)
++ objid_exec_load ((char *) filename_found, from_tty);
++ else if (strcmp (filename, "") != 0)
++ solib_open_map (filename, filename_found);
++ else
++ warning ("Ignoring invalid objid mapping `%s' -> `%s'",
++ filename, filename_found);
++ }
++ }
++ xfree (filename);
++ }
++ xfree (header);
++}
++
+ /* This routine opens and sets up the core file bfd. */
+
+ static void
+@@ -393,6 +765,9 @@ core_open (char *filename, int from_tty)
+ /* Fetch all registers from core file. */
+ target_fetch_registers (-1);
+
++ /* Locate objid section, if present. */
++ objid_locate (core_bfd, from_tty);
++
+ /* Add symbols and section mappings for any shared libraries. */
+ #ifdef SOLIB_ADD
+ catch_errors (solib_add_stub, &from_tty, (char *) 0,
+@@ -679,8 +1054,26 @@ int coreops_suppress_target;
+ void
+ _initialize_corelow (void)
+ {
++ struct cmd_list_element *c;
++
+ init_core_ops ();
+
+ if (!coreops_suppress_target)
+ add_target (&core_ops);
++
++ init_object_path ();
++
++ c = add_cmd ("objectdirectory", class_files, objectdirectory_command,
++ "Add directory DIR to beginning of libobjid based search path\n\
++for binary files.\n\
++DIR can also be $cwd for the current working directory.\n\
++With no argument, reset the search path to be empty, the default.",
++ &cmdlist);
++
++ set_cmd_completer (c, filename_completer);
++
++ add_cmd ("objectdirectories", no_class, show_objectdirectories,
++ "Current search path for libobjid based finding binary files.\n\
++$cwd in the path means the current working directory.",
++ &showlist);
+ }
+diff -u -rup -x testsuite gdb-6.3-orig/gdb/defs.h gdb-6.3/gdb/defs.h
+--- gdb-6.3-orig/gdb/defs.h 2006-12-28 17:29:07.000000000 +0100
++++ gdb-6.3/gdb/defs.h 2006-12-28 18:23:59.000000000 +0100
+@@ -614,6 +614,11 @@ extern void init_source_path (void);
+
+ extern void init_last_source_visited (void);
+
++/* From corelow.c */
++/* FIXME: init.c based. */
++
++extern void objectdirectory_command (char *dirname, int from_tty);
++
+ /* From exec.c */
+
+ extern void exec_set_section_offsets (bfd_signed_vma text_off,
+diff -u -rup -x testsuite gdb-6.3-orig/gdb/main.c gdb-6.3/gdb/main.c
+--- gdb-6.3-orig/gdb/main.c 2006-12-28 17:29:10.000000000 +0100
++++ gdb-6.3/gdb/main.c 2006-12-28 20:23:46.000000000 +0100
+@@ -134,6 +134,13 @@ captured_main (void *data)
+ /* Number of elements of cmdarg used. */
+ int ncmd;
+
++ /* Indices of all arguments of --objectdirectory option. */
++ char **objectdirarg;
++ /* Allocated size. */
++ int objectdirsize;
++ /* Number of elements used. */
++ int nobjectdir;
++
+ /* Indices of all arguments of --directory option. */
+ char **dirarg;
+ /* Allocated size. */
+@@ -173,6 +180,9 @@ captured_main (void *data)
+ dirsize = 1;
+ dirarg = (char **) xmalloc (dirsize * sizeof (*dirarg));
+ ndir = 0;
++ objectdirsize = 1;
++ objectdirarg = (char **) xmalloc (objectdirsize * sizeof (*objectdirarg));
++ nobjectdir = 0;
+
+ quit_flag = 0;
+ line = (char *) xmalloc (linesize);
+@@ -240,7 +250,8 @@ captured_main (void *data)
+ OPT_STATISTICS,
+ OPT_TUI,
+ OPT_NOWINDOWS,
+- OPT_WINDOWS
++ OPT_WINDOWS,
++ OPT_OBJECTDIRECTORY
+ };
+ static struct option long_options[] =
+ {
+@@ -289,6 +300,7 @@ captured_main (void *data)
+ {"interpreter", required_argument, 0, 'i'},
+ {"i", required_argument, 0, 'i'},
+ {"directory", required_argument, 0, 'd'},
++ {"objectdirectory", required_argument, 0, OPT_OBJECTDIRECTORY},
+ {"d", required_argument, 0, 'd'},
+ {"cd", required_argument, 0, OPT_CD},
+ {"tty", required_argument, 0, 't'},
+@@ -457,6 +469,16 @@ extern int gdbtk_test (char *);
+ remote_timeout = i;
+ }
+ break;
++ case OPT_OBJECTDIRECTORY:
++ objectdirarg[nobjectdir++] = optarg;
++ if (nobjectdir >= objectdirsize)
++ {
++ objectdirsize *= 2;
++ objectdirarg = (char **) xrealloc ((char *) objectdirarg,
++ objectdirsize
++ * sizeof (*objectdirarg));
++ }
++ break;
+
+ case '?':
+ fprintf_unfiltered (gdb_stderr,
+@@ -636,6 +658,11 @@ extern int gdbtk_test (char *);
+ catch_command_errors (directory_command, dirarg[i], 0, RETURN_MASK_ALL);
+ xfree (dirarg);
+
++ for (i = 0; i < nobjectdir; i++)
++ catch_command_errors (objectdirectory_command, objectdirarg[i], 0,
++ RETURN_MASK_ALL);
++ xfree (objectdirarg);
++
+ if (execarg != NULL
+ && symarg != NULL
+ && strcmp (execarg, symarg) == 0)
+@@ -845,6 +872,7 @@ Options:\n\n\
+ fputs_unfiltered (_("\
+ --dbx DBX compatibility mode.\n\
+ --directory=DIR Search for source files in DIR.\n\
++ --objectdirectory=DIR Search for binary files by libobjid in DIR.\n\
+ --epoch Output information used by epoch emacs-GDB interface.\n\
+ --exec=EXECFILE Use EXECFILE as the executable.\n\
+ --fullname Output information used by emacs-GDB interface.\n\
+diff -u -rup -x testsuite gdb-6.3-orig/gdb/objid.h gdb-6.3/gdb/objid.h
+--- gdb-6.3-orig/gdb/objid.h 2006-12-29 11:34:47.000000000 +0100
++++ gdb-6.3/gdb/objid.h 2006-12-28 21:27:51.000000000 +0100
+@@ -0,0 +1,29 @@
++#ifndef OBJID_H
++#define OBJID_H 1
++
++
++#include <link.h>
++
++
++#define Elf32_Magic 0x0B11D032
++#define Elf64_Magic 0x0B11D064
++
++typedef struct
++ {
++ ElfW(Addr) filename;
++ ElfW(Word) checksum;
++ } ElfW(LibobjidObj);
++
++typedef struct
++ {
++ ElfW(Word) magic;
++ ElfW(Addr) self;
++ ElfW(Addr) self_not; /* == ~self */
++ /* Total size of all OBJs including this header. */
++ ElfW(Word) size;
++ ElfW(Word) obj_count;
++ ElfW(LibobjidObj) obj[0];
++ } ElfW(LibobjidHdr);
++
++
++#endif /* !OBJID_H */
+diff -u -rup -x testsuite gdb-6.3-orig/gdb/solib.c gdb-6.3/gdb/solib.c
+--- gdb-6.3-orig/gdb/solib.c 2006-12-28 17:29:11.000000000 +0100
++++ gdb-6.3/gdb/solib.c 2006-12-29 01:37:08.000000000 +0100
+@@ -73,6 +73,60 @@ static char *solib_search_path = NULL;
+
+ void add_to_target_sections (int, struct target_ops *, struct so_list *);
+
++struct solib_open_map
++ {
++ struct solib_open_map *next;
++ char *from;
++ char *to;
++ };
++static struct solib_open_map *solib_open_map_list;
++
++static const char *
++solib_open_map_find (const char *from)
++{
++ struct solib_open_map *item;
++
++ for (item = solib_open_map_list; item != NULL; item = item->next)
++ if (strcmp (item->from, from) == 0)
++ return item->to;
++
++ return NULL;
++}
++
++void
++solib_open_map (const char *from, const char *to)
++{
++ const char *to_old;
++ struct solib_open_map *item_new;
++
++ to_old = solib_open_map_find (from);
++ if (to_old != NULL && strcmp (to_old, to) != 0)
++ warning ("Duplicite mapping of `%s' -> `%s' vs. `%s'", from, to_old, to);
++ if (to_old != NULL)
++ return;
++
++ item_new = xmalloc (sizeof (*item_new));
++ item_new->from = xstrdup (from);
++ item_new->to = xstrdup (to);
++ item_new->next = solib_open_map_list;
++ solib_open_map_list = item_new;
++}
++
++static void
++solib_open_map_reset (void)
++{
++ while (solib_open_map_list != NULL)
++ {
++ struct solib_open_map *freeing;
++
++ freeing = solib_open_map_list;
++ xfree (freeing->from);
++ xfree (freeing->to);
++ solib_open_map_list = freeing->next;
++ xfree (freeing);
++ }
++}
++
+ /*
+
+ GLOBAL FUNCTION
+@@ -117,6 +171,11 @@ solib_open (char *in_pathname, char **fo
+ char *temp_pathname = NULL;
+ char *p = in_pathname;
+ int solib_absolute_prefix_is_empty;
++ const char *in_pathname_mapped;
++
++ in_pathname_mapped = solib_open_map_find (in_pathname);
++ if (in_pathname_mapped != NULL)
++ in_pathname = (char *) in_pathname_mapped;
+
+ solib_absolute_prefix_is_empty = (solib_absolute_prefix == NULL
+ || *solib_absolute_prefix == 0);
+@@ -821,6 +880,8 @@ clear_solib (void)
+ }
+
+ TARGET_SO_CLEAR_SOLIB ();
++
++ solib_open_map_reset ();
+ }
+
+ static void
+diff -u -rup -x testsuite gdb-6.3-orig/gdb/solist.h gdb-6.3/gdb/solist.h
+--- gdb-6.3-orig/gdb/solist.h 2006-12-28 17:29:07.000000000 +0100
++++ gdb-6.3/gdb/solist.h 2006-12-29 00:10:49.000000000 +0100
+@@ -121,6 +121,8 @@ struct so_list *master_so_list (void);
+ /* Find solib binary file and open it. */
+ extern int solib_open (char *in_pathname, char **found_pathname);
+
++extern void solib_open_map (const char *from, const char *to);
++
+ /* Add the list of sections in so_list to the target to_sections. */
+ extern void add_to_target_sections (int, struct target_ops *, struct so_list *);
+
+diff -u -rup -x testsuite gdb-6.3-orig/gdb/symfile.c gdb-6.3/gdb/symfile.c
+--- gdb-6.3-orig/gdb/symfile.c 2006-12-28 17:29:10.000000000 +0100
++++ gdb-6.3/gdb/symfile.c 2006-12-28 21:59:10.000000000 +0100
+@@ -973,6 +973,12 @@ symbol_file_add_main (char *args, int fr
+ symbol_file_add_main_1 (args, from_tty, 0);
+ }
+
++void
++symbol_file_add_main_userloaded (char *args, int from_tty)
++{
++ symbol_file_add_main_1 (args, from_tty, OBJF_USERLOADED);
++}
++
+ static void
+ symbol_file_add_main_1 (char *args, int from_tty, int flags)
+ {
+diff -u -rup -x testsuite gdb-6.3-orig/gdb/symfile.h gdb-6.3/gdb/symfile.h
+--- gdb-6.3-orig/gdb/symfile.h 2004-09-08 23:58:19.000000000 +0200
++++ gdb-6.3/gdb/symfile.h 2006-12-28 21:59:11.000000000 +0100
+@@ -310,6 +310,7 @@ extern CORE_ADDR symbol_overlayed_addres
+
+ /* Load symbols from a file. */
+ extern void symbol_file_add_main (char *args, int from_tty);
++extern void symbol_file_add_main_userloaded (char *args, int from_tty);
+
+ /* Clear GDB symbol tables. */
+ extern void symbol_file_clear (int from_tty);