Skip to content

Debugger hook/breakpoint for issue reporting from the Swift runtime #10293

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jun 19, 2017
Merged

Debugger hook/breakpoint for issue reporting from the Swift runtime #10293

merged 5 commits into from
Jun 19, 2017

Conversation

kubamracek
Copy link
Contributor

This implements a debugger hook (breakpoint) API and data structure. This structure is passed to the debugger and describes extra information about a fatal error or a non-fatal warning, which should be logged as a runtime issue.

This debugger hook is then used from two places, which currently only log to stderr:

  • Runtime exclusivity violations.
  • Swift 3 implicit Obj-C entrypoints.

A subsequent LLDB support will be able to catch these callbacks and show the runtime issues in a better way than just logging them to stderr. When the debugger is not attached, this shouldn't have any effect.

@kubamracek
Copy link
Contributor Author

@swift-ci please test

@swift-ci
Copy link
Contributor

Build failed
Jenkins build - Swift Test OS X Platform
Git Commit - 9b5595a438c401ecbf27f7533b101c5c0415e947
Test requested by - @kubamracek

@kubamracek
Copy link
Contributor Author

@swift-ci please test

@swift-ci
Copy link
Contributor

Build failed
Jenkins build - Swift Test Linux Platform
Git Commit - 9b5595a438c401ecbf27f7533b101c5c0415e947
Test requested by - @kubamracek

@swift-ci
Copy link
Contributor

Build failed
Jenkins build - Swift Test OS X Platform
Git Commit - 9b5595a438c401ecbf27f7533b101c5c0415e947
Test requested by - @kubamracek

@gparker42
Copy link
Contributor

Remove some of these leading underscores. The exported function should have one underscore and everything else should have zero.

@kubamracek kubamracek requested a review from gparker42 June 16, 2017 01:21
@najacque
Copy link
Contributor

@swift-ci please test

@swift-ci
Copy link
Contributor

Build failed
Jenkins build - Swift Test Linux Platform
Git Commit - 2e09a4c8403e61b63f56401235a41ff7e1b88740
Test requested by - @najacque

@swift-ci
Copy link
Contributor

Build failed
Jenkins build - Swift Test OS X Platform
Git Commit - 2e09a4c8403e61b63f56401235a41ff7e1b88740
Test requested by - @najacque

fprintf(stderr, "%s ", oldAccess);
if (oldPC) {
dumpStackTraceEntry(0, oldPC, /*shortOutput=*/true);
fprintf(stderr, " (0x%lx).\n", (uintptr_t)oldPC);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this line-ending fprintf come before the dumpStackTraceEntry call?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not trying to change the text output with this patch, so I think this is okay. Notice the /*shortOutput=*/true, so the whole line looks like:

Previous access (a modification) started at module`your_function+0xaa (0x1000a0cd).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, ok.

uint64_t threadID;
uintptr_t numFrames;
void **frames;
};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you want to describe the # of frames to skip here as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it makes sense here: Since the runtime needs to provide the frames itself, it should already strip away any uninteresting frames.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point!

const char *errorType;

// Description of the current thread's stack position.
const char *currentStackDescription;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

# of frames to skip?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good suggestion, I'll add it. It may get tricky to know the right value, though, because we need to know what is inlined and what is not. But it seems to be controllable enough in the two current use cases (implicit objc entrypoints and exclusivity violations).

const char *description;
const char *filename;
uintptr_t line;
uintptr_t column;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the exclusive access to member check using this, or is it intended for SE-0160? It's fiendishly close to describing Fix-Its (we're missing end line/column and replacement text).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is meant for SE-0160, and potentially for future uses as "notes" for runtime issues. I found out that the objc thunks don't have debug info, so the debugger won't point to the declaration on its own.

Any suggestions?

We could also drop these "related objects" completely, and just provide a stacktrace. Users would then have to figure out where the declaration is themselves by looking at stderr.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could add in debug info for these deprecated @objc thunks, which points at the declaration. However, that won't capture the location at which we should insert the @objc in the source.

To be fully general w.r.t. notes with Fix-Its would require something like:

struct RuntimeFixIt {
  const char *filename;
  uintptr_t startLine;             // text in [startLine:startColumn, endLine:endColumn) gets replaced with replacementText
  uintptr_t startColumn;
  uintptr_t endLine;
  uintptr_t endColumn;
  const char *replacementText;

}

and then both RuntimeErrorDetails and RelatedObject would get:

uintptr_t numFixIts;
RuntimeFixIt *fixIts;

Note that having Fix-Its like these for RuntimeErrorDetails means SE-0160 wouldn't need RelatedObjects. That said, if we add the Fix-Its and rename RelatedObject to Note (or RuntimeNote, or whatever), we'll have mirrored the diagnostic information that both the Swift and Clang frontends have... which is defensible and likely to capture everything we want.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's remove the RelatedObjects from this patch. I'll try to re-introduce it in a proper way (and bumb the ABI of this struct to "2") in a subsequent patch. Sounds good?

asprintf(&nullTerminatedFilename, "%*s", (int)filenameLength, filename);

RuntimeErrorDetails::RelatedObject methodDeclaration = {
.description = "Method declaration",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe "Method declaration; add '@objc' here"

@kubamracek
Copy link
Contributor Author

@swift-ci please test

@swift-ci
Copy link
Contributor

Build failed
Jenkins build - Swift Test Linux Platform
Git Commit - f7c1f42ee8b303c5f54a0727c80274e2ae37da69
Test requested by - @kubamracek

@swift-ci
Copy link
Contributor

Build failed
Jenkins build - Swift Test OS X Platform
Git Commit - f7c1f42ee8b303c5f54a0727c80274e2ae37da69
Test requested by - @kubamracek

…structure is passed to the debugger and describes extra information about a fatal error or a non-fatal warning, which should be logged as a runtime issue.

This debugger hook is then used from two places, which currently only log to stderr:
- Runtime exclusivity violations.
- Swift 3 implicit Obj-C entrypoints.

A subsequent LLDB support will be able to catch these callbacks and show the runtime issues in a better way than just logging them to stderr.  When the debugger is not attached, this shouldn't have any effect.
@kubamracek
Copy link
Contributor Author

@swift-ci please test

@swift-ci
Copy link
Contributor

Build failed
Jenkins build - Swift Test OS X Platform
Git Commit - 96014867ef150ae737d90ffa269237438960d5f4
Test requested by - @kubamracek

@swift-ci
Copy link
Contributor

Build failed
Jenkins build - Swift Test Linux Platform
Git Commit - 96014867ef150ae737d90ffa269237438960d5f4
Test requested by - @kubamracek

@kubamracek
Copy link
Contributor Author

@DougGregor is this okay to land?

Copy link
Member

@DougGregor DougGregor left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@kubamracek kubamracek merged commit fec8d72 into swiftlang:master Jun 19, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants