From 05853d0d4abe3d4af5fdadd92e76e3f234babad74af21634478ba2da3f045610 Mon Sep 17 00:00:00 2001 From: Tom de Vries Date: Fri, 17 Jan 2020 08:30:35 +0000 Subject: [PATCH] Accepting request 765148 from home:tomdevries:branches:devel:tools:compiler-dwz-fix-ref-pu-to-cu - Fix reference from compilation unit to partial unit [swo#25398]. * dwz-fix-reference-from-pu-to-cu.patch OBS-URL: https://build.opensuse.org/request/show/765148 OBS-URL: https://build.opensuse.org/package/show/devel:tools:compiler/dwz?expand=0&rev=26 --- dwz-fix-reference-from-pu-to-cu.patch | 98 +++++++++++++++++++++++++++ dwz.changes | 6 ++ dwz.spec | 4 +- 3 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 dwz-fix-reference-from-pu-to-cu.patch diff --git a/dwz-fix-reference-from-pu-to-cu.patch b/dwz-fix-reference-from-pu-to-cu.patch new file mode 100644 index 0000000..77f22b3 --- /dev/null +++ b/dwz-fix-reference-from-pu-to-cu.patch @@ -0,0 +1,98 @@ +Fix reference from PU to CU + +[ Backport of master commit bce3238. ] + +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 + + PR dwz/25398 + * dwz.c (write_die): Skip die_op_type_referenced handling if + cu->cu_kind == CU_PU. + +--- + dwz.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/dwz.c b/dwz.c +index c7db337..298bca1 100644 +--- a/dwz.c ++++ b/dwz.c +@@ -9301,7 +9301,8 @@ write_die (unsigned char *ptr, dw_cu_ref cu, dw_die_ref die, + refdt = refd; + while (refdt->die_toplevel == 0) + refdt = refdt->die_parent; +- if (refdt->die_dup && refdt->die_op_type_referenced) ++ if (refdt->die_dup && refdt->die_op_type_referenced ++ && cu->cu_kind != CU_PU) + { + if (cu == die_cu (refdt->die_dup)) + refd = die_find_dup (refdt, refdt->die_dup, refd); diff --git a/dwz.changes b/dwz.changes index 0120513..40f051c 100644 --- a/dwz.changes +++ b/dwz.changes @@ -1,3 +1,9 @@ +------------------------------------------------------------------- +Fri Jan 17 06:30:58 UTC 2020 - Tom de Vries + +- Fix reference from compilation unit to partial unit [swo#25398]. + * dwz-fix-reference-from-pu-to-cu.patch + ------------------------------------------------------------------- Thu Nov 28 12:56:34 UTC 2019 - Tom de Vries diff --git a/dwz.spec b/dwz.spec index c204639..5949486 100644 --- a/dwz.spec +++ b/dwz.spec @@ -1,7 +1,7 @@ # # spec file for package dwz # -# Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany. +# Copyright (c) 2020 SUSE LINUX GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -77,6 +77,7 @@ Patch1: dwz-update-version-copyright-message.patch Patch2: dwz-fix-die-no-multifile-propagation.patch Patch3: dwz-fix-assertion-off-cu_size-in-recompute_abbrevs.patch Patch4: dwz-fix-refd-NULL-assertion-in-write_die.patch +Patch5: dwz-fix-reference-from-pu-to-cu.patch %if %{build_main} %description @@ -109,6 +110,7 @@ This package contains the testsuite results from DWZ. %patch2 -p1 %patch3 -p1 %patch4 -p1 +%patch5 -p1 %build make %{?_smp_mflags} CFLAGS="%{optflags}"