This is an archive of the discontinued LLVM Phabricator instance.

[Debuginfo][NFC] Create common error handlers for DWARFContext.
ClosedPublic

Authored by avl on Feb 12 2020, 5:41 AM.

Details

Summary

this review is extracted from D74308.

It creates two error handlers which allow to redefine error
reporting routine and should be used for all places
where errors are reported:

std::function<void(Error)> RecoverableErrorHandler = defaultErrorHandler;
std::function<void(Error)> WarningHandler = defaultWarningHandler;

It also creates accessors to above handlers which should be used to
report errors.

function_ref<void(Error)> getRecoverableErrorHandler() {
  return RecoverableErrorHandler;
}

function_ref<void(Error)> getWarningHandler() { return WarningHandler; }

It patches all error reporting places inside DWARFContext and DWARLinker.

Diff Detail

Event Timeline

avl created this revision.Feb 12 2020, 5:41 AM
Herald added a project: Restricted Project. · View Herald TranscriptFeb 12 2020, 5:41 AM
Herald added a subscriber: hiraditya. · View Herald Transcript
jhenderson accepted this revision.Feb 12 2020, 7:28 AM

All looks good to me, but you might want to let @dblaikie or others comment before committing.

This revision is now accepted and ready to land.Feb 12 2020, 7:28 AM
JDevlieghere requested changes to this revision.Feb 12 2020, 10:25 AM

I think we should pass the error handles as part of the DIDumpOptions to the dump methods. That way we have default handlers for when no options are specified and they're inherited when the options are set explicitly. It also has the benefit of not needlessly complicating the interfaces.

This revision now requires changes to proceed.Feb 12 2020, 10:25 AM
avl updated this revision to Diff 244258.Feb 12 2020, 1:16 PM

addressed comments. use DIDumpOptions to pass handlers to the dump methods.

JDevlieghere added inline comments.Feb 12 2020, 1:42 PM
llvm/include/llvm/DebugInfo/DIContext.h
209

Could we make the default handlers static members of the DWARFContext and use those instead of nullptr?

avl marked an inline comment as done.Feb 13 2020, 12:06 AM
avl added inline comments.
llvm/include/llvm/DebugInfo/DIContext.h
209

i.e. to make:

class DWARFContext {
...
 static std::function<void(Error)> RecoverableErrorHandler = defaultErrorHandler;
 static std::function<void(Error)> WarningHandler = defaultWarningHandler;
}

struct DIDumpOptions {
.....
  std::function<void(Error)> RecoverableErrorHandler = DWARFContext::RecoverableErrorHandler;
  std::function<void(Error)> WarningHandler = DWARFContext::WarningHandler;
};

The goal of this refactoring is to allow to redefine error handlers. So that, when DWARFContext is used inside the linker, the linker could specify it`s own error handlers. There would be possible to provide custom error handlers to DWARFContext: either by passing them in the constructor, either by giving them through setters (setRecoverableErrorHandler()) methods. So that concrete instance of DWARFContext would have custom error handlers. That scheme would not work if RecoverableErrorHandler and WarningHandler were static methods of DWARFContext.

So, I propose that we would not do this.

Additionally, DWARFContext is more specific class than DIDumpOptions. So it would not be good to refer it inside DIDumpOptions. It would probably be necessary to move ErrorHandlers into DIContext if that solution would be taken.

jhenderson added inline comments.Feb 13 2020, 1:40 AM
llvm/include/llvm/DebugInfo/DIContext.h
209

Something I've been thinking about is whether something really high-level, e.g. Error.h, has some default handlers that can be used throughout LLVM. Configuring it on a system-wide level may not be right, but at least the defaults could then be used by all the different tools, unless there was a good reason not to. What do you think?

avl marked an inline comment as done.Feb 13 2020, 5:47 AM
avl added inline comments.
llvm/include/llvm/DebugInfo/DIContext.h
209

Speaking of general solution, I think default handler of following form would not be useful in global Error.h:

static void defaultRecoverableErrorHandler ( Error Err ) {
    WithColor::error() << toString(std::move(E)) << '\n';
}

Because if it would be inserted in many places - then it would not be possible to replace it if necessary. It would be useful if the general solution allows a mechanism to replace default implementation. From that point of view, it would be better to avoid direct access to defaultRecoverableErrorHandler.
Some error-handling model could look like this :

Error.h
class ErrorManager {
public:
   void setHandler ( std::function<void(Error)> H = defaultHandler ) {
    Handler = H; 
   }

   void handle (Error Err) {
     Handler(std::move(Err));
   }
   std::function<void(Error)> getHandler () {
      return Handler;  
   }

private:
   void defaultHandler ( Error Err ) {
     WithColor::error() << toString(std::move(Err)) << '\n';
   } 
   std::function<void(Error)> Handler;
};

So that instead following code:

if ( Error Err = foo() ) {
  defaultRecoverableErrorHandler(Err) 
}

There would be something like this:

if ( Error Err = foo() ) {
  Manager.handle(Err) 
}

If default implementation would be OK, then the user could instantiate global single ErrorManager and do nothing more.

If the default implementation would not be OK, then it is possible to provide alternative handler or extend ErrorManager.

above approach is similar to already existed:

void handleAllErrors(Error E, HandlerTs &&... Handlers)

with the difference that handlers are already set and should not be specified at usage point.

JDevlieghere added inline comments.Feb 13 2020, 8:42 AM
llvm/include/llvm/DebugInfo/DIContext.h
209

I agree that, given LLVM's library centric design, a default handler in Error.h is probably a bit risky, but I do think they would make sense to have in WithColor.h, which is already centered around printing.

avl marked an inline comment as done.Feb 13 2020, 2:18 PM
avl added inline comments.
llvm/include/llvm/DebugInfo/DIContext.h
209

The case I am aware of is following :

WithColor.h
static void defaultRecoverableErrorHandler ( Error Err ) {
    WithColor::error() << toString(std::move(E)) << '\n';
}

DIContext.h
struct DIDumpOptions {
.....
  std::function<void(Error)> RecoverableErrorHandler = defaultRecoverableErrorHandler;
};


DWARFContext.setRecoverableHandler(MyNewHandler);

DIDumpOptions options;
DWARFContext.dump(OS, options);

Although there was set MyNewHandler for DWARFContext there would still be used defaultRecoverableErrorHandler. That behavior looks unintuitive.

If that is not a big deal, I will continue with the default handler in WithColor.h solution.
Also, there is a workaround for that case:

DIDumpOptions options;
options.RecevableHandler = MyNewHandler;
DWARFContext.dump(OS, options);

My original intention was to have a single redefinition point which would affect all usage places.

avl updated this revision to Diff 244623.Feb 14 2020, 4:25 AM

addressed comments. Put default handlers into WithColor.h.

JDevlieghere accepted this revision.Feb 14 2020, 12:24 PM

Thanks for bearing with me. This LGTM!

This revision is now accepted and ready to land.Feb 14 2020, 12:24 PM
This revision was automatically updated to reflect the committed changes.
jhenderson added inline comments.Feb 17 2020, 6:16 AM
llvm/include/llvm/Support/WithColor.h
113–114

Please add some comments for these functions.

avl marked an inline comment as done.Feb 17 2020, 8:26 AM
avl added inline comments.
llvm/include/llvm/Support/WithColor.h
113–114

Will add with separate review. Thanks.