Skip to content

[Tools] Add a library to build specialized generic metadata out of process. #70900

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

Conversation

mikeash
Copy link
Contributor

@mikeash mikeash commented Jan 12, 2024

This library uses GenericMetadataBuilder with a ReaderWriter that can read data and resolve pointers from MachO files, and emit a JSON representation of a dylib containing the built metadata.

We use LLVM's binary file readers to parse the MachO files and resolve fixups so we can follow pointers. This code is somewhat MachO specific, but could be generalized to other formats that LLVM supports.

rdar://116592577

@mikeash mikeash force-pushed the swift-generic-metadata-builder-out-of-process branch 2 times, most recently from 0ca8dec to 632ee03 Compare January 17, 2024 04:21
@mikeash
Copy link
Contributor Author

mikeash commented Jan 17, 2024

@swift-ci please test

@mikeash mikeash force-pushed the swift-generic-metadata-builder-out-of-process branch 2 times, most recently from 613974c to 30e17f9 Compare January 17, 2024 22:16
@mikeash
Copy link
Contributor Author

mikeash commented Jan 17, 2024

@swift-ci please test

@mikeash mikeash force-pushed the swift-generic-metadata-builder-out-of-process branch from 30e17f9 to 54f6b3f Compare January 18, 2024 00:30
@mikeash
Copy link
Contributor Author

mikeash commented Jan 18, 2024

@swift-ci please test

@mikeash mikeash force-pushed the swift-generic-metadata-builder-out-of-process branch from 54f6b3f to 599e9f0 Compare January 18, 2024 03:10
@mikeash
Copy link
Contributor Author

mikeash commented Jan 18, 2024

@swift-ci please test

@mikeash mikeash force-pushed the swift-generic-metadata-builder-out-of-process branch from 599e9f0 to 13af9a2 Compare January 18, 2024 14:41
@mikeash mikeash marked this pull request as ready for review January 18, 2024 14:41
@mikeash mikeash requested review from al45tair and a team as code owners January 18, 2024 14:41
@mikeash
Copy link
Contributor Author

mikeash commented Jan 18, 2024

@swift-ci please test

@mikeash mikeash changed the title [WIP][Tools] Add a library to build specialized generic metadata out of process. [Tools] Add a library to build specialized generic metadata out of process. Jan 18, 2024
@mikeash mikeash force-pushed the swift-generic-metadata-builder-out-of-process branch from 13af9a2 to 6ac4da3 Compare January 18, 2024 17:56
@mikeash
Copy link
Contributor Author

mikeash commented Jan 18, 2024

@swift-ci please test

@mikeash mikeash force-pushed the swift-generic-metadata-builder-out-of-process branch from 6ac4da3 to 15f471c Compare January 18, 2024 21:43
@mikeash
Copy link
Contributor Author

mikeash commented Jan 18, 2024

@swift-ci please test windows platform

@mikeash mikeash force-pushed the swift-generic-metadata-builder-out-of-process branch from 15f471c to 6171779 Compare January 19, 2024 00:08
@mikeash
Copy link
Contributor Author

mikeash commented Jan 19, 2024

@swift-ci please test

@mikeash mikeash force-pushed the swift-generic-metadata-builder-out-of-process branch from 6171779 to ef41fbb Compare January 19, 2024 15:26
@mikeash
Copy link
Contributor Author

mikeash commented Jan 19, 2024

@swift-ci please test

@mikeash mikeash force-pushed the swift-generic-metadata-builder-out-of-process branch from ef41fbb to 9bca2a8 Compare January 19, 2024 19:48
@mikeash
Copy link
Contributor Author

mikeash commented Jan 19, 2024

@swift-ci please test

@mikeash mikeash force-pushed the swift-generic-metadata-builder-out-of-process branch from 9bca2a8 to db61333 Compare January 22, 2024 19:02
@mikeash
Copy link
Contributor Author

mikeash commented Jan 22, 2024

@swift-ci please test

@mikeash mikeash force-pushed the swift-generic-metadata-builder-out-of-process branch from db61333 to f62bbd5 Compare January 23, 2024 14:28
@mikeash
Copy link
Contributor Author

mikeash commented Jan 23, 2024

@swift-ci please test

struct SwiftExternalMetadataBuilder *);

// Returns an error string if the dylib could not be added
// The builder owns the string, so the caller does not have to free it
Copy link
Contributor

Choose a reason for hiding this comment

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

Is it just the last error string that's valid? (Maybe the comment should say something about that?)

Comment on lines 562 to 563
if (!VWT_Bi8_)
return *VWT_Bi8_.getError();
Copy link
Contributor

Choose a reason for hiding this comment

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

Should be VWT_Bi16_.

Suggested change
if (!VWT_Bi8_)
return *VWT_Bi8_.getError();
if (!VWT_Bi16_)
return *VWT_Bi16_.getError();

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ouch, major copy/pasta fail there. Good catch.

Comment on lines 571 to 572
if (!VWT_Bi8_)
return *VWT_Bi8_.getError();
Copy link
Contributor

Choose a reason for hiding this comment

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

Should be VWT_Bi32_.

Suggested change
if (!VWT_Bi8_)
return *VWT_Bi8_.getError();
if (!VWT_Bi32_)
return *VWT_Bi32_.getError();

Comment on lines 580 to 581
if (!VWT_Bi8_)
return *VWT_Bi8_.getError();
Copy link
Contributor

Choose a reason for hiding this comment

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

Should be VWT_Bi64_.

Suggested change
if (!VWT_Bi8_)
return *VWT_Bi8_.getError();
if (!VWT_Bi64_)
return *VWT_Bi64_.getError();

