[llvm] [Object] Parsing and dumping of SFrame FDEs (PR #149828)

Pavel Labath via llvm-commits llvm-commits at lists.llvm.org
Thu Jul 24 07:08:27 PDT 2025


================
@@ -6433,6 +6436,86 @@ template <typename ELFT> void ELFDumper<ELFT>::printMemtag() {
   printMemtag(DynamicEntries, AndroidNoteDesc, GlobalDescriptors);
 }
 
+template <typename ELFT>
+void ELFDumper<ELFT>::printSFrameHeader(
+    const SFrameParser<ELFT::Endianness> &Parser) {
+  DictScope HeaderScope(W, "Header");
+
+  const sframe::Preamble<ELFT::Endianness> &Preamble = Parser.getPreamble();
+  W.printHex("Magic", Preamble.Magic.value());
+  W.printEnum("Version", Preamble.Version.value(), sframe::getVersions());
+  W.printFlags("Flags", Preamble.Flags.value(), sframe::getFlags());
+
+  const sframe::Header<ELFT::Endianness> &Header = Parser.getHeader();
+  W.printEnum("ABI", Header.ABIArch.value(), sframe::getABIs());
+
+  W.printNumber(("CFA fixed FP offset" +
+                 Twine(Parser.usesFixedFPOffset() ? "" : " (unused)"))
+                    .str(),
+                Header.CFAFixedFPOffset.value());
+
+  W.printNumber(("CFA fixed RA offset" +
+                 Twine(Parser.usesFixedRAOffset() ? "" : " (unused)"))
+                    .str(),
+                Header.CFAFixedRAOffset.value());
+
+  W.printNumber("Auxiliary header length", Header.AuxHdrLen.value());
+  W.printNumber("Num FDEs", Header.NumFDEs.value());
+  W.printNumber("Num FREs", Header.NumFREs.value());
+  W.printNumber("FRE subsection length", Header.FRELen.value());
+  W.printNumber("FDE subsection offset", Header.FDEOff.value());
+  W.printNumber("FRE subsection offset", Header.FREOff.value());
+
+  if (Expected<ArrayRef<uint8_t>> Aux = Parser.getAuxHeader())
+    W.printHexList("Auxiliary header", *Aux);
+  else
+    reportWarning(Aux.takeError(), FileName);
+}
+
+template <typename ELFT>
+void ELFDumper<ELFT>::printSFrameFDEs(
+    const SFrameParser<ELFT::Endianness> &Parser) {
+  typename SFrameParser<ELFT::Endianness>::FDERange FDEs;
+  if (Error Err = Parser.fdes().moveInto(FDEs)) {
+    reportWarning(std::move(Err), FileName);
+    return;
+  }
+
+  ListScope IndexScope(W, "Function Index");
+  for (auto It = FDEs.begin(); It != FDEs.end(); ++It) {
+    DictScope FDEScope(
+        W,
+        formatv("FuncDescEntry [{0}]", std::distance(FDEs.begin(), It)).str());
+
+    W.printHex("PC", Parser.getAbsoluteStartAddress(It));
+    W.printHex("Size", It->Size);
+    W.printHex("Start FRE Offset", It->StartFREOff);
+    W.printNumber("Num FREs", It->NumFREs);
+
+    W.printHex("Info", It->Info);
+    W.printEnum("FRE Type", It->getFREType(), sframe::getFRETypes());
+    W.printEnum("FDE Type", It->getFDEType(), sframe::getFDETypes());
+    switch (Parser.getHeader().ABIArch) {
+    case sframe::ABI::AArch64EndianBig:
+    case sframe::ABI::AArch64EndianLittle:
+      W.printEnum("PAuth Key", sframe::AArch64PAuthKey(It->getPAuthKey()),
+                  sframe::getAArch64PAuthKeys());
+      break;
+    default:
+      W.printNumber("PAuth Key (unused)", It->getPAuthKey());
+      break;
+    }
----------------
labath wrote:

My reason for including it is that there are two unused bits in the info field which aren't covered by any of the specific fields. I thought it would be nice if every bit of the input was somehow represented in the output, but I'm not insisting on it.

I considered printing just the unused bits separately, but concluded that would be more confusing and ultimately take up the same amount of space. What did you have in mind for the scope idea? Something like this:
```
Info {
  FRE Type: xx
  FDE Type: yy
  PAuth Key: zz
  Raw: 0xXX
}
```
I think that could work. I think we could also skip printing the PAuthKey field for the cases where it's not used (since its value is reflected in the hex dump already)

https://github.com/llvm/llvm-project/pull/149828


More information about the llvm-commits mailing list