This is an archive of the discontinued LLVM Phabricator instance.

Round up zero-sized symbols to 1 byte in `.debug_aranges`.
ClosedPublic

Authored by pcwalton on May 23 2022, 4:32 PM.

Details

Summary

This commit modifies the AsmPrinter to avoid emitting any zero-sized symbols to
the .debug_aranges table, by rounding their size up to 1. Entries with zero
length violate the DWARF 5 spec, which states:

Each descriptor is a triple consisting of a segment selector, the beginning
address within that segment of a range of text or data covered by some entry
owned by the corresponding compilation unit, followed by the non-zero length
of that range.

In practice, these zero-sized entries produce annoying warnings in lld and
cause GNU binutils to truncate the table when parsing it.

Other parts of LLVM, such as DWARFDebugARanges in the DebugInfo module
(specifically the appendRange method), already avoid emitting zero-sized
symbols to .debug_aranges, but not comprehensively in the AsmPrinter. In fact,
the AsmPrinter does try to avoid emitting such zero-sized symbols when labels
aren't involved, but doesn't when the symbol to emitted is a difference of two
labels; this patch extends that logic to handle the case in which the symbol is
defined via labels.

Diff Detail

Event Timeline

pcwalton created this revision.May 23 2022, 4:32 PM
Herald added a project: Restricted Project. · View Herald TranscriptMay 23 2022, 4:32 PM
Herald added a subscriber: hiraditya. · View Herald Transcript
pcwalton requested review of this revision.May 23 2022, 4:32 PM
Herald added a project: Restricted Project. · View Herald TranscriptMay 23 2022, 4:32 PM

@dblaikie Here's a new version of the patch that takes the alternate approach you suggested of rounding lengths up to 1 byte. Feel free to take either diff and I'll close the other.

dblaikie added inline comments.May 23 2022, 5:23 PM
llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
3057–3063

Does this need to be an MCExpr? Rather than a hardcoded value of 1 (which would seem simpler)?

dblaikie added inline comments.May 23 2022, 5:32 PM
llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
3057–3063

Like what if this was just:

if (Span.End && Size != 0)

And let the existing Size == 0 => Size = 1 handling below take it from there?

pcwalton updated this revision to Diff 431834.May 24 2022, 4:34 PM

Emit a constant 1 instead of a more complicated MCExpr when emitting symbols of length 1.

dblaikie accepted this revision.May 24 2022, 5:03 PM

How's this?

If we're going in this direction, I think this is the way to implement it - though I'm still leaning towards GCC's choice of "all symbols (even data symbols) should be non-zero length" (at the object code level, they can be zero length at the source level) to avoid ambiguities/confusion.

This revision is now accepted and ready to land.May 24 2022, 5:03 PM

Thanks!

Wouldn't that mean that those zero-sized data symbols won't show up in the debugger anymore? That might be confusing for Rust users, who do use zero-sized globals reasonably commonly (to attach methods to).

Thanks!

Wouldn't that mean that those zero-sized data symbols won't show up in the debugger anymore? That might be confusing for Rust users, who do use zero-sized globals reasonably commonly (to attach methods to).

Sorry, I'm not following you - I mean for zero-sized data symbols, we should emit a single byte anyway - so that the address of the symbol is unique/actually exists.

What situation are you considering where something would cause things not to show up in the debugger anymore?

Oh, what I mean is that our choices in the case in which zero-sized global symbols are forbidden at the IR level would be (1) don't emit source-level zero-sized symbols into LLVM IR (or don't emit DWARF metadata for them), or (2) round all zero-sized symbols up to one byte. If we pick (1), I don't think they would show up in the debug info, which could be confusing for programmers. If we pick (2), then certain abstractions which are zero-cost today in Rust become non-zero-cost.

Mind you, I don't know of any applications specifically for which adding one extra byte per zero-sized symbol would be a problem. But I'm worried that someone might be, for example, writing a macro which creates thousands of zero-sized globals, as part of some trick along the lines of traits types in C++, and then the runtime space cost of rounding all globals up to size 1 could become noticeable.

Oh, what I mean is that our choices in the case in which zero-sized global symbols are forbidden at the IR level would be (1) don't emit source-level zero-sized symbols into LLVM IR (or don't emit DWARF metadata for them), or (2) round all zero-sized symbols up to one byte. If we pick (1), I don't think they would show up in the debug info, which could be confusing for programmers. If we pick (2), then certain abstractions which are zero-cost today in Rust become non-zero-cost.

Ah, sorry, yes, I wasn't suggesting (1) - I was suggesting (2). like GCC appears to do: https://godbolt.org/z/E89eo15qd

Mind you, I don't know of any applications specifically for which adding one extra byte per zero-sized symbol would be a problem. But I'm worried that someone might be, for example, writing a macro which creates thousands of zero-sized globals, as part of some trick along the lines of traits types in C++, and then the runtime space cost of rounding all globals up to size 1 could become noticeable.

