Tom de Vries [Wed, 10 Mar 2021 05:24:40 +0000 (06:24 +0100)]
Release process improvements
While doing the 0.14 release I ran into a few minor issues when running the
scripts in contrib/release:
- The script contrib/release/upload-release.sh requires a version argument,
but the version can just be read from the VERSION file.
- The contrib/release/do-release.sh does not do the git push. I used
my usual push script which also does a git rebase --ignore-date, which meant
the commit got updated and the tag no longer referred to the commit.
Also, I realized it could be useful to have a release checklist to go through.
So:
- Use $(cat VERSION) in contrib/release/upload-release.sh to get version
- Add git push commands to contrib/release/do-release.sh
- Add README.release-checklist
2021-03-08 Tom de Vries <tdevries@suse.de>
* README.release-checklist: New file.
* contrib/release/do-release.sh: Add git push commands.
* contrib/release/upload-release.sh: Use $(cat VERSION) to get version.
Tom de Vries [Mon, 8 Mar 2021 13:20:31 +0000 (14:20 +0100)]
Add --devel-no-checksum-cycle-opt
In checksum_ref_die, we need to determine a per-toplevel-die checksum based on
the inter-toplevel-die references. It has four modes:
- mode 1, a trivial one in which we walk towards toplevel-dies.
- mode 2, in which we optimistically assume that there are no cycles.
If that is the case, we're done. Otherwise, we use either mode 3 or mode 4.
- mode 3, dealing with cycles in a faster way
- mode 4, dealing with cycles
I did some testing using the testsuite and external testsuite and found that
mode 4 was not triggered once. I'm not quite sure how to construct a
test-case for that either.
Add an option --devel-no-checksum-cycle-opt that can be used to enforce using
mode 3 instead of mode 4, and add a test-case that uses it.
2021-02-23 Tom de Vries <tdevries@suse.de>
PR dwz/27429
* Makefile (TEST_EXECS): Add cycle.
(cycle): New target.
* dwz.c (checksum_cycle_opt): New var.
(checksum_ref_die): Handle checksum_cycle_opt.
(dwz_options, usage): Add --devel-checksum-cycle-opt entries.
* testsuite/dwz.tests/cycle.c: New test.
* testsuite/dwz.tests/cycle.sh: New test.
Tom de Vries [Fri, 5 Mar 2021 09:41:00 +0000 (10:41 +0100)]
[testsuite] Fix odr-loc.sh with -gdwarf-5
When running the test-suite like this:
...
$ make clean; make; make check CC="gcc -gdwarf-5" CXX="g++ -gdwarf-5"
...
we run into:
...
FAIL: src/testsuite/dwz.tests/odr-loc.sh
...
The test-case calls dwz twice, once without and once with
--devel-ignore-locus.
The first call is there to verify that all DIEs that can be deduplicated
without --devel-ignore-locus are indeed deduplicated, but not more.
The FAIL happens because some DIEs are not deduplicated. This is a regression
since commit 61c8d81 "Fix DW_AT_decl_file for odr". This makes sense: the
commit changed partitioning, and now the size heuristics are preventing some
deduplication.
Fix this by ignoring the size heuristics in the first dwz call using
--devel-ignore-size.
2021-03-05 Tom de Vries <tdevries@suse.de>
* testsuite/dwz.tests/odr-loc.sh: Call dwz first time using
--devel-ignore-size.
Tom de Vries [Fri, 5 Mar 2021 06:20:07 +0000 (07:20 +0100)]
Fix .debug_line reference above end of section
Consider the file test-import-repeatedly from PR26738, combined with a trivial
a.out:
...
$ cp test-import-repeatedly 1
$ gcc -m32 -g ~/hello.c
$ cp a.out 2
...
When doing multifile optimization, we run into:
...
$ dwz -m 3 2 1
dwz: 3: .debug_line reference above end of section
...
Using --devel-save-temps and src/contrib/gen-dwz-debug-all.sh we get the
unoptimized multifile, and find there a CU:
...
Compilation Unit @ offset 0x371:
Length: 0x6d (32-bit)
Version: 4
Abbrev Offset: 0x14d
Pointer Size: 4
<0><37c>: Abbrev Number: 1 (DW_TAG_compile_unit)
<37d> DW_AT_stmt_list : 0xda
<381> DW_AT_language : 0 (Unknown: 0)
<382> DW_AT_comp_dir : ./build-3.8
...
which refers to a .debug_line offset 0xda, but the debug_line section only
contains an entry at offset 0x0.
This can be explained as follows. The DIEs written into the CU do not
contain a single DW_AT_decl_file. Consequently, htab_line will be NULL once
we get here in write_multifile:
...
|| (line_htab != NULL && write_multifile_line ()))
...
and no .debug_line contribution will be added. However, the CU DIE
referencing the .debug_line contribution is written regardless.
We could fix this by not writing the DW_AT_stmt_list for the CU DIE in this
case, but that would require changing the order in which abbreviations are
computed.
Instead, fix this conservatively, by removing "line_htab != NULL &&", such we
get a minimal .debug_line contribution.
2021-03-02 Tom de Vries <tdevries@suse.de>
PR dwz/26738
* dwz.c (write_multifile): Also call write_multifile_line when
line_htab == NULL.
Tom de Vries [Thu, 4 Mar 2021 08:02:30 +0000 (09:02 +0100)]
Clean up temporary file in hardlink mode
Consider an executable file with hardlinks a.out and b.out.
When running dwz once:
...
$ dwz -h a.out b.out
...
a.out and b.out are updated, and remain hardlinks to the same file.
But when running dwz once more, a.out and b.out remain unchanged, and a
temporary file b.out.#dwz#.XXXXXX is left.
This is caused by the fact that the code in function dwz that is intended to
handle unchanged hardlinks is never triggered. It is guarded by a
"resa[n].res == 1" condition, but res->res is set to 0 at the end of function
dwz, irrespective of whether the file changed or not.
Fix this by only setting res->res to 0 if the file changed.
This makes test-case twice-multifile.sh fail. The test-case first
dwz-compresses files 1 and 2 in single-file mode. Then it attempts a
dwz -m 3 1 2.
This results in a res.res value of 1 (processed, unchanged) for both files.
This causes the files not to be counted as a success in main, and multifile
mode optimization is skipped.
Fix this by handling res.res == 1 in main.
2021-03-02 Tom de Vries <tdevries@suse.de>
PR dwz/24275
* dwz.c (dwz): Only set res->res to 0 if the file changed.
(main): Handle res.res == 1.
* testsuite/dwz.tests/twice-hardlink.sh: Remove PR24275 workaround.
Tom de Vries [Tue, 2 Mar 2021 07:26:52 +0000 (08:26 +0100)]
Fix assert after goto failure
Consider the following code in function dwz:
...
else if (write_aranges (dso))
{
cleanup ();
failure:
ret = 1;
}
...
char *p1 = realpath (file, NULL);
char *p2 = realpath (multifile, NULL);
...
if (p1 == NULL || p2 == NULL)
{
...
error (0, 0, "Could not compute relative multifile "
"pathname from %s to %s",
file, multifile);
goto failure;
...
I've managed to triggered this error in the following way.
First we do this setup:
...
$ mkdir tmpdir
$ ln -s tmpdir tmpdir-slink
$ cp hello 1
$ cp 1 2
...
Then we want to run dwz with a common file in tmpdir using the symlink
tmpdir-slink:
...
$ dwz -m ./tmpdir-slink/3 -r 1 2
...
but, stop just before calling realpath and remove the symlink to make the p2
realpath call return NULL.
We can do that using gdb:
...
$ gdb -batch \
-ex "b 15451" \
-ex run \
-ex "shell rm -f tmpdir-slink" \
-ex cont \
--args ./dwz -m ./tmpdir-slink/3 -r 1 2
Breakpoint 1 at 0x382d1: file dwz.c, line 15451.
Breakpoint 1, dwz (file=0x7fffffffe285 "1", outfile=0x0, res=0x5555557a5260,
resa=0x0, files=0x7fffffffdeb8) at dwz.c:15451
15451 if (!multifile_relative)
dwz: Could not compute relative multifile pathname from 1 to ./tmpdir-slink/3
dwz: dwz.c:2170: off_htab_add_die: Assertion `*slot == NULL' failed.
Program received signal SIGABRT, Aborted.
0x00007ffff75fffb7 in raise () from /lib/x86_64-linux-gnu/libc.so.6
...
but we hit an assertion.
This is because cleanup is not called.
Fix this by moving the failure label up one line.
2021-03-02 Tom de Vries <tdevries@suse.de>
* dwz.c (dwz): Move failure label to before cleanup.
Tom de Vries [Sat, 27 Feb 2021 10:34:55 +0000 (11:34 +0100)]
Fix reference of PU to CU for odr
When compiling dwz with the assert listed in the commit message for
"Call reorder_dups ASAP", and using test-case cc1.dwz-processed like so, we
run into:
...
$ dwz cc1.dwz-processed -o 1 -lnone --odr
dwz: dwz.c:12567: write_die: Assertion \
`IMPLIES (cu->cu_kind == CU_PU, die_cu (refd)->cu_kind == CU_PU)' failed.
Aborted (core dumped)
...
The assert is related to this duplicate chain:
... 28dd83f O b500801d621b6872 pointer_type \
(type: 28dd72f die_struct structure_type) 2903769 O b500801d621b6872 pointer_type \
(type: 28dd72f die_struct structure_type)
...
which contains two DIEs that are both in the same CU:
...
<0><28d281f>: Abbrev Number: 200 (DW_TAG_compile_unit)
...
<1><28dd72f>: Abbrev Number: 35 (DW_TAG_structure_type)
<28dd730> DW_AT_name : (indirect string, offset: 0x1b2ca6): die_struct
<28dd734> DW_AT_byte_size : 80
<28dd735> DW_AT_decl_file : 87
<28dd736> DW_AT_decl_line : 3069
<28dd738> DW_AT_decl_column : 63
<28dd739> DW_AT_sibling : <0x28dd83b>
<1><28dd83f>: Abbrev Number: 9 (DW_TAG_pointer_type)
<28dd840> DW_AT_byte_size : 8
<28dd841> DW_AT_type : <0x28dd72f>
...
<1><2903769>: Abbrev Number: 9 (DW_TAG_pointer_type)
<290376a> DW_AT_byte_size : 8
<290376b> DW_AT_type : <0x28dd72f>
...
<0><2911617>: Abbrev Number: 177 (DW_TAG_compile_unit)
...
The dup chain is forced to a partial unit, but the die_struct DIE is not,
because it's not part of a duplicate chain, and it's not marked as a
singleton. Fix this by marking the die_struct DIE as singleton.
Tom de Vries [Sat, 27 Feb 2021 10:34:55 +0000 (11:34 +0100)]
Call reorder_dups ASAP
Currently, we call reorder_dups just before partial unit creation, and only for
DIEs that will be copied.
This approach causes a problem with reachable DIE propagation (which is done
in partition_dups after phase 1): when a dup-chain that needs to be reordered
(starts with ODR_DECL but also contains ODR_DEF) is marked as reachable during
this propagation, propagation will stop at the ODR_DECL, while it should
continue at the first ODR_DEF instead.
Fix this by calling reorder_dups ASAP, just after computing the partitions.
The problem can be detected using this assert:
...
@@ -12563,6 +12563,8 @@ write_die
{
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)
{
...
We accept the small performance penalty because this patch is a prerequisite
for the PR25424 bug fix.
2021-02-25 Tom de Vries <tdevries@suse.de>
* dwz.c (calculate_partitions): New function, factored out of ...
(partition_dups_1): ... here. Drop vec_size parameter. Add
nr_partitions and partitions parameter. Iterate over partitions array.
(partition_dups): Call calculate_partitions. Update calls to
partition_dups_1.
Mark Wielaard [Fri, 26 Feb 2021 14:38:58 +0000 (15:38 +0100)]
PR27463 Accept DW_FORM_sdata for DW_AT_decl/call_file
Using DW_FORM_sdata for DW_AT_decl/call_file is somewhat inefficient
since file index numbers are always positive values. But it is a valid
form to encode a constant value. Accept DW_FORM_sdata as long as it
encodes a positive value. Extend the positive value check to
DW_FORM_implicit_const.
* dwz.c (checksum_die): Accept DW_FORM_sdata for
DW_AT_decl/call_file as long as the value is positive. Also
check DW_FORM_implicit_const value is positive for these
attributes.
(die_eq_1): Handle DW_FORM_sdata for DW_AT_decl/call_file.
(build_abbrevs_for_die): Likewise.
(write_die): Likewise.
* testsuite/dwz.tests/pr27463.sh: New test.
* testsuite/lib/unavailable-dwarf-piece.exp: New testfile
from gdb.
* testsuite/dwz.tests/dwz-tests.exp: Add unavailable-dwarf-piece
for pr25109.sh.
* testsuite/dwz.tests/main.c (foo): New function and labels.
(bar): Likewise.
* Makefile (TEST_EXECS_DWARF_ASM): Add unavailable-dwarf-piece.
Tom de Vries [Fri, 26 Feb 2021 11:47:34 +0000 (12:47 +0100)]
[testsuite] Fix pr25109.sh on riscv64
On riscv64, I run into:
...
cc main.c no-multifile-prop-dw.S -o no-multifile-prop
no-multifile-prop-dw.S: Assembler messages:
no-multifile-prop-dw.S:25: Error: non-constant .uleb128 is not supported
make: *** [Makefile:99: no-multifile-prop] Error 1
...
Fix this by allowing to fail to build the test-case, and marking it as
unsupported.
Tom de Vries [Thu, 25 Feb 2021 08:04:33 +0000 (09:04 +0100)]
Fix DW_AT_decl_file for odr
Consider odr-struct. It has two structs aaa (from different CUs), each with
members of type bbb and ccc, but in one case bbb is a decl, in the other case
ccc is a decl.
When doing odr, we end up with one struct aaa, and no decls:
...
$ dwz --odr odr-struct
$ readelf -wi odr-struct \
| egrep -A2 "DW_TAG_structure" \
| egrep "DW_TAG|DW_AT_name|DW_AT_decl"
<1><19>: Abbrev Number: 25 (DW_TAG_structure_type)
<1a> DW_AT_name : ccc
<1><2f>: Abbrev Number: 25 (DW_TAG_structure_type)
<30> DW_AT_name : aaa
<1><4b>: Abbrev Number: 25 (DW_TAG_structure_type)
<4c> DW_AT_name : bbb
...
Now consider using the same file for multifile optimization, combined with
odr:
...
$ cp odr-struct 1; cp 1 2; dwz -m 3 1 2 --odr
...
The desired outcome is that the structs aaa are unified (same as above) in
both 1 and 2, and then moved to multifile 3.
The problem is that the DW_AT_decl_file is different for struct bbb in 1 and
3, and that causes the struct types to linger in 1.
The problem can already be shown without multifile mode using:
....
$ dwz odr-struct --odr
$ llvm-dwarfdump odr-struct \
| grep -A3 struct \
| egrep -v "^--|DW_AT_byte_size" \
| sed 's%/.*/%%'
0x00000019: DW_TAG_structure_type
DW_AT_name ("ccc")
DW_AT_decl_file ("odr.cc")
0x0000002f: DW_TAG_structure_type
DW_AT_name ("aaa")
DW_AT_decl_file ("odr.h")
0x0000004b: DW_TAG_structure_type
DW_AT_name ("bbb")
DW_AT_decl_file ("odr.cc")
...
The DW_AT_decl_file for struct bbb should be odr-2.cc.
The problem is caused by by odr: odr allows defs and decls to be part of the
same duplicate chain, which breaks the invariant that DIEs in the duplicate
chain are isomorph. During write_die, the first DIE in the chain is written
out as the representative copy, which means having a decl as the first in the
chain is counterproductive. We have reorder_dups to fix this problem, which
detects if a duplicate chain starts with a decl and then moves the first def
before it. However, this breaks another variant: that for each partition, all
representative DIEs are from the same CU. Consequently, the file table of the
partition may not match with the DW_AT_decl_file number.
In other words, the reordered duplicate chain is in the wrong partition.
Fix this by:
- ignoring ODR_DECL DIEs at the start of a duplicate chain when partitioning
- moving the reorder_dups call to the start of partial unit creating, such
that we get the correct refcu.
This also breaks the invariant checked in create_import_tree that
partition_dups doesn't generate two seperate partial units with the same set
of referrer CUs, so we allow this for odr.
2021-02-19 Tom de Vries <tdevries@suse.de>
PR dwz/27438
* dwz.c (partition_cmp): Ignore ODR_DECL dies at the
start of a duplicate chain.
(partition_dups_1): Same. Move call to reorder_dups earlier.
(create_import_tree): Allow partial units with same set of referrers
for odr.
* testsuite/dwz.tests/odr-struct-multifile.sh: New test.
Tom de Vries [Tue, 23 Feb 2021 11:07:51 +0000 (12:07 +0100)]
Clean up die_odr_state interface
The die_odr_state function returns the odr state for a die, and if it hasn't
been calculated, it calculates it first using a call to set_die_odr_state:
...
static unsigned int UNUSED
die_odr_state (dw_cu_ref cu, dw_die_ref die)
{
if (die->die_odr_state != ODR_UNKNOWN)
return die->die_odr_state;
The call to set_die_odr_state needs a cu argument, and consequently
die_odr_state also has one. That means a call to die_odr_state needs a proper
CU argument if set_die_odr_state gets called, and for optimality a NULL CU
otherwise.
As it happens, there's only one place where the proper CU argument is
required, and it's easy to accidentally do:
...
die_odr_state (die_cu (die), die)
...
where a NULL CU would suffice.
Fix this by explicitly calling set_die_odr_state and dropping the cu parameter
from die_odr_state.
2021-02-23 Tom de Vries <tdevries@suse.de>
* dwz.c (set_die_odr_state): Assert die->die_odr_state == ODR_UNKNOWN.
(die_odr_state): Drop cu parameter. Assert
die->die_odr_state != ODR_UNKNOWN.
(checksum_die): Call set_die_odr_state. Update call to die_odr_state.
(read_debug_info, split_dups, reorder_dups, merged_singleton)
(partition_dups): Update call to die_odr_state.
Tom de Vries [Tue, 23 Feb 2021 09:24:21 +0000 (10:24 +0100)]
Don't print die_hash2 for ODR_UNKNOWN in dump_die_with_indent
With the following debugging session where we dwz exec hello using odr:
...
$ gdb -q --args dwz hello -o hello.z --odr
Reading symbols from dwz...
(gdb) b checksum_die
Breakpoint 1 at 0x409778: file dwz.c, line 3348.
(gdb) r
Starting program: dwz hello -o hello.z --odr
Breakpoint 1, checksum_die (...) at dwz.c:3348
3348 switch (die->die_ck_state)
(gdb) call dump_die (die)
b X 0(0) 0 ../sysdeps/x86_64/start.S compile_unit
(gdb) p die->die_odr_state
$1 = ODR_UNKNOWN
...
we see that we're printing the die_hash2 for a die with die_odr_state ==
ODR_UNKNOWN, while this is only supposed to trigger for ODR_DECL and ODR_DEF.
Fix this in dump_die_with_indent, by not printing die_hash2 when die_odr_state ==
ODR_UNKNOWN.
2021-02-23 Tom de Vries <tdevries@suse.de>
* dwz.c (dump_die_with_indent): Don't print die_hash2 when
die_odr_state == ODR_UNKNOWN.
Tom de Vries [Mon, 22 Feb 2021 15:38:26 +0000 (16:38 +0100)]
Don't call die_odr_state with unnecessarily defined cu arg
When compiling dwz with this patch:
...
die_odr_state (dw_cu_ref cu, dw_die_ref die)
{
if (die->die_odr_state != ODR_UNKNOWN)
- return die->die_odr_state;
+ {
+ assert (cu == NULL);
+ return die->die_odr_state;
+ }
...
and running f.i. odr-struct.sh, we run into the abort.
The recent commit 3312feb "Fix CK_BAD propagation for --odr" introduced this
code:
...
if (die_odr_state (die_cu (die), die) != ODR_NONE)
die->u.p1.die_ref_hash = die->u.p1.die_hash;
...
and there's no need to pass a CU argument, which makes the abort trigger.
Fix this by passing a NULL CU instead.
2021-02-22 Tom de Vries <tdevries@suse.de>
* dwz.c (read_debug_info): Pass NULL CU to die_odr_state call.
Tom de Vries [Mon, 22 Feb 2021 07:44:16 +0000 (08:44 +0100)]
Fix CK_BAD propagation for --odr
With the reproducer from PR26252 we get:
...
$ dwz 2 -o 2.z --odr -lnone
dwz: dwz.c:7396: partition_found_dups: \
Assertion `die->die_ck_state == CK_KNOWN' failed.
Aborted (core dumped)
...
The problem is caused by the odr code in checksum_ref_die, which skips
checksum calculation for the children of odr types, with as unintended
side-effect that it break the CK_BAD propagation to toplevel DIEs.
Fix this by making the skipping of the checksum calculation less intrusive.
Specially:
- undo all modifications related to odr in checksum_ref_die
- After calling checksum_ref_die in read_debug_info:
- override die_ref_hash for odr DIEs, and
- recalculate die_ref_hash for all other DIEs.
We still have the same amount of compression with cc1, that is: without odr
we have 42.30% reduction:
...
$ dwz cc1 -o cc1.z -lnone --no-odr
$ diff.sh cc1 cc1.z
.debug_info red: 44.84% 11152724861527733
.debug_abbrev red: 40.28% 17227261028968
.debug_str red: 0% 66093556609355
total red: 42.30% 11985932969166056
...
and with odr but without the bug fix we have 54.55%:
...
$ dwz cc1 -o cc1.z -lnone --odr
$ diff.sh cc1 cc1.z
.debug_info red: 57.46% 11152724847449258
.debug_abbrev red: 75.08% 1722726 429434
.debug_str red: 0% 66093556609355
total red: 54.55% 11985932954488047
...
and with odr and the bug fix still 54.55%:
...
$ dwz cc1 -o cc1.z -lnone --odr
$ diff.sh cc1 cc1.z
.debug_info red: 57.46% 11152724847446501
.debug_abbrev red: 75.51% 1722726 422027
.debug_str red: 0% 66093556609355
total red: 54.55% 11985932954477883
...
2021-02-18 Tom de Vries <tdevries@suse.de>
PR dwz/26252
* dwz.c (checksum_ref_die): Undo modifications related to odr.
(read_debug_info): After calling checksum_ref_die, override
die_ref_hash for odr DIEs, and recalculate die_ref_hash for all
other DIEs.
Tom Tromey [Sun, 21 Feb 2021 02:12:54 +0000 (19:12 -0700)]
Print --version and --help to stdout
Normall --version and --help output go to stdout and cause a program
to exit with status 0. The rationale for the exit status is that the
user asked for this behavior, and the program successfully complied.
Printing --help output to stdout is nicer for piping into a pager.
This patch changes dwz to follow this approach.
I kept the program invocation name in the Usage line. Different
programs seem to handle this differently.
Jakub Jelinek [Sat, 20 Feb 2021 09:47:53 +0000 (10:47 +0100)]
PR27440 - add --dwarf-5 support
This adds --dwarf-5 support, so that dwz can emit standard DWARF 5
Supplementary object files with .debug_sup section and debug info referring
to those with .debug_sup section instead of .gnu.debugaltlink and standard
DWARF 5 DW_FORM_*sup instead of the DW_FORM_GNU_*alt forms.
* dwz.1: Document --dwarf-5 and -5 options.
* dwz.c (enum debug_section_kind): Add DEBUG_SUP.
(debug_sections): Add .debug_sup section entry.
(multifile_name, multifile_relative): Adjust comment.
(dwarf_5): New variable.
(note_strp_offset2): Adjust function comment. If dwarf_5, return
DW_FORM_strp_sup instead of DW_FORM_GNU_strp_alt.
(macro_eq, read_macro, optimize_write_macro, handle_macro): Use
standard DWARF 5 DW_MACRO_* names instead of their DW_MACRO_GNU_*
aliases.
(write_macro): Likewise. Handle DW_FORM_strp_sup.
(build_abbrevs_for_die): If dwarf_5, use DW_FORM_ref_sup4 instead of
DW_FORM_GNU_ref_alt.
(write_unit_die): Handle DW_FORM_strp_sup.
(write_die): Handle DW_FORM_ref_sup4 and DW_FORM_strp_sup.
(read_dwarf): Fail if .debug_sup section is present, unless
rd_multifile in dwarf_5 mode.
(dwz): Write .debug_sup section instead of .gnu.debugaltlink if
dwarf_5.
(optimize_multifile): Write .debug_sup section instead of
.note.gnu.build-id.
(dwz_options): Add --dwarf-5 and -5 options.
(dwz_multi_file_options_help): Mention .debug_sup section in -M
description. Add --dwarf-5 description.
(main): Handle --dwarf-5 and -5 options.
Mark Wielaard [Sat, 13 Feb 2021 22:34:55 +0000 (23:34 +0100)]
Don't handle blocks as exprlocs for DWARF version 4 or higher.
Since DWARF version 4 blocks just contain bytes, trying to interpret
them as exprlocs will most likely fail. Also make sure block1 form
and len are correctly passed to add_locexpr_dummy_dies.
* dwz.c (add_locexpr_dummy_dies): Only handle block as exprloc
for cu_version < 4.
(checksum_die): Likewise.
(write_die): Likewise.
(read_debug_info): Get block length before calling
add_locexpr_dummy_dies.
Tom de Vries [Thu, 18 Feb 2021 13:01:57 +0000 (14:01 +0100)]
Add assert in partition_found_dups
With the reproducer from PR26252 we get:
...
$ dwz -m 3 --odr 1 2
dwz: 1: DWARF compression not beneficial - old size 317760 new size 317760
dwz: dwz.c:12431: write_die: \
Assertion `value && refdcu->cu_kind != CU_ALT' failed.
Aborted (core dumped)
...
The assertion fails when writing out the contribution of file 2 to the
multifile.
It's trying to write out a copy of this DIE:
...
<3><9f3e>: Abbrev Number: 149 (DW_TAG_subprogram)
<9f40> DW_AT_name :
_M_access<ydotool::Tool::ToolManager::ScanPath(const string&)::\
<lambda(const string&, dirent*)> >
<9f44> DW_AT_decl_file : 11
<9f45> DW_AT_decl_line : 92
<9f46> DW_AT_decl_column : 7
<9f47> DW_AT_type : <0x1a2a5>
<9f4b> DW_AT_declaration : 1
<9f4b> DW_AT_object_pointer: <0x9f5c>
<9f4f> DW_AT_sibling : <0x9f62>
...
and specifically, for the DW_AT_type attribute it attempts to write out the
reference to the copy of the DIE at 0x1a2a5:
...
<1><1a2a5>: Abbrev Number: 9 (DW_TAG_reference_type)
<1a2a6> DW_AT_byte_size : 8
<1a2a7> DW_AT_type : <0x27cd9>
...
There is no copy of that DIE, because it has a bad checksum:
...
1a2a5 X d27b2f2ad27b2f2a reference_type (type: 27cd9 structure_type)
...
which means that its toplevel DIE 0x9edc:
...
<2><9edc>: Abbrev Number: 182 (DW_TAG_union_type)
<9ede> DW_AT_name : _Any_data
...
should also have a bad checksum, but it doesn't:
...
9edc O 9d6524b49d6524b4 _Any_data union_type
...
while without --odr, it does:
...
9edc X d8f947f35100c9e1 _Any_data union_type
...
Add an assert partition_found_dups such that we can catch the problem of the
checksum much earlier:
...
static void
partition_found_dups (dw_die_ref die, struct obstack *vec)
{
+ assert (die->die_ck_state == CK_KNOWN);
...
which means we can reproduce with just one file:
...
$ dwz 2 --odr
dwz: dwz.c:7372: partition_found_dups: \
Assertion `die->die_ck_state == CK_KNOWN' failed.
Aborted (core dumped)
...
2021-02-18 Tom de Vries <tdevries@suse.de>
* dwz.c (partition_found_dups): Assert that
die->die_ck_state == CK_KNOWN.
Tom de Vries [Thu, 18 Feb 2021 12:17:44 +0000 (13:17 +0100)]
Add --devel-dump-checksum
Add an option --devel-dump-checksum that dumps how the checksum is
calculated in checksum_die.
F.i., for these DIEs:
...
<1><2e5>: Abbrev Number: 8 (DW_TAG_structure_type)
<2e6> DW_AT_name : _IO_marker
<2ea> DW_AT_byte_size : 24
<2eb> DW_AT_decl_file : 4
<2ec> DW_AT_decl_line : 156
<2ed> DW_AT_sibling : <0x316>
<2><2f1>: Abbrev Number: 9 (DW_TAG_member)
<2f2> DW_AT_name : _next
<2f6> DW_AT_decl_file : 4
<2f7> DW_AT_decl_line : 157
<2f8> DW_AT_type : <0x316>
<2fc> DW_AT_data_member_location: 0
<2><2fd>: Abbrev Number: 9 (DW_TAG_member)
<2fe> DW_AT_name : _sbuf
<302> DW_AT_decl_file : 4
<303> DW_AT_decl_line : 158
<304> DW_AT_type : <0x31c>
<308> DW_AT_data_member_location: 8
<2><309>: Abbrev Number: 9 (DW_TAG_member)
<30a> DW_AT_name : _pos
<30e> DW_AT_decl_file : 4
<30f> DW_AT_decl_line : 162
<310> DW_AT_type : <0x129>
<314> DW_AT_data_member_location: 16
<2><315>: Abbrev Number: 0
...
we get:
...
$ dwz --devel-dump-checksum hello
...
DIE 2e5, hash: 6a638d48, tag
DIE 2e5, hash: f9c5744d, attr (0)
DIE 2e5, hash: e83375f6, attr (1)
DIE 2e5, hash: f6c73f89, attr (2)
DIE 2e5, hash: 1cd5a043, attr (3)
DIE 2e5, hash: 1cd5a043, attr (4)
DIE 2f1, hash: 3a09c42b, tag
DIE 2f1, hash: 815dd613, attr (0)
DIE 2f1, hash: 7b47bca, attr (1)
DIE 2f1, hash: 5a509026, attr (2)
DIE 2f1, hash: be759bbc, attr (3)
DIE 2f1, hash: 1684f315, attr (4)
DIE 2f1, hash: 1684f315, final
DIE 2e5, hash: 9178023b, child (0)
DIE 2fd, hash: 3a09c42b, tag
DIE 2fd, hash: 9a2aa48d, attr (0)
DIE 2fd, hash: fc2833ec, attr (1)
DIE 2fd, hash: 41974b9c, attr (2)
DIE 2fd, hash: 36e76cd8, attr (3)
DIE 2fd, hash: ac3098c6, attr (4)
DIE 2fd, hash: ac3098c6, final
DIE 2e5, hash: c4a190a3, child (1)
DIE 309, hash: 3a09c42b, tag
DIE 309, hash: 5ea756dc, attr (0)
DIE 309, hash: 6486eafd, attr (1)
DIE 309, hash: bdc3b14f, attr (2)
DIE 309, hash: 5da7f906, attr (3)
DIE 309, hash: a9c74436, attr (4)
DIE 309, hash: a9c74436, final
DIE 2e5, hash: 40b05772, child (2)
DIE 2e5, hash: 40b05772, final
...
2021-02-15 Tom de Vries <tdevries@suse.de>
* dwz.c (dump_checksum_p): New var.
(checksum_die): Print progression of checksum calculation if
dump_checksum_p.
(dwz_options, usage): Add --devel-dump-checksump entries.
Tom de Vries [Thu, 18 Feb 2021 12:17:44 +0000 (13:17 +0100)]
Print die_hash2 for --odr --devel-dump-dies
For --odr, there's an additional hash value, die->u.p1.die_hash2.
Print this with --devel-dump-dies, such that we have:
...
$ dwz --devel-dump-dies --odr odr-struct
114 O f56004ac(cd46c7ab) f56004ac aaa structure_type
...
1ba O f56004ac(cd46c7ab) f56004ac aaa structure_type
...
Tom de Vries [Tue, 16 Feb 2021 11:19:55 +0000 (12:19 +0100)]
[testsuite] Fix compile warnings for def-decl with clang
When running the test-suite with clang, we run into these warnings:
...
clang++ decl.c def.c def2.c -Itestsuite/dwz.tests -o def-decl -g
clang-10.0: warning: treating 'c' input as 'c++' when in C++ mode, \
this behavior is deprecated [-Wdeprecated]
clang-10.0: warning: treating 'c' input as 'c++' when in C++ mode, \
this behavior is deprecated [-Wdeprecated]
clang-10.0: warning: treating 'c' input as 'c++' when in C++ mode, \
this behavior is deprecated [-Wdeprecated]
...
Fix these by renaming the source files from .c to .cc.
Tom de Vries [Tue, 16 Feb 2021 11:10:29 +0000 (12:10 +0100)]
[testsuite] Fix odr tests with clang
When running the testsuite with clang, I run into:
...
$ make check CC=clang CXX=clang++
...
FAIL: testsuite/dwz.tests/odr-def-decl.sh
FAIL: testsuite/dwz.tests/odr-loc.sh
FAIL: testsuite/dwz.tests/odr-struct-ns.sh
FAIL: testsuite/dwz.tests/odr-struct.sh
...
The problem is that clang emits less DIEs. For this bit from odr-loc.cc:
...
struct bbb;
struct ccc {
int member_three;
};
Tom de Vries [Mon, 15 Feb 2021 12:22:41 +0000 (13:22 +0100)]
Add attribute to checksum for DW_FORM_implicit_const
In checksum_die, we handle DW_FORM_implicit_const like so:
...
case DW_FORM_implicit_const:
if (!handled && die->die_ck_state != CK_BAD)
{
handled = true;
die->u.p1.die_hash
= iterative_hash_object (t->values[i], die->u.p1.die_hash);
}
...
The problem is that the attribute is not hashed in.
We could fix this by removing the "handled = true" assignment, but
generally the order is "attribute first, value second", and this fix would
do the reverse. Consequently, identical attributes, one with form
DW_FORM_sdata and one with form DW_FORM_implicit_const would not get the same
checksum.
Fix this by locally adding hashing of the attribute, before hashing in the
value.
2021-02-15 Tom de Vries <tdevries@suse.de>
PR dwz/27418
* dwz.c (checksum_die): Hash in attribute for DW_FORM_implicit_const.
Mark Wielaard [Sun, 14 Feb 2021 15:19:21 +0000 (16:19 +0100)]
Remove left over "negate" adjustment in compute_abbrevs.
Before commit 47af8da7c "Assorted DW_FORM_implicit_const fixes" there
was a hack to track whether decl/call_file line numbers had been
translated already. This worked by negating the value once it was
translated and not translating again when the value was negative. Then
in compute_abbrevs all negated values were made positive again. Most
of this hack was removed in the above commit. Except for making all
negated values positive again in compute_abbrevs. Remove it there too.
No decl/call_file line number tables can ever be negative.
* dwz.c (compute_abbrevs): Remove negate adjustment for
DW_AT_decl_file and DW_AT_call_file attribute DW_FORM_implicit_const
values.
Tom de Vries [Sun, 14 Feb 2021 21:15:02 +0000 (22:15 +0100)]
Handle DW_FORM_implicit_const for DW_AT_decl_line
When running the test-suite like this:
...
$ make clean; make; make check CC="gcc -gdwarf-5" CXX="g++ -gdwarf-5"
...
we run into:
...
FAIL: dwz/testsuite/dwz.tests/odr-struct.sh
...
The reason for the FAIL is that this DIE:
...
<1><115>: Abbrev Number: 2 (DW_TAG_structure_type)
<116> DW_AT_name : aaa
<11a> DW_AT_byte_size : 16
<11b> DW_AT_decl_file : 2
<11c> DW_AT_decl_line : 4
<11d> DW_AT_sibling : <0x13a>
...
with abbrev:
...
2 DW_TAG_structure_type [has children]
DW_AT_name DW_FORM_string
DW_AT_byte_size DW_FORM_data1
DW_AT_decl_file DW_FORM_data1
DW_AT_decl_line DW_FORM_data1
DW_AT_sibling DW_FORM_ref4
DW_AT value: 0 DW_FORM value: 0
...
is not recognized as a duplicate of DIE:
...
<1><1b9>: Abbrev Number: 2 (DW_TAG_structure_type)
<1ba> DW_AT_name : aaa
<1be> DW_AT_byte_size : 16
<1bf> DW_AT_decl_file : 2
<1c0> DW_AT_decl_line : 4
<1c0> DW_AT_sibling : <0x1dd>
...
with abbrev:
...
2 DW_TAG_structure_type [has children]
DW_AT_name DW_FORM_string
DW_AT_byte_size DW_FORM_data1
DW_AT_decl_file DW_FORM_data1
DW_AT_decl_line DW_FORM_implicit_const: 4
DW_AT_sibling DW_FORM_ref4
DW_AT value: 0 DW_FORM value: 0
...
due to the DW_AT_decl_line attribute having different forms, DW_FORM_data1 and
DW_FORM_implicit_const.
Fix this in checksum_die and die_eq_1 by adding dedicated handling for
DW_AT_decl_line, similar to how that's done for DW_AT_decl_file.
2021-02-14 Tom de Vries <tdevries@suse.de>
PR dwz/27400
* dwz.c (checksum_die, die_eq_1): Handle DW_FORM_implicit_const for
DW_AT_decl_line.
Tom de Vries [Sun, 14 Feb 2021 08:06:27 +0000 (09:06 +0100)]
Support DW_LANG_C_plus_plus_{03,11,14}
When compiling with f.i. g++ 7.5.0, we have GNU C++14 by default:
...
<d3> DW_AT_producer: GNU C++14 7.5.0 -mtune=generic -march=x86-64 -g
...
and the corresponding language setting is:
...
<d7> DW_AT_language: 4 (C++)
...
However, with -gdwarf-5, we have instead:
...
<d4> DW_AT_producer: GNU C++14 7.5.0 -mtune=generic -march=x86-64 -gdwarf-5
<d8> DW_AT_language: 33 (C++14)
...
The current checks in dwz (for --odr and --devel-gen-cu) for language C++
compare only with DW_LANG_C_plus_plus.
Fix this by comparing in addition with DW_LANG_C_plus_plus_{03,11,14}.
2021-02-14 Tom de Vries <tdevries@suse.de>
* dwz.c (set_die_odr_state, partition_lang): Add support for
DW_LANG_C_plus_plus_{03,11,14}.
Tom de Vries [Tue, 9 Feb 2021 22:41:04 +0000 (23:41 +0100)]
[testsuite] Fix tcl error in dwz-tests.exp
When running:
...
$ make check CC="clang -gdwarf-5"
...
I run into:
...
ERROR: tcl error sourcing testsuite/dwz.tests/dwz-tests.exp.
ERROR: 2
readelf: Warning: DIE at offset 0xe6 refers to abbreviation number 8 \
which does not exist while executing
"exec readelf -wi min | grep DW_AT_name | grep -c / "
...
Fix this by wrapping the exec in a catch.
2021-02-09 Tom de Vries <tdevries@suse.de>
* testsuite/dwz.tests/dwz-tests.exp: Wrap "exec readelf" in catch.
Tom de Vries [Tue, 9 Feb 2021 07:31:59 +0000 (08:31 +0100)]
Bail out for unhandled dwarf-5 CU type
With this exec:
...
$ gcc -gdwarf-5 -fdebug-types-section hello.c
...
we run into:
...
$ dwz a.out
dwz: a.out: DWARF CU type DW_UT_type unhandled
dwz: a.out: Could not find DWARF abbreviation 8620
...
Remove the second message by bailing out of read_debug_info once the
unhandled dwarf-5 CU type is encountered.
2021-02-09 Tom de Vries <tdevries@suse.de>
PR dwz/27372
* dwz.c (read_debug_info): Goto fail when encountering unhandled
dwarf-5 CU type.
There is an assert condition as "ref && ref->die_dup == NULL".
As per definition of "struct dw_die", the structure fields starting
from 'die_dup' are present only if 'die_toplevel' is 1. In line with
this at multiple places in code, full/paritial memory is allocated for
pointer of type dw_die.
Ex. die = pool_alloc (dw_die, offsetof (struct dw_die, die_dup));
Due to this, since memory is not allocated for field die_dup onwards,
it may contain junk values. Macro 'die_safe_dupe' must be used in place
of directly accessing 'die_dup' in assert condition here.
* dwz.c (write_types): Use 'die_safe_dup' to access field 'die_dup'.
Mark Wielaard [Tue, 26 Jan 2021 20:12:18 +0000 (21:12 +0100)]
Add DIE offsets in error messages to make it easier to find what is wrong.
With the following patch dwz will give a message like:
libmozjs-78.so: Couldn't find DIE at [bd6b507] referenced by
DW_AT_abstract_origin from DIE at [bd5bb9b]
Which makes it a easier to figure out what is going on.
In the above case you can simply lookup the producer of the CU for those
two DIEs. Which turned out the be "clang LLVM (rustc version 1.49.0)"
which seems to have gotten the abstract origin reference wrong.
* dwz.c (read_exprloc): Add DIE offsets to error messages.
(checksum_die): Likewise.
Mark Wielaard [Fri, 22 Jan 2021 12:37:05 +0000 (13:37 +0100)]
Don't crash on DWARF5 .debug_line table with zero files.
Not having any files in a DWARF5 .debug_line table is odd, but not
technically invalid. Normally there should be a zero file entry that
is equal to the compile unit main file (there is no such zero entry
for early DWARF versions and we handle no file entries fine in that
case).
Jakub Jelinek [Thu, 21 Jan 2021 07:43:08 +0000 (08:43 +0100)]
Assorted DW_FORM_implicit_const fixes
The problem is I think that write_abbrev is always called before write_info,
and the remapping of the DW_AT_decl_file/DW_AT_call_file DW_FORM_implicit_const
is done only in write_die which is called either recursively or from
write_info/write_types. Which means the DW_FORM_implicit_const value encoded
in the abbrev was never updated.
Other fixes include hashing the DW_FORM_implicit_const value in checksum_die
and more importantly comparing the values in die_eq_1.
2021-01-21 Jakub Jelinek <jakub@redhat.com>
PR dwz/27212
PR dwz/27213
* dwz.c (checksum_die): For DW_FORM_implicit_const hash t->values[i].
(die_eq_1): For DW_FORM_implicit_const compare t?->values[?].
(build_abbrevs_for_die): For DW_FORM_implicit_const on DW_AT_*_file
call line_htab_lookup too and store the result into t->values[j].
Otherwise, handle even file ids larger than 32-bit.
(write_die): For DW_FORM_implicit_const on DW_AT_*_file just j++
and continue, don't call line_htab_lookup nor adjust anything.
Simplify.
(alt_clear_dups): Fix function comment.
Mark Wielaard [Sun, 17 Jan 2021 14:44:11 +0000 (15:44 +0100)]
Break out of while loop correctly to make sure loclists are adjusted.
The reading and adjusting of DWARF5 .debug_loclists was modelled on
the DWARF4 .debug_loc section parsing. The .debug_loc parsing used
a while loop and breaks out when done. But .debug_loclists use a
switch statement inside the while loop, so break doesn't actually
break out of the loop when done, and return on end of list exits
the functions too early. This meant that although the loclists were
parsed correctly, then were then not actually adjusted. Fix this
by using gotos inside the switch statements.
* dwz.c (read_loclist_low_mem_phase1): Use again and done
labels to goto inside switch.
(read_loclist): Likewise.
(adjust_loclist): Likewise.
Mark Wielaard [Tue, 22 Sep 2020 16:20:53 +0000 (18:20 +0200)]
Handle DW_FORM_implicit_const
This handles DW_FORM_implicit_const. This form keeps the actual data
value in the abbrev. This makes things tricky because we have to decide
where to keep (a reference to) the value and when to update the value
if necessary.
To not bloat each abbrev_attr struct we add an int64 *values to the
abbrev_tag struct which points to an array of values at the end. We
only allocate values up to the highest implicit_const form (if any)
when we know those upfront. In compute_abbrevs and recompute_abbrevs
we have to allocate a maximum number of values (just like we have to
allocate the maximum number of attributes). But when cloning those
we reduce the number of values (and attributes) to the minimum needed.
To keep the values field up to date always call pool_clone_abbrev
when copying an abbrev.
When a DW_AT_decl_file or DW_AT_call_file attribute references a
file number using DW_FORM_implicit_const we need to be careful when
updating the value for a new file table. The abbrev can be used by
more than one DIE, but the value only needs to be updated once. We
use the fact that file references are positive, but an implicit_const
is signed. When updating we negate the new file number and don't update
a negative file number. Negative file numbers are made positive again when
calculating the new abbrev sizes in compute_abbrevs.
* dwz.c (write_sleb128): New macro.
(struct abbrev_tag): Add values pointer field.
(pool_clone_abbrev): New function.
(abbrev_eq2): Handle DW_FORM_implicit_const by also comparing
the value.
(compute_abbrev_hash): Likewise.
(read_abbrev): Read DW_FORM_implicit_const. Keep track of
highest_implicit_value_ndx. Allocate values.
(get_AT): Return pointer to value for DW_FORM_implicit_const.
(get_AT_int): Return value of DW_FORM_implicit_const.
(checksum_die): Get value for DW_AT_decl_file or DW_AT_call_file
from DW_FORM_implicit_const, skip for others.
(checksum_ref_die): Likewise.
(die_eq_1): Likewise.
(mark_refs): Handle DW_FORM_implicit_const.
(read_debug_info): Handle DW_FORM_implicit_const, set cu_lang
for compile/partial units.
(size_of_sleb128): New function.
(build_abbrevs_for_die): Handle DW_FORM_implicit_const value.
Use pool_clone_abbrev.
(abbrev_cmp): Also compare DW_FORM_implicit_const values.
(compute_abbrevs): Use pool_clone_abbrev. Switch any negative
file implicit_const values back before calculating size.
(write_abbrev): Also write DW_FORM_implicit_const value.
(write_die): Handle DW_FORM_implicit_const, but don't change
form/value for DW_AT_decl_file and DW_AT_call_file.
(recompute_abbrevs): Alloc space for max_nattr values, set
abbrev_tag values field.
Mark Wielaard [Mon, 14 Dec 2020 21:13:56 +0000 (22:13 +0100)]
Update dwarf.exp assembler from gdb.
Includes various fixes and features. Specifically it won't emit a block
for a DWARF expression when the version is >= 4.
The DWARF Assembler is used by invalid-dw-at-stmt-list-encoding.exp
(pr24171.sh) and no-multifile-prop.exp (pr25109.sh)
Also fix up the generated varval.S (pr24823.sh) to use DW_FORM_exprloc.
In more detail, we find the following offsets for partial units:
...
+ offsets='b
6b
da'
...
and then fail to find an import for the one at 6b:
...
++ grep -c 'DW_AT_import.*0x6b' READELF
++ true
+ imports=0
+ '[' 0 -gt 0 ']'
...
But there's actually no partial unit at 6b, the grep matches on a
DW_AT_import:
...
<6b> DW_AT_import : <0xb> [Abbrev Number: 17 (DW_TAG_partial_unit)]
...
Fix this by filtering out the DW_AT_import lines when grepping for partial
units.
2020-12-20 Tom de Vries <tdevries@suse.de>
* testsuite/dwz.tests/pr24468.sh: Fix partial unit grepping.
Mark Wielaard [Wed, 14 Oct 2020 10:30:27 +0000 (12:30 +0200)]
Fix buffer overflow in write_multifile_line.
When writing out a "header only" .debug_line we use a small static
buffer on the stack. Make sure this buffer is large enough to contain
a DWARF5 empty line table header.
ChangeLog:
* dwz.c (write_multi_line): Extend buf to 45 chars. Add assert
to check buf is large enough.
Mark Wielaard [Mon, 12 Oct 2020 14:26:28 +0000 (16:26 +0200)]
Write DWARF5 multifile .debug_line if possible.
This write version 5 .debug_line into the multifile if all .debug_line
segments seen before are also version 5. This is more efficient than
version 2, if we don't have to write out the time and size of the files.
But only if there are more than ~25 files because the header is bigger
and there is some overhead for having to handle zero entry dir and file
entries (those do have to exist, but are not directly referenced by
anything).
ChangeLog:
* dwz.c (lowest_line_version): New static unsigned int, set
to 5 initially.
(read_debug_line): Check version and set lowest_line_version.
(struct line_stats): New.
(list_line_entries): Update data as struct line_stats.
(write_multifile_line): Collect time and size stats and write
out version 5 .debug_line data if lowest_line_version is 5.
Mark Wielaard [Mon, 5 Oct 2020 15:08:24 +0000 (17:08 +0200)]
Read DWARF5 .debug_line.
This handles reading DWARF5 .debug_line just like earlier DWARF versions.
Sets file time and size to zero when not present. It skips the zero entry
file entry (which cannot be referred to from any attribute since the value
zero indicates that no source file), but does read the zero dir entry
(which can be referred to from the file index). It does not yet handle
MD5 checksums.
ChangeLog:
* dwz.c (get_DW_LNCT_str): New function.
(skip_attr_no_dw_form_indirect): Move before read_debug_line.
(read_debug_line): Handle version 5.
(read_loclist_low_mem_phase1): Remove \n from error message.
(read_loclist): Likewise.
(write_dso): Likewise.
(dwz): Likewise.
(optimize_multifile): Likewise.
Mark Wielaard [Thu, 8 Oct 2020 12:11:17 +0000 (14:11 +0200)]
Adjust pr24468.sh test-case for readelf with =follow-links.
Newer binutils readelf have =follow-links which is automatically
enabled with -w. This shows not only the debuginfo of the main file
but also that of the alt file referenced. This causes the pr24468.sh
to see "too many" DW_TAG_partial_units (from both files) which then
doesn't matches the number of DW_AT_imports. The fix is simply to
use -wi instead of -w since we are only interested in the .debug_info
DIEs anyway.
* testsuite/dwz.tests/pr24468.sh: Use readelf -wi.
Tom de Vries [Fri, 2 Oct 2020 17:04:29 +0000 (19:04 +0200)]
Fix error: Unknown DWARF DW_FORM_ref_sig8
When running the gdb testsuite using target board cc-with-dwz, I ran into:
...
dwz: cpexprs-debug-types: Unknown DWARF DW_FORM_ref_sig8
dwz: cpexprs-debug-types: Couldn't read abbrev at offset 0x64
...
I traced this back to some code in read_abbrev, which until recent was:
...
if (form == 2
|| (form > DW_FORM_flag_present && form != DW_FORM_ref_sig8))
{
error (0, 0, "%s: Unknown DWARF %s",
dso->filename, get_DW_FORM_str (form));
...
but now has been extended to:
...
if (form == 2
|| (form > DW_FORM_flag_present
&& (form != DW_FORM_ref_sig8
|| form != DW_FORM_data16
|| form != DW_FORM_line_strp)))
...
Before, form == DW_FORM_ref_sig8 didn't trigger an error because
form != DW_FORM_ref_sig8 evaluated to false.
Now, form == DW_FORM_ref_sig8 does trigger an error because
form != DW_FORM_data16 evaluates to true.
Fix by using this instead:
...
&& !(form == DW_FORM_ref_sig8
|| form == DW_FORM_data16
|| form == DW_FORM_line_strp)))
...
Mark Wielaard [Sat, 26 Sep 2020 00:13:43 +0000 (02:13 +0200)]
Support updating DWARF5 .debug_loclists.
This patch updates dwz to handle .debug_loclists as it updates .debug_locs.
Both sections can be present at the same time (if there are both DWARF5 CUs
and older DWARF CUs). So we need to keep both a loc_htab and loclists_htab.
* dwz.c (read_loclist_low_mem_phase1): Add cu as argument.
Track which section we are reading based on cu->cu_version.
Read DWARF5 loclists entries setting ptr and len up to the
start and length of the location lists to read.
(add_locexpr_dummy_dies): Pass cu to read_loclist_low_mem_phase1.
(loclists_htab): New static htab variable.
(read_loclist): Update like read_loclist_low_mem_phase1 and create
and update loclists_htab for DEBUG_LOCLISTS.
(checksum_die): Pass cu to read_loclists.
(adjust_loclists): New function like adjust_loclist for
DEBUG_LOCLISTS.
(write_loclists): New function like write_locs.
(cleanup): Delete loclists_htab.
(dwz): Call write_loclists.
Mark Wielaard [Sun, 20 Sep 2020 22:37:27 +0000 (00:37 +0200)]
Handle DW_FORM_line_strp by not moving DIE.
DW_FORM_line_strp points into a new string table .debug_line_str.
There is no supplemental .debug_line_str, so DIEs having a line_strp
form attribute cannot be moved. This isn't really a problem because
normally DW_FORM_line_strp is only used for file paths used in top-level
DW_AT_name and DW_AT_comp_dir, which wouldn't be moved anyway.
When we add support for DWARF5 line tables we might revise the decision
to keep the DW_FORM_line_strp as is since it might be advantaguous move
the dir table and file table strings into the supplemental file .debug_str
section.
* dwz.c (read_abbrev): Accept DW_FORM_line_strp.
(skip_attr_no_dw_form_indirect): Handle DW_FORM_line_strp.
(get_AT_string): Return string from DEBUG_LINE_STR for
DW_FORM_line_strp.
(checksum_die): Make DIE CK_BAD for DW_FORM_line_strp to prevent
moving.
(die_eq_1): Handle DW_FORM_line_strp.
(mark_refs): Likewise.
(read_debug_info): Likewise. Don't note string.
(build_abbrevs_for_die): Handle DW_FORM_line_strp. Keep form as is.
(write_unit_die): Write out DW_FORM_line_strp data.
(write_die): Likewise.
Mark Wielaard [Sat, 12 Sep 2020 20:57:42 +0000 (22:57 +0200)]
Handle new DWARF5 operations as their GNU extension variants.
This handles DW_OP_implicit_pointer, DW_OP_entry_value,
DW_OP_const_type, DW_OP_regval_type, DW_OP_deref_type, DW_OP_convert,
DW_OP_reinterpret as the DW_OP_GNU extensions for pre-DWARF5.
This doesn't handle the new DW_OP_addrx and DW_OP_constx which are
used with split-dwarf .debug_addr tables. Nor does it implement
DW_OP_xderef_type which gcc will never emit.
Mark Wielaard [Sun, 13 Sep 2020 21:06:09 +0000 (23:06 +0200)]
Handle new DWARF5 attributes.
There are various new attributes that can hold exprlocs (DW_AT_rank,
DW_AT_call_value, DW_AT_call_target, DW_AT_call_target_clobbered,
DW_AT_call_data_location, DW_AT_call_data_value) or hold addresses
(DW_AT_call_return_pc, DW_AT_call_pc).
Note that DW_AT_call_origin is listed as also holding exprlocs,
but that seems to be a bug in the spec:
http://dwarfstd.org/ShowIssue.php?issue=171103.1
There is a new DW_AT_macros that should work the same as DW_AT_GNU_macros.
Currently unhandled are DW_AT_dwo_name, DW_AT_str_offsets_base,
DW_AT_addr_base, DW_AT_rnglists_base and DW_AT_loclists_base which GCC
only emits when generating split-dwarf.
All other new attributes don't seem to need any special handling.
* dwz.c (add_locexpr_dummy_dies): Handle DW_AT_rank,
DW_AT_call_value, DW_AT_call_target, DW_AT_call_target_clobbered,
DW_AT_call_data_location and DW_AT_call_data_value.
(checksum_die): Handle DW_AT_call_return_pc, DW_AT_call_pc,
DW_AT_macros, DW_AT_rank, DW_AT_call_value, DW_AT_call_target,
DW_AT_call_target_clobbered, DW_AT_call_data_location,
DW_AT_call_data_value, DW_AT_call_return_pc and DW_AT_call_pc.
(die_eq_1): Handle DW_AT_call_return_pc and DW_AT_call_pc.
(read_debug_info): Recognize all new DWARF5 attributes.
(build_abbrevs_for_die): Deal with DW_AT_macros.
(write_die): Likewise. And handle DW_AT_rank, DW_AT_call_value,
DW_AT_call_target, DW_AT_call_target_clobbered,
DW_AT_call_data_location and DW_AT_call_data_value.
Mark Wielaard [Mon, 14 Sep 2020 09:19:51 +0000 (11:19 +0200)]
Handle DWARF5 headers for compile and partial units.
DWARF5 also has separate unit headers for types (replacing .debug_types)
and unit types for split-DWARF both a skeleton tree as compile and split
trees. Which aren't handled yet.
* dwz.c (get_DW_UT_str): New function.
(read_debug_line): Add .debug_line in version message error string.
(try_debug_info): Parse cu_version 5 header for DW_UT_compile and
DW_UT_partial. Add explicit error message for failing to read
abbrev.
(read_debug_info): Likewise.
Mark Wielaard [Mon, 14 Sep 2020 08:01:47 +0000 (10:01 +0200)]
Recognize some new DWARF5 .debug sections.
Recognize .debug_loclists, .debug_rnglists, .debug_line_str. loclists,
rnglists and line_str cannot be moved into a supplemental file.
We already handle .debug_macro (the replacement for .debug_macinfo).
.debug_pubnames and .debug_pubtypes are no more, but we deleted them
already when found. There is a standardized variant of .gdb_index,
.debug_names, but gdb works fine with .gdb_index even for DWARF5, so
just keep supporting .gdb_index for now.
There are two new sections .debug_addr and .debug_str_offsets which
are only emitted in split-dwarf mode by GCC. For now we don't recognize
those because we don't handle split-dwarf.
Finally there is .debug_sup which is the standardized variant of
.gnu_debugaltlink. Which we should generate when operating in "full"
DWARF5 mode. But that would require changes to some consumers.
* dwz.c (enum debug_section_kind): Add DEBUG_LOCLISTS,
DEBUG_RNGLISTS and DEBUG_LINE_STR.
(debug_sections): Add .debug_loclists, .debug_rnglists and
.debug_line_str.
Tom de Vries [Wed, 19 Feb 2020 09:50:15 +0000 (10:50 +0100)]
Add --devel-gen-cu
The DWARF standard appendix E.1 describes techniques that can be used for
compression and deduplication.
It explains that DIEs can be factored out into a PU (a compilation unit with
root DIE using DW_TAG_partial_unit), provided the PUs are then imported by
the CUs from which the DIEs where factored out. This is what dwz implements.
But it explains as well that DIEs can be factored out into a CU (a compilation
unit with root DIE using DW_TAG_compile_unit), which dwz currently doesn't
implement. This only works for DIEs that are globally visible, something
that is not generally valid, but is the case for C++. The benefit of
factoring out into CUs is that imports are not required.
Given a partition of duplication chains, if the set of originating CUs are
all C++ CUs, then use a DW_TAG_compile_unit instead of a DW_TAG_partial_unit,
and don't use imports.
We will show here the effect of the option on the cc1 benchmark:
...
$ dwz -lnone cc1 -o 1 --devel-no-uni-lang --devel-no-gen-cu
$ dwz -lnone cc1 -o 2 --devel-no-uni-lang --devel-gen-cu
$ dwz -lnone cc1 -o 3 --devel-uni-lang --devel-no-gen-cu
$ dwz -lnone cc1 -o 4 --devel-uni-lang --devel-gen-cu
...
The benchmark consists of this many CUs:
...
$ readelf -wi cc1 \
| egrep "\(DW_TAG_(compile|partial)_unit" \
| awk '{print $5}' \
| sort \
| uniq -c
695 (DW_TAG_compile_unit)
...
After normal compression, we have (file 1):
...
695 (DW_TAG_compile_unit)
4206 (DW_TAG_partial_unit)
...
Using --devel-gen-cu (file 2), we get the same result.
Using --devel-uni-lang (file 3), we get slightly less partial units:
...
695 (DW_TAG_compile_unit)
4143 (DW_TAG_partial_unit)
...
And when using both --devel-uni-lang and --devel-gen-cu (file 4), we get:
...
3820 (DW_TAG_compile_unit)
121 (DW_TAG_partial_unit)
...
Tested on-by-default, in combination with --devel-uni-lang on-by-default.
In that configuration, tested:
- regression testsuite, and
- gdb testsuite using board cc-with-dwz and cc-with-dwz-m.
With the external regression test suite, we see this regression:
...
Running src/testsuite/dwz-external.tests/dwz-external-tests.exp ...
dwz: 1: DWARF compression not beneficial - old size 69210922 new size 69428282
FAIL: src/testsuite/dwz-external.tests/pr24204.sh
...
The test-case uses cc1.dwz-processed, a cc1 binary that has already been
dwz-compressed using an older dwz. I presume the FAIL to be due to
PR25566 - "[dwz] Take reference size into account in heuristics".
2020-02-19 Tom de Vries <tdevries@suse.de>
* dwz.c (gen_cu_p): New variable.
(partition_lang): New function.
(partition_dups_1): Create compilation unit with root DIE using tag
DW_TAG_compile_unit, if allowed. Update heuristics.
(create_import_tree): Skip compilation unit with root DIE using tag
DW_TAG_compile_unit. Assert no imports are generated for such
compilation units.
(build_abbrevs_for_die): Add DW_AT_language attribute for compilation
unit root DIE using tag DW_TAG_compile_unit.
Tom de Vries [Tue, 18 Feb 2020 17:36:07 +0000 (18:36 +0100)]
Add --devel-uni-lang
Add a developer-only option --devel-uni-lang, that forces duplicate chains to
consist of DIEs from CUs with the same language.
Note when using the option, each PU root DIE has the language attribute set.
This is done to make multifile work with this option (though the attribute is
also added in regular mode). Alternatively, we could store that information
in a side table, to be kept inbetween multifile phases.
We will show here the effect of the option on the cc1 benchmark:
...
$ dwz -lnone cc1 -o 1 --devel-no-uni-lang
$ dwz -lnone cc1 -o 2 --devel-uni-lang
...
The benchmark consists of CUs with the following languages:
...
$ readelf -wi cc1 \
| grep "DW_AT_language.*:" \
| awk '{print $5, $6}' \
| sort \
| uniq -c
2 (ANSI C)
68 (ANSI C99)
622 (C++)
3 (MIPS assembler)
...
Doing the same analysis for 1 gives the same results, but for 2 we see the
additional language attributes in the PUs:
...
2 (ANSI C)
155 (ANSI C99)
2753 (C++)
3 (MIPS assembler)
...
Tested on-by-default with gdb testsuite using board cc-with-dwz and
cc-with-dwz-m.
2020-02-18 Tom de Vries <tdevries@suse.de>
* dwz.c (uni_lang_p): New var.
(checksum_die, die_eq_1): Handle uni_lang_p.
(read_debug_info): Ensure that the language attribute is read for
uni_lang_p, and for PUs.
(nr_bytes_for): New function.
(partition_dups_1): Handle uni_lang_p in heuristics.
(build_abbrevs_for_die): Add language attribute.
(write_unit_die): Handle language attribute.
(dwz_options, usage): Add --devel-uni-lang/--devel-no-uni-lang entries.
Tom de Vries [Mon, 17 Feb 2020 13:02:16 +0000 (14:02 +0100)]
Add skip_leb128
Currently we use read_uleb128 to skip over a uleb128 or sleb128 number:
...
case DW_FORM_udata:
case DW_FORM_sdata:
read_uleb128 (ptr);
...
Introduce a new macro skip_leb128, and use it instead:
...
case DW_FORM_udata:
case DW_FORM_sdata:
skip_leb128 (ptr);
...
to make it explicit that:
- we're not using the leb128 value, and
- the used call is valid for both uleb128 and sleb128.
Tom de Vries [Mon, 17 Feb 2020 11:55:51 +0000 (12:55 +0100)]
Handle DW_AT_language not encoded using DW_FORM_data{1,2}
Currently we handle DW_AT_language attributes encoded using
DW_FORM_data1 and DW_FORM_data2.
However, dwarf assembly test cases from the gdb testsuite typically use
something like this:
...
{DW_AT_language @DW_LANG_C}
...
where the '@' prefix forces encoding using DW_FORM_sdata.
The DW_FORM_sdata encoding will cause the DW_AT_language attribute to be
ignored.
Fix this by handling the DW_AT_language attribute encoded using any constant
class encoding.
2020-02-17 Tom de Vries <tdevries@suse.de>
* dwz.c (read_u16): New macro.
(read_lang): New function.
(read_debug_info): Read DW_AT_language encoded using DW_FORM_data{4,8}
and DW_FORM_{s,u}data.
Add a developer-only option --devel-deduplication-mode with values:
- none: No deduplication,
- intra-cu: Deduplication of DIEs in the same CU, and
- inter-cu: Deduplication of DIEs, also if they're in different CUs.
2020-02-14 Tom de Vries <tdevries@suse.de>
* dwz.c (enum deduplication_mode): New enum.
(deduplication_mode): New var. Initialize to dm_inter_cu.
(partition_dups_1): Use deduplication_mode.
(deduplication_mode_parsed): New var.
(dwz_options, usage): Add --devel-deduplication-mode entry.
(main): Handle deduplication_mode_parsed.
Tom de Vries [Thu, 13 Feb 2020 17:59:29 +0000 (18:59 +0100)]
[odr] Guard odr code with odr_active_p
The odr optimization is enabled by the odr variable.
When enabled, some DIEs will get an die_odr_state of ODR_DEF or ODR_DECL,
which is then handled further by code guarded with odr.
However, it may be the case that all DIEs were marked with ODR_NONE, because:
- read_debug_info was run in low-mem mode, or
- read_debug_info was run in optimize-multifile mode, or
- there were no DIEs for which the optimization was applicable.
If all DIEs were marked with ODR_NONE, there is no point in entering further
odr handling code.
Add a variable odr_active_p that is set to true when at least one DIE has an
die_odr_state that is not ODR_NONE, and use the variable to guard some odr code.
2020-02-13 Tom de Vries <tdevries@suse.de>
* dwz.c (odr_active_p): New var.
(set_die_odr_state): Set odr_active_p to true.
(read_debug_info): Initialize odr_active_p to false.
(partition_dups_1, partition_dups): Use odr_active_p instead of odr.
Tom de Vries [Thu, 13 Feb 2020 14:10:25 +0000 (15:10 +0100)]
Add --devel-force
We can have the following message from dwz:
...
$ dwz a.out
dwz: a.out: DWARF compression not beneficial \
- old size 69158054 new size 69158333
...
Given that the compression is not beneficial, no output is generated. However,
it may be interesting to have a look at the output, to understand why the
compression is not beneficial.
Add a developer-only option --devel-force that forces generation of output,
even if compression is not beneficial.
ChangeLog:
2020-02-13 Tom de Vries <tdevries@suse.de>
* dwz.c (force_p): New var.
(dwz): Use force_p.
(dwz_options, usage): Add --devel-force entry.
Tom de Vries [Thu, 13 Feb 2020 14:10:25 +0000 (15:10 +0100)]
Rewrite write_unit_die using loop
In write_unit_die, we currently handle attributes by testing if an attribute
is present at a hardcoded location:
...
if (t->attr[0].attr == DW_AT_stmt_list)
...
Rewrite write_unit_die to use a loop over attributes instead, where we handle
each attribute according to its type, independent of the location.
2020-02-11 Tom de Vries <tdevries@suse.de>
* dwz.c (write_unit_die): Rewrite into a loop over attributes.
Tom de Vries [Sat, 25 Jan 2020 22:34:48 +0000 (23:34 +0100)]
Add --import-optimize/--no-import-optimize
The function create_import_tree attempts to reduce the number of
DW_TAG_imported_unit DIEs.
Add command line options --import-optimize/--no-opt-importize to control this
optimization.
2020-01-24 Tom de Vries <tdevries@suse.de>
* dwz.1: Add --import-optimize/--no-import-optimize entry.
* dwz.c (import_opt_p): New variable.
(create_import_tree): Move freeing of seen variable to ASAP instead
of ALAP. Guard optimization part with import_opt_p.
(dwz_options, dwz_common_options_help): Add
--import-optimize/--no-import-optimize.
Tom de Vries [Fri, 24 Jan 2020 16:49:47 +0000 (17:49 +0100)]
Fix segfault in die_cu
When running dwz in normal mode, we get an error:
...
$ dwz clang-offload-bundler-10.debug -lnone
dwz: clang-offload-bundler-10.debug: Couldn't find DIE referenced by \
DW_OP_GNU_implicit_pointer
...
but when forcing low-mem mode, we get a segfault:
...
$ dwz clang-offload-bundler-10.debug -l0
Segmentation fault (core dumped)
...
In normal mode, we hit the error here:
...
ref = off_htab_lookup (NULL, addr);
if (ref == NULL)
{
error (0, 0, "%s: Couldn't find DIE referenced by %s",
dso->filename, get_DW_OP_str (op));
...
but for low-mem mode, this doesn't trigger, because we find the dummy DIE that
has been added by read_exprloc_low_mem_phase1.
Fix this by testing for the dummy DIE in the error condition:
...
- if (ref == NULL)
+ if (ref == NULL || (unlikely (low_mem) && ref->die_tag == 0))
...
2020-01-24 Tom de Vries <tdevries@suse.de>
PR dwz/25456
* dwz.c (read_exprloc): Test for dummy DIE in error condition.
Tom de Vries [Fri, 24 Jan 2020 10:35:09 +0000 (11:35 +0100)]
Simplify --odr/--no-odr parsing
The --odr and --no-odr flags are currently setting odr_parsed and no_odr_parsed
variables, which in turn trigger setting the odr variable.
Simplify this by having the --odr and --no-odr flags set the odr variable
directly.
2020-01-24 Tom de Vries <tdevries@suse.de>
(odr_parsed, no_odr_parsed): Remove variables.
(dwz_options): Use odr variable in --odr and --no-odr entries.
* dwz.c (main): Remove handling of odr_parsed and no_odr_parsed.
Tom de Vries [Tue, 21 Jan 2020 15:00:35 +0000 (16:00 +0100)]
Also call mark_singletons for merged singleton die
When using --odr-mode=link, after splitting up an odr duplicate chain, if we
have an ODR_DECL chain and one or more ODR_DEF chains, we merge the ODR_DECL
chain with the first ODR_DEF chain.
If that ODR_DEF chain was a singleton chain, it's no longer called with
mark_singletons, while that is still necessary.
Fix this by detecting merged singleton DIEs and calling mark_singletons.
2020-01-21 Tom de Vries <tdevries@suse.de>
PR dwz/25424
* dwz.c (merged_singleton): New function.
(partition_dups): Call mark_singletons for merged_singleton die.
Tom de Vries [Mon, 20 Jan 2020 15:17:33 +0000 (16:17 +0100)]
Fix reference from PU to CU (--odr-mode=basic)
The function partition_dups is executed in two phases. In phase 1 we decide
which DIEs we want to move into partial units because it looks profitable,
and in phase 2 we find which DIEs we have to move into partial units because
they are referenced by other DIEs already in partial units.
The process of splitting an odr duplicate chain (before phase 1) can result
in some of the DIEs not being part of any duplicate chain afterwards. If
such a DIE is marked as referenced in phase 2, it won't be moved to a partial
unit, causing a reference from PU to CU.
Fix this by making sure that all the elements of an odr duplicate chain are
part of a duplicate chain after splitting, even if that is a chain of length
one (which we call a singleton). Also make sure that all other singleton DIEs
referenced from singleton DIEs are added as duplicate chain.
The fix means that split_dups no longer returns NULL, which allows some
simplification in partition_dups, but we'll deal with that in a follow-up
patch, to keep this patch shorter and clearer.
2020-01-20 Tom de Vries <tdevries@suse.de>
PR dwz/25411
* dwz.c (mark_singletons): New function.
(split_dups): Add singleton DIE as duplicate chain.
(reset_die_ref_seen): New function.
(partition_dups): Call reset_die_ref_seen. Set reset_die_ref to 1 for
singleton DIEs. Call mark_singletons for singleton DIEs.
Tom de Vries [Mon, 20 Jan 2020 15:17:33 +0000 (16:17 +0100)]
Verify that head of dup-chain is not removed
Check in verify_dups that the head of a duplicate chain has the die_removed
field set to 0, and fix resulting verification failure in split_dups.
Tested with verify_dups_p set on by default.
2020-01-20 Tom de Vries <tdevries@suse.de>
* dwz.c (verify_dups): Check that the head of a duplicate chain has the
die_removed field set to 0.
(split_dups): Make sure that the head of a duplicate chain has the
die_removed field set to 0.
Tom de Vries [Thu, 16 Jan 2020 14:16:59 +0000 (15:16 +0100)]
Fix reference from PU to CU
Consider the following situation:
- we have two duplicate chains: {A, B} and {C, D, E}
- each duplicate chain has a representant: A' and C'
- there's a pseudo-ref from Z to D, which is using one of the CU-local dwarf
operators DW_OP_GNU_{{regval,deref,const}_type,convert,reinterpret} (which
is summarized in the code by setting D->die_op_type_referenced).
Schematically this looks like this:
...
(A') --------d-------> (A) --d--> (B)
| |
r r
| |
v v
(C') --d--> (C) --d--> (D) --d--> (E)
^
|
pr
|
(Z)
...
Because the die D is referenced using a CU-local dwarf operator, the die is
kept in the CU (even though it's part of a duplicate chain), to keep the
pseudo-ref valid. Also other CU-local refs to D keep pointing to D.
A situation however arises while writing out A' to a partial unit using A as
template, when we try to write out the reference to D, and arrive here in
in write_die with die == A', ref == A, refd == D and refdt == D:
...
if (refdt->die_dup && refdt->die_op_type_referenced)
{
if (cu == die_cu (refdt->die_dup))
refd = die_find_dup (refdt, refdt->die_dup, refd);
}
else if (refdt->die_dup)
refd = die_find_dup (refdt, refdt->die_dup, refd);
...
The first if condition evaluates to true because D->die_dup == C' and
D->die_op_type_referenced == 1.
But the following (nested) if condition evalutes to false, because A' and C'
are not part of the same unit.
Consequently, refd remains D, and we get a reference from a die in a partial
unit (A') to a die in a compilation unit (D):
...
(A') --------d--------> (A) --d--> (B)
\ | |
+---------------+ r r
\ | |
v v v
(C') --d--> (C) --d--> (D) ---d--> (E)
^
|
pr
|
(Z)
...
The behaviour that is triggered is one that is valid for writing out A, but is
incorrect because in fact we're writing out A' using A as template. Note that
this problem would not have occurred if the pseudo-reference pointed to E
instead, in which case we would have had the expected reference from A' to C'.
Fix this by detecting that we're writing out A' (in other words,
cu->cu_kind == CU_PU), and skipping the die_op_type_referenced
handling in that case, resulting in a reference from A' to C'.
Tom de Vries [Wed, 8 Jan 2020 13:41:58 +0000 (14:41 +0100)]
Fix get_name in low-mem mode
When using --devel-dump-dups in low-mem mode for benchmark cc1 I run into a
segfault:
...
$ dwz cc1 -o 1 -l0 --devel-dump-dups
...
Segmentation fault (core dumped)
...
The segfault happens in get_AT (called from get_AT_string, called from
get_name) due to trying to access invalidated fields in a DIE with
die_collapsed_child set.
Fix this by handling die_collapsed_child DIEs in get_name.
Tom de Vries [Tue, 7 Jan 2020 14:09:08 +0000 (15:09 +0100)]
Cache file name property in struct dw_file
When profiling with benchmark clang-10, we observe a hotspot in the strlen
call in die_eq_1:
...
│ file_len = strlen (cu_file1->file);
│ or $0xffffffffffffffff,%rcx
0,01 │ mov %r15,%rdi
│ if (cu_file1->dir != NULL)
0,01 │ mov 0x0(%r13),%r13
│ file_len = strlen (cu_file1->file);
26,24 │ repnz scas %es:(%rdi),%al
3,16 │ mov 0x58(%rsp),%r10
...
That is, 29.4% of the time spent in die_eq_1 is spent in this strlen call
(while 23.10% of the overall time is spent in die_eq_1).
The file_len variable is used to calculate a more complex property of the
filename:
...
else if (cu_file1->file[0] == '<'
&& cu_file1->file[file_len - 1] == '>'
&& strchr (cu_file1->file, '/') == NULL
...
which is also calculated in checksum_die.
Cache the property in a new struct dw_file field named
file_angle_brackets_encapsulated_no_slash, and used it in both checksum_die
and die_eq_1.
In particular, with --devel-progress we observe going from:
...
partition_dups split_dups
user: 94.50
sys : 0.16
...
to:
...
partition_dups split_dups
user: 74.44
sys : 0.01
...
which is a reduction of 21.2%.
2020-01-07 Tom de Vries <tdevries@suse.de>
* dwz.c (struct dw_file): Add field
file_angle_brackets_encapsulated_no_slash.
(read_debug_line): Initialize new field.
(checksum_die, eq_1): Use new field.
Tom de Vries [Mon, 6 Jan 2020 15:22:11 +0000 (16:22 +0100)]
[odr, testsuite] Add odr-def-decl.sh
Add a test-case to trigger reorder_dups.
2020-01-06 Tom de Vries <tdevries@suse.de>
* Makefile (def-decl): New target.
(TEST_EXECS): Add def-decl.
* testsuite/dwz.tests/decl.c: New test.
* testsuite/dwz.tests/def.c: New test.
* testsuite/dwz.tests/def.h: New test.
* testsuite/dwz.tests/def2.c: New test.
* testsuite/dwz.tests/odr-def-decl.sh: New test.
Tom de Vries [Mon, 6 Jan 2020 15:22:11 +0000 (16:22 +0100)]
[odr, testsuite] Add test-case odr-loc.sh
Add a test-case that tests whether --odr works in conjunction with
--devel-ignore-locus.
2020-01-06 Tom de Vries <tdevries@suse.de>
* Makefile (odr-loc): New target.
(TEST_EXECS): Add odr-loc.
* testsuite/dwz.tests/odr-loc-2.cc: New test.
* testsuite/dwz.tests/odr-loc.cc: New test.
* testsuite/dwz.tests/odr-loc.sh: New test.
Add basic --odr test-cases, for struct, class and union, both inside and
outside a namespace.
2020-01-06 Tom de Vries <tdevries@suse.de>
* Makefile (odr-struct, odr-union, odr-class, odr-struct-ns)
(odr-union-ns, odr-class-ns): Add new target.
(TEST_EXECS): Add new targets.
* testsuite/dwz.tests/odr-2.cc: New test.
* testsuite/dwz.tests/odr-class-ns.sh: New test.
* testsuite/dwz.tests/odr-class.sh: New test.
* testsuite/dwz.tests/odr-struct-ns.sh: New test.
* testsuite/dwz.tests/odr-struct.sh: New test.
* testsuite/dwz.tests/odr-union-ns.sh: New test.
* testsuite/dwz.tests/odr-union.sh: New test.
* testsuite/dwz.tests/odr.cc: New test.
* testsuite/dwz.tests/odr.h: New test.