This is an archive of the discontinued LLVM Phabricator instance.

Add libc++ data formatter for std::function
ClosedPublic

Authored by shafik on Aug 16 2018, 2:25 PM.

Details

Summary

Adding formatter summary for std::function.

- Added LibcxxFunctionSummaryProvider
- Removed LibcxxFunctionFrontEnd
- Modified data formatter tests to test new summary functionality

Diff Detail

Repository
rL LLVM

Event Timeline

shafik created this revision.Aug 16 2018, 2:25 PM
vsk added a subscriber: vsk.Aug 17 2018, 5:13 PM
vsk added inline comments.
source/Plugins/Language/CPlusPlus/LibCxx.cpp
46 ↗(On Diff #161108)

'or' -> 'or hold a'
'will hold' -> 'points to'

47 ↗(On Diff #161108)

'need' -> 'needed'

49 ↗(On Diff #161108)

Could you explicitly pass in a DynamicValueType into GetChildMemberWithName instead of true? You should be able to find one from valobj->GetManager()->GetUseDynamic().

55 ↗(On Diff #161108)

The address size is a generically useful thing to have around, there's no need to comment about defining this.

58 ↗(On Diff #161108)

Please use an early exit here, and everywhere else in the function where it's possible to do so. If the process has really disappeared, there's no need to print anything. In general there's no need to present an incomplete result from this formatter.

71 ↗(On Diff #161108)

When you say "possible", what do you mean? Could you add a comment?

72 ↗(On Diff #161108)

Do you need to check status.Fail() here?

76 ↗(On Diff #161108)

Before doing anything related to SectionLoadList, it would help to have a short comment explaining the intent of the code. Looking through it, it seems like it'd be even better if split out into a helper function.

80 ↗(On Diff #161108)

Instead of attempting to parse symbol names, which is inherently brittle and complicated, why not get the base address of the callable and look up it's location via the symbol table? You'd lose some precision in being able to disambiguate lambdas vs. regular functions, but that's a great tradeoff to make, because the code would be simpler and more reliable.

For the most part this is fine. There are two bits to work on:

  1. I think you could do all of this work on a static std::function object from the data section even if you don't have a process. It might be worth seeing whether you can do that. It looks like you can make static std::function objects...
  2. I think this code would be a little easier to understand if you first stated clearly the kinds of std::function variants that you've discovered at the beginning of the provider. Then when you get to the section of code that handles each of the cases, start the code with: "This covers the case...". Be kind to two years in the future you when you will have forgotten how all this stuff works...
source/Plugins/Language/CPlusPlus/LibCxx.cpp
58 ↗(On Diff #161108)

Data formatters can get called in the absence of a process. For simple C structs, for instance, they might be used to look at an initialized static object in a DATA section. For instance, I could do something like:

#include <functional>
auto g_func = [](int x, int y) {return x + y; };
int
main(int argc, char ** argv)
{

int ret = g_func(argc, 100);
return ret;

}

and I should be able to see g_func using "target var" before running the program. I think the only place you care about the process here is whether you should resolve a load address or not. Target->ReadMemory will read from a running process if that target has one (but preferring data from the underlying files if that's faster.) So I think this formatter should be able to do its job with or without a process.

But I agree with Vedant that in cases where you can't get useful information (for instance if you can't get the vtable address), then you should return false immediately and not try to present a summary. That way instead of showing an incomplete summary, lldb will show the raw printing of the type, which is more useful than a place-holder summary string.

You already do that for the case where you can't read the process memory. Using early return when you discover an error will make it easier to ensure you are doing that right every time you get an error.

80 ↗(On Diff #161108)

I'm not sure I agree. There were some cases where the only way Shafik could find the target was looking at the demangled name. There's nothing here that's so complex that it isn't worth doing, and we can test the cases to ensure that it keeps working. The alternative is leaving folks with no idea what their std::function holds and no way of knowing why this works sometimes but not others.

129 ↗(On Diff #161108)

This ";" is not doing anything, is it?

136–140 ↗(On Diff #161108)

In the first bit of code, you put the explaining comment before the code that handles the condition. This time it's in the middle of the code. Maybe move this comment before "if (symbol_name.contains(...)"

202–204 ↗(On Diff #161108)

I don't think this is valuable. You are just reporting the value of __f_ here? If that's all you can do, I think it's better to return false indicating that you really couldn't make sense of this object, and showing the raw value.

Sounds like std::function objects need to run static initializers before they are useful. So trying to format them w/o a process won't do any good. Probably better to just return false directly if you don't have a process in that case.

shafik updated this revision to Diff 161837.Aug 21 2018, 4:08 PM
shafik marked 12 inline comments as done.

Fixes based on comments

  • Switched to early exits
  • Added a lot more comments to explain all the cases being dealt with and noting which cases different sections are dealing with

@jingham @vsk I believe I have addressed most of your comments

source/Plugins/Language/CPlusPlus/LibCxx.cpp
58 ↗(On Diff #161108)

AFAIT we can't derive useful information for the static case.

std::function does not have constexpr constructors so it can't be initialized during constant initialization. I confirmed in lldb that all the fields are uninitialized therefore we have no pointers to examine.

136–140 ↗(On Diff #161108)

I updated the commenting a big, hopefully it clears things up.

jingham accepted this revision.Aug 21 2018, 5:38 PM

This looks fine. There was one place where you referred back to case 1 by name not ordinal, but otherwise this is quite clear. Don't need another round of review, just fix that nit and its good to go.

This revision is now accepted and ready to land.Aug 21 2018, 5:38 PM
shafik updated this revision to Diff 161997.Aug 22 2018, 10:45 AM

Updating comment

This revision was automatically updated to reflect the committed changes.