This is an archive of the discontinued LLVM Phabricator instance.

Change DWARFDie::getAttributeValue() to DWARFDie::find(), add DWARFDie::findRecurse() and dwarf::toString() helper functions.
ClosedPublic

Authored by clayborg on Jan 11 2017, 3:03 PM.

Details

Summary

In an effort to get DWARFDie::getAttributeValueAsXXX() calls to be more concise we want to:

  • shorten the function names
  • reduce the number of methods
  • provide robust ways to get attributes and extract value

This is a proposal where we rename:

Optional<DWARFFormValue> DWARFDie::getAttributeValue(dwarf::Attribute Attr) const;

To:

Optional<DWARFFormValue> DWARFDie::find(dwarf::Attribute Attr) const;

And add:

Optional<DWARFFormValue> DWARFDie::findRecurse(dwarf::Attribute Attr) const;

So we can recurse into the DW_AT_abstract_origin and DW_AT_specification DIEs. Then by adding new helper functions, we can extract specific kinds of data from the returned Optional<DWARFFormValue> (see the dwarf::toString() functions in DWARFFormValue.h.

This is a test to see if people like how the code looks and like the interface before we possibly, if we like it, cut all code over to using it.

Diff Detail

Event Timeline

clayborg updated this revision to Diff 84031.Jan 11 2017, 3:03 PM
clayborg retitled this revision from to Change DWARFDie::getAttributeValue() to DWARFDie::find(), add DWARFDie::findRecurse() and dwarf::toString() helper functions..
clayborg updated this object.
dblaikie edited edge metadata.Jan 11 2017, 3:20 PM

I'

lib/DebugInfo/DWARF/DWARFDie.cpp
147

probably 'findRecursively' (open to other ideas on naming 'findIndirectly' seems like it sort of describes things better - but it's not /always/ indirect... meh)

152–157

Do we actually want/need to support the case of walking arbitrarily many abstract_origins and specifications - does that come up/need to be supported? Or is it just one abstract_origin and one specification?

I'm OK with it - don't mind having both, but looking at the code in LLVM so far, it doesn't seem many of the callers actually want/need the default versions.

The callers of the AsString mostly use a default value of nullptr then test for null anyway - so they could equally test the Optional to produce the same result.

Other callers mostly don't provide default values. I'm not sure the defaulting utilities have enough... utility to bother with, but don't much mind if it seems particularly useful to others.

clayborg added inline comments.Jan 11 2017, 3:28 PM
include/llvm/DebugInfo/DWARF/DWARFFormValue.h
191–192

Not sure if we need this one, but I wanted to add it just in case so we can see that it would work. I would probably save a few bytes on a line. Like things in the unit tests currently is:

EXPECT_EQ(DieDG.getAttributeValueAsUnsignedConstant(Attr_DW_FORM_data1)
              .getValueOr(0),
          Data1);

And it would become either:

EXPECT_EQ(Data1, dwarf::ToUnsigned(DieDG.find(Attr_DW_FORM_data1)).getValueOr(0));

Or:

EXPECT_EQ(Data1, dwarf::ToUnsigned(DieDG.find(Attr_DW_FORM_data1), 0));

I kind of like being able to specify the default.

lib/DebugInfo/DWARF/DWARFDie.cpp
147

I am open to ideas as well. findRecursively sound fine to me. Other ideas:

  • findAll
  • recursiveFind

Or maybe we can rename "find" to "get" and the "get" function would only look in the current DIE, while "find" would go through the abs or spec dies?

157

It usually will be just one that I am aware of, but I can't say for sure. I would rather be safe on this one if possible.

I do kind of agree with Adrian that this new code isn't as readable (see the "CallFile =" code...).

If we return a DWARFFormValue that is potentially invalid we would get:

void DWARFDie::getCallerFrame(uint32_t &CallFile, uint32_t &CallLine,
                              uint32_t &CallColumn) const {
  CallFile = find(DW_AT_call_file).toUnsigned(0);
  CallLine = find(DW_AT_call_line).toUnsigned(0);
  CallColumn = find(DW_AT_call_column).toUnsigned(0);
}
include/llvm/DebugInfo/DWARF/DWARFFormValue.h
192

This code:

void DWARFDie::getCallerFrame(uint32_t &CallFile, uint32_t &CallLine,
                              uint32_t &CallColumn) const {
  CallFile = getAttributeValueAsUnsignedConstant(DW_AT_call_file).getValueOr(0);
  CallLine = getAttributeValueAsUnsignedConstant(DW_AT_call_line).getValueOr(0);
  CallColumn =
      getAttributeValueAsUnsignedConstant(DW_AT_call_column).getValueOr(0);
}

would become:

void DWARFDie::getCallerFrame(uint32_t &CallFile, uint32_t &CallLine,
                              uint32_t &CallColumn) const {
  CallFile = toUnsigned(find(DW_AT_call_file), 0);
  CallLine = toUnsigned(find(DW_AT_call_line, 0);
  CallColumn = toUnsigned(find(DW_AT_call_column, 0);
}
clayborg updated this revision to Diff 84047.Jan 11 2017, 3:45 PM
clayborg edited edge metadata.

Renamed findRecursive to findRecursively and don't recurse when looking through DW_AT_abstract_origin or DW_AT_specification DIEs.

My perspective's basically:

Names: find/findRecursively
Non-member: toFoo
Overload toFoo with default parameter versions for cases that seem helpful. (but I'd urge you to change things that are unnecessarily using default values, like this:

const char *name;
if ((name = getAttributeValueAsString(linkage_name, nullptr))
  return name;

instead:

if (auto Name = toString(find(linkage_name)))
  return *Name;

& when you implement findRecursively - looks like DWARFDie::getName could be improved by that.

clayborg updated this revision to Diff 84057.Jan 11 2017, 4:57 PM

A complete version of switching over to use toFoo as Dave suggested.

Please include tests for all the toFoo helpers (in both flavors)

Ideally by creating DWARFFormValue objects directly (if that's not possible currently - ideally make it possible) so the tests don't have to be so long/complicated as generating and parsing DWARF to test these utilities.

lib/DebugInfo/DWARF/DWARFDie.cpp
256–266

Change these all to:

if (auto Name = toString(find(DW_AT_name)))
  return *Name;

If that's correct

lib/DebugInfo/DWARF/DWARFTypeUnit.cpp
29–31

Similarly:

if (auto Name = toString(TD.find(dwarf::DW_AT_name)))
  ... *Name ...
lib/DebugInfo/DWARF/DWARFUnit.cpp
269

Probably remove the nullptr-y-ness here too.

Could remove it from the DWOFileName too in a variety of ways, but *shrug* if you like.

tools/dsymutil/DwarfLinker.cpp
207–208

Could remove the defaulting here as well - placing the HasODR assignment below in a conditional:

if (auto Lang = toUnsigned(CUDie.find(...)))
  HasODR = ...
843–844

Roll the variable declaration into the conditional

aprantl edited edge metadata.Jan 12 2017, 11:27 AM

Now that the default values are part of the to<type>() functions this doesn't look to bad either. It's still strictly better and shorter than the original code.

Since I'm on the fence now and Greg says he can live with both options and David is arguing strongly for this variant, let's do this one.

clayborg updated this revision to Diff 84180.Jan 12 2017, 3:14 PM
clayborg edited edge metadata.

This is a proposed final solution with tests and all needed fixes.

aprantl accepted this revision.Jan 13 2017, 9:29 AM
aprantl edited edge metadata.

Couple of cosmetic comments, but otherwise this is looking good now.
thanks!

include/llvm/DebugInfo/DWARF/DWARFFormValue.h
203

Could this be replaced by getValueOr or does the type system prohibit that?

226

ditto

247

ditto

269

getValueOr?

291

getValueOr?

314

getValueOr?

This revision is now accepted and ready to land.Jan 13 2017, 9:29 AM
aprantl added inline comments.Jan 13 2017, 11:09 AM
include/llvm/DebugInfo/DWARF/DWARFFormValue.h
203

Oh sorry, I just realized that I misread the function signature of this. This comment of mine makes no sense at all ;-)

This revision was automatically updated to reflect the committed changes.