+/* Variable and function hash tables. This is used to speed up look-up
+ in lookup_symbol_in_var_table() and lookup_symbol_in_function_table().
+ In order to share code between variable and function infos, we use
+ a list of untyped pointer for all variable/function info associated with
+ a symbol. We waste a bit of memory for list with one node but that
+ simplifies the code. */
+
+struct info_list_node
+{
+ struct info_list_node *next;
+ void *info;
+};
+
+/* Info hash entry. */
+struct info_hash_entry
+{
+ struct bfd_hash_entry root;
+ struct info_list_node *head;
+};
+
+struct info_hash_table
+{
+ struct bfd_hash_table base;
+};
+
+/* Function to create a new entry in info hash table. */
+
+static struct bfd_hash_entry *
+info_hash_table_newfunc (struct bfd_hash_entry *entry,
+ struct bfd_hash_table *table,
+ const char *string)
+{
+ struct info_hash_entry *ret = (struct info_hash_entry *) entry;
+
+ /* Allocate the structure if it has not already been allocated by a
+ derived class. */
+ if (ret == NULL)
+ {
+ ret = (struct info_hash_entry *) bfd_hash_allocate (table,
+ sizeof (* ret));
+ if (ret == NULL)
+ return NULL;
+ }
+
+ /* Call the allocation method of the base class. */
+ ret = ((struct info_hash_entry *)
+ bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string));
+
+ /* Initialize the local fields here. */
+ if (ret)
+ ret->head = NULL;
+
+ return (struct bfd_hash_entry *) ret;
+}
+
+/* Function to create a new info hash table. It returns a pointer to the
+ newly created table or NULL if there is any error. We need abfd
+ solely for memory allocation. */
+
+static struct info_hash_table *
+create_info_hash_table (bfd *abfd)
+{
+ struct info_hash_table *hash_table;
+
+ hash_table = ((struct info_hash_table *)
+ bfd_alloc (abfd, sizeof (struct info_hash_table)));
+ if (!hash_table)
+ return hash_table;
+
+ if (!bfd_hash_table_init (&hash_table->base, info_hash_table_newfunc,
+ sizeof (struct info_hash_entry)))
+ {
+ bfd_release (abfd, hash_table);
+ return NULL;
+ }
+
+ return hash_table;
+}
+
+/* Insert an info entry into an info hash table. We do not check of
+ duplicate entries. Also, the caller need to guarantee that the
+ right type of info in inserted as info is passed as a void* pointer.
+ This function returns true if there is no error. */
+
+static bfd_boolean
+insert_info_hash_table (struct info_hash_table *hash_table,
+ const char *key,
+ void *info,
+ bfd_boolean copy_p)
+{
+ struct info_hash_entry *entry;
+ struct info_list_node *node;
+
+ entry = (struct info_hash_entry*) bfd_hash_lookup (&hash_table->base,
+ key, TRUE, copy_p);
+ if (!entry)
+ return FALSE;
+
+ node = (struct info_list_node *) bfd_hash_allocate (&hash_table->base,
+ sizeof (*node));
+ if (!node)
+ return FALSE;
+
+ node->info = info;
+ node->next = entry->head;
+ entry->head = node;
+
+ return TRUE;
+}
+
+/* Look up an info entry list from an info hash table. Return NULL
+ if there is none. */
+
+static struct info_list_node *
+lookup_info_hash_table (struct info_hash_table *hash_table, const char *key)
+{
+ struct info_hash_entry *entry;
+
+ entry = (struct info_hash_entry*) bfd_hash_lookup (&hash_table->base, key,
+ FALSE, FALSE);
+ return entry ? entry->head : NULL;
+}
+
+/* Read a section into its appropriate place in the dwarf2_debug
+ struct (indicated by SECTION_BUFFER and SECTION_SIZE). If SYMS is
+ not NULL, use bfd_simple_get_relocated_section_contents to read the
+ section contents, otherwise use bfd_get_section_contents. Fail if
+ the located section does not contain at least OFFSET bytes. */
+
+static bfd_boolean
+read_section (bfd * abfd,
+ const struct dwarf_debug_section *sec,
+ asymbol ** syms,
+ bfd_uint64_t offset,
+ bfd_byte ** section_buffer,
+ bfd_size_type * section_size)
+{
+ asection *msec;
+ const char *section_name = sec->uncompressed_name;
+
+ /* The section may have already been read. */
+ if (*section_buffer == NULL)
+ {
+ msec = bfd_get_section_by_name (abfd, section_name);
+ if (! msec)
+ {
+ section_name = sec->compressed_name;
+ if (section_name != NULL)
+ msec = bfd_get_section_by_name (abfd, section_name);
+ }
+ if (! msec)
+ {
+ (*_bfd_error_handler) (_("Dwarf Error: Can't find %s section."),
+ sec->uncompressed_name);
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
+
+ *section_size = msec->rawsize ? msec->rawsize : msec->size;
+ if (syms)
+ {
+ *section_buffer
+ = bfd_simple_get_relocated_section_contents (abfd, msec, NULL, syms);
+ if (! *section_buffer)
+ return FALSE;
+ }
+ else
+ {
+ *section_buffer = (bfd_byte *) bfd_malloc (*section_size);
+ if (! *section_buffer)
+ return FALSE;
+ if (! bfd_get_section_contents (abfd, msec, *section_buffer,
+ 0, *section_size))
+ return FALSE;
+ }
+ }
+
+ /* It is possible to get a bad value for the offset into the section
+ that the client wants. Validate it here to avoid trouble later. */
+ if (offset != 0 && offset >= *section_size)
+ {
+ (*_bfd_error_handler) (_("Dwarf Error: Offset (%lu)"
+ " greater than or equal to %s size (%lu)."),
+ (long) offset, section_name, *section_size);
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+