+static void
+add_dwo_info (const char * field, dwo_type type)
+{
+ dwo_info * dwinfo = xmalloc (sizeof * dwinfo);
+
+ dwinfo->type = type;
+ dwinfo->value = field;
+ dwinfo->next = first_dwo_info;
+ first_dwo_info = dwinfo;
+}
+
+static void
+add_dwo_name (const char * name)
+{
+ add_dwo_info (name, DWO_NAME);
+}
+
+static void
+add_dwo_dir (const char * dir)
+{
+ add_dwo_info (dir, DWO_DIR);
+}
+
+static void
+add_dwo_id (const char * id)
+{
+ add_dwo_info (id, DWO_ID);
+}
+
+static void
+free_dwo_info (void)
+{
+ dwo_info * dwinfo;
+ dwo_info * next;
+
+ for (dwinfo = first_dwo_info; dwinfo != NULL; dwinfo = next)
+ {
+ next = dwinfo->next;
+ free (dwinfo);
+ }
+ first_dwo_info = NULL;
+}
+
+/* Ensure that START + UVALUE is less than END.
+ Return an adjusted UVALUE if necessary to ensure this relationship. */
+
+static inline dwarf_vma
+check_uvalue (const unsigned char * start,
+ dwarf_vma uvalue,
+ const unsigned char * end)
+{
+ dwarf_vma max_uvalue = end - start;
+
+ /* See PR 17512: file: 008-103549-0.001:0.1.
+ and PR 24829 for examples of where these tests are triggered. */
+ if (uvalue > max_uvalue)
+ {
+ warn (_("Corrupt attribute block length: %lx\n"), (long) uvalue);
+ uvalue = max_uvalue;
+ }
+
+ return uvalue;
+}
+
+static unsigned char *
+skip_attr_bytes (unsigned long form,
+ unsigned char * data,
+ unsigned const char * end,
+ dwarf_vma pointer_size,
+ dwarf_vma offset_size,
+ int dwarf_version,
+ dwarf_vma * value_return)
+{
+ dwarf_signed_vma svalue;
+ dwarf_vma uvalue = 0;
+
+ * value_return = 0;
+
+ switch (form)
+ {
+ case DW_FORM_ref_addr:
+ if (dwarf_version == 2)
+ SAFE_BYTE_GET_AND_INC (uvalue, data, pointer_size, end);
+ else if (dwarf_version == 3 || dwarf_version == 4)
+ SAFE_BYTE_GET_AND_INC (uvalue, data, offset_size, end);
+ else
+ return NULL;
+ break;
+
+ case DW_FORM_addr:
+ SAFE_BYTE_GET_AND_INC (uvalue, data, pointer_size, end);
+ break;
+
+ case DW_FORM_strp:
+ case DW_FORM_line_strp:
+ case DW_FORM_sec_offset:
+ case DW_FORM_GNU_ref_alt:
+ case DW_FORM_GNU_strp_alt:
+ SAFE_BYTE_GET_AND_INC (uvalue, data, offset_size, end);
+ break;
+
+ case DW_FORM_flag_present:
+ uvalue = 1;
+ break;
+
+ case DW_FORM_ref1:
+ case DW_FORM_flag:
+ case DW_FORM_data1:
+ SAFE_BYTE_GET_AND_INC (uvalue, data, 1, end);
+ break;
+
+ case DW_FORM_ref2:
+ case DW_FORM_data2:
+ SAFE_BYTE_GET_AND_INC (uvalue, data, 2, end);
+ break;
+
+ case DW_FORM_ref4:
+ case DW_FORM_data4:
+ SAFE_BYTE_GET_AND_INC (uvalue, data, 4, end);
+ break;
+
+ case DW_FORM_sdata:
+ READ_SLEB (svalue, data, end);
+ uvalue = svalue;
+ break;
+
+ case DW_FORM_ref_udata:
+ case DW_FORM_udata:
+ case DW_FORM_GNU_str_index:
+ case DW_FORM_GNU_addr_index:
+ READ_ULEB (uvalue, data, end);
+ break;
+
+ case DW_FORM_ref8:
+ case DW_FORM_data8:
+ data += 8;
+ break;
+
+ case DW_FORM_data16:
+ data += 16;
+ break;
+
+ case DW_FORM_string:
+ data += strnlen ((char *) data, end - data) + 1;
+ break;
+
+ case DW_FORM_block:
+ case DW_FORM_exprloc:
+ READ_ULEB (uvalue, data, end);
+ break;
+
+ case DW_FORM_block1:
+ SAFE_BYTE_GET (uvalue, data, 1, end);
+ data += 1 + uvalue;
+ break;
+
+ case DW_FORM_block2:
+ SAFE_BYTE_GET (uvalue, data, 2, end);
+ data += 2 + uvalue;
+ break;
+
+ case DW_FORM_block4:
+ SAFE_BYTE_GET (uvalue, data, 4, end);
+ data += 4 + uvalue;
+ break;
+
+ case DW_FORM_ref_sig8:
+ data += 8;
+ break;
+
+ case DW_FORM_indirect:
+ /* FIXME: Handle this form. */
+ default:
+ return NULL;
+ }
+
+ * value_return = uvalue;
+ if (data > end)
+ data = (unsigned char *) end;
+ return data;
+}
+
+/* Return IS_SIGNED set to TRUE if the type at
+ DATA can be determined to be a signed type. */
+
+static void
+get_type_signedness (unsigned char * start,
+ unsigned char * data,
+ unsigned const char * end,
+ dwarf_vma pointer_size,
+ dwarf_vma offset_size,
+ int dwarf_version,
+ bfd_boolean * is_signed,
+ bfd_boolean is_nested)
+{
+ unsigned long abbrev_number;
+ abbrev_entry * entry;
+ abbrev_attr * attr;
+
+ * is_signed = FALSE;
+
+ READ_ULEB (abbrev_number, data, end);
+
+ for (entry = first_abbrev;
+ entry != NULL && entry->entry != abbrev_number;
+ entry = entry->next)
+ continue;
+
+ if (entry == NULL)
+ /* FIXME: Issue a warning ? */
+ return;
+
+ for (attr = entry->first_attr;
+ attr != NULL && attr->attribute;
+ attr = attr->next)
+ {
+ dwarf_vma uvalue = 0;
+
+ data = skip_attr_bytes (attr->form, data, end, pointer_size,
+ offset_size, dwarf_version, & uvalue);
+ if (data == NULL)
+ return;
+
+ switch (attr->attribute)
+ {
+#if 0 /* FIXME: It would be nice to print the name of the type,
+ but this would mean updating a lot of binutils tests. */
+ case DW_AT_name:
+ if (attr->form == DW_FORM_strp)
+ printf ("%s", fetch_indirect_string (uvalue));
+ break;
+#endif
+ case DW_AT_type:
+ /* Recurse. */
+ if (is_nested)
+ {
+ /* FIXME: Warn - or is this expected ?
+ NB/ We need to avoid infinite recursion. */
+ return;
+ }
+ if (uvalue >= (size_t) (end - start))
+ return;
+ get_type_signedness (start, start + uvalue, end, pointer_size,
+ offset_size, dwarf_version, is_signed, TRUE);
+ break;
+
+ case DW_AT_encoding:
+ /* Determine signness. */
+ switch (uvalue)
+ {
+ case DW_ATE_address:
+ /* FIXME - some architectures have signed addresses. */
+ case DW_ATE_boolean:
+ case DW_ATE_unsigned:
+ case DW_ATE_unsigned_char:
+ case DW_ATE_unsigned_fixed:
+ * is_signed = FALSE;
+ break;
+
+ default:
+ case DW_ATE_complex_float:
+ case DW_ATE_float:
+ case DW_ATE_signed:
+ case DW_ATE_signed_char:
+ case DW_ATE_imaginary_float:
+ case DW_ATE_decimal_float:
+ case DW_ATE_signed_fixed:
+ * is_signed = TRUE;
+ break;
+ }
+ break;
+ }
+ }
+}
+
+static void
+read_and_print_leb128 (unsigned char * data,
+ unsigned int * bytes_read,
+ unsigned const char * end,
+ bfd_boolean is_signed)
+{
+ int status;
+ dwarf_vma val = read_leb128 (data, end, is_signed, bytes_read, &status);
+ if (status != 0)
+ report_leb_status (status, __FILE__, __LINE__);
+ else
+ printf ("%s", dwarf_vmatoa (is_signed ? "d" : "u", val));
+}
+
+static void
+display_discr_list (unsigned long form,
+ dwarf_vma uvalue,
+ unsigned char * data,
+ unsigned const char * end,
+ int level)
+{
+ if (uvalue == 0)
+ {
+ printf ("[default]");
+ return;
+ }
+
+ switch (form)
+ {
+ case DW_FORM_block:
+ case DW_FORM_block1:
+ case DW_FORM_block2:
+ case DW_FORM_block4:
+ /* Move data pointer back to the start of the byte array. */
+ data -= uvalue;
+ break;
+ default:
+ printf ("<corrupt>\n");
+ warn (_("corrupt discr_list - not using a block form\n"));
+ return;
+ }
+
+ if (uvalue < 2)
+ {
+ printf ("<corrupt>\n");
+ warn (_("corrupt discr_list - block not long enough\n"));
+ return;
+ }
+
+ bfd_boolean is_signed =
+ (level > 0 && level <= MAX_CU_NESTING)
+ ? level_type_signed [level - 1] : FALSE;
+
+ printf ("(");
+ while (uvalue)
+ {
+ unsigned char discriminant;
+ unsigned int bytes_read;
+
+ SAFE_BYTE_GET (discriminant, data, 1, end);
+ -- uvalue;
+ data ++;
+
+ assert (uvalue > 0);
+ switch (discriminant)
+ {
+ case DW_DSC_label:
+ printf ("label ");
+ read_and_print_leb128 (data, & bytes_read, end, is_signed);
+ assert (bytes_read <= uvalue && bytes_read > 0);
+ uvalue -= bytes_read;
+ data += bytes_read;
+ break;
+
+ case DW_DSC_range:
+ printf ("range ");
+ read_and_print_leb128 (data, & bytes_read, end, is_signed);
+ assert (bytes_read <= uvalue && bytes_read > 0);
+ uvalue -= bytes_read;
+ data += bytes_read;
+
+ printf ("..");
+ read_and_print_leb128 (data, & bytes_read, end, is_signed);
+ assert (bytes_read <= uvalue && bytes_read > 0);
+ uvalue -= bytes_read;
+ data += bytes_read;
+ break;
+
+ default:
+ printf ("<corrupt>\n");
+ warn (_("corrupt discr_list - unrecognised discriminant byte %#x\n"),
+ discriminant);
+ return;
+ }
+
+ if (uvalue)
+ printf (", ");
+ }
+
+ if (is_signed)
+ printf (")(signed)");
+ else
+ printf (")(unsigned)");
+}
+