This is an archive of the discontinued LLVM Phabricator instance.

Fix LLVM's use of DW_OP_bit_piece in DWARF expressions.
ClosedPublic

Authored by aprantl on Dec 7 2016, 3:08 PM.

Details

Summary

This is a follow-up to the discussion in
http://lists.llvm.org/pipermail/llvm-commits/Week-of-Mon-20161114/405934.html

Apologies for the long patch. The good news is that most changes are deleting code.

LLVM's use of DW_OP_bit_piece is incorrect and a based on a
misunderstanding of the wording in the DWARF specification. The offset
argument of DW_OP_bit_piece refers to the offset into the location
that is on the top of the DWARF expression stack, and not an offset
into the source variable. This has since also been clarified in the
DWARF specification.

This patch fixes all uses of DW_OP_bit_piece to emit the correct
offset and simplifies the DwarfExpression class to semi-automaticaly
emit empty DW_OP_pieces to adjust the offset of the source variable,
thus simplifying the code using DwarfExpression.

While this is an incompatible bugfix, in practice I don't expect this
to be much of a problem since LLVM's old interpretation and the
correct interpretation of DW_OP_bit_piece differ only when there are
gaps in the fragmented locations of the described variables or if
individual fragments are smaller than a byte. LLDB at least won't
interpret locations with gaps in them at all because is has no way to present
undefined bits in a variable, and there is a high probability that an
old-form expression will be malformed when interpreted correctly,
because the DW_OP_bit_piece offset will be outside of the location at
the top of the stack.

As a nice side-effect, this patch enables us to use a more efficient
encoding for subregisters: In order to express a sub-register at a
non-zero offset we now use a DW_OP_bit_piece instead of shifting the
value into place manually.

This patch also adds missing test coverage for code paths that weren't
exercised before.

Diff Detail

Event Timeline

aprantl updated this revision to Diff 80673.Dec 7 2016, 3:08 PM
aprantl retitled this revision from to Fix LLVM's use of DW_OP_bit_piece in DWARF expressions..
aprantl updated this object.
aprantl added reviewers: dblaikie, probinson.
aprantl set the repository for this revision to rL LLVM.
aprantl added a subscriber: llvm-commits.
aprantl updated this revision to Diff 80680.Dec 7 2016, 3:50 PM
aprantl removed rL LLVM as the repository for this revision.

Added a testcase I forgot to git-add.

aprantl updated this revision to Diff 80909.Dec 9 2016, 9:22 AM

Add an entire directory of testcases I forgot to git-add m( and fix the edge-case of a fragment sitting in a super-register that is only representably by pieceing together sub-registers.

dblaikie edited edge metadata.Dec 9 2016, 9:54 AM

Not quite following all the changes here, but they look roughly plausible.

Is there some code I couldn't find that sorts all the fragments before emitting them? (the old scheme wouldn't've needed this, since each bit_piece could specify where it appears - but maybe we were already sorting them anyway so pieces were linearly increasing in position? - the new scheme would require such sorting because the positions are implicit relative to prior pieces)

lib/CodeGen/AsmPrinter/DwarfExpression.cpp
233

s/bas/base/ I'm guessing?

lib/CodeGen/AsmPrinter/DwarfExpression.h
99–102

(aside/separate patch: this type doesn't seem to need a virtual dtor - it's never owned polymorphically. Could make the dtor protected non-virtual, and derived classes final)

lib/CodeGen/AsmPrinter/DwarfUnit.cpp
505

makeArrayRef?

test/DebugInfo/AArch64/frameindices.ll
9

Took me a bit to go through both these examples (keeping both the DW_OP_bit_piece/piece interpretations in my head, etc) - but yes, great to see this, as it looks good/right/etc :)

test/DebugInfo/MIR/X86/bit-piece-dh.mir
2

what's 'dh' stand for in the title of this test?

What codepath does this test? (looks like the expression isn't in DIExpression - it's created in some MI/CodeGen layer?)

test/DebugInfo/X86/dw_op_minus_direct.ll
10–13

This is test coverage for DwarfExpression.cpp:244-ish? Probably better as a separate commit?

aprantl marked 4 inline comments as done.Dec 9 2016, 10:43 AM

Not quite following all the changes here, but they look roughly plausible.

Is there some code I couldn't find that sorts all the fragments before emitting them? (the old scheme wouldn't've needed this, since each bit_piece could specify where it appears - but maybe we were already sorting them anyway so pieces were linearly increasing in position? - the new scheme would require such sorting because the positions are implicit relative to prior pieces)

Yes, DebugLocEntry::sortUniqueValues() (and possibly others locations) is sorting the fragments by offset.

lib/CodeGen/AsmPrinter/DwarfUnit.cpp
505

Nice. Didn't know we had that.

test/DebugInfo/AArch64/frameindices.ll
9

Thanks, from past experience, I really appreciate someone double-checking this!

test/DebugInfo/MIR/X86/bit-piece-dh.mir
2

The 8-bit x86 register "dh" hi-part of (r)dx.

0    8   16    32       64
+-----------------------+
|              rdx      |
|        edx    |       |
|    dx   |     |       |
| dl | dh |     |       |
+----+----+-----+-------+

This is testing DwarfExpression.cpp:111 (Walk up the super-register chain until we find a valid number and emit a DW_OP_bit_piece for it).

test/DebugInfo/X86/dw_op_minus_direct.ll
10–13

It tests a bugfix that fell out of this rewrite/factoring. The code in trunk would have crashed when it encountered a DW_OP_minus without a DW_OP_deref. I would leave it in here.

aprantl updated this revision to Diff 80917.Dec 9 2016, 10:43 AM
aprantl edited edge metadata.
aprantl marked 3 inline comments as done.

Adress review comments.

dblaikie accepted this revision.Dec 9 2016, 11:21 AM
dblaikie edited edge metadata.
This revision is now accepted and ready to land.Dec 9 2016, 11:21 AM
This revision was automatically updated to reflect the committed changes.