Comment on lines 589 to 590
if (!VWT_Bi8_)
return *VWT_Bi8_.getError();
Copy link
Contributor

Choose a reason for hiding this comment

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

Should be VWT_Bi128_.

Suggested change
if (!VWT_Bi8_)
return *VWT_Bi8_.getError();
if (!VWT_Bi128_)
return *VWT_Bi128_.getError();

auto contents = section.getContents();
if (!contents) {
consumeError(contents.takeError());
continue;
Copy link
Contributor

Choose a reason for hiding this comment

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

I wonder whether we should expose the error that occurred here somehow? Even just mentioning it in the message below might be useful if it happens, e.g.

  if (hadErrors) {
    return BuilderError("Pointer %p is in file %s but is not in any section (we had errors fetching section contents)",
                                     ptr, file->path.c_str());
  }

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 idea. The MachO implementation can never return an error, but it'll be good in case of future expansion to other formats.

Comment on lines 1011 to 1051
while (cursor) {
switch (cursor->getKind()) {
case Node::Kind::BoundGenericClass:
case Node::Kind::BoundGenericStructure:
case Node::Kind::BoundGenericEnum:
case Node::Kind::BoundGenericProtocol:
case Node::Kind::BoundGenericTypeAlias:
case Node::Kind::BoundGenericFunction:
case Node::Kind::BoundGenericOtherNominalType:
if (foundDepth == depth) {
auto typeList = cursor->getChild(1);
if (!typeList)
return BuilderError(
"Requested generic parameter at depth=%" PRIu64
" index=%" PRIu64
", BoundGeneric node does not have two children",
depth, index);
if (typeList->getKind() != Node::Kind::TypeList)
return BuilderError(
"Requested generic parameter at depth=%" PRIu64
" index=%" PRIu64
", child 1 of BoundGeneric is %s, not TypeList",
depth, index, nodeKindString(typeList->getKind()));

auto child = typeList->getChild(index);
if (!child)
return BuilderError(
"Requested generic parameter at depth=%" PRIu64
" index=%" PRIu64
", but bound generic TypeList only has %zu children",
depth, index, typeList->getNumChildren());

return child;
}
foundDepth++;
break;

default:
break;
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

This loop doesn't appear to advance cursor at all.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oops. Looks like we don't yet have enough support for nested types for this to matter. I added code to walk the tree here, and we'll end up testing it as part of testing expanded support for nested types.

ExternalGenericMetadataBuilderContext<Runtime>::addImagesInPath(
std::string path) {
auto forEachFile = [&](std::string filepath) {
auto error = addImageAtPath(filepath);
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we check the file extension at least, to avoid trying to load everything in sight? Or maybe only generate the warning about not being able to read a dylib if the extension is .dylib, .so or empty? (We expect something with the extension .txt to fail, after all, and in some ways it'd be more interesting if it didn't.)

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 sure what the right approach is here. It doesn't matter too much, as swift_externalMetadataBuilder_addDylib is intended to be the primary interface, and this is a convenience. For the convenience interface, I'd rather it try load everything in sight rather than have it potentially skip something we want to keep if somebody puts a weird extension on their dylib.

if (command.C.cmd == llvm::MachO::LC_LOAD_DYLIB ||
command.C.cmd == llvm::MachO::LC_LOAD_WEAK_DYLIB ||
command.C.cmd == llvm::MachO::LC_REEXPORT_DYLIB ||
command.C.cmd == llvm::MachO::LC_LOAD_UPWARD_DYLIB) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we need LC_LAZY_LOAD_DYLIB?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It seems not. LC_LAZY_LOAD_DYLIB seems to be obsolete, and this matches the behavior of dyld.

let readJSONError = readJSONErrorCStr.map { String(cString: $0) }
expectNil(readJSONError)

// Find libswiftCore dynamically since we don't know where we might have loaded it from.
Copy link
Contributor

Choose a reason for hiding this comment

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

swift_getRuntimeLibraryPath() will tell you this, FWIW.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks, that's much nicer.

@mikeash mikeash force-pushed the swift-generic-metadata-builder-out-of-process branch from f62bbd5 to ad253bb Compare January 23, 2024 21:38
@mikeash
Copy link
Contributor Author

mikeash commented Jan 23, 2024

Addressed review feedback and moved the code to lib to join its library/tool friends. I also improved the test to be a bit more comprehensive and test the full JSON output rather than just looking for key strings.

@mikeash
Copy link
Contributor Author

mikeash commented Jan 23, 2024

@swift-ci please test

@mikeash mikeash force-pushed the swift-generic-metadata-builder-out-of-process branch from ad253bb to 9f54982 Compare January 24, 2024 20:32
@mikeash
Copy link
Contributor Author

mikeash commented Jan 24, 2024

@swift-ci please test

@mikeash
Copy link
Contributor Author

mikeash commented Jan 24, 2024

@swift-ci please clean test Windows platform

…ocess.

This library uses GenericMetadataBuilder with a ReaderWriter that can read data and resolve pointers from MachO files, and emit a JSON representation of a dylib containing the built metadata.

We use LLVM's binary file readers to parse the MachO files and resolve fixups so we can follow pointers. This code is somewhat MachO specific, but could be generalized to other formats that LLVM supports.

rdar://116592577
@mikeash mikeash force-pushed the swift-generic-metadata-builder-out-of-process branch from 9f54982 to 4341102 Compare January 25, 2024 01:45
@mikeash
Copy link
Contributor Author

mikeash commented Jan 25, 2024

@swift-ci please test

@mikeash
Copy link
Contributor Author

mikeash commented Jan 25, 2024

@swift-ci please test macos platform

@mikeash mikeash merged commit 4bc7726 into swiftlang:main Jan 26, 2024
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.

2 participants