[llvm] Reland: [ORC] Tailor ELF debugger support plugin to load-address patching only (PR #169482)
Nikita Popov via llvm-commits
llvm-commits at lists.llvm.org
Wed Dec 17 01:52:27 PST 2025
Stefan =?utf-8?q?Gränitz?= <stefan.graenitz at gmail.com>,
Stefan =?utf-8?q?Gränitz?= <stefan.graenitz at gmail.com>,
Stefan =?utf-8?q?Gränitz?= <stefan.graenitz at gmail.com>,
Stefan =?utf-8?q?Gränitz?= <stefan.graenitz at gmail.com>,
Stefan =?utf-8?q?Gränitz?= <stefan.graenitz at gmail.com>,
Stefan =?utf-8?q?Gränitz?= <stefan.graenitz at gmail.com>,
Stefan =?utf-8?q?Gränitz?= <stefan.graenitz at gmail.com>
Message-ID:
In-Reply-To: <llvm.org/llvm/llvm-project/pull/169482 at github.com>
================
@@ -419,91 +186,165 @@ ELFDebugObjectPlugin::ELFDebugObjectPlugin(ExecutionSession &ES,
ELFDebugObjectPlugin::~ELFDebugObjectPlugin() = default;
+static const std::set<StringRef> DwarfSectionNames = {
+#define HANDLE_DWARF_SECTION(ENUM_NAME, ELF_NAME, CMDLINE_NAME, OPTION) \
+ ELF_NAME,
+#include "llvm/BinaryFormat/Dwarf.def"
+#undef HANDLE_DWARF_SECTION
+};
+
+static bool isDwarfSection(StringRef SectionName) {
+ return DwarfSectionNames.count(SectionName) == 1;
+}
+
void ELFDebugObjectPlugin::notifyMaterializing(
MaterializationResponsibility &MR, LinkGraph &G, JITLinkContext &Ctx,
- MemoryBufferRef ObjBuffer) {
- std::lock_guard<std::mutex> Lock(PendingObjsLock);
- assert(PendingObjs.count(&MR) == 0 &&
- "Cannot have more than one pending debug object per "
- "MaterializationResponsibility");
-
- if (auto DebugObj = createDebugObjectFromBuffer(ES, G, Ctx, ObjBuffer)) {
- // Not all link artifacts allow debugging.
- if (*DebugObj == nullptr)
- return;
- if (RequireDebugSections && !(**DebugObj).hasFlags(HasDebugSections)) {
- LLVM_DEBUG(dbgs() << "Skipping debug registration for LinkGraph '"
- << G.getName() << "': no debug info\n");
- return;
- }
- PendingObjs[&MR] = std::move(*DebugObj);
- } else {
- ES.reportError(DebugObj.takeError());
+ MemoryBufferRef InputObj) {
+ if (InputObj.getBufferSize() == 0)
+ return;
+ if (G.getTargetTriple().getObjectFormat() != Triple::ELF)
+ return;
+
+ unsigned char Class, Endian;
+ std::tie(Class, Endian) = getElfArchType(InputObj.getBuffer());
+ if (Class != ELF::ELFCLASS64 && Class != ELF::ELFCLASS32)
+ return ES.reportError(
+ createStringError(object_error::invalid_file_type,
+ "Skipping debug object registration: Invalid arch "
+ "0x%02x in ELF LinkGraph %s",
+ Class, G.getName().c_str()));
+ if (Endian != ELF::ELFDATA2LSB && Endian != ELF::ELFDATA2MSB)
+ return ES.reportError(
+ createStringError(object_error::invalid_file_type,
+ "Skipping debug object registration: Invalid endian "
+ "0x%02x in ELF LinkGraph %s",
+ Endian, G.getName().c_str()));
+
+ // Step 1: We copy the raw input object into the working memory of a
+ // single-segment read-only allocation
+ size_t Size = InputObj.getBufferSize();
+ auto Alignment = sys::Process::getPageSizeEstimate();
+ SimpleSegmentAlloc::Segment Segment{Size, Align(Alignment)};
+
+ auto Alloc = SimpleSegmentAlloc::Create(
+ Ctx.getMemoryManager(), ES.getSymbolStringPool(), ES.getTargetTriple(),
+ Ctx.getJITLinkDylib(), {{MemProt::Read, Segment}});
+ if (!Alloc) {
+ ES.reportError(Alloc.takeError());
+ return;
}
+
+ std::lock_guard<std::mutex> Lock(PendingObjsLock);
+ assert(PendingObjs.count(&MR) == 0 && "One debug object per materialization");
+ PendingObjs[&MR] = std::make_unique<DebugObject>(
+ InputObj.getBufferIdentifier(), std::move(*Alloc), Ctx, ES);
+
+ MutableArrayRef<char> Buffer = PendingObjs[&MR]->getBuffer();
+ memcpy(Buffer.data(), InputObj.getBufferStart(), Size);
+}
+
+DebugObject *
+ELFDebugObjectPlugin::getPendingDebugObj(MaterializationResponsibility &MR) {
+ std::lock_guard<std::mutex> Lock(PendingObjsLock);
+ auto It = PendingObjs.find(&MR);
+ return It == PendingObjs.end() ? nullptr : It->second.get();
}
void ELFDebugObjectPlugin::modifyPassConfig(MaterializationResponsibility &MR,
LinkGraph &G,
PassConfiguration &PassConfig) {
- // Not all link artifacts have associated debug objects.
- std::lock_guard<std::mutex> Lock(PendingObjsLock);
- auto It = PendingObjs.find(&MR);
- if (It == PendingObjs.end())
+ if (!getPendingDebugObj(MR))
return;
- DebugObject &DebugObj = *It->second;
- if (DebugObj.hasFlags(ReportFinalSectionLoadAddresses)) {
- PassConfig.PostAllocationPasses.push_back(
- [&DebugObj](LinkGraph &Graph) -> Error {
- for (const Section &GraphSection : Graph.sections())
- DebugObj.reportSectionTargetMemoryRange(GraphSection.getName(),
- SectionRange(GraphSection));
- return Error::success();
+ PassConfig.PostAllocationPasses.push_back([this, &MR](LinkGraph &G) -> Error {
+ size_t SectionsPatched = 0;
+ bool HasDebugSections = false;
+ DebugObject *DebugObj = getPendingDebugObj(MR);
+ assert(DebugObj && "Don't inject passes if we have no debug object");
+
+ // Step 2: Once the target memory layout is ready, we write the
+ // addresses of the LinkGraph sections into the load-address fields of the
+ // section headers in our debug object allocation
+ Error Err = DebugObj->visitSections(
+ [&G, &SectionsPatched, &HasDebugSections](StringRef Name) {
+ SectionsPatched += 1;
+ if (isDwarfSection(Name))
+ HasDebugSections = true;
+ Section *S = G.findSectionByName(Name);
+ assert(S && "No graph section for object section");
----------------
nikic wrote:
I think the right fix here is probably to just replace the assert with a check? I took a stab at that here: https://github.com/llvm/llvm-project/pull/172622
https://github.com/llvm/llvm-project/pull/169482
More information about the llvm-commits
mailing list