X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Fsymfile.c;h=1066b5292ed3762c04140af4bae9b2cd161aac1d;hb=9b254dd1ce46c19dde1dde5b8d1e22e862dfacce;hp=2a35e34afb175ad0ac994c009838cbf4f960d1f0;hpb=3bd72c6f17a8488ebe6394e7276c25fc0e08ffad;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/symfile.c b/gdb/symfile.c index 2a35e34afb..1066b5292e 100644 --- a/gdb/symfile.c +++ b/gdb/symfile.c @@ -1,7 +1,7 @@ /* Generic symbol file reading for the GNU debugger, GDB. - Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, + 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. Contributed by Cygnus Support, using pieces from other GDB modules. @@ -10,7 +10,7 @@ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -19,9 +19,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. */ + along with this program. If not, see . */ #include "defs.h" #include "bfdlink.h" @@ -51,6 +49,9 @@ #include "block.h" #include "observer.h" #include "exec.h" +#include "parser-defs.h" +#include "varobj.h" +#include "elf-bfd.h" #include #include @@ -60,9 +61,6 @@ #include #include -#ifndef O_BINARY -#define O_BINARY 0 -#endif int (*deprecated_ui_load_progress_hook) (const char *section, unsigned long num); void (*deprecated_show_load_progress) (const char *section, @@ -72,7 +70,6 @@ void (*deprecated_show_load_progress) (const char *section, unsigned long total_size); void (*deprecated_pre_add_symbol_hook) (const char *); void (*deprecated_post_add_symbol_hook) (void); -void (*deprecated_target_new_objfile_hook) (struct objfile *); static void clear_symtab_users_cleanup (void *ignore); @@ -108,7 +105,7 @@ bfd *symfile_bfd_open (char *); int get_section_index (struct objfile *, char *); -static void find_sym_fns (struct objfile *); +static struct sym_fns *find_sym_fns (bfd *); static void decrement_reading_symtab (void *); @@ -148,6 +145,8 @@ static char *find_separate_debug_file (struct objfile *objfile); static void init_filename_language_table (void); +static void symfile_find_segment_sections (struct objfile *objfile); + void _initialize_symfile (void); /* List of all available sym_fns. On gdb startup, each object file reader @@ -432,12 +431,19 @@ init_objfile_sect_indices (struct objfile *objfile) /* This is where things get really weird... We MUST have valid indices for the various sect_index_* members or gdb will abort. So if for example, there is no ".text" section, we have to - accomodate that. Except when explicitly adding symbol files at - some address, section_offsets contains nothing but zeros, so it - doesn't matter which slot in section_offsets the individual - sect_index_* members index into. So if they are all zero, it is - safe to just point all the currently uninitialized indices to the - first slot. */ + accomodate that. First, check for a file with the standard + one or two segments. */ + + symfile_find_segment_sections (objfile); + + /* Except when explicitly adding symbol files at some address, + section_offsets contains nothing but zeros, so it doesn't matter + which slot in section_offsets the individual sect_index_* members + index into. So if they are all zero, it is safe to just point + all the currently uninitialized indices to the first slot. But + beware: if this is the main executable, it may be relocated + later, e.g. by the remote qOffsets packet, and then this will + be wrong! That's why we try segments first. */ for (i = 0; i < objfile->num_sections; i++) { @@ -478,8 +484,8 @@ place_section (bfd *abfd, asection *sect, void *obj) int done; ULONGEST align = ((ULONGEST) 1) << bfd_get_section_alignment (abfd, sect); - /* We are only interested in loadable sections. */ - if ((bfd_get_section_flags (abfd, sect) & SEC_LOAD) == 0) + /* We are only interested in allocated sections. */ + if ((bfd_get_section_flags (abfd, sect) & SEC_ALLOC) == 0) return; /* If the user specified an offset, honor it. */ @@ -503,13 +509,8 @@ place_section (bfd *abfd, asection *sect, void *obj) if (cur_sec == sect) continue; - /* We can only conflict with loadable sections. */ - if ((bfd_get_section_flags (abfd, cur_sec) & SEC_LOAD) == 0) - continue; - - /* We do not expect this to happen; just ignore sections in a - relocatable file with an assigned VMA. */ - if (bfd_section_vma (abfd, cur_sec) != 0) + /* We can only conflict with allocated sections. */ + if ((bfd_get_section_flags (abfd, cur_sec) & SEC_ALLOC) == 0) continue; /* If the section offset is 0, either the section has not been placed @@ -582,9 +583,62 @@ default_symfile_offsets (struct objfile *objfile, if ((bfd_get_file_flags (objfile->obfd) & (EXEC_P | DYNAMIC)) == 0) { struct place_section_arg arg; - arg.offsets = objfile->section_offsets; - arg.lowest = 0; - bfd_map_over_sections (objfile->obfd, place_section, &arg); + bfd *abfd = objfile->obfd; + asection *cur_sec; + CORE_ADDR lowest = 0; + + for (cur_sec = abfd->sections; cur_sec != NULL; cur_sec = cur_sec->next) + /* We do not expect this to happen; just skip this step if the + relocatable file has a section with an assigned VMA. */ + if (bfd_section_vma (abfd, cur_sec) != 0) + break; + + if (cur_sec == NULL) + { + CORE_ADDR *offsets = objfile->section_offsets->offsets; + + /* Pick non-overlapping offsets for sections the user did not + place explicitly. */ + arg.offsets = objfile->section_offsets; + arg.lowest = 0; + bfd_map_over_sections (objfile->obfd, place_section, &arg); + + /* Correctly filling in the section offsets is not quite + enough. Relocatable files have two properties that + (most) shared objects do not: + + - Their debug information will contain relocations. Some + shared libraries do also, but many do not, so this can not + be assumed. + + - If there are multiple code sections they will be loaded + at different relative addresses in memory than they are + in the objfile, since all sections in the file will start + at address zero. + + Because GDB has very limited ability to map from an + address in debug info to the correct code section, + it relies on adding SECT_OFF_TEXT to things which might be + code. If we clear all the section offsets, and set the + section VMAs instead, then symfile_relocate_debug_section + will return meaningful debug information pointing at the + correct sections. + + GDB has too many different data structures for section + addresses - a bfd, objfile, and so_list all have section + tables, as does exec_ops. Some of these could probably + be eliminated. */ + + for (cur_sec = abfd->sections; cur_sec != NULL; + cur_sec = cur_sec->next) + { + if ((bfd_get_section_flags (abfd, cur_sec) & SEC_ALLOC) == 0) + continue; + + bfd_set_section_vma (abfd, cur_sec, offsets[cur_sec->index]); + offsets[cur_sec->index] = 0; + } + } } /* Remember the bfd indexes for the .text, .data, .bss and @@ -593,6 +647,70 @@ default_symfile_offsets (struct objfile *objfile, } +/* Divide the file into segments, which are individual relocatable units. + This is the default version of the sym_fns.sym_segments function for + symbol readers that do not have an explicit representation of segments. + It assumes that object files do not have segments, and fully linked + files have a single segment. */ + +struct symfile_segment_data * +default_symfile_segments (bfd *abfd) +{ + int num_sections, i; + asection *sect; + struct symfile_segment_data *data; + CORE_ADDR low, high; + + /* Relocatable files contain enough information to position each + loadable section independently; they should not be relocated + in segments. */ + if ((bfd_get_file_flags (abfd) & (EXEC_P | DYNAMIC)) == 0) + return NULL; + + /* Make sure there is at least one loadable section in the file. */ + for (sect = abfd->sections; sect != NULL; sect = sect->next) + { + if ((bfd_get_section_flags (abfd, sect) & SEC_ALLOC) == 0) + continue; + + break; + } + if (sect == NULL) + return NULL; + + low = bfd_get_section_vma (abfd, sect); + high = low + bfd_get_section_size (sect); + + data = XZALLOC (struct symfile_segment_data); + data->num_segments = 1; + data->segment_bases = XCALLOC (1, CORE_ADDR); + data->segment_sizes = XCALLOC (1, CORE_ADDR); + + num_sections = bfd_count_sections (abfd); + data->segment_info = XCALLOC (num_sections, int); + + for (i = 0, sect = abfd->sections; sect != NULL; i++, sect = sect->next) + { + CORE_ADDR vma; + + if ((bfd_get_section_flags (abfd, sect) & SEC_ALLOC) == 0) + continue; + + vma = bfd_get_section_vma (abfd, sect); + if (vma < low) + low = vma; + if (vma + bfd_get_section_size (sect) > high) + high = vma + bfd_get_section_size (sect); + + data->segment_info[i] = 1; + } + + data->segment_bases[0] = low; + data->segment_sizes[0] = high - low; + + return data; +} + /* Process a symbol file, as either the main file or as a dynamically loaded file. @@ -639,7 +757,7 @@ syms_from_objfile (struct objfile *objfile, gdb_assert (! (addrs && offsets)); init_entry_point_info (objfile); - find_sym_fns (objfile); + objfile->sf = find_sym_fns (objfile->obfd); if (objfile->sf == NULL) return; /* No symbols. */ @@ -900,7 +1018,7 @@ symbol_file_add_with_addrs_or_offsets (bfd *abfd, int from_tty, { struct objfile *objfile; struct partial_symtab *psymtab; - char *debugfile; + char *debugfile = NULL; struct section_addr_info *orig_addrs = NULL; struct cleanup *my_cleanups; const char *name = bfd_get_filename (abfd); @@ -964,7 +1082,11 @@ symbol_file_add_with_addrs_or_offsets (bfd *abfd, int from_tty, } } - debugfile = find_separate_debug_file (objfile); + /* If the file has its own symbol tables it has no separate debug info. + `.dynsym'/`.symtab' go to MSYMBOLS, `.debug_info' goes to SYMTABS/PSYMTABS. + `.gnu_debuglink' may no longer be present with `.note.gnu.build-id'. */ + if (objfile->psymtabs == NULL) + debugfile = find_separate_debug_file (objfile); if (debugfile) { if (addrs != NULL) @@ -1020,8 +1142,7 @@ symbol_file_add_with_addrs_or_offsets (bfd *abfd, int from_tty, new_symfile_objfile (objfile, mainline, from_tty); - if (deprecated_target_new_objfile_hook) - deprecated_target_new_objfile_hook (objfile); + observer_notify_new_objfile (objfile); bfd_cache_close_all (); return (objfile); @@ -1107,6 +1228,97 @@ symbol_file_clear (int from_tty) printf_unfiltered (_("No symbol file now.\n")); } +struct build_id + { + size_t size; + gdb_byte data[1]; + }; + +/* Locate NT_GNU_BUILD_ID from ABFD and return its content. */ + +static struct build_id * +build_id_bfd_get (bfd *abfd) +{ + struct build_id *retval; + + if (!bfd_check_format (abfd, bfd_object) + || bfd_get_flavour (abfd) != bfd_target_elf_flavour + || elf_tdata (abfd)->build_id == NULL) + return NULL; + + retval = xmalloc (sizeof *retval - 1 + elf_tdata (abfd)->build_id_size); + retval->size = elf_tdata (abfd)->build_id_size; + memcpy (retval->data, elf_tdata (abfd)->build_id, retval->size); + + return retval; +} + +/* Return if FILENAME has NT_GNU_BUILD_ID matching the CHECK value. */ + +static int +build_id_verify (const char *filename, struct build_id *check) +{ + bfd *abfd; + struct build_id *found = NULL; + int retval = 0; + + /* We expect to be silent on the non-existing files. */ + abfd = bfd_openr (filename, gnutarget); + if (abfd == NULL) + return 0; + + found = build_id_bfd_get (abfd); + + if (found == NULL) + warning (_("File \"%s\" has no build-id, file skipped"), filename); + else if (found->size != check->size + || memcmp (found->data, check->data, found->size) != 0) + warning (_("File \"%s\" has a different build-id, file skipped"), filename); + else + retval = 1; + + if (!bfd_close (abfd)) + warning (_("cannot close \"%s\": %s"), filename, + bfd_errmsg (bfd_get_error ())); + return retval; +} + +static char * +build_id_to_debug_filename (struct build_id *build_id) +{ + char *link, *s, *retval = NULL; + gdb_byte *data = build_id->data; + size_t size = build_id->size; + + /* DEBUG_FILE_DIRECTORY/.build-id/ab/cdef */ + link = xmalloc (strlen (debug_file_directory) + (sizeof "/.build-id/" - 1) + 1 + + 2 * size + (sizeof ".debug" - 1) + 1); + s = link + sprintf (link, "%s/.build-id/", debug_file_directory); + if (size > 0) + { + size--; + s += sprintf (s, "%02x", (unsigned) *data++); + } + if (size > 0) + *s++ = '/'; + while (size-- > 0) + s += sprintf (s, "%02x", (unsigned) *data++); + strcpy (s, ".debug"); + + /* lrealpath() is expensive even for the usually non-existent files. */ + if (access (link, F_OK) == 0) + retval = lrealpath (link); + xfree (link); + + if (retval != NULL && !build_id_verify (retval, build_id)) + { + xfree (retval); + retval = NULL; + } + + return retval; +} + static char * get_debug_link_info (struct objfile *objfile, unsigned long *crc32_out) { @@ -1158,7 +1370,7 @@ separate_debug_file_exists (const char *name, unsigned long crc) return crc == file_crc; } -static char *debug_file_directory = NULL; +char *debug_file_directory = NULL; static void show_debug_file_directory (struct ui_file *file, int from_tty, struct cmd_list_element *c, const char *value) @@ -1180,9 +1392,29 @@ find_separate_debug_file (struct objfile *objfile) char *dir; char *debugfile; char *name_copy; + char *canon_name; bfd_size_type debuglink_size; unsigned long crc32; int i; + struct build_id *build_id; + + build_id = build_id_bfd_get (objfile->obfd); + if (build_id != NULL) + { + char *build_id_name; + + build_id_name = build_id_to_debug_filename (build_id); + free (build_id); + /* Prevent looping on a stripped .debug file. */ + if (build_id_name != NULL && strcmp (build_id_name, objfile->name) == 0) + { + warning (_("\"%s\": separate debug info file has no debug info"), + build_id_name); + xfree (build_id_name); + } + else if (build_id_name != NULL) + return build_id_name; + } basename = get_debug_link_info (objfile, &crc32); @@ -1247,6 +1479,30 @@ find_separate_debug_file (struct objfile *objfile) return xstrdup (debugfile); } + /* If the file is in the sysroot, try using its base path in the + global debugfile directory. */ + canon_name = lrealpath (dir); + if (canon_name + && strncmp (canon_name, gdb_sysroot, strlen (gdb_sysroot)) == 0 + && IS_DIR_SEPARATOR (canon_name[strlen (gdb_sysroot)])) + { + strcpy (debugfile, debug_file_directory); + strcat (debugfile, canon_name + strlen (gdb_sysroot)); + strcat (debugfile, "/"); + strcat (debugfile, basename); + + if (separate_debug_file_exists (debugfile, crc32)) + { + xfree (canon_name); + xfree (basename); + xfree (dir); + return xstrdup (debugfile); + } + } + + if (canon_name) + xfree (canon_name); + xfree (basename); xfree (dir); return NULL; @@ -1435,29 +1691,23 @@ add_symtab_fns (struct sym_fns *sf) struct sym_fns in the objfile structure, that contains cached information about the symbol file. */ -static void -find_sym_fns (struct objfile *objfile) +static struct sym_fns * +find_sym_fns (bfd *abfd) { struct sym_fns *sf; - enum bfd_flavour our_flavour = bfd_get_flavour (objfile->obfd); - char *our_target = bfd_get_target (objfile->obfd); + enum bfd_flavour our_flavour = bfd_get_flavour (abfd); if (our_flavour == bfd_target_srec_flavour || our_flavour == bfd_target_ihex_flavour || our_flavour == bfd_target_tekhex_flavour) - return; /* No symbols. */ + return NULL; /* No symbols. */ for (sf = symtab_fns; sf != NULL; sf = sf->next) - { - if (our_flavour == sf->sym_flavour) - { - objfile->sf = sf; - return; - } - } + if (our_flavour == sf->sym_flavour) + return sf; error (_("I'm sorry, Dave, I can't do that. Symbol format `%s' unknown."), - bfd_get_target (objfile->obfd)); + bfd_get_target (abfd)); } @@ -1467,7 +1717,47 @@ static void load_command (char *arg, int from_tty) { if (arg == NULL) - arg = get_exec_file (1); + { + char *parg; + int count = 0; + + parg = arg = get_exec_file (1); + + /* Count how many \ " ' tab space there are in the name. */ + while ((parg = strpbrk (parg, "\\\"'\t "))) + { + parg++; + count++; + } + + if (count) + { + /* We need to quote this string so buildargv can pull it apart. */ + char *temp = xmalloc (strlen (arg) + count + 1 ); + char *ptemp = temp; + char *prev; + + make_cleanup (xfree, temp); + + prev = parg = arg; + while ((parg = strpbrk (parg, "\\\"'\t "))) + { + strncpy (ptemp, prev, parg - prev); + ptemp += parg - prev; + prev = parg++; + *ptemp++ = '\\'; + } + strcpy (ptemp, prev); + + arg = temp; + } + } + + /* The user might be reloading because the binary has changed. Take + this opportunity to check. */ + reopen_exec_file (); + reread_symbols (); + target_load (arg, from_tty); /* After re-loading the executable, we don't really know which @@ -1484,15 +1774,6 @@ load_command (char *arg, int from_tty) we don't want to run a subprocess. On the other hand, I'm not sure how performance compares. */ -static int download_write_size = 512; -static void -show_download_write_size (struct ui_file *file, int from_tty, - struct cmd_list_element *c, const char *value) -{ - fprintf_filtered (file, _("\ -The write size used when downloading a program is %s.\n"), - value); -} static int validate_download = 0; /* Callback service function for generic_load (bfd_map_over_sections). */ @@ -1508,139 +1789,194 @@ add_section_size_callback (bfd *abfd, asection *asec, void *data) /* Opaque data for load_section_callback. */ struct load_section_data { unsigned long load_offset; + struct load_progress_data *progress_data; + VEC(memory_write_request_s) *requests; +}; + +/* Opaque data for load_progress. */ +struct load_progress_data { + /* Cumulative data. */ unsigned long write_count; unsigned long data_count; bfd_size_type total_size; }; +/* Opaque data for load_progress for a single section. */ +struct load_progress_section_data { + struct load_progress_data *cumulative; + + /* Per-section data. */ + const char *section_name; + ULONGEST section_sent; + ULONGEST section_size; + CORE_ADDR lma; + gdb_byte *buffer; +}; + +/* Target write callback routine for progress reporting. */ + +static void +load_progress (ULONGEST bytes, void *untyped_arg) +{ + struct load_progress_section_data *args = untyped_arg; + struct load_progress_data *totals; + + if (args == NULL) + /* Writing padding data. No easy way to get at the cumulative + stats, so just ignore this. */ + return; + + totals = args->cumulative; + + if (bytes == 0 && args->section_sent == 0) + { + /* The write is just starting. Let the user know we've started + this section. */ + ui_out_message (uiout, 0, "Loading section %s, size 0x%s lma 0x%s\n", + args->section_name, paddr_nz (args->section_size), + paddr_nz (args->lma)); + return; + } + + if (validate_download) + { + /* Broken memories and broken monitors manifest themselves here + when bring new computers to life. This doubles already slow + downloads. */ + /* NOTE: cagney/1999-10-18: A more efficient implementation + might add a verify_memory() method to the target vector and + then use that. remote.c could implement that method using + the ``qCRC'' packet. */ + gdb_byte *check = xmalloc (bytes); + struct cleanup *verify_cleanups = make_cleanup (xfree, check); + + if (target_read_memory (args->lma, check, bytes) != 0) + error (_("Download verify read failed at 0x%s"), + paddr (args->lma)); + if (memcmp (args->buffer, check, bytes) != 0) + error (_("Download verify compare failed at 0x%s"), + paddr (args->lma)); + do_cleanups (verify_cleanups); + } + totals->data_count += bytes; + args->lma += bytes; + args->buffer += bytes; + totals->write_count += 1; + args->section_sent += bytes; + if (quit_flag + || (deprecated_ui_load_progress_hook != NULL + && deprecated_ui_load_progress_hook (args->section_name, + args->section_sent))) + error (_("Canceled the download")); + + if (deprecated_show_load_progress != NULL) + deprecated_show_load_progress (args->section_name, + args->section_sent, + args->section_size, + totals->data_count, + totals->total_size); +} + /* Callback service function for generic_load (bfd_map_over_sections). */ static void load_section_callback (bfd *abfd, asection *asec, void *data) { + struct memory_write_request *new_request; struct load_section_data *args = data; + struct load_progress_section_data *section_data; + bfd_size_type size = bfd_get_section_size (asec); + gdb_byte *buffer; + const char *sect_name = bfd_get_section_name (abfd, asec); - if (bfd_get_section_flags (abfd, asec) & SEC_LOAD) - { - bfd_size_type size = bfd_get_section_size (asec); - if (size > 0) - { - gdb_byte *buffer; - struct cleanup *old_chain; - CORE_ADDR lma = bfd_section_lma (abfd, asec) + args->load_offset; - bfd_size_type block_size; - int err; - const char *sect_name = bfd_get_section_name (abfd, asec); - bfd_size_type sent; - - if (download_write_size > 0 && size > download_write_size) - block_size = download_write_size; - else - block_size = size; + if ((bfd_get_section_flags (abfd, asec) & SEC_LOAD) == 0) + return; - buffer = xmalloc (size); - old_chain = make_cleanup (xfree, buffer); + if (size == 0) + return; - /* Is this really necessary? I guess it gives the user something - to look at during a long download. */ - ui_out_message (uiout, 0, "Loading section %s, size 0x%s lma 0x%s\n", - sect_name, paddr_nz (size), paddr_nz (lma)); + new_request = VEC_safe_push (memory_write_request_s, + args->requests, NULL); + memset (new_request, 0, sizeof (struct memory_write_request)); + section_data = xcalloc (1, sizeof (struct load_progress_section_data)); + new_request->begin = bfd_section_lma (abfd, asec) + args->load_offset; + new_request->end = new_request->begin + size; /* FIXME Should size be in instead? */ + new_request->data = xmalloc (size); + new_request->baton = section_data; - bfd_get_section_contents (abfd, asec, buffer, 0, size); + buffer = new_request->data; - sent = 0; - do - { - int len; - bfd_size_type this_transfer = size - sent; - - if (this_transfer >= block_size) - this_transfer = block_size; - len = target_write_memory_partial (lma, buffer, - this_transfer, &err); - if (err) - break; - if (validate_download) - { - /* Broken memories and broken monitors manifest - themselves here when bring new computers to - life. This doubles already slow downloads. */ - /* NOTE: cagney/1999-10-18: A more efficient - implementation might add a verify_memory() - method to the target vector and then use - that. remote.c could implement that method - using the ``qCRC'' packet. */ - gdb_byte *check = xmalloc (len); - struct cleanup *verify_cleanups = - make_cleanup (xfree, check); - - if (target_read_memory (lma, check, len) != 0) - error (_("Download verify read failed at 0x%s"), - paddr (lma)); - if (memcmp (buffer, check, len) != 0) - error (_("Download verify compare failed at 0x%s"), - paddr (lma)); - do_cleanups (verify_cleanups); - } - args->data_count += len; - lma += len; - buffer += len; - args->write_count += 1; - sent += len; - if (quit_flag - || (deprecated_ui_load_progress_hook != NULL - && deprecated_ui_load_progress_hook (sect_name, sent))) - error (_("Canceled the download")); - - if (deprecated_show_load_progress != NULL) - deprecated_show_load_progress (sect_name, sent, size, - args->data_count, - args->total_size); - } - while (sent < size); + section_data->cumulative = args->progress_data; + section_data->section_name = sect_name; + section_data->section_size = size; + section_data->lma = new_request->begin; + section_data->buffer = buffer; - if (err != 0) - error (_("Memory access error while loading section %s."), sect_name); + bfd_get_section_contents (abfd, asec, buffer, 0, size); +} - do_cleanups (old_chain); - } +/* Clean up an entire memory request vector, including load + data and progress records. */ + +static void +clear_memory_write_data (void *arg) +{ + VEC(memory_write_request_s) **vec_p = arg; + VEC(memory_write_request_s) *vec = *vec_p; + int i; + struct memory_write_request *mr; + + for (i = 0; VEC_iterate (memory_write_request_s, vec, i, mr); ++i) + { + xfree (mr->data); + xfree (mr->baton); } + VEC_free (memory_write_request_s, vec); } void generic_load (char *args, int from_tty) { - asection *s; bfd *loadfile_bfd; struct timeval start_time, end_time; char *filename; - struct cleanup *old_cleanups; - char *offptr; + struct cleanup *old_cleanups = make_cleanup (null_cleanup, 0); struct load_section_data cbdata; + struct load_progress_data total_progress; + CORE_ADDR entry; + char **argv; + + memset (&cbdata, 0, sizeof (cbdata)); + memset (&total_progress, 0, sizeof (total_progress)); + cbdata.progress_data = &total_progress; + + make_cleanup (clear_memory_write_data, &cbdata.requests); - cbdata.load_offset = 0; /* Offset to add to vma for each section. */ - cbdata.write_count = 0; /* Number of writes needed. */ - cbdata.data_count = 0; /* Number of bytes written to target memory. */ - cbdata.total_size = 0; /* Total size of all bfd sectors. */ + argv = buildargv (args); - /* Parse the input argument - the user can specify a load offset as - a second argument. */ - filename = xmalloc (strlen (args) + 1); - old_cleanups = make_cleanup (xfree, filename); - strcpy (filename, args); - offptr = strchr (filename, ' '); - if (offptr != NULL) + if (argv == NULL) + nomem(0); + + make_cleanup_freeargv (argv); + + filename = tilde_expand (argv[0]); + make_cleanup (xfree, filename); + + if (argv[1] != NULL) { char *endptr; - cbdata.load_offset = strtoul (offptr, &endptr, 0); - if (offptr == endptr) - error (_("Invalid download offset:%s."), offptr); - *offptr = '\0'; + cbdata.load_offset = strtoul (argv[1], &endptr, 0); + + /* If the last word was not a valid number then + treat it as a file name with spaces in. */ + if (argv[1] == endptr) + error (_("Invalid download offset:%s."), argv[1]); + + if (argv[2] != NULL) + error (_("Too many parameters.")); } - else - cbdata.load_offset = 0; /* Open the file for loading. */ loadfile_bfd = bfd_openr (filename, gnutarget); @@ -1662,11 +1998,15 @@ generic_load (char *args, int from_tty) } bfd_map_over_sections (loadfile_bfd, add_section_size_callback, - (void *) &cbdata.total_size); + (void *) &total_progress.total_size); + + bfd_map_over_sections (loadfile_bfd, load_section_callback, &cbdata); gettimeofday (&start_time, NULL); - bfd_map_over_sections (loadfile_bfd, load_section_callback, &cbdata); + if (target_write_memory_blocks (cbdata.requests, flash_discard, + load_progress) != 0) + error (_("Load failed")); gettimeofday (&end_time, NULL); @@ -1674,7 +2014,7 @@ generic_load (char *args, int from_tty) ui_out_text (uiout, "Start address "); ui_out_field_fmt (uiout, "address", "0x%s", paddr_nz (entry)); ui_out_text (uiout, ", load size "); - ui_out_field_fmt (uiout, "load-size", "%lu", cbdata.data_count); + ui_out_field_fmt (uiout, "load-size", "%lu", total_progress.data_count); ui_out_text (uiout, "\n"); /* We were doing this in remote-mips.c, I suspect it is right for other targets too. */ @@ -1686,8 +2026,9 @@ generic_load (char *args, int from_tty) file is loaded in. Some targets do (e.g., remote-vx.c) but others don't (or didn't - perhaps they have all been deleted). */ - print_transfer_performance (gdb_stdout, cbdata.data_count, - cbdata.write_count, &start_time, &end_time); + print_transfer_performance (gdb_stdout, total_progress.data_count, + total_progress.write_count, + &start_time, &end_time); do_cleanups (old_cleanups); } @@ -1719,7 +2060,7 @@ print_transfer_performance (struct ui_file *stream, const struct timeval *start_time, const struct timeval *end_time) { - unsigned long time_count; + ULONGEST time_count; /* Compute the elapsed time in milliseconds, as a tradeoff between accuracy and overflow. */ @@ -1729,9 +2070,23 @@ print_transfer_performance (struct ui_file *stream, ui_out_text (uiout, "Transfer rate: "); if (time_count > 0) { - ui_out_field_fmt (uiout, "transfer-rate", "%lu", - 1000 * (data_count * 8) / time_count); - ui_out_text (uiout, " bits/sec"); + unsigned long rate = ((ULONGEST) data_count * 1000) / time_count; + + if (ui_out_is_mi_like_p (uiout)) + { + ui_out_field_fmt (uiout, "transfer-rate", "%lu", rate * 8); + ui_out_text (uiout, " bits/sec"); + } + else if (rate < 1024) + { + ui_out_field_fmt (uiout, "transfer-rate", "%lu", rate); + ui_out_text (uiout, " bytes/sec"); + } + else + { + ui_out_field_fmt (uiout, "transfer-rate", "%lu", rate / 1024); + ui_out_text (uiout, " KB/sec"); + } } else { @@ -1769,6 +2124,7 @@ add_symbol_file_command (char *args, int from_tty) int i; int expecting_sec_name = 0; int expecting_sec_addr = 0; + char **argv; struct sect_opt { @@ -1790,28 +2146,15 @@ add_symbol_file_command (char *args, int from_tty) if (args == NULL) error (_("add-symbol-file takes a file name and an address")); - /* Make a copy of the string that we can safely write into. */ - args = xstrdup (args); - - while (*args != '\000') - { - /* Any leading spaces? */ - while (isspace (*args)) - args++; - - /* Point arg to the beginning of the argument. */ - arg = args; - - /* Move args pointer over the argument. */ - while ((*args != '\000') && !isspace (*args)) - args++; + argv = buildargv (args); + make_cleanup_freeargv (argv); - /* If there are more arguments, terminate arg and - proceed past it. */ - if (*args != '\000') - *args++ = '\000'; + if (argv == NULL) + nomem (0); - /* Now process the argument. */ + for (arg = argv[0], argcnt = 0; arg != NULL; arg = argv[++argcnt]) + { + /* Process the argument. */ if (argcnt == 0) { /* The first argument is the file name. */ @@ -1825,7 +2168,7 @@ add_symbol_file_command (char *args, int from_tty) to load the program. */ sect_opts[section_index].name = ".text"; sect_opts[section_index].value = arg; - if (++section_index > num_sect_opts) + if (++section_index >= num_sect_opts) { num_sect_opts *= 2; sect_opts = ((struct sect_opt *) @@ -1861,7 +2204,7 @@ add_symbol_file_command (char *args, int from_tty) { sect_opts[section_index].value = arg; expecting_sec_addr = 0; - if (++section_index > num_sect_opts) + if (++section_index >= num_sect_opts) { num_sect_opts *= 2; sect_opts = ((struct sect_opt *) @@ -1874,7 +2217,6 @@ add_symbol_file_command (char *args, int from_tty) error (_("USAGE: add-symbol-file [-mapped] [-readnow] [-s ]*")); } } - argcnt++; } /* This command takes at least two arguments. The first one is a @@ -2063,7 +2405,6 @@ reread_symbols (void) sizeof (objfile->msymbol_hash)); memset (&objfile->msymbol_demangled_hash, 0, sizeof (objfile->msymbol_demangled_hash)); - objfile->fundamental_types = NULL; clear_objfile_data (objfile); if (objfile->sf != NULL) { @@ -2210,6 +2551,8 @@ reread_separate_symbols (struct objfile *objfile) objfile->separate_debug_objfile->separate_debug_objfile_backlink = objfile; } + if (debug_file) + xfree (debug_file); } @@ -2344,6 +2687,7 @@ init_filename_language_table (void) add_filename_language (".f", language_fortran); add_filename_language (".F", language_fortran); add_filename_language (".s", language_asm); + add_filename_language (".sx", language_asm); add_filename_language (".S", language_asm); add_filename_language (".pas", language_pascal); add_filename_language (".p", language_pascal); @@ -2405,14 +2749,6 @@ allocate_symtab (char *filename, struct objfile *objfile) symtab->next = objfile->symtabs; objfile->symtabs = symtab; - /* FIXME: This should go away. It is only defined for the Z8000, - and the Z8000 definition of this macro doesn't have anything to - do with the now-nonexistent EXTRA_SYMTAB_INFO macro, it's just - here for convenience. */ -#ifdef INIT_EXTRA_SYMTAB_INFO - INIT_EXTRA_SYMTAB_INFO (symtab); -#endif - return (symtab); } @@ -2501,8 +2837,17 @@ clear_symtab_users (void) breakpoint_re_set (); set_default_breakpoint (0, 0, 0, 0); clear_pc_function_cache (); - if (deprecated_target_new_objfile_hook) - deprecated_target_new_objfile_hook (NULL); + observer_notify_new_objfile (NULL); + + /* Clear globals which might have pointed into a removed objfile. + FIXME: It's not clear which of these are supposed to persist + between expressions and which ought to be reset each time. */ + expression_context_block = NULL; + innermost_block = NULL; + + /* Varobj may refer to old symbols, perform a cleanup. */ + varobj_invalidate (); + } static void @@ -2800,75 +3145,6 @@ add_psymbol_to_list (char *name, int namelength, domain_enum domain, return psym; } -/* Add a symbol with a long value to a psymtab. This differs from - * add_psymbol_to_list above in taking both a mangled and a demangled - * name. */ - -void -add_psymbol_with_dem_name_to_list (char *name, int namelength, char *dem_name, - int dem_namelength, domain_enum domain, - enum address_class class, - struct psymbol_allocation_list *list, long val, /* Value as a long */ - CORE_ADDR coreaddr, /* Value as a CORE_ADDR */ - enum language language, - struct objfile *objfile) -{ - struct partial_symbol *psym; - char *buf = alloca (namelength + 1); - /* psymbol is static so that there will be no uninitialized gaps in the - structure which might contain random data, causing cache misses in - bcache. */ - static struct partial_symbol psymbol; - - /* Create local copy of the partial symbol */ - - memcpy (buf, name, namelength); - buf[namelength] = '\0'; - DEPRECATED_SYMBOL_NAME (&psymbol) = deprecated_bcache (buf, namelength + 1, - objfile->psymbol_cache); - - buf = alloca (dem_namelength + 1); - memcpy (buf, dem_name, dem_namelength); - buf[dem_namelength] = '\0'; - - switch (language) - { - case language_c: - case language_cplus: - SYMBOL_CPLUS_DEMANGLED_NAME (&psymbol) = - deprecated_bcache (buf, dem_namelength + 1, objfile->psymbol_cache); - break; - /* FIXME What should be done for the default case? Ignoring for now. */ - } - - /* val and coreaddr are mutually exclusive, one of them *will* be zero */ - if (val != 0) - { - SYMBOL_VALUE (&psymbol) = val; - } - else - { - SYMBOL_VALUE_ADDRESS (&psymbol) = coreaddr; - } - SYMBOL_SECTION (&psymbol) = 0; - SYMBOL_LANGUAGE (&psymbol) = language; - PSYMBOL_DOMAIN (&psymbol) = domain; - PSYMBOL_CLASS (&psymbol) = class; - SYMBOL_INIT_LANGUAGE_SPECIFIC (&psymbol, language); - - /* Stash the partial symbol away in the cache */ - psym = deprecated_bcache (&psymbol, sizeof (struct partial_symbol), - objfile->psymbol_cache); - - /* Save pointer to partial symbol in psymtab, growing symtab if needed. */ - if (list->next >= list->list + list->size) - { - extend_psymbol_list (list, objfile); - } - *list->next++ = psym; - OBJSTAT (objfile, n_psyms++); -} - /* Initialize storage for partial symbols. */ void @@ -2962,10 +3238,6 @@ init_psymbol_list (struct objfile *objfile, int total_symbols) enum overlay_debugging_state overlay_debugging = ovly_off; int overlay_cache_invalid = 0; /* True if need to refresh mapped state */ -/* Target vector for refreshing overlay mapped state */ -static void simple_overlay_update (struct obj_section *); -void (*target_overlay_update) (struct obj_section *) = simple_overlay_update; - /* Function: section_is_overlay (SECTION) Returns true if SECTION has VMA not equal to LMA, ie. SECTION is loaded at an address different from where it will "run". */ @@ -3019,9 +3291,9 @@ overlay_is_mapped (struct obj_section *osect) case ovly_off: return 0; /* overlay debugging off */ case ovly_auto: /* overlay debugging automatic */ - /* Unles there is a target_overlay_update function, + /* Unles there is a gdbarch_overlay_update function, there's really nothing useful to do here (can't really go auto) */ - if (target_overlay_update) + if (gdbarch_overlay_update_p (current_gdbarch)) { if (overlay_cache_invalid) { @@ -3029,7 +3301,7 @@ overlay_is_mapped (struct obj_section *osect) overlay_cache_invalid = 0; } if (osect->ovly_mapped == -1) - (*target_overlay_update) (osect); + gdbarch_overlay_update (current_gdbarch, osect); } /* fall thru to manual case */ case ovly_on: /* overlay debugging manual */ @@ -3382,8 +3654,8 @@ overlay_off_command (char *args, int from_tty) static void overlay_load_command (char *args, int from_tty) { - if (target_overlay_update) - (*target_overlay_update) (NULL); + if (gdbarch_overlay_update_p (current_gdbarch)) + gdbarch_overlay_update (current_gdbarch, NULL); else error (_("This target does not know how to read its overlay state.")); } @@ -3407,7 +3679,7 @@ overlay_command (char *args, int from_tty) This is GDB's default target overlay layer. It works with the minimal overlay manager supplied as an example by Cygnus. The - entry point is via a function pointer "target_overlay_update", + entry point is via a function pointer "gdbarch_overlay_update", so targets that use a different runtime overlay manager can substitute their own overlay_update function and take over the function pointer. @@ -3454,7 +3726,8 @@ enum ovly_index { VMA, SIZE, LMA, MAPPED }; -#define TARGET_LONG_BYTES (TARGET_LONG_BIT / TARGET_CHAR_BIT) +#define TARGET_LONG_BYTES (gdbarch_long_bit (current_gdbarch) \ + / TARGET_CHAR_BIT) /* Throw away the cached copy of _ovly_table */ static void @@ -3610,7 +3883,7 @@ simple_overlay_update_1 (struct obj_section *osect) If a cached entry can't be found or the cache isn't valid, then re-read the entire cache, and go ahead and update all sections. */ -static void +void simple_overlay_update (struct obj_section *osect) { struct objfile *objfile; @@ -3694,6 +3967,133 @@ symfile_relocate_debug_section (bfd *abfd, asection *sectp, bfd_byte *buf) return bfd_simple_get_relocated_section_contents (abfd, sectp, buf, NULL); } +struct symfile_segment_data * +get_symfile_segment_data (bfd *abfd) +{ + struct sym_fns *sf = find_sym_fns (abfd); + + if (sf == NULL) + return NULL; + + return sf->sym_segments (abfd); +} + +void +free_symfile_segment_data (struct symfile_segment_data *data) +{ + xfree (data->segment_bases); + xfree (data->segment_sizes); + xfree (data->segment_info); + xfree (data); +} + + +/* Given: + - DATA, containing segment addresses from the object file ABFD, and + the mapping from ABFD's sections onto the segments that own them, + and + - SEGMENT_BASES[0 .. NUM_SEGMENT_BASES - 1], holding the actual + segment addresses reported by the target, + store the appropriate offsets for each section in OFFSETS. + + If there are fewer entries in SEGMENT_BASES than there are segments + in DATA, then apply SEGMENT_BASES' last entry to all the segments. + + If there are more, then verify that all the excess addresses are + the same as the last legitimate one, and then ignore them. This + allows "TextSeg=X;DataSeg=X" qOffset replies for files which have + only a single segment. */ +int +symfile_map_offsets_to_segments (bfd *abfd, struct symfile_segment_data *data, + struct section_offsets *offsets, + int num_segment_bases, + const CORE_ADDR *segment_bases) +{ + int i; + asection *sect; + + /* It doesn't make sense to call this function unless you have some + segment base addresses. */ + gdb_assert (segment_bases > 0); + + /* If we do not have segment mappings for the object file, we + can not relocate it by segments. */ + gdb_assert (data != NULL); + gdb_assert (data->num_segments > 0); + + /* Check any extra SEGMENT_BASES entries. */ + if (num_segment_bases > data->num_segments) + for (i = data->num_segments; i < num_segment_bases; i++) + if (segment_bases[i] != segment_bases[data->num_segments - 1]) + return 0; + + for (i = 0, sect = abfd->sections; sect != NULL; i++, sect = sect->next) + { + int which = data->segment_info[i]; + + gdb_assert (0 <= which && which <= data->num_segments); + + /* Don't bother computing offsets for sections that aren't + loaded as part of any segment. */ + if (! which) + continue; + + /* Use the last SEGMENT_BASES entry as the address of any extra + segments mentioned in DATA->segment_info. */ + if (which > num_segment_bases) + which = num_segment_bases; + + offsets->offsets[i] = (segment_bases[which - 1] + - data->segment_bases[which - 1]); + } + + return 1; +} + +static void +symfile_find_segment_sections (struct objfile *objfile) +{ + bfd *abfd = objfile->obfd; + int i; + asection *sect; + struct symfile_segment_data *data; + + data = get_symfile_segment_data (objfile->obfd); + if (data == NULL) + return; + + if (data->num_segments != 1 && data->num_segments != 2) + { + free_symfile_segment_data (data); + return; + } + + for (i = 0, sect = abfd->sections; sect != NULL; i++, sect = sect->next) + { + CORE_ADDR vma; + int which = data->segment_info[i]; + + if (which == 1) + { + if (objfile->sect_index_text == -1) + objfile->sect_index_text = sect->index; + + if (objfile->sect_index_rodata == -1) + objfile->sect_index_rodata = sect->index; + } + else if (which == 2) + { + if (objfile->sect_index_data == -1) + objfile->sect_index_data = sect->index; + + if (objfile->sect_index_bss == -1) + objfile->sect_index_bss = sect->index; + } + } + + free_symfile_segment_data (data); +} + void _initialize_symfile (void) { @@ -3706,8 +4106,8 @@ to execute."), &cmdlist); set_cmd_completer (c, filename_completer); c = add_cmd ("add-symbol-file", class_files, add_symbol_file_command, _("\ +Load symbols from FILE, assuming FILE has been dynamically loaded.\n\ Usage: add-symbol-file FILE ADDR [-s -s ...]\n\ -Load the symbols from FILE, assuming FILE has been dynamically loaded.\n\ ADDR is the starting address of the file's text.\n\ The optional arguments are section-name section-address pairs and\n\ should be specified if the data and bss segments are not contiguous\n\ @@ -3724,7 +4124,8 @@ Load the symbols from shared objects in the dynamic linker's link map."), c = add_cmd ("load", class_files, load_command, _("\ Dynamically load FILE into the running program, and record its symbols\n\ -for access from GDB."), &cmdlist); +for access from GDB.\n\ +A load OFFSET may also be given."), &cmdlist); set_cmd_completer (c, filename_completer); add_setshow_boolean_cmd ("symbol-reloading", class_support, @@ -3774,20 +4175,6 @@ Usage: set extension-language .foo bar"), add_info ("extensions", info_ext_lang_command, _("All filename extensions associated with a source language.")); - add_setshow_integer_cmd ("download-write-size", class_obscure, - &download_write_size, _("\ -Set the write size used when downloading a program."), _("\ -Show the write size used when downloading a program."), _("\ -Only used when downloading a program onto a remote\n\ -target. Specify zero, or a negative value, to disable\n\ -blocked writes. The actual size of each transfer is also\n\ -limited by the size of the target packet and the memory\n\ -cache."), - NULL, - show_download_write_size, - &setlist, &showlist); - - debug_file_directory = xstrdup (DEBUGDIR); add_setshow_optional_filename_cmd ("debug-file-directory", class_support, &debug_file_directory, _("\ Set the directory where separate debug symbols are searched for."), _("\