]> sourceware.org Git - dwz.git/log
dwz.git
3 years agoBump version to 0.14 dwz-0.14
Tom de Vries [Mon, 8 Mar 2021 07:49:46 +0000 (08:49 +0100)]
Bump version to 0.14

3 years ago[testsuite] Fix odr-loc.sh with -gdwarf-5
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.

3 years agoFix .debug_line reference above end of section
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.

3 years agoClean up temporary file in hardlink mode
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.

3 years agoRemove dead code in function dwz
Tom de Vries [Thu, 4 Mar 2021 08:02:30 +0000 (09:02 +0100)]
Remove dead code in function dwz

Function dwz contains this code:
...
  free (dso);
  if (ret == 0 && !low_mem)
    res->res = 0;
...

The value of low_mem will always be false here.  At that point, cleanup has
been called, which resets multifile_mode back to 0.

Fix this by removing the "&& !low_mem".

2021-03-02  Tom de Vries  <tdevries@suse.de>

* dwz.c (dwz): Remove dead code.

3 years agoFix assert after goto failure
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.

3 years agoDocument experimental status of odr
Tom de Vries [Sat, 27 Feb 2021 10:34:55 +0000 (11:34 +0100)]
Document experimental status of odr

Add documentation of the experimental status of the odr optimization in dwz.1.

2021-02-25  Tom de Vries  <tdevries@suse.de>

PR dwz/27401
* dwz.1: Document experimental status of odr.

3 years agoAdd assert checking that CU is not referenced from PU
Tom de Vries [Sat, 27 Feb 2021 10:34:55 +0000 (11:34 +0100)]
Add assert checking that CU is not referenced from PU

One of the invariants of dwz is that references from a newly created PU can
only reference other PUs.

Add an assert that checks this.

2021-02-25  Tom de Vries  <tdevries@suse.de>

* dwz.c (write_die): Add assert.

3 years agoFix reference of PU to CU for odr
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 b500801d 621b6872  pointer_type \
   (type: 28dd72f die_struct structure_type)
 2903769 O b500801d 621b6872  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.

2021-02-25  Tom de Vries  <tdevries@suse.de>

PR dwz/27464
* dwz.c (partition_dups): Call mark_singletons if
cnt_ref_cus (die) == 1.

3 years agoCall reorder_dups ASAP
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)
  {
...

2020-01-25  Tom de Vries  <tdevries@suse.de>

PR dwz/25424
* dwz.c (partition_dups_1): Move calling of reorder_dups ...
(partition_dups): ... here.

3 years agoPrecompute partitions
Tom de Vries [Sat, 27 Feb 2021 10:34:55 +0000 (11:34 +0100)]
Precompute partitions

Currently, we calculate the duplicate chain partitions in partition_dups_1.
This is done twice, once for phase 1 and once for phase 2.

Instead, calculate the partitions once in partition_dups, and use those for
both calls to partition_dups_1.

Performance tested on cc1.  This causes a small performance regresssion:
...
user:
series:  5140 5100 5120 5130 5150 5160 5160 5180 5170 5130 \
         5180 5160 5090 5230 5140 5140 5210 5100 5170 5130
mean:  5149.50 (100%)
stddev:  35.46
series:  5120 5190 5230 5190 5200 5160 5170 5210 5270 5180 \
         5270 5240 5200 5200 5200 5170 5150 5220 5180 5140
mean:  5194.50 (100.87%)
stddev:  39.13
...

There's no significant increase of memory usage:
...
mem:
series:  1260512 1260456 1260492 1260368 1260608 1260268 1260656 1260488 \
         1260420 1260332 1260464 1260488 1260536 1260340 1260352 1260492 \
         1260268 1260276 1260316 1260316
mean:  1260422.40 (100%)
stddev:  113.73
series:  1260456 1260296 1260244 1260360 1260584 1260344 1260548 1260388 \
         1260424 1260304 1260252 1260560 1260664 1260476 1260480 1260416 \
         1260580 1260504 1260604 1260324
mean:  1260440.40 (100.00%)
...

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.

3 years agoPR27463 Accept DW_FORM_sdata for DW_AT_decl/call_file
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.

https://sourceware.org/bugzilla/show_bug.cgi?id=27463

3 years ago[testsuite] Fix pr25109.sh on riscv64
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.

2021-02-26  Tom de Vries  <tdevries@suse.de>

* Makefile (no-multifile-prop): Add target rule.
* testsuite/dwz.tests/dwz-tests.exp: Require no-multifile-prop for
pr25109.sh.

3 years agoUpdate SUSE Copyright years
Tom de Vries [Fri, 26 Feb 2021 08:42:25 +0000 (09:42 +0100)]
Update SUSE Copyright years

Update the SUSE copyright range for changes made in 2020 and 2021.

2021-02-26  Tom de Vries  <tdevries@suse.de>

* dwz.c: Extend SUSE Copyright range to 2021.
* COPYRIGHT_YEARS: Regenerate.

3 years agoFactor out same_ref_cus_p and cnt_ref_cus
Tom de Vries [Thu, 25 Feb 2021 09:40:38 +0000 (10:40 +0100)]
Factor out same_ref_cus_p and cnt_ref_cus

Factor out new functions same_ref_cus_p and cnt_ref_cus out of
partition_dups_1.

Performance tested with cc1, no regression found.

2021-02-25  Tom de Vries  <tdevries@suse.de>

* dwz.c (same_ref_cus_p, cnt_ref_cus): New function, factored out
of ...
(partition_dups_1): ... here.

3 years agoFix DW_AT_decl_file for odr
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 multifile looks good:
...
$ readelf -wi 3 \
    | egrep -A2 "DW_TAG_structure" \
    | egrep "DW_TAG|DW_AT_name|DW_AT_decl"
 <1><14>: Abbrev Number: 15 (DW_TAG_structure_type)
    <15>   DW_AT_name        : ccc
 <1><2a>: Abbrev Number: 15 (DW_TAG_structure_type)
    <2b>   DW_AT_name        : aaa
 <1><46>: Abbrev Number: 15 (DW_TAG_structure_type)
    <47>   DW_AT_name        : bbb
...
but some struct types are left in 1:
...
$ readelf -wi 1 \
    | egrep -A2 "DW_TAG_structure" \
    | egrep "DW_TAG|DW_AT_name|DW_AT_decl"
 <1><1e>: Abbrev Number: 12 (DW_TAG_structure_type)
    <1f>   DW_AT_name        : aaa
 <1><3d>: Abbrev Number: 12 (DW_TAG_structure_type)
    <3e>   DW_AT_name        : bbb
...

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.

3 years agoClean up die_odr_state interface
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;

  set_die_odr_state (cu, die);
  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.

3 years agoDon't print die_hash2 for ODR_UNKNOWN in dump_die_with_indent
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.

3 years agoDon't call die_odr_state with unnecessarily defined cu arg
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.

3 years agoFix CK_BAD propagation for --odr
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%    111527248  61527733
.debug_abbrev    red: 40.28%    1722726  1028968
.debug_str       red: 0%        6609355  6609355
total            red: 42.30%    119859329 69166056
...
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%    111527248  47449258
.debug_abbrev    red: 75.08%    1722726  429434
.debug_str       red: 0%        6609355  6609355
total            red: 54.55%    119859329 54488047
...
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%    111527248  47446501
.debug_abbrev    red: 75.51%    1722726  422027
.debug_str       red: 0%        6609355  6609355
total            red: 54.55%    119859329 54477883
...

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.

3 years agoAdd .gitignore
Tom Tromey [Sun, 21 Feb 2021 02:13:39 +0000 (19:13 -0700)]
Add .gitignore

This adds a basic .gitignore.

3 years agoPrint --version and --help to stdout
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.

3 years agoman page: Clarify DWARF 5 support after addition of --dwarf-5 option
Jakub Jelinek [Sat, 20 Feb 2021 10:22:46 +0000 (11:22 +0100)]
man page: Clarify DWARF 5 support after addition of --dwarf-5 option

* dwz.1: Clarify DWARF 5 support after addition of --dwarf-5
option.

3 years agoPR27440 - add --dwarf-5 support
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.

3 years agoDon't handle blocks as exprlocs for DWARF version 4 or higher.
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.

https://sourceware.org/bugzilla/show_bug.cgi?id=26987

3 years agoPR27402 Document DWARF5 support
Mark Wielaard [Fri, 12 Feb 2021 13:11:29 +0000 (14:11 +0100)]
PR27402 Document DWARF5 support

* dwz.1: Explain what subset of DWARF5 is supported, update date,
authors and add a reference to the dwz home page and mailinglist.

3 years agoAdd assert in partition_found_dups
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 d27b2f2a d27b2f2a  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 9d6524b4 9d6524b4 _Any_data union_type
...
while without --odr, it does:
...
   9edc X d8f947f3 5100c9e1 _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.

3 years agoAdd --devel-dump-checksum
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.

3 years agoPrint die_hash2 for --odr --devel-dump-dies
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(cd46c7abf56004ac aaa structure_type
  ...
  1ba O f56004ac(cd46c7abf56004ac aaa structure_type
...

Used to debug PR27400.

2021-02-15  Tom de Vries  <tdevries@suse.de>

* dwz.c (dump_die_with_indent): Print die->u.p1.die_hash2.

3 years ago[testsuite] Fix compile warnings for def-decl with clang
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.

2021-02-16  Tom de Vries  <tdevries@suse.de>

* testsuite/dwz.tests/decl.c: Rename to .cc.
* testsuite/dwz.tests/def.c: Same.
* testsuite/dwz.tests/def2.c: Same.
* Makefile (def-decl): Update source file names.

3 years ago[testsuite] Fix odr tests with clang
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;
};

struct aaa
{
  struct bbb *member_one;
  struct ccc *member_two;
};

struct aaa var1;
...
it ignores the definition of struct ccc, and therefore only has a
DW_AT_declaration DIE for ccc.

Fix this by adding variables for the type definitions that are ignored by
clang.

2021-02-16  Tom de Vries  <tdevries@suse.de>

* testsuite/dwz.tests/def2.c (foo): New function.  Allocate ao_ref.
* testsuite/dwz.tests/odr-def-decl.sh: Update expected counts.
* testsuite/dwz.tests/odr-2.cc: Add var.
* testsuite/dwz.tests/odr-loc-2.cc: Same.
* testsuite/dwz.tests/odr-loc.cc:  Same.
* testsuite/dwz.tests/odr.cc: Same.

3 years agoAdd attribute to checksum for DW_FORM_implicit_const
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.

3 years agoRemove left over "negate" adjustment in compute_abbrevs.
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.

3 years agoHandle DW_FORM_implicit_const for DW_AT_decl_line
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.

3 years agoSupport DW_LANG_C_plus_plus_{03,11,14}
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}.

3 years agoUpdate FSF Copyright years to include 2021.
Mark Wielaard [Fri, 12 Feb 2021 12:26:59 +0000 (13:26 +0100)]
Update FSF Copyright years to include 2021.

This should have been done as part of commit f7c0d8afb
"Sync dwarf2.{def,h} and dwarfnames.c from gcc/libiberty."

3 years ago[testsuite] Fix tcl error in dwz-tests.exp
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.

3 years agoBail out for unhandled dwarf-5 CU type
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.

3 years agoAllow .debug_macro section with version 5
Tom de Vries [Tue, 9 Feb 2021 07:31:59 +0000 (08:31 +0100)]
Allow .debug_macro section with version 5

With this executable:
...
$ gcc -ggdb3 -gdwarf-5 hello.c
...
we run into:
...
$ cp a.out 1; cp 1 2; ./dwz-for-test -m 3 1 2
./dwz-for-test: 1: Unhandled .debug_macro version 5
./dwz-for-test: 2: Unhandled .debug_macro version 5
./dwz-for-test: No suitable DWARF found for multifile optimization
...

Fix this by allowing version 5 when reading .debug_macro.

2021-02-09  Tom de Vries  <tdevries@suse.de>

PR dwz/27368
* dwz.c (read_macro): Allow version 5 .debug_macro.

3 years agoSync dwarf2.{def,h} and dwarfnames.c from gcc/libiberty.
Mark Wielaard [Sat, 6 Feb 2021 14:15:12 +0000 (15:15 +0100)]
Sync dwarf2.{def,h} and dwarfnames.c from gcc/libiberty.

* dwarf2.def: Synced.
* dwarf2.h: Likewise.
* dwarfnames.c: Likewise.
* dwz.c (get_DW_AT_str): Use get_DW_AT_name.

https://sourceware.org/bugzilla/show_bug.cgi?id=27357

3 years agoDWZ aborted "write_types: Assertion `ref && ref->die_dup == NULL'"
Alok Kumar Sharma [Mon, 1 Feb 2021 18:27:51 +0000 (23:57 +0530)]
DWZ aborted "write_types: Assertion `ref && ref->die_dup == NULL'"

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'.

3 years ago[testsuite] Fix make check CC="gcc -m32"
Tom de Vries [Wed, 3 Feb 2021 10:12:05 +0000 (11:12 +0100)]
[testsuite] Fix make check CC="gcc -m32"

When running:
...
$ make check CC="gcc -m32"
...
we run into:
...
gcc -m32 py-section-script.s -o py-section-script -g
py-section-script.s: Assembler messages:
py-section-script.s:53: Error: bad register name `%rbp'
  ...
make[1]: *** [Makefile:50: py-section-script] Error 1
...

Fix this by adding "|| touch $@" in the Makefile rule for this test-case (and
a few others), which makes the test unsupported.

2021-02-03  Tom de Vries  <tdevries@suse.de>

* Makefile (dw2-skip-prologue, py-section-script)
(implptr-64bit-d2o4a8r8t0): Add "|| touch $@".

3 years agoAdd DIE offsets in error messages to make it easier to find what is wrong.
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.

3 years agoDon't crash on DWARF5 .debug_line table with zero files.
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).

https://bugzilla.redhat.com/show_bug.cgi?id=1919243

3 years agoAssorted DW_FORM_implicit_const fixes
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.

3 years agoUpdate Copyright years.
Mark Wielaard [Mon, 18 Jan 2021 09:08:45 +0000 (10:08 +0100)]
Update Copyright years.

Updated the RH copyright range for changes made in 2020 and 2021.

* COPYRIGHT_YEARS (RH_YEARS): Set to 2001-2021.
* dwz.c: Extend Copyright range to 2021.

3 years agoBreak out of while loop correctly to make sure loclists are adjusted.
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.

3 years agoHandle DW_FORM_implicit_const
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.

3 years ago[testsuite] Detect when devel-ignore-size.sh is unsupported
Tom de Vries [Mon, 4 Jan 2021 09:06:32 +0000 (10:06 +0100)]
[testsuite] Detect when devel-ignore-size.sh is unsupported

In PR27115, a failure of devel-ignore-size.sh is reported.

The test-case:
- tries to transform an executable
- checks that it didn't transform
- retries using --devel-ignore-size
- check that it did transform

The reported failure is in the second step.

Fix this by marking the test unsupported if the second step fails.

2021-01-04  Tom de Vries  <tdevries@suse.de>

PR dwz/27115
* testsuite/dwz.tests/devel-ignore-size.sh: If exec is transformed
without --devel-ignore-size, mark unsupported.

3 years agoUpdate dwarf.exp assembler from gdb.
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.

3 years ago[testsuite] Fix partial unit grepping in pr24468.sh
Tom de Vries [Sun, 20 Dec 2020 07:50:51 +0000 (08:50 +0100)]
[testsuite] Fix partial unit grepping in pr24468.sh

I'm running into:
...
FAIL: src/testsuite/dwz.tests/pr24468.sh
...

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.

4 years agoFix buffer overflow in write_multifile_line.
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.

4 years agoWrite DWARF5 multifile .debug_line if possible.
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.

4 years agoRead DWARF5 .debug_line.
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.

4 years agoAdjust pr24468.sh test-case for readelf with =follow-links.
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.

4 years agoFix error: Unknown DWARF DW_FORM_ref_sig8
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)))
...

Tested dwz testsuite, and cpexprs-debug-types.

2020-10-02  Tom de Vries  <tdevries@suse.de>

* dwz.c (read_abbrev): Fix "Unknown DWARF DW_FORM_ref_sig8" error.

4 years agoSupport updating DWARF5 .debug_loclists.
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.

4 years agoHandle DW_FORM_line_strp by not moving DIE.
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.

4 years agoHandle DW_FORM_data16.
Mark Wielaard [Sat, 19 Sep 2020 23:12:03 +0000 (01:12 +0200)]
Handle DW_FORM_data16.

This is a simple form to handle, it just encodes 16 bytes of DIE data.

* dwz.c (read_abbrev): Accept DW_FORM_data16.
(skip_attr_no_dw_form_indirect): Handle DW_FORM_data16.
(checksum_die): Likewise.
(checksum_ref_die): Likewise.
(die_eq_1): Likewise.
(mark_refs): Likewise.
(read_debug_info): Likewise.
(build_abbrevs_for_die): Likewise.
(DW_FORM_ref_sig8): Likewise.

4 years agoCalculate size and write correct DWARF5 compile and partial unit headers.
Mark Wielaard [Tue, 22 Sep 2020 23:48:39 +0000 (01:48 +0200)]
Calculate size and write correct DWARF5 compile and partial unit headers.

* dwz.c (try_debug_info): Add header size check for cu_version 5.
(read_debug_info): Likewise.
(partition_dups_1): Add 1 to pu_size for cu_version 5.
(create_import_tree): Include header_size, 13 or 14 depending on
cu_version, in cost comparision.
(compute_abbrevs): Adjust headersz depending on cu_version.
(recompute_abbrevs): Likewise.
(write_info): Write cu_version 5 unit type.

4 years agoHandle new DWARF5 operations as their GNU extension variants.
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.

* dwz.c (read_exprloc): Handle DW_OP_implicit_pointer,
DW_OP_entry_value, DW_OP_convert, DW_OP_reinterpret,
DW_OP_regval_type, DW_OP_const_type and DW_OP_deref_type.
(read_exprloc_low_mem_phase1): Likewise.
(adjust_exprloc): Likewise.

4 years agoHandle new DWARF5 attributes.
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.

4 years agoHandle DWARF5 headers for compile and partial units.
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.

4 years agoRecognize some new DWARF5 .debug sections.
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.

4 years agoAdd --devel-gen-cu
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)
...

The size effect for this example seems to be in the noise range:
...
$ diff.sh cc1 1
.debug_info      red: 44.84%    111527248  61527733
.debug_abbrev    red: 40.28%    1722726  1028968
.debug_str       red: 0%        6609355  6609355
total            red: 42.30%    119859329 69166056
$ diff.sh cc1 2
.debug_info      red: 44.84%    111527248  61527733
.debug_abbrev    red: 40.28%    1722726  1028968
.debug_str       red: 0%        6609355  6609355
total            red: 42.30%    119859329 69166056
$ diff.sh cc1 3
.debug_info      red: 44.84%    111527248  61521767
.debug_abbrev    red: 39.99%    1722726  1033916
.debug_str       red: 0%        6609355  6609355
total            red: 42.30%    119859329 69165038
$ diff.sh cc1 4
.debug_info      red: 44.89%    111527248  61463616
.debug_abbrev    red: 40.20%    1722726  1030280
.debug_str       red: 0%        6609355  6609355
total            red: 42.35%    119859329 69103251
...

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.

4 years agoAdd --devel-uni-lang
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)
...

The size effect for this example seems to be in the noise range:
...
$ diff.sh cc1 1
.debug_info      red: 44.84%    111527248  61527733
.debug_abbrev    red: 40.28%    1722726  1028968
.debug_str       red: 0%        6609355  6609355
total            red: 42.30%    119859329 69166056
$ diff.sh cc1 2
.debug_info      red: 44.84%    111527248  61521767
.debug_abbrev    red: 39.99%    1722726  1033916
.debug_str       red: 0%        6609355  6609355
total            red: 42.30%    119859329 69165038
...

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.

4 years agoAdd skip_leb128
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.

2020-02-17  Tom de Vries  <tdevries@suse.de>

* dwz.c (skip_leb128): New macro.
(read_abbrev): Replace call to read_uleb128 with ignored result by
call to skip_leb128.
(read_debug_line): Same.
(skip_attr_no_dw_form_indirect): Same.
(get_AT): Same.
(read_exprloc): Same.
(read_exprloc_low_mem_phase1): Same.
(set_die_odr_state): Same.
(checksum_die): Same.
(checksum_ref_die): Same.
(expand_child): Same.
(die_eq_1): Same.
(mark_refs): Same.
(read_debug_info): Same.
(mark_singletons): Same.
(macro_eq): Same.
(read_macro): Same.
(optimize_write_macro): Same.
(handle_macro): Same.
(write_macro): Same.
(build_abbrevs_for_die): Same.
(adjust_exprloc): Same.
(write_die): Same.
(propagate_multifile_refs_backward): Same.

4 years agoHandle DW_AT_language not encoded using DW_FORM_data{1,2}
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.

4 years ago[odr] Disable --odr by default
Tom de Vries [Fri, 14 Feb 2020 15:44:54 +0000 (16:44 +0100)]
[odr] Disable --odr by default

With a few PRs open related to odr, it seems prudent to change the default to
disabled till we sort those out.

2020-02-14  Tom de Vries  <tdevries@suse.de>

* dwz.1: Update --odr/--no-odr default to disabled.
* dwz.c (odr): Initalize to 0.
(dwz_common_options_help): Update --odr/--no-odr default to disabled.

4 years agoAdd --devel-deduplication-mode={none,intra-cu,inter-cu}
Tom de Vries [Fri, 14 Feb 2020 14:27:06 +0000 (15:27 +0100)]
Add --devel-deduplication-mode={none,intra-cu,inter-cu}

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.

4 years agoSpecify pu_size initialization constant in more detail
Tom de Vries [Fri, 14 Feb 2020 11:30:45 +0000 (12:30 +0100)]
Specify pu_size initialization constant in more detail

The variable pu_size in partition_dups_1 is initialized to constant 21.

Specify that constant in more detail.

2020-02-14  Tom de Vries  <tdevries@suse.de>

* dwz.c (partition_dups_1): Make initialization of pu_size to 21 more
detailed.

4 years ago[odr] Guard odr code with odr_active_p
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.

4 years agoFix --import-optimize/--no-import-optimize
Tom de Vries [Thu, 13 Feb 2020 14:27:10 +0000 (15:27 +0100)]
Fix --import-optimize/--no-import-optimize

Commit 50c5518 "Add --import-optimize/--no-import-optimize" actually
introduced --import-optimization/--no-import-optimization:
...
$ dwz hello --import-optimize 2>/dev/null; echo $?
1
$ dwz hello --import-optimization 2>/dev/null; echo $?
0
...

Fix this by making dwz accepting --import-optimize:
...
$ dwz hello --import-optimize 2>/dev/null; echo $?
0
...

2020-02-13  Tom de Vries  <tdevries@suse.de>

* dwz.c (dwz_options, dwz_common_options_help): Fix
--import-optimization/--no-import-optimization entries.

4 years agoAdd --devel-force
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.

4 years agoRestructure new_size calculation
Tom de Vries [Thu, 13 Feb 2020 14:10:25 +0000 (15:10 +0100)]
Restructure new_size calculation

Restructure the calculation of new_size in partition_dups_1, by introducing
variables for various quantities.

2020-02-11  Tom de Vries  <tdevries@suse.de>

* dwz.c (partition_dups_1): Restructure the calculation of new_size.

4 years agoRewrite write_unit_die using loop
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.

4 years agoFactor out write_unit_die
Tom de Vries [Thu, 13 Feb 2020 14:10:25 +0000 (15:10 +0100)]
Factor out write_unit_die

Factor out new function write_unit_die out of function write_die.

2020-02-11  Tom de Vries  <tdevries@suse.de>

* dwz.c (write_unit_die): New function, factor out of ...
(write_die): ... here.

4 years agoAdd --import-optimize/--no-import-optimize
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.

4 years agoFix segfault in die_cu
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.

4 years agoAdd missing --devel-dump-dups in usage
Tom de Vries [Fri, 24 Jan 2020 10:50:40 +0000 (11:50 +0100)]
Add missing --devel-dump-dups in usage

2020-01-24  Tom de Vries  <tdevries@suse.de>

* dwz.c (usage): Add --devel-dump-dups.

4 years agoSimplify --odr/--no-odr parsing
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.

4 years agoAlso call mark_singletons for merged singleton die
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.

4 years agoSimplify code now that split_dups no longer returns NULL
Tom de Vries [Mon, 20 Jan 2020 15:17:33 +0000 (16:17 +0100)]
Simplify code now that split_dups no longer returns NULL

Now that split_dups no longer returns NULL, simplify the code in
partition_dups.

2020-01-20  Tom de Vries  <tdevries@suse.de>

* dwz.c (partition_dups): Assume split_dups doesn't return NULL.

4 years agoFix reference from PU to CU (--odr-mode=basic)
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.

4 years agoVerify that head of dup-chain is not removed
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.

4 years agoFix reference from PU to CU
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'.

2020-01-16  Tom de Vries  <tdevries@suse.de>

PR dwz/25398
* dwz.c (write_die): Skip die_op_type_referenced handling if
cu->cu_kind == CU_PU.

4 years agoAdd --devel-dump-pus
Tom de Vries [Thu, 9 Jan 2020 14:14:39 +0000 (15:14 +0100)]
Add --devel-dump-pus

Add an option --devel-dump-pus to print information about which duplicate
chains have been selected by partition_dups to be copied into partial units.

Output looks like this:
...
$ dwz hello --devel-dump-pus
Partial unit (phase one):
 60 O 6649b943 6649b943 long unsigned int base_type
 75 O e00eb67a e00eb67a int base_type
 81 O 7df8cdbf 7df8cdbf long int base_type
 88 O 6fe25160 6fe25160 char base_type
Partial unit (phase one):
 4b O 6737a1ef 6737a1ef unsigned char base_type
 52 O 168f1291 168f1291 short unsigned int base_type
 59 O 8b473491 8b473491 unsigned int base_type
 67 O 4ab0f4e6 4ab0f4e6 signed char base_type
 6e O 8a462495 8a462495 short int base_type
...

2020-01-09  Tom de Vries  <tdevries@suse.de>

* dwz.c (dump_pus_p): New variable.
(partition_dups_1): Handle dump_pus_p.
(dwz_options, usage): Add dump_pus_p entry.

4 years agoAdd assert to verify_dups for low-mem mode
Tom de Vries [Thu, 9 Jan 2020 13:26:01 +0000 (14:26 +0100)]
Add assert to verify_dups for low-mem mode

In low-mem mode, toplevel DIEs can have collapsed children.  The head of a
duplicate chain though needs to be with uncollapsed children.

Add an assert to that effect to verify_dups.

Tested with --devel-verify-dups on by default.

2020-01-09  Tom de Vries  <tdevries@suse.de>

* dwz.c (verify_dups): Assert die->die_collapsed_children == 0.

4 years agoAdd --devel-stats
Tom de Vries [Thu, 9 Jan 2020 13:07:53 +0000 (14:07 +0100)]
Add --devel-stats

Add a developer option --devel-stats that prints parsing, duplicate and
partitioning statistics.

F.i., for cc1:
...
$ dwz cc1 -lnone --devel-stats
Parse statistics for cc1
root_count                     :        695
namespace_count                :       5033
upper_toplevel                 :       5728
lower_toplevel                 :    1170391
toplevel                       :    1176119
non_toplevel                   :    9012822
die_count                      :   10188941
Duplicate statistics for cc1
lower_toplevel with checksum   :    1124430
dup_cnt                        :    1037350
dup_chain_cnt                  :      23512
average dup_chain length       :      44.12
max dup_chain length           :        598
Partition statistics for cc1
part_cnt                       :       7536
pu_ph1_cnt                     :       4522
pu_ph2_cnt                     :        351
pu_cnt                         :       4873
pu_toplevel_die_cnt            :      20166
...

2020-01-09  Tom de Vries  <tdevries@suse.de>

* dwz.c (stats_p): New variable.
(struct stats): New struct.
(stats): New variable.
(init_stats, print_parse_stats, print_dups_stats, print_part_stats):
New function.
(find_dups, read_debug_info, partition_found_dups, partition_dups_1):
Update stats.
(partition_dups): Call print_dups_stats after partition_find_dups.
Call print_part_stats.
(read_dwarf): Call print_parse_stats after read_debug_info.
(dwz_options, usage): Add --devel-stats entry.
(main): Call init_stats.  Free stats.

4 years agoFix get_name in low-mem mode
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.

2020-01-08  Tom de Vries  <tdevries@suse.de>

* dwz.c (get_name): Handle die->die_collapsed_child == 1.

4 years agoCache file name property in struct dw_file
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.

This speeds up processing of clang-10 with ~6.5%:
...
real:  mean:  263942.00  100.00%  stddev:  1558.78
       mean:  247611.33   93.81%  stddev:   687.17
user:  mean:  253755.33  100.00%  stddev:   447.36
       mean:  236928.33   93.37%  stddev:  1721.72
sys:   mean:    5296.00  100.00%  stddev:   820.97
       mean:    5396.67  101.90%  stddev:  1013.13
...

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.

4 years ago[odr] Add --odr/--no-odr and --odr-mode entries to man page
Tom de Vries [Mon, 6 Jan 2020 15:22:11 +0000 (16:22 +0100)]
[odr] Add --odr/--no-odr and --odr-mode entries to man page

Add an --odr/--no-odr entry and a --odr-mode entry to the man page, advertising
the optimization to the user.

2020-01-06  Tom de Vries  <tdevries@suse.de>

* dwz.1: Add --odr/--no-odr and --odr-mode entries.

4 years ago[odr] Enable --odr by default
Tom de Vries [Mon, 6 Jan 2020 15:22:11 +0000 (16:22 +0100)]
[odr] Enable --odr by default

The overhead of the odr optimization is small enough to enable it by default.

Enable --odr by default.

2020-01-06  Tom de Vries  <tdevries@suse.de>

* dwz.c (odr): Initialize to 1.

4 years ago[odr, testsuite] Add odr-def-decl.sh
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.

4 years ago[odr, testsuite] Add test-case odr-loc.sh
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.

4 years ago[odr, testsuite] Add test-cases odr-{struct,class,union}.sh
Tom de Vries [Mon, 6 Jan 2020 15:22:11 +0000 (16:22 +0100)]
[odr, testsuite] Add test-cases odr-{struct,class,union}.sh

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.

4 years ago[odr] Add --odr/--no-odr and --odr-mode=<basic,link> command line options
Tom de Vries [Mon, 6 Jan 2020 15:22:11 +0000 (16:22 +0100)]
[odr] Add --odr/--no-odr and --odr-mode=<basic,link> command line options

Add optimization options --odr/--no-odr and --odr-mode=<basic|link>, making
the optimization user accessible.

2020-01-06  Tom de Vries  <tdevries@suse.de>

* dwz.c (odr_parsed, no_odr_parsed, int odr_mode_parsed): New variable.
(dwz_options, dwz_common_options_help): Add --odr, --no-odr and
--odr-mode entries.
(print_options_help): Allow entries with NULL short_name and NULL msg.
(main): Handle --odr, --no-odr and --odr-mode.

4 years ago[odr] Combine decls duplicate chain with def duplicate chain
Tom de Vries [Mon, 6 Jan 2020 15:22:11 +0000 (16:22 +0100)]
[odr] Combine decls duplicate chain with def duplicate chain

Add an optimization mode ODR_LINK in which we combine the decl chain with one
of the defs chains.

The duplicate chain containing the decls, combined with one type of def cannot
be handled by the backend if it starts with a decl.  So, we reorder it to
make sure it doesn't start with a decl.

We do this reordering ALAP, because the order of the duplicate chain is
required to be in increasing die_cu (die)->cu_chunk order starting from
the qsort in partition_dups (which sorts the array with duplicate chains into
equivalence classes with the same set of referrer CUs) up until the outer
loops of partition_dups_1 (which determine the equivalence class boundaries in
the array with duplicate chains).

2020-01-06  Tom de Vries  <tdevries@suse.de>

* dwz.c (enum odr_mode): New enum.
(merge_dups): New function.
(split_dups): Call merge_dups if odr_mode != ODR_BASIC.
(reorder_dups): New function.
(partition_dups_1): Call reorder_dups if odr_mode != ODR_BASIC.

4 years ago[odr] Split the maximal duplicate chains
Tom de Vries [Mon, 6 Jan 2020 15:22:11 +0000 (16:22 +0100)]
[odr] Split the maximal duplicate chains

Split the duplicate chains containing decl and defs into:
- one chain containing the decls
- chains containing structurally equivalent def

2020-01-06  Tom de Vries  <tdevries@suse.de>

* dwz.c (struct dw_die): Add die_hash2 field.
(checksum_die): Initialize die_hash2 field.
(odr_phase): New variable.
(die_eq_1): Compare using die_hash2 for odr_phase == 2.
(read_debug_info): Set odr_phase to 1.
(split_dups): New function.
(partition_dups): Set odr_phase to 2, and call split_dups.

4 years ago[odr] Construct maximal duplicate chains
Tom de Vries [Mon, 6 Jan 2020 15:22:11 +0000 (16:22 +0100)]
[odr] Construct maximal duplicate chains

Make sure structs with the same name end up in the same duplicate chain.
Likewise for class and union.

2020-01-06  Tom de Vries  <tdevries@suse.de>

* dwz.c (checksum_die, checksum_ref_die): Make checksum the same for
        structs with the same name.  Likewise for class and union.
(die_eq_1): Return 1 for structs with the same name.  Likewise for
class and union.

This page took 0.455042 seconds and 5 git commands to generate.