--- ./bfd/aoutx.h 2007-08-10 01:14:55.000000000 +0200 +++ ./bfd/aoutx.h 2008-06-18 23:36:29.000000000 +0200 @@ -1291,7 +1291,9 @@ aout_get_external_symbols (bfd *abfd) { bfd_size_type count; struct external_nlist *syms; +#ifndef USE_MMAP bfd_size_type amt; +#endif count = exec_hdr (abfd)->a_syms / EXTERNAL_NLIST_SIZE; if (count == 0) --- ./gdb/Makefile.in 2008-06-18 22:54:17.000000000 +0200 +++ ./gdb/Makefile.in 2008-06-18 23:36:29.000000000 +0200 @@ -613,6 +613,7 @@ SFILES = ada-exp.y ada-lang.c ada-typepr m2-exp.y m2-lang.c m2-typeprint.c m2-valprint.c \ macrotab.c macroexp.c macrocmd.c macroscope.c main.c maint.c \ mdebugread.c memattr.c mem-break.c minsyms.c mipsread.c memory-map.c \ + mmapcache.c mmapcache-alloc.c \ objc-exp.y objc-lang.c \ objfiles.c osabi.c observer.c \ p-exp.y p-lang.c p-typeprint.c p-valprint.c parse.c printcmd.c \ @@ -840,6 +841,8 @@ mips_tdep_h = mips-tdep.h memory_map_h = memory-map.h $(memattr_h) mn10300_tdep_h = mn10300-tdep.h monitor_h = monitor.h +mmapcache_h = mmapcache.h +mmapcache_alloc_h = mmapcache-alloc.h nbsd_nat_h = nbsd-nat.h nbsd_tdep_h = nbsd-tdep.h nto_tdep_h = nto-tdep.h $(solist_h) $(osabi_h) $(regset_h) @@ -991,6 +994,7 @@ HFILES_NO_SRCDIR = bcache.h buildsym.h c symfile.h stabsread.h target.h terminal.h typeprint.h \ xcoffsolib.h \ macrotab.h macroexp.h macroscope.h \ + mmapcache.h mmapcache-alloc.h \ prologue-value.h \ ada-lang.h c-lang.h f-lang.h \ jv-lang.h \ @@ -1043,6 +1047,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $ interps.o \ main.o \ macrotab.o macrocmd.o macroexp.o macroscope.o \ + mmapcache.o mmapcache-alloc.o \ event-loop.o event-top.o inf-loop.o completer.o \ gdbarch.o arch-utils.o gdbtypes.o osabi.o copying.o \ memattr.o mem-break.o target.o parse.o language.o buildsym.o \ --- ./gdb/TODO 1970-01-01 01:00:00.000000000 +0100 +++ ./gdb/TODO 2008-06-20 00:12:36.000000000 +0200 @@ -0,0 +1,15 @@ +canonicalize filename +check timestamp +sanity check the same gdb binary build +provide some mmapcache freeing/optimization +delete the readonly mmapcache fragments +tune the 16MB pregap +protect creating a cache with atexit +symbol_file_add_with_addrs_or_offsets cleanups +freeing/deleting +freeing from mmapalloc not in xmem_mmapalloc? +splay_tree_node of mmapcache_mem should contain only base and mapped +disk mmapcache should get exclusively locked and shared-updated later +xmem_mmapalloc_push protect by cleanup +gdb_id: read the first pagesize of /proc/self/exe +~/.gdb_cache should have deep directory tree --- ./gdb/ada-lang.c 2008-06-18 22:54:17.000000000 +0200 +++ ./gdb/ada-lang.c 2008-06-18 23:36:29.000000000 +0200 @@ -1203,9 +1203,9 @@ ada_decode_symbol (const struct general_ if (*resultp == NULL) { const char *decoded = ada_decode (gsymbol->name); - if (gsymbol->bfd_section != NULL) + if (gsymbol->objfile != NULL) { - bfd *obfd = gsymbol->bfd_section->owner; + bfd *obfd = gsymbol->objfile->obfd; if (obfd != NULL) { struct objfile *objf; --- ./gdb/config.in 2008-06-18 22:54:17.000000000 +0200 +++ ./gdb/config.in 2008-06-18 23:36:29.000000000 +0200 @@ -174,6 +174,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_LINK_H +/* Define to 1 if you have the header file. */ +#undef HAVE_LINUX_MAGIC_H + /* Define to 1 if the compiler supports long double. */ #undef HAVE_LONG_DOUBLE --- ./gdb/configure.ac 2008-06-18 22:54:17.000000000 +0200 +++ ./gdb/configure.ac 2008-06-18 23:36:29.000000000 +0200 @@ -527,6 +527,7 @@ AC_CHECK_HEADERS(sys/user32.h sys/procfs AC_CHECK_HEADERS(sys/wait.h wait.h) AC_CHECK_HEADERS(termios.h termio.h sgtty.h) AC_CHECK_HEADERS(unistd.h) +AC_CHECK_HEADERS(linux/magic.h) # On Solaris 2.[789], we need to define _MSE_INT_H to avoid a clash # between and that would cause AC_CHECK_HEADERS to --- ./gdb/dwarf2-frame.c 2008-01-01 23:53:09.000000000 +0100 +++ ./gdb/dwarf2-frame.c 2008-06-18 23:36:29.000000000 +0200 @@ -1978,6 +1978,8 @@ dwarf2_build_frame_info (struct objfile struct comp_unit unit; gdb_byte *frame_ptr; +return; // FIXME: This functions has no effect! + /* Build a minimal decoding of the DWARF2 compilation unit. */ unit.abfd = objfile->obfd; unit.objfile = objfile; @@ -1991,8 +1993,9 @@ dwarf2_build_frame_info (struct objfile asection *got, *txt; unit.cie = NULL; - unit.dwarf_frame_buffer = dwarf2_read_section (objfile, - dwarf_eh_frame_section); + gdb_assert (0); +// dwarf2_map_section (objfile, dwarf_eh_frame_section, +// &unit.dwarf_frame_buffer); unit.dwarf_frame_size = bfd_get_section_size (dwarf_eh_frame_section); unit.dwarf_frame_section = dwarf_eh_frame_section; @@ -2019,8 +2022,9 @@ dwarf2_build_frame_info (struct objfile if (dwarf_frame_section) { unit.cie = NULL; - unit.dwarf_frame_buffer = dwarf2_read_section (objfile, - dwarf_frame_section); + gdb_assert (0); +// dwarf2_map_section (objfile, dwarf_frame_section, +// &unit.dwarf_frame_buffer); unit.dwarf_frame_size = bfd_get_section_size (dwarf_frame_section); unit.dwarf_frame_section = dwarf_frame_section; --- ./gdb/dwarf2read.c 2008-06-18 22:54:17.000000000 +0200 +++ ./gdb/dwarf2read.c 2008-06-18 23:36:29.000000000 +0200 @@ -48,6 +48,10 @@ #include "gdbcmd.h" #include "dwarf2block.h" #include "f-lang.h" +#include "gdb_stdint.h" +#include "mmapcache.h" +#include +#include "libbfd.h" #include #include "gdb_string.h" @@ -142,6 +146,13 @@ _STATEMENT_PROLOGUE; static const struct objfile_data *dwarf2_objfile_data_key; +struct mapping + { + struct mapping *next; + uint8_t *base; + size_t size; + }; + struct dwarf2_per_objfile { /* Sizes of debugging sections. */ @@ -180,6 +191,9 @@ struct dwarf2_per_objfile /* A flag indicating wether this objfile has a section loaded at a VMA of 0. */ int has_section_at_zero; + + /* Readonly files mappings we need to unmap on FREE_OBJFILE. */ + struct mapping *mapping; }; static struct dwarf2_per_objfile *dwarf2_per_objfile; @@ -813,10 +827,6 @@ static char *read_indirect_string (bfd * const struct comp_unit_head *, unsigned int *); -static unsigned long read_unsigned_leb128 (bfd *, gdb_byte *, unsigned int *); - -static long read_signed_leb128 (bfd *, gdb_byte *, unsigned int *); - static gdb_byte *skip_leb128 (bfd *, gdb_byte *); static void set_cu_language (unsigned int, struct dwarf2_cu *); @@ -981,6 +991,9 @@ static char *dwarf_bool_name (unsigned i static char *dwarf_type_encoding_name (unsigned int); +static void dwarf2_map_section (struct objfile *objfile, asection *sectp, + gdb_byte **data_pointer); + #if 0 static char *dwarf_cfi_name (unsigned int); @@ -1092,10 +1105,19 @@ dwarf2_has_info (struct objfile *objfile { struct dwarf2_per_objfile *data; - /* Initialize per-objfile state. */ - data = obstack_alloc (&objfile->objfile_obstack, sizeof (*data)); - memset (data, 0, sizeof (*data)); - set_objfile_data (objfile, dwarf2_objfile_data_key, data); + data = objfile_data (objfile, dwarf2_objfile_data_key); + if (data == NULL) + { + /* Initialize per-objfile state. */ + data = obstack_alloc (&objfile->objfile_obstack, sizeof (*data)); + memset (data, 0, sizeof (*data)); + set_objfile_data (objfile, dwarf2_objfile_data_key, data); + } + else + { + /* Formerly mapped files must be mapped again. */ + data->mapping = NULL; + } dwarf2_per_objfile = data; dwarf_info_section = 0; @@ -1192,35 +1214,44 @@ dwarf2_build_psymtabs (struct objfile *o { /* We definitely need the .debug_info and .debug_abbrev sections */ - dwarf2_per_objfile->info_buffer = dwarf2_read_section (objfile, dwarf_info_section); - dwarf2_per_objfile->abbrev_buffer = dwarf2_read_section (objfile, dwarf_abbrev_section); + dwarf2_map_section (objfile, dwarf_info_section, + &dwarf2_per_objfile->info_buffer); + dwarf2_map_section (objfile, dwarf_abbrev_section, + &dwarf2_per_objfile->abbrev_buffer); if (dwarf_line_section) - dwarf2_per_objfile->line_buffer = dwarf2_read_section (objfile, dwarf_line_section); + dwarf2_map_section (objfile, dwarf_line_section, + &dwarf2_per_objfile->line_buffer); else dwarf2_per_objfile->line_buffer = NULL; if (dwarf_str_section) - dwarf2_per_objfile->str_buffer = dwarf2_read_section (objfile, dwarf_str_section); + dwarf2_map_section (objfile, dwarf_str_section, + &dwarf2_per_objfile->str_buffer); else dwarf2_per_objfile->str_buffer = NULL; if (dwarf_macinfo_section) - dwarf2_per_objfile->macinfo_buffer = dwarf2_read_section (objfile, - dwarf_macinfo_section); + dwarf2_map_section (objfile, dwarf_macinfo_section, + &dwarf2_per_objfile->macinfo_buffer); else dwarf2_per_objfile->macinfo_buffer = NULL; if (dwarf_ranges_section) - dwarf2_per_objfile->ranges_buffer = dwarf2_read_section (objfile, dwarf_ranges_section); + dwarf2_map_section (objfile, dwarf_ranges_section, + &dwarf2_per_objfile->ranges_buffer); else dwarf2_per_objfile->ranges_buffer = NULL; if (dwarf_loc_section) - dwarf2_per_objfile->loc_buffer = dwarf2_read_section (objfile, dwarf_loc_section); + dwarf2_map_section (objfile, dwarf_loc_section, + &dwarf2_per_objfile->loc_buffer); else dwarf2_per_objfile->loc_buffer = NULL; + if (objfile->flags & OBJF_MAPPED) + return; + if ((mainline == 1) || (objfile->global_psymbols.size == 0 && objfile->static_psymbols.size == 0)) @@ -5410,6 +5441,67 @@ dwarf2_read_section (struct objfile *obj return buf; } +static void +dwarf2_map_section (struct objfile *objfile, asection *sectp, + gdb_byte **data_pointer) +{ + bfd *abfd = objfile->obfd; + bfd_size_type size = bfd_get_section_size (sectp); + + if (size == 0) + { + *data_pointer = NULL; + return; + } + + /* We could also read-write map (bfd_get_file_window (..., TRUE)) the + relocated sections but they are uncommon for the debugging. */ + if (!symfile_relocate_debug_section_if (abfd, sectp) + && abfd->iostream != NULL && abfd->iovec != NULL + && abfd->iovec->bseek (abfd, sectp->filepos, SEEK_SET) == 0) + { + /* We cannot use bfd_get_file_window () as it cannot map to the requested + address for restoring a previously mapped file. */ + + size_t file_start = sectp->filepos; + size_t file_end = file_start + size; + uint8_t *addr; + int fd = fileno ((FILE *) abfd->iostream); + uint8_t *want = *data_pointer; + + file_start -= file_start & (pagesize - 1); + file_end += pagesize - 1; + file_end -= file_end & (pagesize - 1); + size = file_end - file_start; + if (want) + want -= sectp->filepos - file_start; + + addr = mmap (want, size, PROT_READ, MAP_SHARED | MAP_FILE, fd, + file_start); + if (addr != MAP_FAILED && (want == NULL || addr == want)) + { + struct mapping *mapping; + + mapping = obstack_alloc (&objfile->objfile_obstack, + sizeof (*mapping)); + mapping->base = addr; + mapping->size = size; + mapping->next = dwarf2_per_objfile->mapping; + dwarf2_per_objfile->mapping = mapping; + + *data_pointer = addr + (sectp->filepos - file_start); +//printf("addr:mmap:@%p: 0x%8lx of %s\n", addr, (unsigned long)sectp->filepos, objfile->name); + return; + } + if (addr != MAP_FAILED && munmap (addr, size) != 0) + warning (_("Failed to unmap file \"%s\" at %p-%p"), objfile->name, addr, + addr + size); +//printf("addr:mmap:@%p: FAILED (%p)\n", *data_pointer, addr); + } + + *data_pointer = dwarf2_read_section (objfile, sectp); +} + /* In DWARF version 2, the description of the debugging information is stored in a separate .debug_abbrev section. Before we read any dies from a section we read in all abbreviations and install them @@ -6543,63 +6635,6 @@ read_indirect_string (bfd *abfd, gdb_byt return (char *) (dwarf2_per_objfile->str_buffer + str_offset); } -static unsigned long -read_unsigned_leb128 (bfd *abfd, gdb_byte *buf, unsigned int *bytes_read_ptr) -{ - unsigned long result; - unsigned int num_read; - int i, shift; - unsigned char byte; - - result = 0; - shift = 0; - num_read = 0; - i = 0; - while (1) - { - byte = bfd_get_8 (abfd, buf); - buf++; - num_read++; - result |= ((unsigned long)(byte & 127) << shift); - if ((byte & 128) == 0) - { - break; - } - shift += 7; - } - *bytes_read_ptr = num_read; - return result; -} - -static long -read_signed_leb128 (bfd *abfd, gdb_byte *buf, unsigned int *bytes_read_ptr) -{ - long result; - int i, shift, num_read; - unsigned char byte; - - result = 0; - shift = 0; - num_read = 0; - i = 0; - while (1) - { - byte = bfd_get_8 (abfd, buf); - buf++; - num_read++; - result |= ((long)(byte & 127) << shift); - shift += 7; - if ((byte & 128) == 0) - { - break; - } - } - if ((shift < 8 * sizeof (result)) && (byte & 0x40)) - result |= -(((long)1) << shift); - *bytes_read_ptr = num_read; - return result; -} - /* Return a pointer to just past the end of an LEB128 number in BUF. */ static gdb_byte * @@ -10271,11 +10306,18 @@ free_one_cached_comp_unit (void *target_ void dwarf2_free_objfile (struct objfile *objfile) { + struct mapping *mapping; + dwarf2_per_objfile = objfile_data (objfile, dwarf2_objfile_data_key); if (dwarf2_per_objfile == NULL) return; + for (mapping = dwarf2_per_objfile->mapping; mapping; mapping = mapping->next) + if (munmap (mapping->base, mapping->size) != 0) + warning (_("Failed to unmap file at %p-%p"), mapping->base, + mapping->base + mapping->size); + /* Cached DIE trees use xmalloc and the comp_unit_obstack. */ free_cached_comp_units (NULL); --- ./gdb/elfread.c 2008-06-18 22:54:17.000000000 +0200 +++ ./gdb/elfread.c 2008-06-18 23:36:29.000000000 +0200 @@ -560,6 +560,9 @@ elf_symfile_read (struct objfile *objfil asymbol **symbol_table = NULL, **dyn_symbol_table = NULL; asymbol *synthsyms; + if (objfile->flags & OBJF_MAPPED) + goto mapped; + init_minimal_symbol_collection (); back_to = make_cleanup_discard_minimal_symbols (); @@ -691,6 +694,7 @@ elf_symfile_read (struct objfile *objfil str_sect->filepos, bfd_section_size (abfd, str_sect)); } +mapped: if (dwarf2_has_info (objfile)) { /* DWARF 2 sections */ --- ./gdb/minsyms.c 2008-06-18 22:54:17.000000000 +0200 +++ ./gdb/minsyms.c 2008-06-18 23:36:29.000000000 +0200 @@ -689,7 +689,7 @@ prim_record_minimal_symbol_and_info (con SYMBOL_VALUE_ADDRESS (msymbol) = address; SYMBOL_SECTION (msymbol) = section; - SYMBOL_BFD_SECTION (msymbol) = bfd_section; + msymbol->ginfo.objfile = objfile; MSYMBOL_TYPE (msymbol) = ms_type; /* FIXME: This info, if it remains, needs its own field. */ --- ./gdb/mmapcache-alloc.c 1970-01-01 01:00:00.000000000 +0100 +++ ./gdb/mmapcache-alloc.c 2008-06-19 15:01:43.000000000 +0200 @@ -0,0 +1,588 @@ +/* mmapcache-alloc.c --- implementation of an allocator on top of mmapcache. + + Copyright (C) 2008 Free Software Foundation, Inc. + + This file is part of GDB. + + 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, see . */ + +#include "defs.h" +#include "mmapcache-alloc.h" +#include "mmapcache.h" +#include "splay-tree.h" +#include "gdb_assert.h" +#include "gdb_stdint.h" +#include +#include "gdb_obstack.h" + +struct mmapalloc + { + struct mmapcache_mem *mmapcache; + /* KEY is size_t block_size, + VALUE is struct mmapnode * for the same BLOCK_SIZEs. */ + struct splay_tree_s size_s; + /* KEY is struct mmapnode *, VALUE is NULL. */ + struct splay_tree_s addr_s; + void *user_data; + }; + +struct mmapnode + { + struct splay_tree_node_s size_s; + struct splay_tree_node_s addr_s; + }; +#define SIZE_NODE_TO_MMAPNODE(size_node_ptr) \ + ((struct mmapnode *) ((uint8_t *) (size_node_ptr) \ + - offsetof (struct mmapnode, size_s))) +#define ADDR_NODE_TO_MMAPNODE(addr_node_ptr) \ + ((struct mmapnode *) ((uint8_t *) (addr_node_ptr) \ + - offsetof (struct mmapnode, addr_s))) +#define MMAPNODE_SIZE(mmapnode) ((mmapnode)->size_s.key) +#define MMAPNODE_SAME_SIZE_LINK(mmapnode) ((mmapnode)->size_s.value) + +static int +compare_size (splay_tree_key k1, splay_tree_key k2) +{ + size_t k1s = k1; + size_t k2s = k2; + + if (k1s < k2s) + return -1; + else if (k1s > k2s) + return 1; + else + return 0; +} + +static splay_tree_node allocate_node; +static splay_tree allocate_tree; + +static void * +allocate (int size, void *data_unused) +{ + if (size == sizeof (*allocate_node) && allocate_node != NULL) + return allocate_node; + if (size == sizeof (*allocate_tree) && allocate_tree != NULL) + return allocate_tree; + gdb_assert (0); + return NULL; +} + +static void +deallocate (void *ptr, void *data_unused) +{ +} + +struct mmapalloc * +mmapalloc_create (struct mmapcache_mem **mmapcache) +{ + struct mmapalloc *mmapalloc; + splay_tree tree; + + mmapcache_align (*mmapcache, sizeof (long)); + mmapalloc = mmapcache_allocate (mmapcache, sizeof (*mmapalloc)); + if (mmapalloc == NULL) + return NULL; + + mmapcache_align (*mmapcache, sizeof (struct mmapnode)); + + allocate_tree = &mmapalloc->size_s; + tree = splay_tree_new_with_allocator (compare_size, NULL, NULL, allocate, + deallocate, NULL); + allocate_tree = NULL; + gdb_assert (tree == &mmapalloc->size_s); + + allocate_tree = &mmapalloc->addr_s; + tree = splay_tree_new_with_allocator (splay_tree_compare_pointers, NULL, NULL, + allocate, deallocate, NULL); + allocate_tree = NULL; + gdb_assert (tree == &mmapalloc->addr_s); + + mmapalloc->mmapcache = *mmapcache; + mmapcache_user_data (*mmapcache, mmapalloc); + + return mmapalloc; +} + +struct mmapalloc * +mmapalloc_fetch (struct mmapcache_mem *mmapcache, void *base) +{ + struct mmapalloc *mmapalloc; + uint8_t *base8 = base; + + base8 += sizeof (long) - 1; + base8 -= (unsigned long) base8 & (sizeof (long) - 1); + mmapalloc = (void *) base8; + + mmapalloc->mmapcache = mmapcache; + gdb_assert (mmapalloc == mmapcache_user_data (mmapcache, NULL)); + + return mmapalloc; +} + +void * +mmapalloc_user_data (struct mmapalloc *mmapalloc, void *user_data) +{ + void *retval = mmapalloc->user_data; + + if (user_data) + mmapalloc->user_data = user_data; + + return retval; +} + +struct mmapcache_mem *mmapalloc_delete (struct mmapalloc *mmapalloc) +{ + return mmapalloc->mmapcache; +} + +struct mmapalloc *mmapalloc_from_mmapcache (struct mmapcache_mem *mmapcache) +{ + struct mmapalloc *retval = mmapcache_user_data (mmapcache, NULL); + + gdb_assert (retval != NULL); + + return retval; +} + +static void +mmapnode_remove (struct mmapalloc *mmapalloc, struct mmapnode *mmapnode) +{ + splay_tree_node node; + + /* SIZE tree. */ + + node = splay_tree_lookup (&mmapalloc->size_s, MMAPNODE_SIZE (mmapnode)); + gdb_assert (node); + /* We were the first item in the size link chain? */ + if (SIZE_NODE_TO_MMAPNODE (node) == mmapnode) + { + struct mmapnode *next_link; + + splay_tree_remove (&mmapalloc->size_s, MMAPNODE_SIZE (mmapnode)); + next_link = (void *) MMAPNODE_SAME_SIZE_LINK (mmapnode); + if (next_link) + { + gdb_assert (MMAPNODE_SIZE (mmapnode) == MMAPNODE_SIZE (next_link)); + + allocate_node = &next_link->size_s; + node = splay_tree_insert (&mmapalloc->size_s, + MMAPNODE_SIZE (next_link), + MMAPNODE_SAME_SIZE_LINK (next_link)); + allocate_node = NULL; + gdb_assert (node == &next_link->size_s); + + gdb_assert (MMAPNODE_SIZE (mmapnode) == MMAPNODE_SIZE (next_link)); + } + } + else + { + /* We are somewhere in the link list. */ + struct mmapnode *mmapnode_iter = SIZE_NODE_TO_MMAPNODE (node); + struct mmapnode **link_pointer; + + do + { + link_pointer = (struct mmapnode **) + &MMAPNODE_SAME_SIZE_LINK (mmapnode_iter); + mmapnode_iter = *link_pointer; + gdb_assert (mmapnode_iter); + } + while (mmapnode_iter != mmapnode); + *link_pointer = (struct mmapnode *) MMAPNODE_SAME_SIZE_LINK (mmapnode); + } + + /* ADDR tree. */ + + splay_tree_remove (&mmapalloc->addr_s, (splay_tree_key) mmapnode); +} + +static void +mmapnode_create (struct mmapalloc *mmapalloc, void *base, size_t size) +{ + struct mmapnode *mmapnode = base; + splay_tree_node node; + + /* SIZE tree. */ + + node = splay_tree_lookup (&mmapalloc->size_s, size); + if (node) + { + struct mmapnode *mmapnode_head = SIZE_NODE_TO_MMAPNODE (node); + + /* Insert in a LIFO way right after the found NODE. Is it worth + reinserting the node to place it first for the next allocation of the + appropriate size? pro: CPU caching. con: Tree reinsertion effort. */ + + MMAPNODE_SIZE (mmapnode) = size; + MMAPNODE_SAME_SIZE_LINK (mmapnode) = + MMAPNODE_SAME_SIZE_LINK (mmapnode_head); + MMAPNODE_SAME_SIZE_LINK (mmapnode_head) = (unsigned long) mmapnode; + } + else + { + allocate_node = &mmapnode->size_s; + node = splay_tree_insert (&mmapalloc->size_s, size, + (splay_tree_value) NULL); + allocate_node = NULL; + gdb_assert (node == &mmapnode->size_s); + gdb_assert (MMAPNODE_SIZE (mmapnode) == size); + gdb_assert (MMAPNODE_SAME_SIZE_LINK (mmapnode) == (unsigned long) NULL); + } + + /* ADDR tree. */ + + allocate_node = &mmapnode->addr_s; + node = splay_tree_insert (&mmapalloc->addr_s, (splay_tree_key) mmapnode, + (splay_tree_value) NULL); + allocate_node = NULL; + gdb_assert (node == &mmapnode->addr_s); +} + +static void +mmapalloc_absfree (struct mmapalloc *mmapalloc, void *base, size_t size) +{ + struct mmapnode *mmapnode = NULL; + struct mmapnode *prev_node = NULL, *succ_node = NULL; + uint8_t *start = base; + uint8_t *end = start + size; + + gdb_assert (size % sizeof (struct mmapnode) == 0); + gdb_assert ((unsigned long) base % sizeof (struct mmapnode) == 0); + + splay_tree_lookup (&mmapalloc->addr_s, (splay_tree_key) start); + if (mmapalloc->addr_s.root) + mmapnode = ADDR_NODE_TO_MMAPNODE (mmapalloc->addr_s.root); + gdb_assert ((uint8_t *) mmapnode != start); + if (mmapnode && (uint8_t *) mmapnode < start) + { + splay_tree_node node; + + prev_node = mmapnode; + node = splay_tree_successor (&mmapalloc->addr_s, + (splay_tree_key) mmapnode); + if (node) + succ_node = ADDR_NODE_TO_MMAPNODE (node); + } + else if (mmapnode && start < (uint8_t *) mmapnode) + { + splay_tree_node node; + + node = splay_tree_predecessor (&mmapalloc->addr_s, + (splay_tree_key) mmapnode); + if (node) + prev_node = ADDR_NODE_TO_MMAPNODE (node); + succ_node = mmapnode; + } + + if (prev_node && (uint8_t *) prev_node + MMAPNODE_SIZE (prev_node) == start) + { + start = (uint8_t *) prev_node; + mmapnode_remove (mmapalloc, prev_node); + } + if (succ_node && end == (uint8_t *) succ_node) + { + end = (uint8_t *) succ_node + MMAPNODE_SIZE (succ_node); + mmapnode_remove (mmapalloc, succ_node); + } + size = end - start; + + /* Shrink the tail? We need the PREV_NODE check before but we do not need + the SUCC_NODE check - it must not exist if we would shtink the tail. */ + if (end == mmapcache_allocate (&mmapalloc->mmapcache, 0)) + { + void *tail = mmapcache_allocate (&mmapalloc->mmapcache, -size); + gdb_assert (tail == end); + gdb_assert (!succ_node); + return; + } + + mmapnode_create (mmapalloc, start, end - start); +} + +static void * +mmapalloc_allocate (struct mmapalloc *mmapalloc, size_t size) +{ + void *retval; + struct mmapnode *mmapnode = NULL; + + gdb_assert (size % sizeof (struct mmapnode) == 0); + + /* Find the block in the SIZE tree. */ + + splay_tree_lookup (&mmapalloc->size_s, size); + if (mmapalloc->size_s.root) + mmapnode = SIZE_NODE_TO_MMAPNODE (mmapalloc->size_s.root); + if (mmapnode && MMAPNODE_SIZE (mmapnode) < size) + { + splay_tree_node node; + + node = splay_tree_successor (&mmapalloc->size_s, + MMAPNODE_SIZE (mmapnode)); + if (node) + mmapnode = SIZE_NODE_TO_MMAPNODE (node); + else + mmapnode = NULL; + } + if (mmapnode) + { + size_t size_old = MMAPNODE_SIZE (mmapnode); + splay_tree_node node, node_next; + + gdb_assert (size_old >= size); + mmapnode_remove (mmapalloc, mmapnode); + if (size_old > size) + mmapnode_create (mmapalloc, (uint8_t *) mmapnode + size, + size_old - size); + return mmapnode; + } + + /* Extend the tail. */ + + retval = mmapcache_allocate (&mmapalloc->mmapcache, size); + if (retval == NULL) + return NULL; + + return retval; +} + +/* Returns success. We support only allocation with BASE right after some + allocated block. */ + +static int +mmapalloc_absalloc (struct mmapalloc *mmapalloc, void *base, size_t size) +{ + struct mmapnode *mmapnode; + splay_tree_node node; + uint8_t *start = base; + uint8_t *end = start + size; + + gdb_assert (size % sizeof (struct mmapnode) == 0); + gdb_assert ((unsigned long) base % sizeof (struct mmapnode) == 0); + gdb_assert (size > 0); + + node = splay_tree_lookup (&mmapalloc->addr_s, (splay_tree_key) start); + if (!node) + return 0; + mmapnode = ADDR_NODE_TO_MMAPNODE (node); + + if (MMAPNODE_SIZE (mmapnode) < size) + return 0; + + mmapnode_remove (mmapalloc, mmapnode); + if (MMAPNODE_SIZE (mmapnode) > size) + mmapnode_create (mmapalloc, end, MMAPNODE_SIZE (mmapnode) - size); + + return 1; +} + +void * +mmapalloc_alloc (struct mmapalloc *mmapalloc, size_t size) +{ + uint8_t *base; + + if (mmapalloc == NULL || mmapalloc->mmapcache == NULL) + return xmalloc (size); + + size += sizeof (size_t); + size = (size + sizeof (struct mmapnode) - 1) / sizeof (struct mmapnode) + * sizeof (struct mmapnode); + + base = mmapalloc_allocate (mmapalloc, size); + if (base == NULL) + return NULL; + gdb_assert ((unsigned long) base % sizeof (struct mmapnode) == 0); + + *(size_t *) base = size; + + return base + sizeof (size_t); +} + +void +mmapalloc_free (struct mmapalloc *mmapalloc, void *chunk) +{ + uint8_t *base = (uint8_t *) chunk - sizeof (size_t); + size_t size = *(size_t *) base; + + if (mmapalloc == NULL || mmapalloc->mmapcache == NULL) + return; + + if (mmapcache_contains (mmapalloc->mmapcache, base)) + mmapalloc_absfree (mmapalloc, base, size); +} + +void * +mmapalloc_realloc (struct mmapalloc *mmapalloc_for_allocate, + struct mmapalloc *mmapalloc_for_free, void *chunk, size_t size) +{ + uint8_t *base_old = (uint8_t *) chunk - sizeof (size_t); + uint8_t *base_new; + size_t size_old = *(size_t *) base_old; + uint8_t *chunk_new; + + gdb_assert (chunk != NULL); + gdb_assert (size > 0); + gdb_assert (mmapalloc_for_free == NULL + || mmapalloc_for_free->mmapcache == NULL + || mmapcache_contains (mmapalloc_for_free->mmapcache, chunk)); + + size += sizeof (size_t); + size = (size + sizeof (struct mmapnode) - 1) / sizeof (struct mmapnode) + * sizeof (struct mmapnode); + + if (size_old == size) + return chunk; + + if (size_old > size) + { + if (mmapalloc_for_free && mmapalloc_for_free->mmapcache) + mmapalloc_absfree (mmapalloc_for_free, base_old + size, size_old - size); + *(size_t *) base_old = size; + return chunk; + } + + /* size_old < size */ + + if (mmapalloc_for_free && mmapalloc_for_allocate == mmapalloc_for_free + && mmapalloc_for_free->mmapcache) + { + if (mmapalloc_absalloc (mmapalloc_for_free, base_old + size_old, + size - size_old)) + { + *(size_t *) base_old = size; + return chunk; + } + } + + if (mmapalloc_for_allocate && mmapalloc_for_allocate->mmapcache) + { + uint8_t *tail; + + /* May we just extend the tail of mmapcache? */ + tail = mmapcache_allocate (&mmapalloc_for_allocate->mmapcache, 0); + if (tail == base_old + size_old) + { + tail = mmapcache_allocate (&mmapalloc_for_allocate->mmapcache, + size - size_old); + if (tail == NULL) + return NULL; + gdb_assert (tail == base_old + size_old); + *(size_t *) base_old = size; + return chunk; + } + + base_new = mmapalloc_allocate (mmapalloc_for_allocate, size); + if (base_new == NULL) + return NULL; + + *(size_t *) base_new = size; + chunk_new = base_new + sizeof (size_t); + } + else + chunk_new = xmalloc (size - sizeof (size_t)); + + memcpy (chunk_new, chunk, size_old - sizeof (size_t)); + + if (mmapalloc_for_free && mmapalloc_for_free->mmapcache) + mmapalloc_absfree (mmapalloc_for_free, base_old, size_old); + + return chunk_new; +} + +struct mmapalloc * +mmapalloc_find (void *p) +{ + struct mmapcache_mem *mmapcache; + + mmapcache = mmapcache_find (p); + if (mmapcache == NULL) + return NULL; + + return mmapcache_user_data (mmapcache, NULL); +} + +struct bundle + { + struct mmapalloc *mmapalloc; + struct obstack *obstack; + }; + +static void * +mmapalloc_obstack_chunkfun (struct bundle *bundle, long size) +{ + struct mmapalloc *mmapalloc = bundle->mmapalloc; + struct obstack *obstack = bundle->obstack; + + if (obstack->next_free) + { + uint8_t *chunk = obstack->object_base; + uint8_t *base = chunk - sizeof (size_t); + size_t size_old = *(size_t *) base; + uint8_t *want_end; + + want_end = obstack->chunk_limit + size; + want_end += sizeof (struct mmapnode) - 1; + want_end -= (unsigned long) want_end % sizeof (struct mmapnode); + + gdb_assert (size_old > 0); + gdb_assert (size_old % sizeof (struct mmapnode) == 0); + gdb_assert ((unsigned long) base % sizeof (struct mmapnode) == 0); + + /* We covered the allocation requirements by our alignments. */ + if (base + size == want_end) + return chunk; + + if (mmapalloc_absalloc (mmapalloc, base + size_old, + want_end - (base + size_old))) + { + *(size_t *) base = want_end - base; + return chunk; + } + } + + return mmapalloc_alloc (mmapalloc, size); +} + +static void +mmapalloc_obstack_freefun (struct bundle *bundle, void *block) +{ + struct mmapalloc *mmapalloc = bundle->mmapalloc; + + mmapalloc_free (mmapalloc, block); +} + +/* Returns success. */ + +void +mmapalloc_obstack_init (struct mmapalloc *mmapalloc, struct obstack *obstack) +{ + struct bundle bundle_local = { mmapalloc : mmapalloc, obstack : obstack }; + struct bundle *bundle; + + if (mmapalloc == NULL) + { + obstack_init (obstack); + return; + } + + obstack->next_free = NULL; + obstack_specify_allocation_with_arg (obstack, pagesize, 0, + mmapalloc_obstack_chunkfun, + mmapalloc_obstack_freefun, + &bundle_local); + gdb_assert (obstack->extra_arg == &bundle_local); + bundle = obstack_alloc (obstack, sizeof (*bundle)); + *bundle = bundle_local; + obstack->extra_arg = bundle; +} --- ./gdb/mmapcache-alloc.h 1970-01-01 01:00:00.000000000 +0100 +++ ./gdb/mmapcache-alloc.h 2008-06-19 12:49:32.000000000 +0200 @@ -0,0 +1,51 @@ +/* mmapcache-alloc.h --- interface to an allocator on top of mmapcache. + + Copyright (C) 2008 Free Software Foundation, Inc. + + This file is part of GDB. + + 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, see . */ + +#ifndef MMAPCACHE_ALLOC_H +#define MMAPCACHE_ALLOC_H + +struct mmapcache_mem; +struct mmapalloc; + +extern struct mmapalloc *mmapalloc_create (struct mmapcache_mem **mmapcache); + +extern struct mmapalloc *mmapalloc_fetch (struct mmapcache_mem *mmapcache, + void *base); + +extern void *mmapalloc_user_data (struct mmapalloc *mmapalloc, void *user_data); + +extern struct mmapalloc *mmapalloc_from_mmapcache + (struct mmapcache_mem *mmapcache); + +extern struct mmapcache_mem *mmapalloc_delete (struct mmapalloc *mmapalloc); + +extern void *mmapalloc_alloc (struct mmapalloc *mmapalloc, size_t size); + +extern void mmapalloc_free (struct mmapalloc *mmapalloc, void *chunk); + +extern void *mmapalloc_realloc (struct mmapalloc *mmapalloc_for_allocate, + struct mmapalloc *mmapalloc_for_free, + void *chunk, size_t size); + +extern struct mmapalloc *mmapalloc_find (void *p); + +extern void mmapalloc_obstack_init (struct mmapalloc *mmapalloc, + struct obstack *obstack); + +#endif /* MMAPCACHE_ALLOC_H */ --- ./gdb/mmapcache.c 1970-01-01 01:00:00.000000000 +0100 +++ ./gdb/mmapcache.c 2008-06-18 23:36:29.000000000 +0200 @@ -0,0 +1,766 @@ +/* mmapcache.c --- implementation of MMAP-based data caching blocks. + + Copyright (C) 2008 Free Software Foundation, Inc. + + This file is part of GDB. + + 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, see . */ + +#include "defs.h" +#include "mmapcache.h" +#include +#include "gdb_assert.h" +#include "gdb_stdint.h" +#include +#include +#include "readline/tilde.h" +#include +#include "command.h" +#include "gdbcmd.h" +#include "splay-tree.h" +#include + +#ifdef HAVE_LINUX_MAGIC_H +# include +#endif + +#define DEFAULT_DEBUG_CACHE_DIRECTORY "~/.gdb_cache" + +#define RESERVE_SIZE(reference_size) (0x40000 + 64 * (reference_size)) + +/* Range of addresses occupied by any mmapcache. */ +void *mmapcache_low = (void *) -1L, *mmapcache_high = (void *) 0L; + +size_t pagesize; + +struct gdb_id + { + time_t mtime; + void *var_address; + }; + +struct mmapcache_file + { + uint32_t magic; + struct mmapcache_file *self; + struct gdb_id gdb_id; + size_t allocated; + /* User data for MMAPCACHE_USER_DATA. */ + void *user_data; + unsigned int synced : 1; + }; +#define MMAPCACHE_FILE_MAGIC 0x8C6A71CA + +struct mmapcache_mem + { + /* Sorted by BASE and MAPPED. */ + struct splay_tree_node_s node_s; + /* If non-(-1) we are creating FILENAME now. */ + int fd; + char *filename; + uint8_t *base; + struct mmapcache_file *file; + /* FILE->ALLOCATED <= TRUNCATED <= MAPPED. + MAPPED is the mmap(2)ed area specified during MMAPCACHE_CREATE, you + cannot extend it later. TRUNCATED is the current file size. We may map + file earlier than we extend its size. We must not touch memory which + behind TRUNCATED that time. */ + size_t truncated; /* PAGESIZE aligned. */ + size_t mapped; /* PAGESIZE aligned. */ + /* If it is readonly we do not lock the file and we use MAP_PRIVATE with + * still read/write mapping as GDB needs the memory writable. */ + unsigned readonly : 1; + }; + +/* Splay tree of MMAPCACHE_MEM: */ + +/* Linking MMAPCACHA_MEM->NODE_S, sorted by BASE and MAPPED. */ +static struct splay_tree_s mem_tree_s; + +static splay_tree_node mem_allocate_node; + +static void * +mem_allocate (int size, void *data_unused) +{ + if (size == sizeof (*mem_allocate_node) && mem_allocate_node != NULL) + return mem_allocate_node; + if (size == sizeof (mem_tree_s)) + return &mem_tree_s; + gdb_assert (0); + return NULL; +} + +static void +mem_deallocate (void *ptr, void *data_unused) +{ +} + +/* Any K1 contained in K2 or vice versa is equality (0). */ +static int +mem_compare (splay_tree_key k1, splay_tree_key k2) +{ + struct mmapcache_mem *k1m = (struct mmapcache_mem *) k1; + struct mmapcache_mem *k2m = (struct mmapcache_mem *) k2; + + if ((k1m->base >= k2m->base + && k1m->base + k1m->mapped <= k2m->base + k2m->mapped) + || (k2m->base >= k1m->base + && k2m->base + k2m->mapped <= k1m->base + k1m->mapped)) + return 0; + + if (k1m->base < k2m->base) + return -1; + else if (k1m->base > k2m->base) + return 1; + gdb_assert (0); + return 0; +} + +/* GDB binary unique identification GDB_ID: */ + +struct gdb_id gdb_id = { var_address : &mmapcache_low }; + +static void +gdb_id_generate (void) +{ + struct stat statbuf; + + if (stat ("/proc/self/exe", &statbuf) == 0) + gdb_id.mtime = statbuf.st_mtime; +} + +/* MMAPCACHE: */ + +static void +mem_insert (struct mmapcache_mem *mem) +{ + splay_tree_node node; + + mem_allocate_node = &mem->node_s; + node = splay_tree_insert (&mem_tree_s, (splay_tree_key) mem, + (splay_tree_value) NULL); + mem_allocate_node = NULL; + gdb_assert (node == &mem->node_s); + + if (mem->base < (uint8_t *) mmapcache_low) + mmapcache_low = mem->base; + if (mem->base + mem->mapped > (uint8_t *) mmapcache_high) + mmapcache_high = mem->base + mem->mapped; +} + +static int +file_is_valid (struct mmapcache_file *file, size_t size) +{ + if (file->magic != MMAPCACHE_FILE_MAGIC) + return 0; +#if 0 // FIXME: valgrind + if (memcmp (&file->gdb_id, &gdb_id, sizeof (gdb_id)) != 0) + return 0; +#endif + if (file->allocated > size) + return 0; + if (file->synced == 0) + return 0; + return 1; +} + +static int +mem_lock (struct mmapcache_mem *mem) +{ + struct flock flock; + + memset (&flock, 0, sizeof (flock)); + flock.l_type = (mem->readonly ? F_RDLCK : F_WRLCK); + flock.l_whence = SEEK_SET; + flock.l_start = 0; + flock.l_len = 0; + return fcntl (mem->fd, F_SETLK, &flock) == 0; +} + +struct mmapcache_mem * +mmapcache_create (const char *filename, size_t reference_size) +{ + struct mmapcache_mem *mem; + void *addr, *addr2; + size_t reserve; + + mem = malloc (sizeof (*mem)); + if (mem == NULL) + nomem (sizeof (*mem)); + mem->filename = xstrdup (filename); + mem->fd = -1; + mem->base = NULL; + mem->file = NULL; + mem->truncated = 0; + mem->mapped = 0; + mem->readonly = 0; + + /* The original filename may have private permissions => 0600. */ + mem->fd = open (mem->filename, O_RDWR | O_CREAT | O_EXCL | O_BINARY, 0600); + if (mem->fd == -1) + { +err: + /* A corrupted file would get already deleted by MMAPCACHE_FETCH. */ + if (errno != EEXIST) + warning (_("Error creating cache file \"%s\": %s"), mem->filename, + safe_strerror (errno)); + mmapcache_delete (mem); + return NULL; + } + if (!mem_lock (mem)) + { + warning (_("Refusing to create unsafe cache \"%s\", fcntl error: %s"), + mem->filename, safe_strerror (errno)); + mmapcache_delete (mem); + return NULL; + } + + reserve = RESERVE_SIZE (reference_size) & -pagesize; + + addr = mmap (NULL, reserve, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FILE, + mem->fd, 0); + if (addr == MAP_FAILED) + goto err; + mem->base = addr; + mem->mapped = reserve; +//printf("addr:create:@%p: %s\n", addr, mem->filename); + + /* MEM->FILE must still stay NULL here. */ + addr2 = mmapcache_allocate (&mem, sizeof (*mem->file)); + + if (mem == NULL || addr2 == NULL) + goto err; + mem->file = addr2; + gdb_assert ((uint8_t *) mem->file == mem->base); + mem->file->magic = MMAPCACHE_FILE_MAGIC; + mem->file->self = mem->file; + mem->file->gdb_id = gdb_id; + mem->file->allocated = sizeof (*mem->file); + mem->file->synced = 0; + + /* MEM->BASE must be already set. */ + mem_insert (mem); + + return mem; +} + +/* Returns a handle for FILENAME. *BASE_RETURN is the first allocated memory + chunk address. Use negative REFERENCE_SIZE to specify RESERVE instead. */ + +struct mmapcache_mem * +mmapcache_fetch (const char *filename, void **base_return, + ssize_t reference_size, int want_readonly) +{ + struct mmapcache_mem *mem; + struct mmapcache_file file_local; + off_t off; + void *addr; + size_t reserve; + int in_use = 0; + + mem = malloc (sizeof (*mem)); + if (mem == NULL) + nomem (sizeof (*mem)); + mem->filename = xstrdup (filename); + mem->fd = -1; + mem->base = NULL; + mem->file = NULL; + mem->truncated = 0; + mem->mapped = 0; + mem->readonly = want_readonly; + + if (!mem->readonly) + mem->fd = open (mem->filename, O_RDWR | O_BINARY); + + if (mem->fd == -1) + { +readonly: + mem->fd = open (mem->filename, O_RDONLY | O_BINARY); + mem->readonly = 1; + } + + /* Do not complain on just a missing cache file. */ + if (mem->fd == -1 && errno == ENOENT) + { + mmapcache_delete (mem); + return NULL; + } + + if (mem->fd == -1) + { + warning (_("Error opening cache file \"%s\": %s"), mem->filename, + safe_strerror (errno)); + mmapcache_delete (mem); + return NULL; + } + + if (!mem_lock (mem)) + { + if (!mem->readonly) + { + in_use = 1; + goto readonly; + } + mmapcache_delete (mem); + return NULL; + } + + if (pread (mem->fd, &file_local, sizeof (file_local), 0) + != sizeof (file_local)) + { +fail: + if (!mem->readonly) + { + warning (_("Corrupted cache file \"%s\" - deleted"), mem->filename); + if (unlink (mem->filename) != 0) + warning (_("Error deleting the cache file \"%s\": %s"), mem->filename, + safe_strerror (errno)); + } + mmapcache_delete (mem); + return NULL; + } + + off = lseek (mem->fd, 0, SEEK_END); + if (off == (off_t) -1) + goto fail; + mem->truncated = off; + if ((mem->truncated & (pagesize - 1)) != 0) + goto fail; + + if (!file_is_valid (&file_local, mem->truncated)) + goto fail; + + if (reference_size >= 0) + reserve = RESERVE_SIZE (reference_size) & -pagesize; + else + reserve = -reference_size; + + if (mem->truncated > reserve) + goto fail; + addr = mmap (file_local.self, reserve, PROT_READ | PROT_WRITE, + (mem->readonly ? MAP_PRIVATE : MAP_SHARED) | MAP_FILE, mem->fd, + 0); +//printf("addr:fetch :@%p %s (%p): %s\n", addr, (addr == file_local.self ? "ok " : "BAD"), file_local.self, mem->filename); + if (addr != MAP_FAILED) + { + mem->base = addr; + mem->file = addr; + mem->mapped = reserve; + } + + if (addr != file_local.self) + { + warning (_("Unable to map the cache file \"%s\" to %p-%p"), mem->filename, + file_local.self, (uint8_t *) file_local.self + reserve); + mmapcache_delete (mem); + return NULL; + } + + /* MEM->BASE must be already set. */ + mem_insert (mem); + + /* We already checked it in FILE_LOCAL above. We have no security protection + against malicious cache files, they must be public non-writable. */ + gdb_assert (file_is_valid (mem->file, mem->truncated)); + + mem->file->synced = 0; + if (!mem->readonly + && msync (mem->file, sizeof (*mem->file), MS_SYNC) != 0) + goto fail; + + if (in_use) + warning (_("Cache file \"%s\" is in use, accessing it read-only."), + mem->filename); + + if (base_return) + *base_return = &mem->file[1]; + return mem; +} + +/* Returns NULL on failure and MEM gets deleted with the allocated memory + remaining still intact. */ + +void * +mmapcache_allocate (struct mmapcache_mem **mem_pointer, ssize_t size) +{ + struct mmapcache_mem *mem = *mem_pointer; + void *retval; + static int count; + size_t allocated; + +//printf("#%02d: %p: %lu + %lu = %lu\n", ++count, mem, (unsigned long)mem->allocated, (unsigned long)size, (unsigned long)(mem->allocated+size)); + + if (mem->file != NULL) + allocated = mem->file->allocated; + else + allocated = 0; + + if (allocated + size > mem->truncated) + { + void *check; + size_t truncated_new; + + gdb_assert (mem->base != NULL); + truncated_new = (allocated + size + pagesize - 1) & -pagesize; + if (truncated_new > mem->mapped) + { + /* Delete the client pointer first as otherwise we could possibly + deadlock at WARNING. */ + *mem_pointer = NULL; + warning (_("Allocation of %lu bytes exceeded its reserved %lu bytes " + "of the cache file \"%s\""), + (unsigned long) size, (unsigned long) mem->mapped, + mem->filename); + goto hibernate_mem; + } + + if ((mem->readonly == 0 && ftruncate (mem->fd, truncated_new) != 0) + || (mem->readonly == 1 + && mmap (mem->base + mem->truncated, + truncated_new - mem->truncated, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) != 0)) + { + /* Delete the client pointer first as otherwise we could possibly + deadlock at WARNING. */ + *mem_pointer = NULL; + warning (_("Error writing %lu bytes to the cache file \"%s\" " + "of %lu bytes"), + (unsigned long) (truncated_new - mem->truncated), + mem->filename, (unsigned long) mem->truncated); + + /* Destroy the cache MEM while keeping the data in memory. It may + * happen if the disk gets full while writing the temporary file. + * FIXME: We leave the allocated part never freed in the memory. */ +hibernate_mem: + /* Do not MMAPCACHE_DELETE, we need to keep it linked for + MMAPCACHE_FIND. */ + if (mem->fd != -1) + { + close (mem->fd); + mem->fd = -1; + } + return NULL; + } + +//printf("truncated: %lu -> %lu (%p-%p)\n",(unsigned long)mem->truncated,(unsigned long)truncated_new,mem->base,mem->base+truncated_new); + mem->truncated = truncated_new; + } + + retval = mem->base + allocated; + allocated += size; + gdb_assert (allocated <= mem->truncated); + if (mem->file != NULL) + mem->file->allocated = allocated; + + return retval; +} + +void +mmapcache_delete (struct mmapcache_mem *mem) +{ + if (mem == NULL) + return; + + splay_tree_remove (&mem_tree_s, (splay_tree_key) mem); + + if (mem->mapped != 0 && munmap (mem->base, mem->mapped) != 0) + warning (_("Error unmapping the cache file \"%s\": %s"), mem->filename, + safe_strerror (errno)); + + if (mem->fd != -1 && !mem->readonly) + { + /* Delete the temporary unfinished file we were creating now. */ + /* FIXME: Protect with ATEXIT. */ + unlink (mem->filename); + } + + if (mem->fd != -1) + close (mem->fd); + xfree (mem->filename); + xfree (mem); +} + +int +mmapcache_close (struct mmapcache_mem *mem) +{ + int success = 1; + + if (!mem->readonly && msync (mem->base, mem->truncated, MS_SYNC) != 0) + success = 0; + + gdb_assert (mem->file->synced == 0); + if (success) + mem->file->synced = 1; + if (!mem->readonly + && msync (mem->file, sizeof (*mem->file), MS_SYNC) != 0) + success = 0; + + if (close (mem->fd) != 0) + success = 0; + + if (success) + mem->fd = -1; + else + { + /* FD is left valid so MMAPCACHE_DELETE is going to delete the file. */ + warning (_("Error closing the cache file \"%s\": %s"), mem->filename, + safe_strerror (errno)); + } + mmapcache_delete (mem); + + return success; +} + +void +mmapcache_set_readonly (struct mmapcache_mem **mem) +{ + char *filename; + size_t mapped = (*mem)->mapped; + + if ((*mem)->readonly) + return; + + filename = xstrdup ((*mem)->filename); + if (!mmapcache_close (*mem)) + *mem = NULL; + else + *mem = mmapcache_fetch (filename, NULL, -mapped, 1); + xfree (filename); +} + +int +mmapcache_get_readonly (struct mmapcache_mem *mem) +{ + return mem->readonly; +} + +void +close_all (void *data_unused) +{ + splay_tree_node current; + char *sync_s = getenv ("MMAPCACHE_SYNC"); + int sync = sync_s ? atoi (sync_s) : 0; + + current = splay_tree_min (&mem_tree_s); + if (current == NULL) + return; + + if (!sync) + switch (fork ()) + { + case -1: + perror_with_name (_("Cannot fork")); + case 0: + break; + default: + /* We must not RETURN here as the mappings still may be MAP_SHARED and + writable. */ + _exit (0); + return; + } + + printf_unfiltered (_("Closing the cache files...")); + gdb_flush (gdb_stdout); + while (current) + { + struct mmapcache_mem *mmapcache; + splay_tree_key current_key = current->key; + + mmapcache = (struct mmapcache_mem *) + ((uint8_t *) current - offsetof (struct mmapcache_mem, node_s)); + /* CURRENT_KEY gets invalid by MMAPCACHE_SET_READONLY. */ + current = splay_tree_successor (&mem_tree_s, current_key); + mmapcache_set_readonly (&mmapcache); + + putchar_unfiltered ('.'); + gdb_flush (gdb_stdout); + } + printf_unfiltered (_(" done\n")); +} + +void * +mmapcache_user_data (struct mmapcache_mem *mem, void *user_data) +{ + void *retval = mem->file->user_data; + + if (user_data) + mem->file->user_data = user_data; + + return retval; +} + +void +mmapcache_align (struct mmapcache_mem *mem, size_t alignment) +{ + gdb_assert (alignment > 0); + /* Power of 2? */ + gdb_assert ((alignment & (alignment - 1)) == 0); + + mem->file->allocated += alignment - 1; + mem->file->allocated -= mem->file->allocated & (alignment - 1); +} + +int +mmapcache_contains (struct mmapcache_mem *mem, void *p) +{ + return mem->base <= (uint8_t *) p + && (uint8_t *) p < mem->base + mem->mapped; +} + +/* malloc() can create its own mmap()ped sections in between our MMAPCACHE + areas. In such case the fast check of MMAPCACHE_LOW-MMAPCACHE_HIGH would + give us a false positive. */ + +struct mmapcache_mem * +mmapcache_find (void *p) +{ + splay_tree_node node; + struct mmapcache_mem key_mem; + + /* Acceleration only. */ + if (p < mmapcache_low || p > mmapcache_high) + return NULL; + + key_mem.base = p; + key_mem.mapped = 0; + node = splay_tree_lookup (&mem_tree_s, (splay_tree_key) &key_mem); + if (node == NULL) + return NULL; + return (struct mmapcache_mem *) ((uint8_t *) node + - offsetof (struct mmapcache_mem, node_s)); +} + +/* GDB interface: */ + +static char *debug_cache_directory = DEFAULT_DEBUG_CACHE_DIRECTORY; +static void +show_debug_cache_directory (struct ui_file *file, int from_tty, + struct cmd_list_element *c, const char *value) +{ + fprintf_filtered (file, _("\ +The directory for the debug info cache files is \"%s\".\n"), + value); +} + +static const char * +basedir (void) +{ + static char *user_last; + static char *return_last; + + if (user_last == NULL || strcmp (user_last, debug_cache_directory) != 0) + { + char *expanded = tilde_expand (debug_cache_directory); + int fd; + int fail = 0; + + fd = open (expanded, O_DIRECTORY | O_RDONLY); + if (fd == -1 && errno == ENOENT) + { + if (mkdir (expanded, 0700) == 0) + fd = open (expanded, O_DIRECTORY | O_RDONLY); + } + +#ifdef NFS_SUPER_MAGIC + if (fd != -1) + { + struct statvfs buf; + + if (fstatvfs (fd, &buf) == 0 && buf.f_fsid == NFS_SUPER_MAGIC) + fail = 1; + + close (fd); + } +#endif /* NFS_SUPER_MAGIC */ + + xfree (return_last); + if (fail || fd == -1) + { + xfree (expanded); + return_last = NULL; + } + else + return_last = expanded; + + xfree (user_last); + user_last = xstrdup (debug_cache_directory); + } + return return_last; +} + +char * +mmapcache_map_filename (const char *filename) +{ + const char *basedir_path; + size_t basedir_len, filename_len; + char *path, *s; + const char suffix[] = ".mmapcache"; + size_t path_size; + + basedir_path = basedir (); + if (basedir_path == NULL) + return NULL; + + while (filename[0] == '/') + filename++; + basedir_len = strlen (basedir_path); + filename_len = strlen (filename); + path_size = basedir_len + 1 + filename_len + sizeof suffix; + path = malloc (path_size); + if (path == NULL) + nomem (path_size); + memcpy (path, basedir_path, basedir_len); + path[basedir_len] = '/'; + memcpy (&path[basedir_len + 1], filename, filename_len); + strcpy (&path[basedir_len + 1 + filename_len], suffix); + for (s = &path[basedir_len + 1]; *s != 0; s++) + if (*s == '/' || isspace (*s)) + *s = '-'; + + return path; +} + +void _initialize_mmapcache (void); + +void +_initialize_mmapcache (void) +{ + splay_tree tree; + +#if defined PAGE_SIZE + pagesize = PAGE_SIZE; +#elif defined HAVE_GETPAGESIZE + pagesize = getpagesize (); +#else +# error "Missing page size for mmap()" +#endif + + gdb_id_generate (); + + tree = splay_tree_new_with_allocator (mem_compare, NULL, NULL, mem_allocate, + mem_deallocate, NULL); + gdb_assert (tree == &mem_tree_s); + + make_final_cleanup (close_all, NULL); + + add_setshow_optional_filename_cmd ("debug-cache-directory", class_support, + &debug_cache_directory, _("\ +Set the directory where debug info cache is stored."), _("\ +Show the directory where debug info cache is stored."), _("\ +Loaded debug symbols are stored into memory mapped files in this directory\n\ +and later mapped back for better performance."), + NULL, + show_debug_cache_directory, + &setlist, &showlist); +} --- ./gdb/mmapcache.h 1970-01-01 01:00:00.000000000 +0100 +++ ./gdb/mmapcache.h 2008-06-18 23:36:29.000000000 +0200 @@ -0,0 +1,61 @@ +/* mmapcache.h --- interface to MMAP-based data caching blocks. + + Copyright (C) 2008 Free Software Foundation, Inc. + + This file is part of GDB. + + 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, see . */ + +#ifndef MMAPCACHE_H +#define MMAPCACHE_H + +struct mmapcache_mem; + +extern size_t pagesize; + +extern struct mmapcache_mem *mmapcache_create (const char *filename, + size_t reference_size); + +/* Returns a handle for MMAPCACHE_DELETE. *BASE_RETURN is the first allocated + chunk address. Use negative REFERENCE_SIZE to specify RESERVE instead. */ +extern struct mmapcache_mem *mmapcache_fetch (const char *filename, + void **base_return, + ssize_t reference_size, + int want_readonly); + +/* Returns NULL on failure and MEM gets deleted with the allocated memory + remaining still intact. */ +extern void *mmapcache_allocate (struct mmapcache_mem **mem_pointer, + ssize_t size); + +extern void mmapcache_delete (struct mmapcache_mem *mem); + +extern int mmapcache_close (struct mmapcache_mem *mem); + +extern void mmapcache_set_readonly (struct mmapcache_mem **mem); +extern int mmapcache_get_readonly (struct mmapcache_mem *mem); + +/* Map the real file FILENAME to its cache file filename. */ +extern char *mmapcache_map_filename (const char *filename); + +/* Set USER_DATA if not NULL and return the former value there. */ +extern void *mmapcache_user_data (struct mmapcache_mem *mem, void *user_data); + +extern void mmapcache_align (struct mmapcache_mem *mem, size_t alignment); + +extern int mmapcache_contains (struct mmapcache_mem *mem, void *p); + +extern struct mmapcache_mem *mmapcache_find (void *p); + +#endif /* MMAPCACHE_H */ --- ./gdb/objfiles.c 2008-06-18 22:54:17.000000000 +0200 +++ ./gdb/objfiles.c 2008-06-19 15:04:55.000000000 +0200 @@ -48,6 +48,9 @@ #include "dictionary.h" #include "source.h" #include "addrmap.h" +#include "mmapcache.h" +#include "gdb_stdint.h" +#include "mmapcache-alloc.h" #include "auxv.h" #include "elf/common.h" @@ -99,8 +102,7 @@ add_to_objfile_sections (struct bfd *abf section.ovly_mapped = 0; section.addr = bfd_section_vma (abfd, asect); section.endaddr = section.addr + bfd_section_size (abfd, asect); - obstack_grow (&objfile->objfile_obstack, (char *) §ion, sizeof (section)); - objfile->sections_end = (struct obj_section *) (((unsigned long) objfile->sections_end) + 1); + *objfile->sections_end++ = section; } /* Builds a section table for OBJFILE. @@ -122,20 +124,69 @@ add_to_objfile_sections (struct bfd *abf int build_objfile_section_table (struct objfile *objfile) { + asection *asect; + int asecti; + + objfile->sections_array = xmalloc (sizeof (*objfile->sections_array) + * objfile->num_sections); + asecti = 0; + for (asect = objfile->obfd->sections; asect != NULL; asect = asect->next) + { + objfile->sections_array[asecti++] = asect; + } + gdb_assert (asecti == objfile->num_sections); + /* objfile->sections can be already set when reading a mapped symbol file. I believe that we do need to rebuild the section table in this case (we rebuild other things derived from the bfd), but we can't free the old one (it's in the objfile_obstack). So we just waste some memory. */ - objfile->sections_end = 0; + objfile->sections = xmalloc (sizeof (*objfile->sections) + * objfile->num_sections); + objfile->sections_end = objfile->sections; bfd_map_over_sections (objfile->obfd, add_to_objfile_sections, (char *) objfile); - objfile->sections = (struct obj_section *) - obstack_finish (&objfile->objfile_obstack); - objfile->sections_end = objfile->sections + (unsigned long) objfile->sections_end; + return (0); } +/* no caching: Return NULL, XMEM_MMAPALLOC is NULL. + Cache was fetched: Return OBJFILE, XMEM_MMAPALLOC is NULL. + Cache was created: Return NULL, XMEM_MMAPALLOC is non-NULL. */ + +static struct mmapalloc * +dwarf2_mmapcache_check (const char *objfile_filename, size_t objfile_filesize) +{ + char *mmapcache_filename; + + if (objfile_filename == NULL) + return NULL; + + mmapcache_filename = mmapcache_map_filename (objfile_filename); + + if (mmapcache_filename != NULL) + { + void *base; + struct mmapcache_mem *mmapcache; + + mmapcache = mmapcache_fetch (mmapcache_filename, &base, objfile_filesize, + 0); + if (mmapcache != NULL) + { + /* Did read an existing cache. */ + + xfree (mmapcache_filename); + return mmapalloc_fetch (mmapcache, base); + } + mmapcache = mmapcache_create (mmapcache_filename, objfile_filesize); + xfree (mmapcache_filename); + if (mmapcache != NULL) + return mmapalloc_create (&mmapcache); + } + + return NULL; +} + /* Given a pointer to an initialized bfd (ABFD) and some flag bits allocate a new objfile struct, fill it in as best we can, link it into the list of all known objfiles, and return a pointer to the @@ -159,6 +210,17 @@ allocate_objfile (bfd *abfd, int flags) { struct objfile *objfile = NULL; struct objfile *last_one = NULL; + struct mmapalloc *mmapalloc; + + if (abfd != NULL) + mmapalloc = dwarf2_mmapcache_check (bfd_get_filename (abfd), + bfd_get_size (abfd)); + if (mmapalloc) + { + objfile = mmapalloc_user_data (mmapalloc, NULL); + if (objfile) + objfile->mmapalloc = mmapalloc; + } /* If we don't support mapped symbol files, didn't ask for the file to be mapped, or failed to open the mapped file for some reason, then revert @@ -166,32 +228,39 @@ allocate_objfile (bfd *abfd, int flags) if (objfile == NULL) { - objfile = (struct objfile *) xmalloc (sizeof (struct objfile)); + objfile = mmapalloc_alloc (mmapalloc, sizeof (*objfile)); + if (mmapalloc) + mmapalloc_user_data (mmapalloc, objfile); memset (objfile, 0, sizeof (struct objfile)); - objfile->md = NULL; + objfile->mmapalloc = mmapalloc; objfile->psymbol_cache = bcache_xmalloc (); objfile->macro_cache = bcache_xmalloc (); /* We could use obstack_specify_allocation here instead, but gdb_obstack.h specifies the alloc/dealloc functions. */ - obstack_init (&objfile->objfile_obstack); + mmapalloc_obstack_init (objfile->mmapalloc, &objfile->objfile_obstack); terminate_minimal_symbol_table (objfile); + objfile_alloc_data (objfile); + } + else + { + /* Found an existing cache. Flag is not set only on the initial load. */ + objfile->flags |= OBJF_MAPPED; } - - objfile_alloc_data (objfile); /* Update the per-objfile information that comes from the bfd, ensuring that any data that is reference is saved in the per-objfile data region. */ objfile->obfd = abfd; - if (objfile->name != NULL) - { - xfree (objfile->name); - } if (abfd != NULL) { - objfile->name = xstrdup (bfd_get_filename (abfd)); - objfile->mtime = bfd_get_mtime (abfd); + if (!(objfile->flags & OBJF_MAPPED)) + { + objfile->name = xstrdup (bfd_get_filename (abfd)); + objfile->mtime = bfd_get_mtime (abfd); + /* Forward reference by BUILD_OBJFILE_SECTION_TABLE. */ + objfile->num_sections = bfd_count_sections (abfd); + } /* Build section table. */ @@ -206,17 +275,21 @@ allocate_objfile (bfd *abfd, int flags) objfile->name = xstrdup ("<>"); } - /* Initialize the section indexes for this objfile, so that we can - later detect if they are used w/o being properly assigned to. */ + if (!(objfile->flags & OBJF_MAPPED)) + { - objfile->sect_index_text = -1; - objfile->sect_index_data = -1; - objfile->sect_index_bss = -1; - objfile->sect_index_rodata = -1; + /* Initialize the section indexes for this objfile, so that we can later + detect if they are used w/o being properly assigned to. */ - /* We don't yet have a C++-specific namespace symtab. */ + objfile->sect_index_text = -1; + objfile->sect_index_data = -1; + objfile->sect_index_bss = -1; + objfile->sect_index_rodata = -1; - objfile->cp_namespace_symtab = NULL; + /* We don't yet have a C++-specific namespace symtab. */ + + objfile->cp_namespace_symtab = NULL; + } /* Add this file onto the tail of the linked list of other such files. */ @@ -409,7 +482,17 @@ free_objfile (struct objfile *objfile) doesn't reference it. */ objfile->separate_debug_objfile_backlink->separate_debug_objfile = NULL; } - + + if (objfile->mmapalloc) + { + struct mmapalloc *mmapalloc = objfile->mmapalloc; + struct mmapcache_mem *mmapcache; + + objfile->mmapalloc = NULL; + mmapcache = mmapalloc_delete (mmapalloc); + mmapcache_close (mmapcache); + } + /* Remove any references to this objfile in the global value lists. */ preserve_values (objfile); @@ -480,6 +563,10 @@ free_objfile (struct objfile *objfile) /* The last thing we do is free the objfile struct itself. */ + if (objfile->flags & OBJF_MAPPED) + xfree (objfile->msymbols); + xfree (objfile->sections_array); + xfree (objfile->sections); objfile_free_data (objfile); if (objfile->name != NULL) { --- ./gdb/objfiles.h 2008-01-01 23:53:12.000000000 +0100 +++ ./gdb/objfiles.h 2008-06-18 23:36:29.000000000 +0200 @@ -28,6 +28,7 @@ struct bcache; struct htab; struct symtab; struct objfile_data; +struct mmapalloc; /* This structure maintains information on a per-objfile basis about the "entry point" of the objfile, and the scope within which the entry point @@ -171,6 +172,12 @@ extern void print_symbol_bcache_statisti /* Number of entries in the minimal symbol hash table. */ #define MINIMAL_SYMBOL_HASH_SIZE 2039 +struct window_entry + { + struct window_entry *next; + bfd_window window; + }; + /* Master structure for keeping track of each file from which gdb reads symbols. There are several ways these get allocated: 1. The main symbol file, symfile_objfile, set by the symbol-file command, @@ -279,18 +286,6 @@ struct objfile struct minimal_symbol *msymbol_demangled_hash[MINIMAL_SYMBOL_HASH_SIZE]; - /* The mmalloc() malloc-descriptor for this objfile if we are using - the memory mapped malloc() package to manage storage for this objfile's - data. NULL if we are not. */ - - void *md; - - /* The file descriptor that was used to obtain the mmalloc descriptor - for this objfile. If we call mmalloc_detach with the malloc descriptor - we should then close this file descriptor. */ - - int mmfd; - /* Structure which keeps track of functions that manipulate objfile's of the same type as this objfile. I.E. the function to read partial symbols for example. Note that this structure is in statically @@ -392,10 +387,27 @@ struct objfile /* FIXME/carlton-2003-06-27: Delete this in a few years once "possible namespace symbols" go away. */ struct symtab *cp_namespace_symtab; + + /* Handle of MMAPCACHE if we are using to manage storage for this objfile's + data. NULL otherwise. */ + struct mmapalloc *mmapalloc; + + /* BFD indexable, count is NUM_SECTIONS. */ + asection **sections_array; }; /* Defines for the objfile flag word. */ +/* Gdb can arrange to allocate storage for all objects related to + a particular objfile in a designated section of its address space, + managed at a low level by mmap() and using a special version of malloc + (./mmapcache.c). This allows the "internal gdb state" for a particular + objfile to be dumped to a gdb state file and subsequently reloaded at + a later time. Flag is set only in memory for an already loaded OBJFILE, + if we are creating a new cache this flag is still cleared. */ + +#define OBJF_MAPPED (1 << 0) /* Objfile data is mmap'd */ + /* When using mapped/remapped predigested gdb symbol information, we need a flag that indicates that we have previously done an initial symbol table read from this particular objfile. We can't just look for the --- ./gdb/symfile.c 2008-06-18 22:54:17.000000000 +0200 +++ ./gdb/symfile.c 2008-06-18 23:36:29.000000000 +0200 @@ -907,7 +907,10 @@ syms_from_objfile (struct objfile *objfi clear_complaints (&symfile_complaints, 1, verbo); if (addrs) - (*objfile->sf->sym_offsets) (objfile, addrs); + { + if (!(objfile->flags & OBJF_MAPPED)) + (*objfile->sf->sym_offsets) (objfile, addrs); + } else { size_t size = SIZEOF_N_SECTION_OFFSETS (num_offsets); @@ -1083,11 +1086,15 @@ symbol_file_add_with_addrs_or_offsets (b deprecated_pre_add_symbol_hook (name); else { - printf_unfiltered (_("Reading symbols from %s..."), name); + if (objfile->flags & OBJF_MAPPED) + printf_unfiltered (_("Mapped symbols from %s..."), name); + else + printf_unfiltered (_("Reading symbols from %s..."), name); wrap_here (""); gdb_flush (gdb_stdout); } } + syms_from_objfile (objfile, addrs, offsets, num_offsets, mainline, from_tty); @@ -3282,7 +3289,6 @@ reread_symbols (void) } /* We never make this a mapped file. */ - objfile->md = NULL; objfile->psymbol_cache = bcache_xmalloc (); objfile->macro_cache = bcache_xmalloc (); /* obstack_init also initializes the obstack so it is @@ -4813,6 +4819,25 @@ symfile_dummy_outputs (bfd *abfd, asecti sectp->output_offset = 0; } +bfd_boolean +symfile_relocate_debug_section_if (bfd *abfd, asection *sectp) +{ + /* Executable files have all the relocations already resolved. + * Handle files linked with --emit-relocs. + * http://sources.redhat.com/ml/gdb/2006-08/msg00137.html */ + if ((abfd->flags & EXEC_P) != 0) + return FALSE; + + /* We're only interested in debugging sections with relocation + information. */ + if ((sectp->flags & SEC_RELOC) == 0) + return FALSE; + if ((sectp->flags & SEC_DEBUGGING) == 0) + return FALSE; + + return TRUE; +} + /* Relocate the contents of a debug section SECTP in ABFD. The contents are stored in BUF if it is non-NULL, or returned in a malloc'd buffer otherwise. @@ -4827,17 +4852,7 @@ symfile_dummy_outputs (bfd *abfd, asecti bfd_byte * symfile_relocate_debug_section (bfd *abfd, asection *sectp, bfd_byte *buf) { - /* Executable files have all the relocations already resolved. - * Handle files linked with --emit-relocs. - * http://sources.redhat.com/ml/gdb/2006-08/msg00137.html */ - if ((abfd->flags & EXEC_P) != 0) - return NULL; - - /* We're only interested in debugging sections with relocation - information. */ - if ((sectp->flags & SEC_RELOC) == 0) - return NULL; - if ((sectp->flags & SEC_DEBUGGING) == 0) + if (!symfile_relocate_debug_section_if (abfd, sectp)) return NULL; /* We will handle section offsets properly elsewhere, so relocate as if --- ./gdb/symfile.h 2008-06-18 22:54:17.000000000 +0200 +++ ./gdb/symfile.h 2008-06-18 23:36:29.000000000 +0200 @@ -21,9 +21,6 @@ #if !defined (SYMFILE_H) #define SYMFILE_H -/* This file requires that you first include "bfd.h". */ -#include "symtab.h" - /* Opaque declarations. */ struct section_table; struct objfile; @@ -192,6 +189,9 @@ extern void extend_psymbol_list (struct /* #include "demangle.h" */ +/* This file requires that you first include "bfd.h". */ +#include "symtab.h" + extern const struct partial_symbol *add_psymbol_to_list (char *, int, domain_enum, enum address_class, @@ -350,6 +350,8 @@ extern void simple_overlay_update (struc extern bfd_byte *symfile_relocate_debug_section (bfd *abfd, asection *sectp, bfd_byte * buf); +extern bfd_boolean symfile_relocate_debug_section_if (bfd *abfd, + asection *sectp); extern int symfile_map_offsets_to_segments (bfd *, struct symfile_segment_data *, --- ./gdb/symtab.c 2008-06-18 22:54:17.000000000 +0200 +++ ./gdb/symtab.c 2008-06-18 23:36:29.000000000 +0200 @@ -976,8 +976,9 @@ fixup_section (struct general_symbol_inf if (msym) { - ginfo->bfd_section = SYMBOL_BFD_SECTION (msym); + ginfo->objfile = msym->ginfo.objfile; ginfo->section = SYMBOL_SECTION (msym); + gdb_assert (ginfo->section < ginfo->objfile->num_sections); } else if (objfile) { @@ -1029,8 +1030,9 @@ fixup_section (struct general_symbol_inf if (s->addr - offset <= addr && addr < s->endaddr - offset) { - ginfo->bfd_section = s->the_bfd_section; + ginfo->objfile = objfile; ginfo->section = idx; + gdb_assert (ginfo->section < ginfo->objfile->num_sections); return; } } --- ./gdb/symtab.h 2008-02-05 23:17:40.000000000 +0100 +++ ./gdb/symtab.h 2008-06-18 23:36:29.000000000 +0200 @@ -149,7 +149,9 @@ struct general_symbol_info /* The bfd section associated with this symbol. */ - asection *bfd_section; + /* asection *bfd_section; was removed in the favor of OBJFILE. */ + + struct objfile *objfile; }; extern CORE_ADDR symbol_overlayed_address (CORE_ADDR, asection *); @@ -170,7 +172,9 @@ extern CORE_ADDR symbol_overlayed_addres #define SYMBOL_VALUE_CHAIN(symbol) (symbol)->ginfo.value.chain #define SYMBOL_LANGUAGE(symbol) (symbol)->ginfo.language #define SYMBOL_SECTION(symbol) (symbol)->ginfo.section -#define SYMBOL_BFD_SECTION(symbol) (symbol)->ginfo.bfd_section +#define SYMBOL_BFD_SECTION(symbol) \ + ((symbol)->ginfo.objfile == NULL ? NULL \ + : (symbol)->ginfo.objfile->sections_array[SYMBOL_SECTION (symbol)]) #define SYMBOL_CPLUS_DEMANGLED_NAME(symbol) \ (symbol)->ginfo.language_specific.cplus_specific.demangled_name @@ -1407,4 +1411,7 @@ struct symbol *lookup_global_symbol_from extern struct symtabs_and_lines expand_line_sal (struct symtab_and_line sal); +/* For SYMBOL_BFD_SECTION, include it last to avoid deadlocks. */ +#include "objfiles.h" + #endif /* !defined(SYMTAB_H) */ --- ./libiberty/obstack.c 2008-06-18 22:54:17.000000000 +0200 +++ ./libiberty/obstack.c 2008-06-19 12:47:54.000000000 +0200 @@ -255,6 +255,15 @@ _obstack_newchunk (struct obstack *h, PT new_chunk = CALL_CHUNKFUN (h, new_size); if (!new_chunk) (*obstack_alloc_failed_handler) (); + + /* If we had a luck just extend existing OLD_CHUNK. */ + if (new_chunk == h->object_base) + { + h->next_free += new_size; + old_chunk->limit += new_size; + return; + } + h->chunk = new_chunk; new_chunk->prev = old_chunk; new_chunk->limit = h->chunk_limit = (char *) new_chunk + new_size;