+/* Routines to manipulate hash table of CUs. */
+
+static hashval_t
+htab_macinfo_hash (const void *of)
+{
+ const macinfo_entry *const entry =
+ (const macinfo_entry *) of;
+
+ return htab_hash_string (entry->info);
+}
+
+static int
+htab_macinfo_eq (const void *of1, const void *of2)
+{
+ const macinfo_entry *const entry1 = (const macinfo_entry *) of1;
+ const macinfo_entry *const entry2 = (const macinfo_entry *) of2;
+
+ return !strcmp (entry1->info, entry2->info);
+}
+
+/* Output a single .debug_macinfo entry. */
+
+static void
+output_macinfo_op (macinfo_entry *ref)
+{
+ int file_num;
+ size_t len;
+ struct indirect_string_node *node;
+ char label[MAX_ARTIFICIAL_LABEL_BYTES];
+ struct dwarf_file_data *fd;
+
+ switch (ref->code)
+ {
+ case DW_MACINFO_start_file:
+ fd = lookup_filename (ref->info);
+ file_num = maybe_emit_file (fd);
+ dw2_asm_output_data (1, DW_MACINFO_start_file, "Start new file");
+ dw2_asm_output_data_uleb128 (ref->lineno,
+ "Included from line number %lu",
+ (unsigned long) ref->lineno);
+ dw2_asm_output_data_uleb128 (file_num, "file %s", ref->info);
+ break;
+ case DW_MACINFO_end_file:
+ dw2_asm_output_data (1, DW_MACINFO_end_file, "End file");
+ break;
+ case DW_MACINFO_define:
+ case DW_MACINFO_undef:
+ len = strlen (ref->info) + 1;
+ if (!dwarf_strict
+ && len > DWARF_OFFSET_SIZE
+ && !DWARF2_INDIRECT_STRING_SUPPORT_MISSING_ON_TARGET
+ && (debug_str_section->common.flags & SECTION_MERGE) != 0)
+ {
+ ref->code = ref->code == DW_MACINFO_define
+ ? DW_MACRO_GNU_define_indirect
+ : DW_MACRO_GNU_undef_indirect;
+ output_macinfo_op (ref);
+ return;
+ }
+ dw2_asm_output_data (1, ref->code,
+ ref->code == DW_MACINFO_define
+ ? "Define macro" : "Undefine macro");
+ dw2_asm_output_data_uleb128 (ref->lineno, "At line number %lu",
+ (unsigned long) ref->lineno);
+ dw2_asm_output_nstring (ref->info, -1, "The macro");
+ break;
+ case DW_MACRO_GNU_define_indirect:
+ case DW_MACRO_GNU_undef_indirect:
+ node = find_AT_string (ref->info);
+ if (node->form != DW_FORM_strp)
+ {
+ char label[32];
+ ASM_GENERATE_INTERNAL_LABEL (label, "LASF", dw2_string_counter);
+ ++dw2_string_counter;
+ node->label = xstrdup (label);
+ node->form = DW_FORM_strp;
+ }
+ dw2_asm_output_data (1, ref->code,
+ ref->code == DW_MACRO_GNU_define_indirect
+ ? "Define macro indirect"
+ : "Undefine macro indirect");
+ dw2_asm_output_data_uleb128 (ref->lineno, "At line number %lu",
+ (unsigned long) ref->lineno);
+ dw2_asm_output_offset (DWARF_OFFSET_SIZE, node->label,
+ debug_str_section, "The macro: \"%s\"",
+ ref->info);
+ break;
+ case DW_MACRO_GNU_transparent_include:
+ dw2_asm_output_data (1, ref->code, "Transparent include");
+ ASM_GENERATE_INTERNAL_LABEL (label,
+ DEBUG_MACRO_SECTION_LABEL, ref->lineno);
+ dw2_asm_output_offset (DWARF_OFFSET_SIZE, label, NULL, NULL);
+ break;
+ default:
+ fprintf (asm_out_file, "%s unrecognized macinfo code %lu\n",
+ ASM_COMMENT_START, (unsigned long) ref->code);
+ break;
+ }
+}
+
+/* Attempt to make a sequence of define/undef macinfo ops shareable with
+ other compilation unit .debug_macinfo sections. IDX is the first
+ index of a define/undef, return the number of ops that should be
+ emitted in a comdat .debug_macinfo section and emit
+ a DW_MACRO_GNU_transparent_include entry referencing it.
+ If the define/undef entry should be emitted normally, return 0. */
+
+static unsigned
+optimize_macinfo_range (unsigned int idx, VEC (macinfo_entry, gc) *files,
+ htab_t *macinfo_htab)
+{
+ macinfo_entry *first, *second, *cur, *inc;
+ char linebuf[sizeof (HOST_WIDE_INT) * 3 + 1];
+ unsigned char checksum[16];
+ struct md5_ctx ctx;
+ char *grp_name, *tail;
+ const char *base;
+ unsigned int i, count, encoded_filename_len, linebuf_len;
+ void **slot;
+
+ first = VEC_index (macinfo_entry, macinfo_table, idx);
+ second = VEC_index (macinfo_entry, macinfo_table, idx + 1);
+
+ /* Optimize only if there are at least two consecutive define/undef ops,
+ and either all of them are before first DW_MACINFO_start_file
+ with lineno {0,1} (i.e. predefined macro block), or all of them are
+ in some included header file. */
+ if (second->code != DW_MACINFO_define && second->code != DW_MACINFO_undef)
+ return 0;
+ if (VEC_empty (macinfo_entry, files))
+ {
+ if (first->lineno > 1 || second->lineno > 1)
+ return 0;
+ }
+ else if (first->lineno == 0)
+ return 0;
+
+ /* Find the last define/undef entry that can be grouped together
+ with first and at the same time compute md5 checksum of their
+ codes, linenumbers and strings. */
+ md5_init_ctx (&ctx);
+ for (i = idx; VEC_iterate (macinfo_entry, macinfo_table, i, cur); i++)
+ if (cur->code != DW_MACINFO_define && cur->code != DW_MACINFO_undef)
+ break;
+ else if (VEC_empty (macinfo_entry, files) && cur->lineno > 1)
+ break;
+ else
+ {
+ unsigned char code = cur->code;
+ md5_process_bytes (&code, 1, &ctx);
+ checksum_uleb128 (cur->lineno, &ctx);
+ md5_process_bytes (cur->info, strlen (cur->info) + 1, &ctx);
+ }
+ md5_finish_ctx (&ctx, checksum);
+ count = i - idx;
+
+ /* From the containing include filename (if any) pick up just
+ usable characters from its basename. */
+ if (VEC_empty (macinfo_entry, files))
+ base = "";
+ else
+ base = lbasename (VEC_last (macinfo_entry, files)->info);
+ for (encoded_filename_len = 0, i = 0; base[i]; i++)
+ if (ISIDNUM (base[i]) || base[i] == '.')
+ encoded_filename_len++;
+ /* Count . at the end. */
+ if (encoded_filename_len)
+ encoded_filename_len++;
+
+ sprintf (linebuf, HOST_WIDE_INT_PRINT_UNSIGNED, first->lineno);
+ linebuf_len = strlen (linebuf);
+
+ /* The group name format is: wmN.[<encoded filename>.]<lineno>.<md5sum> */
+ grp_name = XALLOCAVEC (char, 4 + encoded_filename_len + linebuf_len + 1
+ + 16 * 2 + 1);
+ memcpy (grp_name, DWARF_OFFSET_SIZE == 4 ? "wm4." : "wm8.", 4);
+ tail = grp_name + 4;
+ if (encoded_filename_len)
+ {
+ for (i = 0; base[i]; i++)
+ if (ISIDNUM (base[i]) || base[i] == '.')
+ *tail++ = base[i];
+ *tail++ = '.';
+ }
+ memcpy (tail, linebuf, linebuf_len);
+ tail += linebuf_len;
+ *tail++ = '.';
+ for (i = 0; i < 16; i++)
+ sprintf (tail + i * 2, "%02x", checksum[i] & 0xff);
+
+ /* Construct a macinfo_entry for DW_MACRO_GNU_transparent_include
+ in the empty vector entry before the first define/undef. */
+ inc = VEC_index (macinfo_entry, macinfo_table, idx - 1);
+ inc->code = DW_MACRO_GNU_transparent_include;
+ inc->lineno = 0;
+ inc->info = ggc_strdup (grp_name);
+ if (*macinfo_htab == NULL)
+ *macinfo_htab = htab_create (10, htab_macinfo_hash, htab_macinfo_eq, NULL);
+ /* Avoid emitting duplicates. */
+ slot = htab_find_slot (*macinfo_htab, inc, INSERT);
+ if (*slot != NULL)
+ {
+ inc->code = 0;
+ inc->info = NULL;
+ /* If such an entry has been used before, just emit
+ a DW_MACRO_GNU_transparent_include op. */
+ inc = (macinfo_entry *) *slot;
+ output_macinfo_op (inc);
+ /* And clear all macinfo_entry in the range to avoid emitting them
+ in the second pass. */
+ for (i = idx;
+ VEC_iterate (macinfo_entry, macinfo_table, i, cur)
+ && i < idx + count;
+ i++)
+ {
+ cur->code = 0;
+ cur->info = NULL;
+ }
+ }
+ else
+ {
+ *slot = inc;
+ inc->lineno = htab_elements (*macinfo_htab);
+ output_macinfo_op (inc);
+ }
+ return count;
+}
+
+/* Output macinfo section(s). */
+