diff -Nru dwz-0.13+20210219/COPYRIGHT_YEARS dwz-0.14/COPYRIGHT_YEARS --- dwz-0.13+20210219/COPYRIGHT_YEARS 2021-02-18 13:36:58.000000000 +0000 +++ dwz-0.14/COPYRIGHT_YEARS 2021-03-08 07:56:18.976431406 +0000 @@ -1,3 +1,3 @@ -DFSF_YEARS='"1992-2021"' -DRH_YEARS='"2001-2021"' --DSUSE_YEARS='"2019"' +-DSUSE_YEARS='"2019-2021"' diff -Nru dwz-0.13+20210219/debian/changelog dwz-0.14/debian/changelog --- dwz-0.13+20210219/debian/changelog 2021-02-19 13:34:09.000000000 +0000 +++ dwz-0.14/debian/changelog 2021-03-08 14:35:45.000000000 +0000 @@ -1,3 +1,9 @@ +dwz (0.14-1) unstable; urgency=medium + + * New upstream version. + + -- Matthias Klose Mon, 08 Mar 2021 15:35:45 +0100 + dwz (0.13+20210219-1) experimental; urgency=medium * Snapshot build, taken from the trunk 20210219. diff -Nru dwz-0.13+20210219/dwz.1 dwz-0.14/dwz.1 --- dwz-0.13+20210219/dwz.1 2021-02-19 13:31:34.000000000 +0000 +++ dwz-0.14/dwz.1 2021-03-08 07:56:18.976431406 +0000 @@ -22,11 +22,12 @@ While most of DWARF 5 is supported dwz doesn't yet generate spec compliant DWARF Supplementary Object Files (DWARF 5, section -7.3.6). Instead of a \fI.debug_sup\fR section it will generate a -\fI.gnu_debugaltlink\fR section. And it will use the -\fIDW_FORM_GNU_strp_alt\fR and \fIDW_FORM_GNU_reg_alt\fR, instead of -\fIDW_FORM_strp_sup\fR and \fIDW_FORM_ref_sup\fR to keep compatibility -with existing DWARF consumers. +7.3.6) unless the \fI--dwarf-5\fR option is used. Instead of a +\fI.debug_sup\fR section it will generate by default a \fI.gnu_debugaltlink\fR +section. And it will use the \fIDW_FORM_GNU_strp_alt\fR and +\fIDW_FORM_GNU_reg_alt\fR, instead of \fIDW_FORM_strp_sup\fR +and \fIDW_FORM_ref_sup\fR to keep compatibility with existing DWARF +consumers. DWARF 4 \fI.debug_types\fR are supported, but DWARF 5 \fIDW_UT_type\fR units are not. Likewise \fI.gdb_index\fR is supported, but the DWARF 5 @@ -105,12 +106,19 @@ \fICOUNT\fR DIEs at all. The default is 50 million DIEs. Specifying none as argument disables the limit. .TP +.B \-5 \-\-dwarf\-5 +Emit standard DWARF 5 Supplementary Object Files with \fI.debug_sup\fR and +corresponding forms, instead of the GNU extension \fI.gnu_debugaltlink\fR +and corresponding forms. +.TP .B \-\-odr / \-\-no-odr +.B Experimental. Enable/disable One-Definition-Rule optimization for C++ compilation units. This optimization causes struct/union/class DIEs with the same name to be considered equal. This has the effect that DIEs referring to distinct DIEs representing the same type (like f.i. pointer type DIEs) are considered equal, -and may be deduplicated. +and may be deduplicated. The status of this optimization is experimental. +It's disabled in low-mem mode. Disabled by default. .TP .B \-\-odr-mode= diff -Nru dwz-0.13+20210219/dwz.c dwz-0.14/dwz.c --- dwz-0.13+20210219/dwz.c 2021-02-19 13:31:34.000000000 +0000 +++ dwz-0.14/dwz.c 2021-03-08 07:56:18.980431379 +0000 @@ -1,6 +1,6 @@ /* Copyright (C) 2001-2021 Red Hat, Inc. Copyright (C) 2003 Free Software Foundation, Inc. - Copyright (C) 2019 SUSE LLC. + Copyright (C) 2019-2021 SUSE LLC. Written by Jakub Jelinek , 2012. This program is free software; you can redistribute it and/or modify @@ -753,6 +753,7 @@ DEBUG_RANGES, DEBUG_RNGLISTS, DEBUG_LINE_STR, + DEBUG_SUP, DEBUG_GDB_SCRIPTS, GDB_INDEX, GNU_DEBUGALTLINK, @@ -789,6 +790,7 @@ { ".debug_ranges", NULL, NULL, 0, 0, 0 }, { ".debug_rnglists", NULL, NULL, 0, 0, 0 }, { ".debug_line_str", NULL, NULL, 0, 0, 0 }, + { ".debug_sup", NULL, NULL, 0, 0, 0 }, { ".debug_gdb_scripts", NULL, NULL, 0, 0, 0 }, { ".gdb_index", NULL, NULL, 0, 0, 0 }, { ".gnu_debugaltlink", NULL, NULL, 0, 0, 0 }, @@ -866,10 +868,10 @@ static const char *multifile; /* Argument of -M option, i.e. preferred name that should be stored - into the .gnu_debugaltlink section. */ + into the .gnu_debugaltlink or .debug_sup section. */ static const char *multifile_name; -/* True if -r option is present, i.e. .gnu_debugaltlink section +/* True if -r option is present, i.e. .gnu_debugaltlink or .debug_sup section should contain a filename relative to the directory in which the particular file is present. */ static bool multifile_relative; @@ -877,6 +879,11 @@ /* SHA1 checksum (build-id) of the common file. */ static unsigned char multifile_sha1[0x14]; +/* True if DWARF 5 .debug_sup and DW_FORM_ref_sup4 / DW_FORM_strp_sup + should be used instead of the GNU extensions .gnu_debugaltlink + and DW_FORM_GNU_ref_alt / DW_FORM_GNU_strp_alt etc. */ +static bool dwarf_5; + /* True if -q option has been passed. */ static bool quiet; @@ -3220,6 +3227,7 @@ bool name_p; bool other_p; + assert (die->die_odr_state == ODR_UNKNOWN); die->die_odr_state = ODR_NONE; if (low_mem) @@ -3303,12 +3311,9 @@ /* Return the initialized die_odr_state field for DIE with CU. */ static unsigned int UNUSED -die_odr_state (dw_cu_ref cu, dw_die_ref die) +die_odr_state (dw_die_ref die) { - if (die->die_odr_state != ODR_UNKNOWN) - return die->die_odr_state; - - set_die_odr_state (cu, die); + assert (die->die_odr_state != ODR_UNKNOWN); return die->die_odr_state; } @@ -3373,7 +3378,10 @@ fprintf (stderr, "DIE %x, hash: %x, lang\n", die->die_offset, die->u.p1.die_hash); } - only_hash_name_p = odr && die_odr_state (die_cu (die), die) != ODR_NONE; + + if (odr && die->die_odr_state == ODR_UNKNOWN) + set_die_odr_state (die_cu (die), die); + only_hash_name_p = odr && die_odr_state (die) != ODR_NONE; die_hash2 = 0; if (only_hash_name_p) die_hash2 = die->u.p1.die_hash; @@ -3454,8 +3462,35 @@ case DW_FORM_data8: value = read_64 (ptr); handled = true; break; case DW_FORM_udata: value = read_uleb128 (ptr); handled = true; break; + case DW_FORM_sdata: + { + int64_t svalue = read_sleb128 (ptr); + if (svalue >= 0) + { + value = svalue; + handled = true; + break; + } + else + { + negative: + error (0, 0, "%s: negative value %" PRId64 " for %s", + dso->filename, svalue, + get_DW_AT_str (t->attr[i].attr)); + return 1; + } + } case DW_FORM_implicit_const: - value = t->values[i]; handled = true; break; + { + if (t->values[i] >= 0) + { + value = t->values[i]; + handled = true; + break; + } + else + goto negative; + } default: error (0, 0, "%s: Unhandled %s for %s", dso->filename, get_DW_FORM_str (form), @@ -3533,8 +3568,27 @@ case DW_FORM_data8: value = read_64 (ptr); handled = true; break; case DW_FORM_udata: value = read_uleb128 (ptr); handled = true; break; + case DW_FORM_sdata: + { + int64_t svalue = read_sleb128 (ptr); + if (svalue >= 0) + { + value = svalue; + handled = true; + break; + } + else + goto negative; + } case DW_FORM_implicit_const: - value = t->values[i]; handled = true; break; + if (t->values[i] >= 0) + { + value = t->values[i]; + handled = true; + break; + } + else + goto negative; default: error (0, 0, "%s: Unhandled %s for %s", dso->filename, get_DW_FORM_str (form), @@ -3993,7 +4047,6 @@ unsigned int i, ret = 0; unsigned char *ptr; dw_die_ref child; - bool only_hash_name_p; if (top_die == die) { @@ -4024,7 +4077,6 @@ else assert (top_die == NULL || die->die_ck_state == CK_KNOWN); t = die->die_abbrev; - only_hash_name_p = odr && die_odr_state (die_cu (die), die) != ODR_NONE; for (i = 0; i < t->nattr; ++i) if (t->attr[i].attr != DW_AT_sibling) switch (t->attr[i].form) @@ -4208,24 +4260,25 @@ } } - if (!only_hash_name_p - && (top_die == NULL || top_die->die_ck_state != CK_BAD)) - for (child = die->die_child; child; child = child->die_sib) - { - unsigned int r - = checksum_ref_die (cu, - top_die ? top_die - : child->die_named_namespace - ? NULL : child, child, - second_idx, second_hash); - if (top_die == NULL) - assert (r == 0 && obstack_object_size (&ob) == 0); - - if (ret == 0 || (r && r < ret)) - ret = r; - if (top_die && top_die->die_ck_state == CK_BAD) - break; - } + if (top_die == NULL || top_die->die_ck_state != CK_BAD) + { + for (child = die->die_child; child; child = child->die_sib) + { + unsigned int r + = checksum_ref_die (cu, + top_die ? top_die + : child->die_named_namespace + ? NULL : child, child, + second_idx, second_hash); + if (top_die == NULL) + assert (r == 0 && obstack_object_size (&ob) == 0); + + if (ret == 0 || (r && r < ret)) + ret = r; + if (top_die && top_die->die_ck_state == CK_BAD) + break; + } + } if (top_die == die) { @@ -4768,6 +4821,7 @@ case DW_FORM_data4: value1 = read_32 (ptr1); break; case DW_FORM_data8: value1 = read_64 (ptr1); break; case DW_FORM_udata: value1 = read_uleb128 (ptr1); break; + case DW_FORM_sdata: value1 = read_sleb128 (ptr1); break; case DW_FORM_implicit_const: value1 = t1->values[i]; break; default: abort (); } @@ -4778,6 +4832,7 @@ case DW_FORM_data4: value2 = read_32 (ptr2); break; case DW_FORM_data8: value2 = read_64 (ptr2); break; case DW_FORM_udata: value2 = read_uleb128 (ptr2); break; + case DW_FORM_sdata: value2 = read_sleb128 (ptr2); break; case DW_FORM_implicit_const: value2 = t2->values[j]; break; default: abort (); } @@ -4860,6 +4915,7 @@ case DW_FORM_data4: value1 = read_32 (ptr1); break; case DW_FORM_data8: value1 = read_64 (ptr1); break; case DW_FORM_udata: value1 = read_uleb128 (ptr1); break; + case DW_FORM_sdata: value1 = read_sleb128 (ptr1); break; case DW_FORM_implicit_const: value1 = t1->values[i]; break; default: abort (); } @@ -4870,6 +4926,7 @@ case DW_FORM_data4: value2 = read_32 (ptr2); break; case DW_FORM_data8: value2 = read_64 (ptr2); break; case DW_FORM_udata: value2 = read_uleb128 (ptr2); break; + case DW_FORM_sdata: value2 = read_sleb128 (ptr2); break; case DW_FORM_implicit_const: value2 = t2->values[j]; break; default: abort (); } @@ -5476,7 +5533,8 @@ fprintf (stderr, "%*s %x %c %x", indent, "", die->die_offset, die->die_ck_state == CK_KNOWN ? 'O' : 'X', (unsigned) die->u.p1.die_hash); - if (odr && die->die_odr_state != ODR_NONE) + if (odr && die->die_odr_state != ODR_NONE + && die->die_odr_state != ODR_UNKNOWN) fprintf (stderr, "(%x)", (unsigned) die->u.p1.die_hash2); fprintf (stderr, " %x %s %s", (unsigned) die->u.p1.die_ref_hash, name ? name : "", get_DW_TAG_name (die->die_tag) + 7); @@ -5732,8 +5790,8 @@ /* Note .debug_str offset during write_macro or compute_abbrevs, return either DW_FORM_strp if the string will be in the local - .debug_str section, or DW_FORM_GNU_strp_alt if it will be in - the shared .debug_str section. */ + .debug_str section, or DW_FORM_strp_sup / DW_FORM_GNU_strp_alt if it + will be in the shared .debug_str section. */ static enum dwarf_form note_strp_offset2 (unsigned int off) { @@ -5751,7 +5809,7 @@ len = strlen ((char *) p); hash = iterative_hash (p, len, 0); if (htab_find_with_hash (alt_strp_htab, p, hash)) - return DW_FORM_GNU_strp_alt; + return dwarf_5 ? DW_FORM_strp_sup : DW_FORM_GNU_strp_alt; } return DW_FORM_strp; } @@ -7240,6 +7298,20 @@ if (checksum_die (dso, cu, NULL, cu->cu_die)) goto fail; checksum_ref_die (cu, NULL, cu->cu_die, NULL, NULL); + if (odr) + { + dw_die_ref die; + FOREACH_LOW_TOPLEVEL_DIE_IN_CU (die, cu) + { + if (die->die_ck_state != CK_KNOWN) + continue; + if (die_odr_state (die) != ODR_NONE) + die->u.p1.die_ref_hash = die->u.p1.die_hash; + else + die->die_ref_hash_computed = 0; + } + checksum_ref_die (cu, NULL, cu->cu_die, NULL, NULL); + } if (dump_dies_p) dump_dies (0, cu->cu_die); @@ -7379,8 +7451,20 @@ dw_die_ref die2 = *(dw_die_ref *) q; dw_die_ref ref1, ref2; dw_cu_ref last_cu1 = NULL, last_cu2 = NULL; - for (ref1 = die1, ref2 = die2;; - ref1 = ref1->die_nextdup, ref2 = ref2->die_nextdup) + ref1 = die1; + ref2 = die2; + if (odr_active_p && odr_mode != ODR_BASIC) + { + while (ref1 && die_odr_state (ref1) == ODR_DECL) + ref1 = ref1->die_nextdup; + if (ref1 == NULL) + ref1 = die1; + while (ref2 && die_odr_state (ref2) == ODR_DECL) + ref2 = ref2->die_nextdup; + if (ref2 == NULL) + ref2 = die2; + } + for (;; ref1 = ref1->die_nextdup, ref2 = ref2->die_nextdup) { dw_cu_ref ref1cu = NULL; dw_cu_ref ref2cu = NULL; @@ -7635,7 +7719,7 @@ for (i = 0; i < count; i++) { d = arr[i]; - if (die_odr_state (NULL, d) != ODR_DECL) + if (die_odr_state (d) != ODR_DECL) continue; if (!head) head = d; @@ -7654,14 +7738,14 @@ { d = arr[i]; if (d->die_dup || d->die_nextdup - || die_odr_state (NULL, d) == ODR_DECL) + || die_odr_state (d) == ODR_DECL) continue; tail = d; for (j = i + 1; j < count; j++) { d2 = arr[j]; if (d2->die_dup || d2->die_nextdup - || die_odr_state (NULL, d2) == ODR_DECL) + || die_odr_state (d2) == ODR_DECL) continue; die_eq (d, d2); } @@ -7675,7 +7759,7 @@ for (i = 0; i < count; i++) { d = arr[i]; - if (die_odr_state (NULL, d) == ODR_DECL + if (die_odr_state (d) == ODR_DECL || d->die_dup != NULL) continue; def = d; @@ -7753,12 +7837,12 @@ unsigned def_count = 0; dw_die_ref d; - if (die_odr_state (NULL, die) == ODR_NONE) + if (die_odr_state (die) == ODR_NONE) return die; for (d = die; d; d = d->die_nextdup) { - if (die_odr_state (NULL, d) == ODR_DECL) + if (die_odr_state (d) == ODR_DECL) decl_count++; else def_count++; @@ -7766,14 +7850,14 @@ if (def_count == 0 || decl_count == 0) return die; - if (die_odr_state (NULL, die) != ODR_DECL) + if (die_odr_state (die) != ODR_DECL) return die; dw_die_ref def = NULL; dw_die_ref prev = NULL; for (d = die; d; prev = d, d = d->die_nextdup) { - if (die_odr_state (NULL, d) == ODR_DECL) + if (die_odr_state (d) == ODR_DECL) continue; def = d; break; @@ -7881,70 +7965,100 @@ return n; } +/* Return true if duplicate chains REF1 and REF2 have the same set of + referrer CUs. If so, return the number of unique referrer CUs + in *CNT. */ +static inline unsigned int FORCE_INLINE +same_ref_cus_p (dw_die_ref ref1, dw_die_ref ref2, size_t *cnt) +{ + dw_cu_ref last_cu1 = NULL, last_cu2 = NULL; + + *cnt = 0; + + if (odr_active_p && odr_mode != ODR_BASIC) + { + dw_die_ref orig_ref1 = ref1, orig_ref2 = ref2; + while (ref1 && die_odr_state (ref1) == ODR_DECL) + ref1 = ref1->die_nextdup; + if (ref1 == NULL) + ref1 = orig_ref1; + while (ref2 && die_odr_state (ref2) == ODR_DECL) + ref2 = ref2->die_nextdup; + if (ref2 == NULL) + ref2 = orig_ref2; + } + for (;; ref1 = ref1->die_nextdup, ref2 = ref2->die_nextdup) + { + dw_cu_ref ref1cu = NULL; + dw_cu_ref ref2cu = NULL; + + while (ref1 && (ref1cu = die_cu (ref1)) == last_cu1) + ref1 = ref1->die_nextdup; + while (ref2 && (ref2cu = die_cu (ref2)) == last_cu2) + ref2 = ref2->die_nextdup; + if (ref1 == NULL || ref2 == NULL) + break; + + last_cu1 = ref1cu; + last_cu2 = ref2cu; + + if (last_cu1 != last_cu2) + break; + else + (*cnt)++; + } + + if (ref1 || ref2) + return false; + + return true; +} + +/* Return the number of unique referrer CUs in duplicate chain REF. */ +static inline size_t FORCE_INLINE +cnt_ref_cus (dw_die_ref ref) +{ + dw_cu_ref last_cu1 = NULL; + size_t cnt = 0; + + for (;; ref = ref->die_nextdup) + { + dw_cu_ref refcu = NULL; + while (ref && (refcu = die_cu (ref)) == last_cu1) + ref = ref->die_nextdup; + if (ref == NULL) + break; + last_cu1 = refcu; + cnt++; + } + + return cnt; +} + /* Helper function of partition_dups_1. Decide what DIEs matching in multiple CUs might be worthwhile to be moved into partial units, construct those partial units. */ static bool -partition_dups_1 (dw_die_ref *arr, size_t vec_size, +partition_dups_1 (dw_die_ref *arr, size_t nr_partitions, size_t *partitions, dw_cu_ref *first_partial_cu, dw_cu_ref *last_partial_cu, bool second_phase) { - size_t i, j; + size_t i, j, cnt; bool ret = false; - for (i = 0; i < vec_size; i = j) + size_t idx = 0; + for (idx = 0; idx < nr_partitions * 2; idx += 2) { + i = partitions[idx]; + cnt = partitions[idx + 1]; + j = partitions[idx + 2]; + + if (arr[i]->die_dup != NULL) + continue; + dw_die_ref ref; - size_t cnt = 0, size = 0, k, orig_size, new_size, namespaces = 0; + size_t size = 0, k, orig_size, new_size, namespaces = 0; unsigned int force = 0; - if (arr[i]->die_dup != NULL) - { - j = i + 1; - continue; - } - for (j = i + 1; j < vec_size; j++) - { - dw_die_ref ref1, ref2; - dw_cu_ref last_cu1 = NULL, last_cu2 = NULL; - size_t this_cnt = 0; - for (ref1 = arr[i], ref2 = arr[j];; - ref1 = ref1->die_nextdup, ref2 = ref2->die_nextdup) - { - dw_cu_ref ref1cu = NULL; - dw_cu_ref ref2cu = NULL; - while (ref1 && (ref1cu = die_cu (ref1)) == last_cu1) - ref1 = ref1->die_nextdup; - while (ref2 && (ref2cu = die_cu (ref2)) == last_cu2) - ref2 = ref2->die_nextdup; - if (ref1 == NULL || ref2 == NULL) - break; - last_cu1 = ref1cu; - last_cu2 = ref2cu; - if (last_cu1 != last_cu2) - break; - else - this_cnt++; - } - if (ref1 || ref2) - break; - cnt = this_cnt; - } - if (stats_p && !second_phase) - stats->part_cnt++; - if (cnt == 0) - { - dw_cu_ref last_cu1 = NULL; - for (ref = arr[i];; ref = ref->die_nextdup) - { - dw_cu_ref refcu = NULL; - while (ref && (refcu = die_cu (ref)) == last_cu1) - ref = ref->die_nextdup; - if (ref == NULL) - break; - last_cu1 = refcu; - cnt++; - } - } enum dwarf_source_language part_lang = gen_cu_p ? partition_lang (arr[i]) : 0; for (k = i; k < j; k++) @@ -8113,8 +8227,6 @@ dw_die_ref child; if (second_phase && !arr[k]->die_ref_seen) continue; - if (odr_active_p && odr_mode != ODR_BASIC) - arr[k] = reorder_dups (arr[k]); if (dump_pus_p) dump_die (arr[k]); child = copy_die_tree (die, arr[k]); @@ -8212,6 +8324,36 @@ return ret; } +/* Partition the duplicate chains in array ARR with size VEC_SIZE, and store + the partitions on obstack ob2, with for each partition two entries: + the start and the number of unique reffer CUs. */ +static void +calculate_partitions (dw_die_ref *arr, size_t vec_size) +{ + size_t i, j; + for (i = 0; i < vec_size; i = j) + { + size_t cnt = 0; + for (j = i + 1; j < vec_size; j++) + { + size_t this_cnt; + if (!same_ref_cus_p (arr[i], arr[j], &this_cnt)) + break; + cnt = this_cnt; + } + if (cnt == 0) + cnt = cnt_ref_cus (arr[i]); + obstack_grow (&ob2, &i, sizeof (size_t)); + obstack_grow (&ob2, &cnt, sizeof (size_t)); + } + + /* Add element to mark end of partition list. This allows us to do + 'j = partitions[idx + 2]' for all partitions. */ + obstack_grow (&ob2, &j, sizeof (size_t)); + size_t zero = 0; + obstack_grow (&ob2, &zero, sizeof (size_t)); +} + static inline void FORCE_INLINE reset_die_ref_seen (void) { @@ -8232,7 +8374,7 @@ size_t decl_cnt = 0; for (d = die; d; d = d->die_nextdup) - switch (die_odr_state (NULL, d)) + switch (die_odr_state (d)) { case ODR_DEF: if (res) @@ -8292,7 +8434,7 @@ for (i = 0; i < vec_size; i++) { dw_die_ref die = arr[i]; - if (die_odr_state (NULL, die) == ODR_NONE) + if (die_odr_state (die) == ODR_NONE) continue; die = split_dups (die, &ob2); assert (die != NULL); @@ -8319,12 +8461,15 @@ && die->die_nextdup == NULL) mark_singletons (die_cu (die), die, die, &ob2); else if (odr_mode != ODR_BASIC - && die_odr_state (NULL, die) != ODR_NONE) + && die_odr_state (die) != ODR_NONE) { dw_die_ref s = merged_singleton (die); if (s) mark_singletons (die_cu (s), s, s, &ob2); } + else if (cnt_ref_cus (die) == 1) + mark_singletons (die_cu (die), die, die, &ob2); + arr = (dw_die_ref *) obstack_base (&ob2); } @@ -8366,7 +8511,19 @@ report_progress (); fprintf (stderr, "partition_dups after qsort\n"); } - if (partition_dups_1 (arr, vec_size, &first_partial_cu, + + size_t *partitions = (size_t *) obstack_base (&ob2); + calculate_partitions (arr, vec_size); + size_t nr_partitions + = (obstack_object_size (&ob2) / sizeof (size_t)) / 2 - 1; + partitions = (size_t *) obstack_finish (&ob2); + if (stats_p) + stats->part_cnt += nr_partitions; + + if (odr_active_p && odr_mode != ODR_BASIC) + for (i = 0; i < vec_size; ++i) + arr[i] = reorder_dups (arr[i]); + if (partition_dups_1 (arr, nr_partitions, partitions, &first_partial_cu, &last_partial_cu, false)) { for (i = 0; i < vec_size; i++) @@ -8375,7 +8532,7 @@ if (arr[i]->die_dup != NULL) mark_refs (die_cu (arr[i]), arr[i], arr[i], MARK_REFS_FOLLOW_DUPS); - partition_dups_1 (arr, vec_size, &first_partial_cu, + partition_dups_1 (arr, nr_partitions, partitions, &first_partial_cu, &last_partial_cu, true); for (i = 0; i < vec_size; i++) arr[i]->die_ref_seen = 0; @@ -9374,6 +9531,9 @@ { if (unlikely (fi_multifile) && ipu2->idx < npus + ncus) continue; + if (odr_active_p && odr_mode != ODR_BASIC + && ipu2->idx < npus + ncus) + continue; /* If IPU and IPU2 have the same set of src nodes, then (if beneficial, with edge_cost != 0 always), merge IPU2 node into IPU, by removing all incoming edges @@ -9867,13 +10027,13 @@ switch (op) { - case DW_MACRO_GNU_define: - case DW_MACRO_GNU_undef: + case DW_MACRO_define: + case DW_MACRO_undef: skip_leb128 (p1); p1 = (unsigned char *) strchr ((char *) p1, '\0') + 1; break; - case DW_MACRO_GNU_define_indirect: - case DW_MACRO_GNU_undef_indirect: + case DW_MACRO_define_strp: + case DW_MACRO_undef_strp: skip_leb128 (p1); if (memcmp (s1, p2, p1 - s1) != 0) return 0; @@ -9986,21 +10146,21 @@ switch (op) { - case DW_MACRO_GNU_define: - case DW_MACRO_GNU_undef: + case DW_MACRO_define: + case DW_MACRO_undef: skip_leb128 (ptr); ptr = (unsigned char *) strchr ((char *) ptr, '\0') + 1; break; - case DW_MACRO_GNU_start_file: + case DW_MACRO_start_file: skip_leb128 (ptr); skip_leb128 (ptr); can_share = false; break; - case DW_MACRO_GNU_end_file: + case DW_MACRO_end_file: can_share = false; break; - case DW_MACRO_GNU_define_indirect: - case DW_MACRO_GNU_undef_indirect: + case DW_MACRO_define_strp: + case DW_MACRO_undef_strp: skip_leb128 (ptr); strp = read_32 (ptr); note_strp_offset (strp); @@ -10016,7 +10176,7 @@ s = ptr; } break; - case DW_MACRO_GNU_transparent_include: + case DW_MACRO_import: ptr += 4; can_share = false; break; @@ -10102,25 +10262,25 @@ switch (op) { - case DW_MACRO_GNU_define: - case DW_MACRO_GNU_undef: + case DW_MACRO_define: + case DW_MACRO_undef: skip_leb128 (ptr); ptr = (unsigned char *) strchr ((char *) ptr, '\0') + 1; break; - case DW_MACRO_GNU_start_file: + case DW_MACRO_start_file: skip_leb128 (ptr); skip_leb128 (ptr); can_share = false; break; - case DW_MACRO_GNU_end_file: + case DW_MACRO_end_file: can_share = false; break; - case DW_MACRO_GNU_define_indirect: - case DW_MACRO_GNU_undef_indirect: + case DW_MACRO_define_strp: + case DW_MACRO_undef_strp: skip_leb128 (ptr); ptr += 4; break; - case DW_MACRO_GNU_transparent_include: + case DW_MACRO_import: ptr += 4; can_share = false; break; @@ -10140,13 +10300,13 @@ switch (op) { - case DW_MACRO_GNU_define: - case DW_MACRO_GNU_undef: + case DW_MACRO_define: + case DW_MACRO_undef: skip_leb128 (ptr); ptr = (unsigned char *) strchr ((char *) ptr, '\0') + 1; break; - case DW_MACRO_GNU_define_indirect: - case DW_MACRO_GNU_undef_indirect: + case DW_MACRO_define_strp: + case DW_MACRO_undef_strp: skip_leb128 (ptr); memcpy (dst, start, ptr - start); dst += ptr - start; @@ -10190,13 +10350,13 @@ switch (op) { - case DW_MACRO_GNU_define: - case DW_MACRO_GNU_undef: + case DW_MACRO_define: + case DW_MACRO_undef: skip_leb128 (p); p = (unsigned char *) strchr ((char *) p, '\0') + 1; break; - case DW_MACRO_GNU_define_indirect: - case DW_MACRO_GNU_undef_indirect: + case DW_MACRO_define_strp: + case DW_MACRO_undef_strp: skip_leb128 (p); memcpy (*pp, s, p - s); *pp += p - s; @@ -10257,13 +10417,13 @@ switch (op) { - case DW_MACRO_GNU_define: - case DW_MACRO_GNU_undef: + case DW_MACRO_define: + case DW_MACRO_undef: skip_leb128 (ptr); ptr = (unsigned char *) strchr ((char *) ptr, '\0') + 1; break; - case DW_MACRO_GNU_define_indirect: - case DW_MACRO_GNU_undef_indirect: + case DW_MACRO_define_strp: + case DW_MACRO_undef_strp: skip_leb128 (ptr); hash = iterative_hash (s, ptr - s, hash); p = debug_sections[DEBUG_STR].data + read_32 (ptr); @@ -10373,38 +10533,43 @@ switch (op) { - case DW_MACRO_GNU_define: - case DW_MACRO_GNU_undef: + case DW_MACRO_define: + case DW_MACRO_undef: skip_leb128 (ptr); ptr = (unsigned char *) strchr ((char *) ptr, '\0') + 1; break; - case DW_MACRO_GNU_start_file: + case DW_MACRO_start_file: skip_leb128 (ptr); skip_leb128 (ptr); break; - case DW_MACRO_GNU_end_file: + case DW_MACRO_end_file: break; - case DW_MACRO_GNU_define_indirect: - case DW_MACRO_GNU_undef_indirect: + case DW_MACRO_define_strp: + case DW_MACRO_undef_strp: memcpy (dst, s, ptr - 1 - s); dst += ptr - 1 - s; s = ptr - 1; skip_leb128 (ptr); strp = read_32 (ptr); - if (note_strp_offset2 (strp) == DW_FORM_GNU_strp_alt) + switch (note_strp_offset2 (strp)) { - *dst = op == DW_MACRO_GNU_define_indirect - ? DW_MACRO_GNU_define_indirect_alt - : DW_MACRO_GNU_undef_indirect_alt; + case DW_FORM_GNU_strp_alt: + case DW_FORM_strp_sup: + *dst = op == DW_MACRO_define_strp + ? DW_MACRO_define_sup + : DW_MACRO_undef_sup; dst++; s++; + break; + default: + break; } memcpy (dst, s, ptr - 4 - s); dst += ptr - 4 - s; write_32 (dst, lookup_strp_offset (strp)); s = ptr; break; - case DW_MACRO_GNU_transparent_include: + case DW_MACRO_import: memcpy (dst, s, ptr - 1 - s); dst += ptr - 1 - s; me.ptr = debug_sections[DEBUG_MACRO].data + read_32 (ptr); @@ -10413,9 +10578,9 @@ me.ptr - debug_sections[DEBUG_MACRO].data); if (m->len) - *dst = DW_MACRO_GNU_transparent_include_alt; + *dst = DW_MACRO_import_sup; else - *dst = DW_MACRO_GNU_transparent_include; + *dst = DW_MACRO_import; dst++; write_32 (dst, m->hash); s = ptr; @@ -10580,6 +10745,7 @@ case DW_FORM_data4: value = read_32 (ptr); break; case DW_FORM_data8: value = read_64 (ptr); break; case DW_FORM_udata: value = read_uleb128 (ptr); break; + case DW_FORM_sdata: value = read_sleb128 (ptr); break; case DW_FORM_implicit_const: value = reft->values[i]; break; @@ -10672,7 +10838,8 @@ && die_cu (refdt->die_dup)->cu_kind == CU_ALT) { t->attr[j].attr = reft->attr[i].attr; - t->attr[j++].form = DW_FORM_GNU_ref_alt; + t->attr[j++].form + = dwarf_5 ? DW_FORM_ref_sup4 : DW_FORM_GNU_ref_alt; die->die_size += 4; continue; } @@ -10875,14 +11042,16 @@ if (cu == die_cu (refd)) form = DW_FORM_ref4; else if (die_cu (refd)->cu_kind == CU_ALT) - form = DW_FORM_GNU_ref_alt; + form = (dwarf_5 + ? DW_FORM_ref_sup4 : DW_FORM_GNU_ref_alt); else form = DW_FORM_ref_addr; } } if (form == DW_FORM_ref_addr) die->die_size += cu->cu_version == 2 ? ptr_size : 4; - else if (form == DW_FORM_GNU_ref_alt) + else if (form == DW_FORM_GNU_ref_alt + || form == DW_FORM_ref_sup4) die->die_size += 4; else { @@ -11008,7 +11177,7 @@ t->nattr = 1; if (die_cu (die->die_nextdup)->cu_kind == CU_ALT) { - t->attr[0].form = DW_FORM_GNU_ref_alt; + t->attr[0].form = dwarf_5 ? DW_FORM_ref_sup4 : DW_FORM_GNU_ref_alt; die->die_size = 4; } else @@ -12070,7 +12239,8 @@ assert (p); assert (form == attr->form || (form == DW_FORM_strp - && attr->form == DW_FORM_GNU_strp_alt)); + && (attr->form == DW_FORM_GNU_strp_alt + || attr->form == DW_FORM_strp_sup))); if (form == DW_FORM_strp) { if (unlikely (wr_multifile || op_multifile || fi_multifile)) @@ -12196,6 +12366,9 @@ case DW_FORM_udata: value = read_uleb128 (inptr); break; + case DW_FORM_sdata: + value = read_sleb128 (inptr); + break; case DW_FORM_implicit_const: /* DW_FORM_implicit_const should have been updated already when computing abbrevs. */ @@ -12211,6 +12384,7 @@ case DW_FORM_data4: write_32 (ptr, value); break; case DW_FORM_data8: write_64 (ptr, value); break; case DW_FORM_udata: write_uleb128 (ptr, value); break; + case DW_FORM_sdata: write_sleb128 (ptr, value); break; default: abort (); } j++; @@ -12240,7 +12414,8 @@ case DW_FORM_ref_addr: { dw_die_ref refd, refdt; - if (t->attr[j].form != DW_FORM_GNU_ref_alt) + if (t->attr[j].form != DW_FORM_GNU_ref_alt + && t->attr[j].form != DW_FORM_ref_sup4) { memcpy (ptr, orig_ptr, inptr - orig_ptr); ptr += inptr - orig_ptr; @@ -12259,7 +12434,8 @@ if (refdt->die_dup && !refdt->die_op_type_referenced) { refd = die_find_dup (refdt, refdt->die_dup, refd); - if (t->attr[j].form == DW_FORM_GNU_ref_alt) + if (t->attr[j].form == DW_FORM_GNU_ref_alt + || t->attr[j].form == DW_FORM_ref_sup4) { assert (die_cu (refd)->cu_kind == CU_ALT); write_32 (ptr, refd->die_offset); @@ -12268,7 +12444,8 @@ } } assert (refd->u.p2.die_new_offset - && t->attr[j].form != DW_FORM_GNU_ref_alt); + && t->attr[j].form != DW_FORM_GNU_ref_alt + && t->attr[j].form != DW_FORM_ref_sup4); value = die_cu (refd)->cu_new_offset + refd->u.p2.die_new_offset; write_size (ptr, cu->cu_version == 2 ? ptr_size : 4, @@ -12440,7 +12617,8 @@ } else if (refdt->die_dup) refd = die_find_dup (refdt, refdt->die_dup, refd); - if (t->attr[j].form == DW_FORM_GNU_ref_alt) + if (t->attr[j].form == DW_FORM_GNU_ref_alt + || t->attr[j].form == DW_FORM_ref_sup4) { value = refd->die_offset; assert (die_cu (refd)->cu_kind == CU_ALT); @@ -12449,6 +12627,8 @@ { dw_cu_ref refdcu = die_cu (refd); value = refd->u.p2.die_new_offset; + assert (IMPLIES (cu->cu_kind == CU_PU, + die_cu (refd)->cu_kind == CU_PU)); assert (value && refdcu->cu_kind != CU_ALT); if (t->attr[j].form == DW_FORM_ref_addr) { @@ -12471,7 +12651,13 @@ value); ptr += cu->cu_version == 2 ? ptr_size : 4; break; - case DW_FORM_GNU_ref_alt: write_32 (ptr, value); break; + case DW_FORM_GNU_ref_alt: + case DW_FORM_ref_sup4: + write_32 (ptr, value); + break; + case DW_FORM_ref_sup8: + write_64 (ptr, value); + break; default: abort (); } @@ -12545,7 +12731,8 @@ unsigned char *p = get_AT (origin, DW_AT_name, &form); assert (p && (form == t->attr[0].form || (form == DW_FORM_strp - && t->attr[0].form == DW_FORM_GNU_strp_alt))); + && (t->attr[0].form == DW_FORM_GNU_strp_alt + || t->attr[0].form == DW_FORM_strp_sup)))); if (form == DW_FORM_strp) { if (unlikely (wr_multifile || op_multifile || fi_multifile)) @@ -12595,7 +12782,8 @@ } case DW_TAG_imported_unit: refcu = die_cu (origin); - if (t->attr[0].form == DW_FORM_GNU_ref_alt) + if (t->attr[0].form == DW_FORM_GNU_ref_alt + || t->attr[0].form == DW_FORM_ref_sup4) { assert (refcu->cu_kind == CU_ALT); write_32 (ptr, origin->die_offset); @@ -13505,6 +13693,13 @@ return 3; } + if (debug_sections[DEBUG_SUP].data != NULL && !(dwarf_5 && rd_multifile)) + { + error (0, 0, "%s: .debug_sup section already present", + dso->filename); + return 1; + } + if (debug_sections[GNU_DEBUGALTLINK].data != NULL) { error (0, 0, "%s: .gnu_debugaltlink section already present", @@ -14955,7 +15150,7 @@ debug_sections[DEBUG_MACRO].new_size) != (ssize_t) debug_sections[DEBUG_MACRO].new_size) || (strp_htab != NULL && write_multifile_strp ()) - || (line_htab != NULL && write_multifile_line ())) + || write_multifile_line ()) { error (0, 0, "Error writing multi-file temporary files"); ret = 1; @@ -15060,6 +15255,10 @@ /* Helper structure for hardlink discovery. */ struct file_result { + /* -2: Already processed under different name. + -1: Ignore. + 0: Processed, changed. + 1: Processed, unchanged. */ int res; dev_t dev; ino_t ino; @@ -15120,7 +15319,7 @@ file); close (fd); res->res = -2; - return 1; + return 0; } /* If it changed, try to hardlink it again. */ if (resa[n].res == 0) @@ -15239,8 +15438,8 @@ } else if (write_aranges (dso)) { - cleanup (); failure: + cleanup (); ret = 1; } else @@ -15249,6 +15448,8 @@ { size_t len; const char *name = multifile_name; + enum debug_section_kind sec_kind; + unsigned char *ptr; if (multifile_name == NULL) { if (!multifile_relative) @@ -15308,14 +15509,24 @@ } } len = strlen (name) + 1; - debug_sections[GNU_DEBUGALTLINK].new_size = len + 0x14; - debug_sections[GNU_DEBUGALTLINK].new_data - = malloc (debug_sections[GNU_DEBUGALTLINK].new_size); - if (debug_sections[GNU_DEBUGALTLINK].new_data == NULL) + sec_kind = dwarf_5 ? DEBUG_SUP : GNU_DEBUGALTLINK; + debug_sections[sec_kind].new_size + = len + 0x14 + (dwarf_5 ? 4 : 0); + debug_sections[sec_kind].new_data + = malloc (debug_sections[sec_kind].new_size); + if (debug_sections[sec_kind].new_data == NULL) dwz_oom (); - memcpy (debug_sections[GNU_DEBUGALTLINK].new_data, name, len); - memcpy (debug_sections[GNU_DEBUGALTLINK].new_data + len, - multifile_sha1, 0x14); + ptr = debug_sections[sec_kind].new_data; + if (dwarf_5) + { + write_16 (ptr, 5); + write_8 (ptr, 0); + } + memcpy (ptr, name, len); + ptr += len; + if (dwarf_5) + write_uleb128 (ptr, 0x14); + memcpy (ptr, multifile_sha1, 0x14); if (name != multifile_name && name != multifile) free ((void *) name); write_macro (); @@ -15365,6 +15576,9 @@ if (write_dso (dso, outfile, &st, save_to_temp)) ret = 1; + else + res->res = 0; + if (unlikely (progress_p)) report_progress (); } @@ -15388,8 +15602,6 @@ close (fd); free (dso); - if (ret == 0 && !low_mem) - res->res = 0; if (ret == 3) { ret = (outfile != NULL) ? 1 : 0; @@ -15419,11 +15631,17 @@ Elf_Scn *scn; Elf_Data *data; char *e_ident; - const char shstrtab[] + const char shstrtab_gnu[] = "\0.shstrtab\0.note.gnu.build-id\0.gdb_index\0" ".debug_info\0.debug_abbrev\0.debug_line\0.debug_str\0.debug_macro"; + const char shstrtab_dwarf5[] + = "\0.shstrtab\0.gdb_index\0" + ".debug_info\0.debug_abbrev\0.debug_line\0.debug_str\0.debug_macro\0" + ".debug_sup"; + const char *shstrtab; + size_t shstrtab_len; const char *p; - unsigned char note[0x24], *np; + unsigned char note[0x24], *np, *supp; struct sha1_ctx ctx; if (multi_ehdr.e_ident[0] == '\0' @@ -15447,6 +15665,16 @@ fprintf (stderr, "optimize_multifile\n"); } + if (dwarf_5) + { + shstrtab = shstrtab_dwarf5; + shstrtab_len = sizeof shstrtab_dwarf5; + } + else + { + shstrtab = shstrtab_gnu; + shstrtab_len = sizeof shstrtab_gnu; + } debug_sections[DEBUG_INFO].size = multi_info_off; debug_sections[DEBUG_INFO].data = (multi_info_off @@ -15611,6 +15839,21 @@ write_32 (np, 0x14); write_32 (np, NT_GNU_BUILD_ID); + supp = NULL; + if (dwarf_5) + { + debug_sections[DEBUG_SUP].new_size = 0x14 + 5; + debug_sections[DEBUG_SUP].new_data + = malloc (debug_sections[DEBUG_SUP].new_size); + if (debug_sections[DEBUG_SUP].new_data == NULL) + dwz_oom (); + supp = debug_sections[DEBUG_SUP].new_data; + write_16 (supp, 5); + write_8 (supp, 1); + write_8 (supp, 0); + write_uleb128 (supp, 0x14); + } + cleanup (); fd = open (multifile, O_RDWR | O_CREAT, 0600); vfd = fd; @@ -15632,8 +15875,13 @@ multi_ehdr.e_entry = 0; multi_ehdr.e_phoff = 0; multi_ehdr.e_phnum = 0; - multi_ehdr.e_shoff = multi_ehdr.e_ehsize + 0x24; - multi_ehdr.e_shnum = 3; + multi_ehdr.e_shoff = multi_ehdr.e_ehsize; + multi_ehdr.e_shnum = 2; + if (!dwarf_5) + { + multi_ehdr.e_shoff += 0x24; + multi_ehdr.e_shnum++; + } for (i = 0; debug_sections[i].name; i++) if (debug_sections[i].new_size) { @@ -15684,22 +15932,28 @@ memcpy (np, "GNU", sizeof ("GNU")); memcpy (np + 4, multifile_sha1, 0x14); + if (dwarf_5) + memcpy (supp, multifile_sha1, 0x14); + memset (&shdr, '\0', sizeof (shdr)); - shdr.sh_type = SHT_NOTE; shdr.sh_offset = multi_ehdr.e_ehsize; - shdr.sh_addralign = 4; - shdr.sh_size = 0x24; - scn = elf_newscn (elf); - elf_flagscn (scn, ELF_C_SET, ELF_F_DIRTY); - shdr.sh_name = (strchr (shstrtab + 1, '\0') + 1) - shstrtab; - gelf_update_shdr (scn, &shdr); - data = elf_newdata (scn); - data->d_buf = (char *) note; - data->d_type = ELF_T_BYTE; - data->d_version = EV_CURRENT; - data->d_size = shdr.sh_size; - data->d_off = 0; - data->d_align = 1; + if (!dwarf_5) + { + shdr.sh_type = SHT_NOTE; + shdr.sh_addralign = 4; + shdr.sh_size = 0x24; + scn = elf_newscn (elf); + elf_flagscn (scn, ELF_C_SET, ELF_F_DIRTY); + shdr.sh_name = (strchr (shstrtab + 1, '\0') + 1) - shstrtab; + gelf_update_shdr (scn, &shdr); + data = elf_newdata (scn); + data->d_buf = (char *) note; + data->d_type = ELF_T_BYTE; + data->d_version = EV_CURRENT; + data->d_size = shdr.sh_size; + data->d_off = 0; + data->d_align = 1; + } shdr.sh_type = SHT_PROGBITS; shdr.sh_offset += shdr.sh_size; @@ -15710,7 +15964,7 @@ continue; scn = elf_newscn (elf); elf_flagscn (scn, ELF_C_SET, ELF_F_DIRTY); - for (p = shstrtab + 1; p < shstrtab + sizeof (shstrtab); + for (p = shstrtab + 1; p < shstrtab + shstrtab_len; p = strchr (p, '\0') + 1) if (strcmp (p, debug_sections[i].name) == 0) { @@ -15743,7 +15997,7 @@ shdr.sh_name = 1; shdr.sh_offset = multi_ehdr.e_shoff + multi_ehdr.e_shnum * multi_ehdr.e_shentsize; - shdr.sh_size = sizeof (shstrtab); + shdr.sh_size = shstrtab_len; shdr.sh_type = SHT_STRTAB; shdr.sh_flags = 0; shdr.sh_entsize = 0; @@ -15770,6 +16024,11 @@ fchmod (fd, 0644); + if (dwarf_5) + { + free (debug_sections[DEBUG_SUP].new_data); + debug_sections[DEBUG_SUP].new_data = NULL; + } munmap (debug_sections[DEBUG_INFO].data, debug_sections[DEBUG_INFO].size); munmap (debug_sections[DEBUG_ABBREV].data, debug_sections[DEBUG_ABBREV].size); @@ -16022,6 +16281,7 @@ no_argument, &import_opt_p, 1 }, { "no-import-optimize", no_argument, &import_opt_p, 0 }, + { "dwarf-5", no_argument, 0, '5' }, #if DEVEL { "devel-trace", no_argument, &tracing, 1 }, { "devel-progress", no_argument, &progress_p, 1 }, @@ -16110,10 +16370,13 @@ "Enable multifile optimization, placing common DIEs in multifile" " COMMONFILE." }, { "M", "multifile-name", "NAME", NULL, - "Set .gnu_debugaltlink in files to NAME." }, + "Set .gnu_debugaltlink or .debug_sup in files to NAME." }, { "r", "relative", NULL, NULL, "Set .gnu_debugaltlink in files to relative path from file directory" - " to multifile." } + " to multifile." }, + { "5", "dwarf-5", NULL, NULL, + "Emit DWARF 5 standardized supplementary object files instead of" + " GNU extension .debug_altlink." } }; /* Describe misc command line options. */ @@ -16125,20 +16388,20 @@ "Display this information." } }; -/* Print LEN spaces to stderr. */ +/* Print LEN spaces to STREAM. */ static void -do_indent (unsigned int len) +do_indent (FILE *stream, unsigned int len) { unsigned int i; for (i = 0; i < len; i++) - fprintf (stderr, " "); + fprintf (stream, " "); } -/* Print MSG to stderr, indenting to INDENT and wrapping at LIMIT. Assume - starting position is at INDENT. */ +/* Print MSG to STREAM, indenting to INDENT and wrapping at LIMIT. + Assume starting position is at INDENT. */ static void -wrap (unsigned int indent, unsigned int limit, const char *msg) +wrap (FILE *stream, unsigned int indent, unsigned int limit, const char *msg) { unsigned int len = indent; const char *s = msg; @@ -16155,13 +16418,13 @@ if (len + 1 /* space */ + word_len > limit) { - fprintf (stderr, "\n"); - do_indent (indent); + fprintf (stream, "\n"); + do_indent (stream ,indent); len = indent; } else if (len > indent) { - fprintf (stderr, " "); + fprintf (stream, " "); len += 1; } @@ -16169,10 +16432,10 @@ { const char *i; for (i = s; i < e; ++i) - fprintf (stderr, "%c", *i); + fprintf (stream, "%c", *i); } else - fprintf (stderr, "%s", s); + fprintf (stream, "%s", s); len += word_len; if (e == NULL) @@ -16182,10 +16445,10 @@ } } -/* Print OPTIONS_HELP of length H to stderr, indenting to help message to +/* Print OPTIONS_HELP of length H to STREAM, indenting to help message to INDENT an wrapping at LIMIT. */ static void -print_options_help (struct option_help *options_help, unsigned int n, +print_options_help (FILE *stream, struct option_help *options_help, unsigned int n, unsigned int indent, unsigned int limit) { unsigned len; @@ -16196,29 +16459,29 @@ { len = 0; - fprintf (stderr, " "); + fprintf (stream, " "); len += 2; s = options_help[i].short_name; if (s) { - fprintf (stderr, "-%s", s); + fprintf (stream, "-%s", s); len += 2; } s = options_help[i].long_name; if (len == 4) { - fprintf (stderr, ", "); + fprintf (stream, ", "); len += 2; } - fprintf (stderr, "--%s", s); + fprintf (stream, "--%s", s); len += 2 + strlen (s); s = options_help[i].argument; if (s) { - fprintf (stderr, " %s", s); + fprintf (stream, " %s", s); len += 1 + strlen (s); } @@ -16227,104 +16490,102 @@ { if (len > indent) { - fprintf (stderr, "\n"); - do_indent (indent); + fprintf (stream, "\n"); + do_indent (stream, indent); } else - do_indent (indent - len); + do_indent (stream, indent - len); len = indent; - wrap (indent, limit, s); + wrap (stream, indent, limit, s); } - fprintf (stderr, "\n"); + fprintf (stream, "\n"); s = options_help[i].default_value; if (s) { - do_indent (indent); - fprintf (stderr, "Default value: %s.\n", s); + do_indent (stream, indent); + fprintf (stream, "Default value: %s.\n", s); } } } /* Print usage and exit. */ static void -usage (void) +usage (const char *progname, int failing) { unsigned int n; unsigned int indent, limit; - const char *msg; + FILE *stream = failing ? stderr : stdout; - msg - = ("Usage:\n" - " dwz [common options] [-h] [-m COMMONFILE] [-M NAME | -r] [FILES]\n" - " dwz [common options] -o OUTFILE FILE\n" - " dwz [ -v | -? ]"); - error (0, 0, "%s", msg); + fprintf (stream, + ("Usage:\n" + " %s [common options] [-h] [-m COMMONFILE] [-M NAME | -r] [FILES]\n" + " %s [common options] -o OUTFILE FILE\n" + " %s [ -v | -? ]\n"), + progname, progname, progname); indent = 30; limit = 80; - fprintf (stderr, "Common options:\n"); + fprintf (stream, "Common options:\n"); n = (sizeof (dwz_common_options_help) / sizeof (dwz_common_options_help[0])); - print_options_help (dwz_common_options_help, n, indent, limit); + print_options_help (stream, dwz_common_options_help, n, indent, limit); - fprintf (stderr, "Single-file options:\n"); + fprintf (stream, "Single-file options:\n"); n = (sizeof (dwz_single_file_options_help) / sizeof (dwz_single_file_options_help[0])); - print_options_help (dwz_single_file_options_help, n, indent, limit); + print_options_help (stream, dwz_single_file_options_help, n, indent, limit); - fprintf (stderr, "Multi-file options:\n"); + fprintf (stream, "Multi-file options:\n"); n = (sizeof (dwz_multi_file_options_help) / sizeof (dwz_multi_file_options_help[0])); - print_options_help (dwz_multi_file_options_help, n, indent, limit); + print_options_help (stream, dwz_multi_file_options_help, n, indent, limit); - fprintf (stderr, "Miscellaneous options:\n"); + fprintf (stream, "Miscellaneous options:\n"); n = (sizeof (dwz_misc_options_help) / sizeof (dwz_misc_options_help[0])); - print_options_help (dwz_misc_options_help, n, indent, limit); + print_options_help (stream, dwz_misc_options_help, n, indent, limit); #if DEVEL - fprintf (stderr, "Development options:\n"); - msg - = (" --devel-trace\n" - " --devel-progress\n" - " --devel-stats\n" - " --devel-ignore-size\n" - " --devel-ignore-locus\n" - " --devel-force\n" - " --devel-save-temps\n" - " --devel-dump-checksum\n" - " --devel-dump-dies\n" - " --devel-dump-dups\n" - " --devel-dump-pus\n" - " --devel-unoptimized-multifile\n" - " --devel-verify-dups\n" - " --devel-verify-edges\n" - " --devel-dump-edges\n" - " --devel-partition-dups-opt\n" - " --devel-die-count-method\n" - " --devel-deduplication-mode={none,intra-cu,inter-cu}\n" - " --devel-uni-lang / --devel-no-uni-lang\n" - " --devel-gen-cu / --devel-no-gen-cu\n"); - fprintf (stderr, "%s", msg); + fprintf (stream, "Development options:\n"); + fprintf (stream, "%s", + (" --devel-trace\n" + " --devel-progress\n" + " --devel-stats\n" + " --devel-ignore-size\n" + " --devel-ignore-locus\n" + " --devel-force\n" + " --devel-save-temps\n" + " --devel-dump-checksum\n" + " --devel-dump-dies\n" + " --devel-dump-dups\n" + " --devel-dump-pus\n" + " --devel-unoptimized-multifile\n" + " --devel-verify-dups\n" + " --devel-verify-edges\n" + " --devel-dump-edges\n" + " --devel-partition-dups-opt\n" + " --devel-die-count-method\n" + " --devel-deduplication-mode={none,intra-cu,inter-cu}\n" + " --devel-uni-lang / --devel-no-uni-lang\n" + " --devel-gen-cu / --devel-no-gen-cu\n")); #endif - exit (1); + exit (failing); } /* Print version and exit. */ static void version (void) { - fprintf (stderr, - "dwz version " DWZ_VERSION "\n" - "Copyright (C) " RH_YEARS " Red Hat, Inc.\n" - "Copyright (C) " FSF_YEARS " Free Software Foundation, Inc.\n" - "Copyright (C) " SUSE_YEARS " SUSE LLC.\n" - "This program is free software; you may redistribute it under the terms of\n" - "the GNU General Public License version 3 or (at your option) any later version.\n" - "This program has absolutely no warranty.\n"); + printf ("dwz version " DWZ_VERSION "\n" + "Copyright (C) " RH_YEARS " Red Hat, Inc.\n" + "Copyright (C) " FSF_YEARS " Free Software Foundation, Inc.\n" + "Copyright (C) " SUSE_YEARS " SUSE LLC.\n" + "This program is free software; you may redistribute it under the terms of\n" + "the GNU General Public License version 3 or (at your option) any later version.\n" + "This program has absolutely no warranty.\n"); exit (0); } @@ -16345,15 +16606,15 @@ while (1) { - int option_index; - int c = getopt_long (argc, argv, "m:o:qhl:L:M:r?v", dwz_options, &option_index); + int option_index = -1; + int c = getopt_long (argc, argv, "m:o:qhl:L:M:r?v5", dwz_options, &option_index); if (c == -1) break; switch (c) { default: case '?': - usage (); + usage (argv[0], option_index == -1); break; case 0: @@ -16461,6 +16722,10 @@ max_die_limit = l; break; + case '5': + dwarf_5 = true; + break; + case 'v': version (); break; @@ -16544,10 +16809,10 @@ thisret = dwz (file, NULL, &resa[i - optind], hardlinks ? resa : NULL, &argv[optind]); } - else if (resa[i - optind].res == 0) - successcount++; else if (thisret == 1) ret = 1; + else if (resa[i - optind].res >= 0) + successcount++; if (hardlink && resa[i - optind].res >= 0 && resa[i - optind].nlink > 1) @@ -16586,8 +16851,7 @@ multifile_mode = MULTIFILE_MODE_FI; /* Don't process again files that couldn't be processed successfully. */ - if (resa[i - optind].res == -1 - || resa[i - optind].res == 1) + if (resa[i - optind].res == -1) continue; for (cu = alt_first_cu; cu; cu = cu->cu_next) alt_clear_dups (cu->cu_die); diff -Nru dwz-0.13+20210219/.gitignore dwz-0.14/.gitignore --- dwz-0.13+20210219/.gitignore 1970-01-01 00:00:00.000000000 +0000 +++ dwz-0.14/.gitignore 2021-03-08 07:56:18.976431406 +0000 @@ -0,0 +1,7 @@ +*.o +*.dwo +*~ +dwz +dwz.sum +dwz.log +testsuite/dwz.tests/execs diff -Nru dwz-0.13+20210219/Makefile dwz-0.14/Makefile --- dwz-0.13+20210219/Makefile 2021-02-18 13:36:58.000000000 +0000 +++ dwz-0.14/Makefile 2021-03-08 07:56:18.976431406 +0000 @@ -26,7 +26,8 @@ PWD:=$(shell pwd -P) TEST_SRC = $(srcdir)/testsuite/dwz.tests -TEST_EXECS_DWARF_ASM = no-multifile-prop invalid-dw-at-stmt-list-encoding +TEST_EXECS_DWARF_ASM = no-multifile-prop invalid-dw-at-stmt-list-encoding \ + unavailable-dwarf-piece TEST_EXECS_x86_64 = py-section-script dw2-skip-prologue \ implptr-64bit-d2o4a8r8t0 varval TEST_EXECS = hello dwz-for-test min two-typedef start hello-gold-gdb-index \ @@ -95,9 +96,13 @@ export DEJAGNU=$(DEJAGNU); \ runtest --tool=dwz -srcdir $(srcdir)/testsuite/ lib/$*.exp -$(TEST_EXECS_DWARF_ASM): %: %-dw.S +$(filter-out no-multifile-prop, $(TEST_EXECS_DWARF_ASM)): %: %-dw.S $(CC) $(TEST_SRC)/main.c $< -o $@ +# Fails to compile on riscv64: Error: non-constant .uleb128 is not supported. +no-multifile-prop: %: %-dw.S + $(CC) $(TEST_SRC)/main.c $< -o $@ || true + odr-struct: $(CXX) $(TEST_SRC)/odr.cc $(TEST_SRC)/odr-2.cc -I$(TEST_SRC) -o $@ -g \ -DKIND=struct diff -Nru dwz-0.13+20210219/testsuite/dwz.tests/dwz-tests.exp dwz-0.14/testsuite/dwz.tests/dwz-tests.exp --- dwz-0.13+20210219/testsuite/dwz.tests/dwz-tests.exp 2021-02-18 13:36:58.000000000 +0000 +++ dwz-0.14/testsuite/dwz.tests/dwz-tests.exp 2021-03-08 07:56:18.980431379 +0000 @@ -86,6 +86,12 @@ continue } } + if { $basename == "pr25109.sh" } { + lappend required_execs no-multifile-prop + } + if { $basename == "pr27463.sh" } { + lappend required_execs unavailable-dwarf-piece + } set unsupported 0 foreach required_exec $required_execs { diff -Nru dwz-0.13+20210219/testsuite/dwz.tests/main.c dwz-0.14/testsuite/dwz.tests/main.c --- dwz-0.13+20210219/testsuite/dwz.tests/main.c 2019-07-01 19:57:02.000000000 +0000 +++ dwz-0.14/testsuite/dwz.tests/main.c 2021-03-08 07:56:18.980431379 +0000 @@ -3,3 +3,23 @@ { return 0; } + +int +foo (int i) +{ + int j; + asm (".global foo_start_lbl\nfoo_start_lbl:"); + j = i *2; + asm (".global foo_end_lbl\nfoo_end_lbl:"); + return j; +} + +int +bar (int i) +{ + int j; + asm (".global bar_start_lbl\nbar_start_lbl:"); + j = i *2; + asm (".global bar_end_lbl\nbar_end_lbl:"); + return j; +} diff -Nru dwz-0.13+20210219/testsuite/dwz.tests/odr-loc.sh dwz-0.14/testsuite/dwz.tests/odr-loc.sh --- dwz-0.13+20210219/testsuite/dwz.tests/odr-loc.sh 2020-02-18 16:37:04.000000000 +0000 +++ dwz-0.14/testsuite/dwz.tests/odr-loc.sh 2021-03-08 07:56:18.980431379 +0000 @@ -9,7 +9,7 @@ [ $cnt -eq 2 ] done -$execs/dwz-for-test --odr 1 +$execs/dwz-for-test --odr 1 --devel-ignore-size verify-dwarf.sh 1 diff -Nru dwz-0.13+20210219/testsuite/dwz.tests/odr-struct-multifile.sh dwz-0.14/testsuite/dwz.tests/odr-struct-multifile.sh --- dwz-0.13+20210219/testsuite/dwz.tests/odr-struct-multifile.sh 1970-01-01 00:00:00.000000000 +0000 +++ dwz-0.14/testsuite/dwz.tests/odr-struct-multifile.sh 2021-03-08 07:56:18.980431379 +0000 @@ -0,0 +1,53 @@ +if ! $execs/dwz-for-test --odr -v 2>/dev/null; then + exit 77 +fi + +cp $execs/odr-struct 1 +cp 1 2 + +for name in aaa bbb ccc; do + cnt=$(readelf -wi 1 | grep -c "DW_AT_name.*:.*$name" || true) + [ $cnt -eq 2 ] +done + +for name in member_one member_two member_three member_four; do + cnt=$(readelf -wi 1 | grep -c "DW_AT_name.*:.*$name" || true) + case $name in + member_one|member_two) + [ $cnt -eq 2 ] + ;; + member_three|member_four) + [ $cnt -eq 1 ] + ;; + esac +done + +decl_cnt=$(readelf -wi 1 | grep -c "DW_AT_declaration" || true) + +$execs/dwz-for-test --odr 1 2 -m 3 + +verify-dwarf.sh 1 +verify-dwarf.sh 3 + +for name in aaa bbb ccc; do + cnt=$(readelf -wi 3 | grep -c "DW_AT_name.*:.*$name" || true) + [ $cnt -eq 1 ] +done + +for name in member_one member_two member_three member_four; do + cnt=$(readelf -wi 3 | grep -c "DW_AT_name.*:.*$name" || true) + [ $cnt -eq 1 ] +done + + +for name in aaa bbb ccc; do + cnt=$(readelf -wi 1 | grep -c "DW_AT_name.*:.*$name" || true) + [ $cnt -eq 0 ] +done + +for name in member_one member_two member_three member_four; do + cnt=$(readelf -wi 1 | grep -c "DW_AT_name.*:.*$name" || true) + [ $cnt -eq 0 ] +done + +rm -f 1 2 3 diff -Nru dwz-0.13+20210219/testsuite/dwz.tests/pr27463.sh dwz-0.14/testsuite/dwz.tests/pr27463.sh --- dwz-0.13+20210219/testsuite/dwz.tests/pr27463.sh 1970-01-01 00:00:00.000000000 +0000 +++ dwz-0.14/testsuite/dwz.tests/pr27463.sh 2021-03-08 07:56:18.980431379 +0000 @@ -0,0 +1,6 @@ +cp $execs/unavailable-dwarf-piece 1 +cp 1 2 + +dwz -m 3 1 2 + +rm -f 1 2 3 diff -Nru dwz-0.13+20210219/testsuite/dwz.tests/twice-hardlink.sh dwz-0.14/testsuite/dwz.tests/twice-hardlink.sh --- dwz-0.13+20210219/testsuite/dwz.tests/twice-hardlink.sh 2019-07-01 19:57:02.000000000 +0000 +++ dwz-0.14/testsuite/dwz.tests/twice-hardlink.sh 2021-03-08 07:56:18.980431379 +0000 @@ -29,8 +29,3 @@ cmp 1 1.saved rm -f 1 1.saved 2 2.saved dwz.err - -if [ -f 2.#dwz#.* ]; then - echo "PR24275 workaround used" > dwz.info - rm -f 2.#dwz#.* -fi diff -Nru dwz-0.13+20210219/testsuite/dwz.tests/version.sh dwz-0.14/testsuite/dwz.tests/version.sh --- dwz-0.13+20210219/testsuite/dwz.tests/version.sh 2019-07-01 19:57:02.000000000 +0000 +++ dwz-0.14/testsuite/dwz.tests/version.sh 2021-03-08 07:56:18.984431355 +0000 @@ -1,9 +1,9 @@ cp $execs/hello 1 -dwz -v 1 2> dwz.err +dwz -v 1 > dwz.out 2> /dev/null -grep -q "dwz version" dwz.err +grep -q "dwz version" dwz.out cmp 1 $execs/hello -rm -f 1 dwz.err +rm -f 1 dwz.out diff -Nru dwz-0.13+20210219/testsuite/lib/unavailable-dwarf-piece.exp dwz-0.14/testsuite/lib/unavailable-dwarf-piece.exp --- dwz-0.13+20210219/testsuite/lib/unavailable-dwarf-piece.exp 1970-01-01 00:00:00.000000000 +0000 +++ dwz-0.14/testsuite/lib/unavailable-dwarf-piece.exp 2021-03-08 07:56:18.984431355 +0000 @@ -0,0 +1,272 @@ +# Copyright (C) 2013-2021 Free Software Foundation, Inc. + +# 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 . + +load_lib dwarf-lib.exp +load_lib dwarf.exp + +set asm_file unavailable-dwarf-piece-dw.S + +Dwarf::assemble $asm_file { + declare_labels uchar_label struct_s_label foo_label struct_t_label bar_label + + cu {} { + compile_unit {{language @DW_LANG_C}} { + uchar_label: DW_TAG_base_type { + {name "unsigned char"} + {byte_size 1 DW_FORM_sdata} + {encoding @DW_ATE_unsigned_char} + } + + struct_s_label: DW_TAG_structure_type { + {name s} + {byte_size 3 DW_FORM_sdata} + {decl_file 0 DW_FORM_udata} + {decl_line 1 DW_FORM_sdata} + } { + DW_TAG_member { + {name a} + {type :$uchar_label} + {data_member_location { + DW_OP_plus_uconst 0 + } SPECIAL_expr} + } + DW_TAG_member { + {name b} + {type :$uchar_label} + {data_member_location { + DW_OP_plus_uconst 1 + } SPECIAL_expr} + } + DW_TAG_member { + {name c} + {type :$uchar_label} + {data_member_location { + DW_OP_plus_uconst 2 + } SPECIAL_expr} + } + } + + struct_t_label: DW_TAG_structure_type { + {name t} + {byte_size 3 DW_FORM_sdata} + {decl_file 0 DW_FORM_udata} + {decl_line 1 DW_FORM_sdata} + } { + DW_TAG_member { + {name a} + {type :$uchar_label} + {data_member_location { + DW_OP_plus_uconst 0 + } SPECIAL_expr} + } + DW_TAG_member { + {name b} + {type :$uchar_label} + {byte_size 1 DW_FORM_sdata} + {bit_size 1 DW_FORM_sdata} + {bit_offset 7 DW_FORM_sdata} + {data_member_location { + DW_OP_plus_uconst 1 + } SPECIAL_expr} + } + DW_TAG_member { + {name c} + {type :$uchar_label} + {byte_size 1 DW_FORM_sdata} + {bit_size 1 DW_FORM_sdata} + {bit_offset 6 DW_FORM_sdata} + {data_member_location { + DW_OP_plus_uconst 1 + } SPECIAL_expr} + } + DW_TAG_member { + {name d} + {type :$uchar_label} + {byte_size 1 DW_FORM_sdata} + {bit_size 1 DW_FORM_sdata} + {bit_offset 5 DW_FORM_sdata} + {data_member_location { + DW_OP_plus_uconst 1 + } SPECIAL_expr} + } + DW_TAG_member { + {name e} + {type :$uchar_label} + {byte_size 1 DW_FORM_sdata} + {bit_size 1 DW_FORM_sdata} + {bit_offset 4 DW_FORM_sdata} + {data_member_location { + DW_OP_plus_uconst 1 + } SPECIAL_expr} + } + DW_TAG_member { + {name f} + {type :$uchar_label} + {byte_size 1 DW_FORM_sdata} + {bit_size 1 DW_FORM_sdata} + {bit_offset 3 DW_FORM_sdata} + {data_member_location { + DW_OP_plus_uconst 1 + } SPECIAL_expr} + } + DW_TAG_member { + {name g} + {type :$uchar_label} + {byte_size 1 DW_FORM_sdata} + {bit_size 1 DW_FORM_sdata} + {bit_offset 2 DW_FORM_sdata} + {data_member_location { + DW_OP_plus_uconst 1 + } SPECIAL_expr} + } + DW_TAG_member { + {name h} + {type :$uchar_label} + {byte_size 1 DW_FORM_sdata} + {bit_size 1 DW_FORM_sdata} + {bit_offset 1 DW_FORM_sdata} + {data_member_location { + DW_OP_plus_uconst 1 + } SPECIAL_expr} + } + DW_TAG_member { + {name i} + {type :$uchar_label} + {byte_size 1 DW_FORM_sdata} + {bit_size 1 DW_FORM_sdata} + {bit_offset 0 DW_FORM_sdata} + {data_member_location { + DW_OP_plus_uconst 1 + } SPECIAL_expr} + } + DW_TAG_member { + {name j} + {type :$uchar_label} + {data_member_location { + DW_OP_plus_uconst 2 + } SPECIAL_expr} + } + } + + DW_TAG_subprogram { + {name foo} + {decl_file 0 udata} + {low_pc foo_start_lbl addr} + {high_pc foo_end_lbl addr} + } { + DW_TAG_formal_parameter { + {type :$struct_s_label} + {name x} + {location { + DW_OP_lit0 + DW_OP_stack_value + DW_OP_piece 2 + DW_OP_reg0 + DW_OP_piece 1 + } SPECIAL_expr} + } + DW_TAG_formal_parameter { + {type :$struct_s_label} + {name y} + {location { + DW_OP_lit0 + DW_OP_stack_value + DW_OP_piece 1 + DW_OP_reg0 + DW_OP_piece 1 + DW_OP_lit0 + DW_OP_stack_value + DW_OP_piece 1 + } SPECIAL_expr} + } + DW_TAG_formal_parameter { + {type :$struct_s_label} + {name z} + {location { + DW_OP_reg0 + DW_OP_piece 1 + DW_OP_lit0 + DW_OP_stack_value + DW_OP_piece 2 + } SPECIAL_expr} + } + } + + + DW_TAG_subprogram { + {name bar} + {decl_file 0 udata} + {low_pc bar_start_lbl addr} + {high_pc bar_end_lbl addr} + } { + DW_TAG_formal_parameter { + {type :$struct_t_label} + {name x} + {location { + DW_OP_lit0 + DW_OP_stack_value + DW_OP_piece 1 + DW_OP_reg0 + DW_OP_bit_piece 1 0 + DW_OP_lit0 + DW_OP_stack_value + DW_OP_bit_piece 7 0 + DW_OP_lit0 + DW_OP_stack_value + DW_OP_piece 1 + } SPECIAL_expr} + } + DW_TAG_formal_parameter { + {type :$struct_t_label} + {name y} + {location { + DW_OP_lit0 + DW_OP_stack_value + DW_OP_piece 1 + DW_OP_lit0 + DW_OP_stack_value + DW_OP_bit_piece 3 0 + DW_OP_reg0 + DW_OP_bit_piece 1 0 + DW_OP_lit0 + DW_OP_stack_value + DW_OP_bit_piece 4 0 + DW_OP_lit0 + DW_OP_stack_value + DW_OP_piece 1 + } SPECIAL_expr} + } + DW_TAG_formal_parameter { + {type :$struct_t_label} + {name z} + {location { + DW_OP_lit0 + DW_OP_stack_value + DW_OP_piece 1 + DW_OP_lit0 + DW_OP_stack_value + DW_OP_bit_piece 7 0 + DW_OP_reg0 + DW_OP_bit_piece 1 0 + DW_OP_lit0 + DW_OP_stack_value + DW_OP_piece 1 + } SPECIAL_expr} + } + } + + } + } +} diff -Nru dwz-0.13+20210219/VERSION dwz-0.14/VERSION --- dwz-0.13+20210219/VERSION 2019-08-11 15:16:07.000000000 +0000 +++ dwz-0.14/VERSION 2021-03-08 07:56:18.976431406 +0000 @@ -1 +1 @@ -0.13 +0.14