-
Notifications
You must be signed in to change notification settings - Fork 10.5k
[Reflection] Add support for reading ELF. #17771
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
Conversation
return false; | ||
auto ReflStrMdSec = findELFSectionByName("swift5_reflstr"); | ||
if (ReflStrMdSec.first == nullptr || ReflStrMdSec.second == nullptr) | ||
return false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For Mach-O, we succeed if any of the sections are found, as at least some of them are optional. I think ELF should probably do the same. That would also allow you to have this code read swift5_builtin and swift5_capture, and then it will start reading those whenever the compiler starts emitting them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the semantics that Mach-O gives are fine (for now), but we might want to revisit them in the future.
If, e.g. for some reason the compiler doesn't emit the typeref
section or the reflstr
section then we're in big trouble because the debugger kind-of relies on them to be present. I imagine in that case you might at least emit a warning and degrade gracefully in lldb, but I also understand this is a discussion for another day.
[... or similarly, somebody runs the executable through strip or objcopy which drops these sections on the floor]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess it depends on whether you want best effort or all-or-nothing. Might depend on the API’s client. I think some of these sections really are optional, at least I’ve seen freshly built binaries that don’t have them all.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the compiler has nothing to emit for any of the sections, it probably ends up being omitted entirely from the binary. For that reason, I think that it's best to consider them all as optional, or treat the associated section as effectively empty if it doesn't exist in the binary in question. We should treat the lack of a section when the debugger expects it as a format error further down at the point we find out we need it, IMO.
Hooray, ELF support! |
@mikeash This passes all the tests, so I guess it's in a mergeable state. Can you please take another look while I run the tests? |
@swift-ci please test |
@compnerd do you have any thoughts here? |
Build failed |
Build failed |
@mikeash this seems to be a bug in the existing support, unfortunately :|
|
@swift-ci please test osx |
@swift-ci please test macos |
Build failed |
|
||
#else // ELF platforms. | ||
bool addImage(RemoteAddress ImageStart) { | ||
auto Buf = this->getReader().readBytes(ImageStart, sizeof(Elf64_Ehdr)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that we shouldn't assume 64-bitness. 32-bit ARM is pretty common still with Linux. Byte 5 should identify the correct bitsex: 1 -> 32-bit, 2 -> 64-bit. This is technically named EI_CLASS
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My understanding is that there's no 32-bit support for swift (Linux).
As such, I think we can generalize this as a follow up. Probably we should have an assertion "unimplemented"
for anything that's 32-bits?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Um, pretty sure that the x86 and ARM support in 32-bit is reasonably there :)
return false; | ||
|
||
// From the header, grab informations about the section header table. | ||
auto SectionHdrAddress = ImageStart.getAddressData() + Hdr->e_shoff; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is definitely broken with 32-bit images. offsetof(Elf_Ehdr, e_shoff)
is going to be 0x20 vs 0x28. It also is a 4-byte vs 8-byte value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I understand this all is 64-bit specific. We can generalize to 32-bits later.
|
||
// From the header, grab informations about the section header table. | ||
auto SectionHdrAddress = ImageStart.getAddressData() + Hdr->e_shoff; | ||
auto SectionHdrNumEntries = Hdr->e_shnum; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again broken: offsetof(Elf_EHdr, e_shnum)
is 0x30 vs 0x3c.
// From the header, grab informations about the section header table. | ||
auto SectionHdrAddress = ImageStart.getAddressData() + Hdr->e_shoff; | ||
auto SectionHdrNumEntries = Hdr->e_shnum; | ||
auto SectionEntrySize = Hdr->e_shentsize; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again broken: offsetof(Elf_EHdr, e_shentsize)
is 0x2e vs 0x3a
// This provides quick access to the section header string table index. | ||
// We also here handle the unlikely even where the section index overflows | ||
// and it's just a pointer to secondary storage (SHN_XINDEX). | ||
uint32_t SecIdx = Hdr->e_shstrndx; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again broken: offsetof(Elf_EHdr, e_shstrndx)
is 0x32 vs 0x3e
|
||
const Elf64_Shdr *SecHdrStrTab = SecHdrVec[SecIdx]; | ||
Elf64_Off StrTabOffset = SecHdrStrTab->sh_offset; | ||
Elf64_Xword StrTabSize = SecHdrStrTab->sh_size; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Both of these are wrong. offsetof(Elf_SHdr, sh_offset)
is 0x10 vs 0x18. offsetof(Elf_SHdr, sh_size)
is 0x14 vs 0x20. They are 3 vs 8 bytes as well.
return {{nullptr, nullptr}, 0}; | ||
}; | ||
|
||
// FIXME: there's no swift5_builtin and swift5_capture section on Linux. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a stale comment. I'll remove it, thanks.
@@ -263,7 +263,8 @@ static int doDumpReflectionSections(ArrayRef<std::string> binaryFilenames, | |||
objectOwners.push_back(std::move(objectOwner)); | |||
objectFiles.push_back(objectFile); | |||
|
|||
context.addReflectionInfo(findReflectionInfo(objectFile)); | |||
auto startAddress = (uintptr_t)objectFile->getData().begin(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
C++ style casts please.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure.
It really is unfortunate, but, yes, this is the right approach. For remote inspection of binaries, we can't just access the internal special variables to find the section bounds and have to look up the sections manually :-(. This is a super expensive solution, but I think that the best way to handle it for ELF. |
@swift-ci please test |
I and Saleem agreed 32-bits can be done as followup offline.
Build failed |
Build failed |
<rdar://problem/41901725>
Finally ready. |
<rdar://problem/41901725>
@swift-ci test and merge |
@swift-ci test and merge |
This ports Mike's work for the new reflection API to ELF.
This was discussed in abstract several times and I decided to prototype it to see how it looked like.
It needs some cleanups and I need to make sure all the tests pass, but I got to a checkpoint where the basic structure is all there, so I decided it could be a good idea to have another pair of eyes on it.