Yeah - OK, I can see the hypothetical argument. All the more reason, from my perspective, to avoid enabling these to be truly zero-size now only to realize we need to change this later.

The ability to talk about unique addresses for each entity seems important to me (important for C++ at the language level, I think - though admittedly zero-size entities are an extension, so C++ doesn't really say what it means to take their address, compare that address, etc) - but also for DWARF consumers to search for things. If they're really zero length, then searching for the address sort of /should/ result in no result (because the address you're searching for is not part of the object, even though it is the address of the object - because the object takes up no space) - or should/must result in all the zero-length objects at the address plus whatever object follows it - making any kind of identification (eg: debuggers print out what global a pointer points to - but now it points to more than one thing...) complicated/ambiguous/confusing for the consumer and the users.

This revision was landed with ongoing or failed builds.May 25 2022, 1:32 PM
This revision was automatically updated to reflect the committed changes.

In https://reviews.llvm.org/rG38eb4fe74b38 I moved the generic test into the X86 folder as it uses an X86 triple. You could think of the folder names there having 2 meanings, 1: the tests look at things specific to that arch and 2: they use that arch's triple (I think X86 is usually the one people choose if they want to test something generic anyway).

bjope added a subscriber: bjope.May 26 2022, 9:26 AM
bjope added inline comments.
llvm/test/CodeGen/Generic/dwarf-aranges-zero-size.ll
18

Notice that align here is specified in bits. I think it is a bit weird to have a 1 bit alignment?

So why do I care? Our downstream fork is checking that alignment is a multiple of byte size since the getAlignInBytes methods in DebugInfoMetadata.h is dividing the alignment specified in bits by the byte size. This test case hit such assertions.

Do you think it is ok to change this to "align: 8"?

In https://reviews.llvm.org/rG38eb4fe74b38 I moved the generic test into the X86 folder as it uses an X86 triple. You could think of the folder names there having 2 meanings, 1: the tests look at things specific to that arch and 2: they use that arch's triple (I think X86 is usually the one people choose if they want to test something generic anyway).

Thanks for the catch/cleanup!

llvm/test/CodeGen/Generic/dwarf-aranges-zero-size.ll
18

Guessing we could probably just remove the "align: " field entirely here.

Usually I'd advocate for generating the example from some C++ source code fed into clang, since that's the most canonical IR we have - a small example with a zero-length array or the like. Though that might lead to more type information than is really helpful in a test like this.

I guess this was generated by Rust? So might be worth seeing why/where this alignment was created, maybe there's some bugs there to be sorted out too.

As for the alignment restrictions: Might be worth upstreaming your check into LLVM's debug info verifier to make it an explicit constraint of the IR - would make it easier to detect these sort of things sooner.

bjope added inline comments.May 26 2022, 12:02 PM
llvm/test/DebugInfo/X86/dwarf-aranges.ll
25

I do not fully understand what happened here.
The old label range was not zero-sized, right? So this is not rounding up to 1 byte, it is truncating it down to 1 byte, right? Is that really the intention with the patch?

dblaikie added inline comments.May 26 2022, 1:20 PM
llvm/test/DebugInfo/X86/dwarf-aranges.ll
25

Yep. Looks buggy to me - I guess maybe functions don't have a known size so appear to have size zero (when it's really unknown size) & that ends up overriding the real size computation.

@pcwalton might be worth reverting this to figure that out?

bjope added a subscriber: ayermolo.May 31 2022, 1:23 AM
bjope added inline comments.
llvm/test/DebugInfo/X86/dwarf-aranges.ll
25

Still no comments from @pcwalton (nor @ayermolo who committed this patch).

I guess I can perform the revert while waiting for feedback. But then I also need to revert the follow-up commit by @DavidSpickett. Later when/if re-applying one would need to also re-apply that commit (and preferably also fix the problem with the align field in the dwarf-aranges-zero-size.ll test case discussed above).

Sorry for the delay. I was looking at this on Friday but didn't get around to finishing it. Feel free to revert in the meantime.

bjope added a comment.May 31 2022, 2:05 AM

Sorry for the delay. I was looking at this on Friday but didn't get around to finishing it. Feel free to revert in the meantime.

Well, this has already only caused me trouble. And since it isn't as trivial as to just revert a single commit I'm not saying that I really look forward to clean up the mess (I probably won't spend much time on explaining the reverts in the commit messages etc, but I guess I still need to follow up to make sure I haven't broken something that make build bots go crazy due to the reverts, so even more of my time being invested in this). If you are aware of the problem and doesn't have a quick solution I think you should react quicker and make the reverts yourself next time.

Anyway, I've landed the revert now!

I see. I don't have commit access unfortunately.

Hmm for some reason I wan't getting any notifications on this diff. My apologies.

Abandoned in favor of D126835.

hans added a subscriber: hans.Jun 13 2022, 6:42 AM

As another data point, in Chromium we lost line numbers in backtraces after this, see https://bugs.chromium.org/p/chromium/issues/detail?id=1335630