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 /* needed for F_OK and friends */ #endif +#include +#include /* 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 #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 + + +#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);