-
Notifications
You must be signed in to change notification settings - Fork 13.6k
[llvm] Win x64 Unwind V2 2/n: Support dumping UOP_Epilog #110338
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
@llvm/pr-subscribers-llvm-support @llvm/pr-subscribers-llvm-binary-utilities Author: Daniel Paoliello (dpaoliello) ChangesAdds support to objdump and readobj for reading the
The first
Any subsequent Full diff: https://github.com/llvm/llvm-project/pull/110338.diff 3 Files Affected:
diff --git a/llvm/tools/llvm-objdump/COFFDump.cpp b/llvm/tools/llvm-objdump/COFFDump.cpp
index 71697fa01e627d..97901ebf9851d8 100644
--- a/llvm/tools/llvm-objdump/COFFDump.cpp
+++ b/llvm/tools/llvm-objdump/COFFDump.cpp
@@ -240,10 +240,10 @@ static unsigned getNumUsedSlots(const UnwindCode &UnwindCode) {
case UOP_AllocSmall:
case UOP_SetFPReg:
case UOP_PushMachFrame:
+ case UOP_Epilog:
return 1;
case UOP_SaveNonVol:
case UOP_SaveXMM128:
- case UOP_Epilog:
return 2;
case UOP_SaveNonVolBig:
case UOP_SaveXMM128Big:
@@ -257,7 +257,7 @@ static unsigned getNumUsedSlots(const UnwindCode &UnwindCode) {
// Prints one unwind code. Because an unwind code can occupy up to 3 slots in
// the unwind codes array, this function requires that the correct number of
// slots is provided.
-static void printUnwindCode(ArrayRef<UnwindCode> UCs) {
+static void printUnwindCode(ArrayRef<UnwindCode> UCs, bool &SeenFirstEpilog) {
assert(UCs.size() >= getNumUsedSlots(UCs[0]));
outs() << format(" 0x%02x: ", unsigned(UCs[0].u.CodeOffset))
<< getUnwindCodeTypeName(UCs[0].getUnwindOp());
@@ -301,11 +301,30 @@ static void printUnwindCode(ArrayRef<UnwindCode> UCs) {
outs() << " " << (UCs[0].getOpInfo() ? "w/o" : "w")
<< " error code";
break;
+
+ case UOP_Epilog:
+ if (SeenFirstEpilog) {
+ uint32_t Offset = (UCs[0].getOpInfo() << 8) |
+ static_cast<uint32_t>(UCs[0].u.CodeOffset);
+ if (Offset == 0) {
+ outs() << " padding";
+ } else {
+ outs() << " offset=" << format("0x%X", Offset);
+ }
+ } else {
+ SeenFirstEpilog = true;
+ bool AtEnd = (UCs[0].getOpInfo() & 0x1) != 0;
+ uint32_t Length = UCs[0].u.CodeOffset;
+ outs() << " atend=" << (AtEnd ? "yes" : "no")
+ << ", length=" << format("0x%X", Length);
+ }
+ break;
}
outs() << "\n";
}
static void printAllUnwindCodes(ArrayRef<UnwindCode> UCs) {
+ bool SeenFirstEpilog = false;
for (const UnwindCode *I = UCs.begin(), *E = UCs.end(); I < E; ) {
unsigned UsedSlots = getNumUsedSlots(*I);
if (UsedSlots > UCs.size()) {
@@ -316,7 +335,7 @@ static void printAllUnwindCodes(ArrayRef<UnwindCode> UCs) {
<< " remaining in buffer";
return ;
}
- printUnwindCode(ArrayRef(I, E));
+ printUnwindCode(ArrayRef(I, E), SeenFirstEpilog);
I += UsedSlots;
}
}
diff --git a/llvm/tools/llvm-readobj/Win64EHDumper.cpp b/llvm/tools/llvm-readobj/Win64EHDumper.cpp
index e4bd772191514a..ee043c9d0d10a1 100644
--- a/llvm/tools/llvm-readobj/Win64EHDumper.cpp
+++ b/llvm/tools/llvm-readobj/Win64EHDumper.cpp
@@ -65,6 +65,8 @@ static StringRef getUnwindCodeTypeName(uint8_t Code) {
case UOP_SaveXMM128: return "SAVE_XMM128";
case UOP_SaveXMM128Big: return "SAVE_XMM128_FAR";
case UOP_PushMachFrame: return "PUSH_MACHFRAME";
+ case UOP_Epilog:
+ return "EPILOG";
}
}
@@ -99,6 +101,7 @@ static unsigned getNumUsedSlots(const UnwindCode &UnwindCode) {
case UOP_AllocSmall:
case UOP_SetFPReg:
case UOP_PushMachFrame:
+ case UOP_Epilog:
return 1;
case UOP_SaveNonVol:
case UOP_SaveXMM128:
@@ -254,7 +257,8 @@ void Dumper::printRuntimeFunctionEntry(const Context &Ctx,
// Prints one unwind code. Because an unwind code can occupy up to 3 slots in
// the unwind codes array, this function requires that the correct number of
// slots is provided.
-void Dumper::printUnwindCode(const UnwindInfo& UI, ArrayRef<UnwindCode> UC) {
+void Dumper::printUnwindCode(const UnwindInfo &UI, ArrayRef<UnwindCode> UC,
+ bool &SeenFirstEpilog) {
assert(UC.size() >= getNumUsedSlots(UC[0]));
SW.startLine() << format("0x%02X: ", unsigned(UC[0].u.CodeOffset))
@@ -306,6 +310,24 @@ void Dumper::printUnwindCode(const UnwindInfo& UI, ArrayRef<UnwindCode> UC) {
case UOP_PushMachFrame:
OS << " errcode=" << (UC[0].getOpInfo() == 0 ? "no" : "yes");
break;
+
+ case UOP_Epilog:
+ if (SeenFirstEpilog) {
+ uint32_t Offset =
+ (UC[0].getOpInfo() << 8) | static_cast<uint32_t>(UC[0].u.CodeOffset);
+ if (Offset == 0) {
+ OS << " padding";
+ } else {
+ OS << " offset=" << format("0x%X", Offset);
+ }
+ } else {
+ SeenFirstEpilog = true;
+ bool AtEnd = (UC[0].getOpInfo() & 0x1) != 0;
+ uint32_t Length = UC[0].u.CodeOffset;
+ OS << " atend=" << (AtEnd ? "yes" : "no")
+ << ", length=" << format("0x%X", Length);
+ }
+ break;
}
OS << "\n";
@@ -330,6 +352,7 @@ void Dumper::printUnwindInfo(const Context &Ctx, const coff_section *Section,
{
ListScope UCS(SW, "UnwindCodes");
ArrayRef<UnwindCode> UC(&UI.UnwindCodes[0], UI.NumCodes);
+ bool SeenFirstEpilog = false;
for (const UnwindCode *UCI = UC.begin(), *UCE = UC.end(); UCI < UCE; ++UCI) {
unsigned UsedSlots = getNumUsedSlots(*UCI);
if (UsedSlots > UC.size()) {
@@ -337,7 +360,7 @@ void Dumper::printUnwindInfo(const Context &Ctx, const coff_section *Section,
return;
}
- printUnwindCode(UI, ArrayRef(UCI, UCE));
+ printUnwindCode(UI, ArrayRef(UCI, UCE), SeenFirstEpilog);
UCI = UCI + UsedSlots - 1;
}
}
diff --git a/llvm/tools/llvm-readobj/Win64EHDumper.h b/llvm/tools/llvm-readobj/Win64EHDumper.h
index 97458c916bec6f..a23d30be7a113d 100644
--- a/llvm/tools/llvm-readobj/Win64EHDumper.h
+++ b/llvm/tools/llvm-readobj/Win64EHDumper.h
@@ -44,7 +44,8 @@ class Dumper {
const object::coff_section *Section,
uint64_t SectionOffset,
const RuntimeFunction &RF);
- void printUnwindCode(const UnwindInfo& UI, ArrayRef<UnwindCode> UC);
+ void printUnwindCode(const UnwindInfo &UI, ArrayRef<UnwindCode> UC,
+ bool &SeenFirstEpilog);
void printUnwindInfo(const Context &Ctx, const object::coff_section *Section,
off_t Offset, const UnwindInfo &UI);
void printRuntimeFunction(const Context &Ctx,
|
Can you use yaml2obj to write testcases? 12 bits seems a bit small, but I guess I'll see how you address that in followup patches. |
Done
Yep, it's one of the limitations of v2: epilogs must be within 4Kb of the function end. Essentially, there will be two different modes that can be enabled:
|
AArch64 Windows has a similar limitation to function size (the function size limit is 20 bits, but still similar idea). The way we handle it there is that we emit multiple EH records for the function (the first record contains a normal prologue, the subsequent records are marked up to indicate they don't contain the prologue). Is there some reason we can't do that for x64? |
@pmsjt thoughts on splitting EH records to workaround the 4Kb offset limit? I know that we can chain unwind records, but I'm not sure if we can set a different function end location on each of the chained records. |
Ping... |
Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] | ||
VirtualAddress: 4096 | ||
VirtualSize: 113 | ||
SectionData: C3662E0F1F8400000000000F1F4400005048890C2458C3660F1F8400000000004883EC38E8D7FFFFFFE900000000488D4C2430E8D8FFFFFF904883C438C3488944242889542424488D4C2430E8BFFFFFFF488B4C2428E805000000CC0F1F4000C3662E0F1F8400000000000F1F440000C3 |
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 test doesn't actually parse the contents of the text section, please zero it out. (We don't want difficult-to-audit bits of binary data in the regression tests where we can avoid it.)
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.
llvm/tools/llvm-objdump/COFFDump.cpp
Outdated
case UOP_Epilog: | ||
if (SeenFirstEpilog) { | ||
uint32_t Offset = (UCs[0].getOpInfo() << 8) | | ||
static_cast<uint32_t>(UCs[0].u.CodeOffset); |
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.
Would it make sense to package up this math into a helper in Win64EH.h?
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.
Good idea.
1e0a70f
to
df629ad
Compare
df629ad
to
f6d628f
Compare
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.
LGTM
We are seeing failures in our Windows clang builders and this PR seems to be the only one related to Windows from the blamelist. I am trying to verify if this PR is the root cause. Find below the links to the failing builder and the logs. Thank you. Builder: https://luci-milo.appspot.com/ui/p/fuchsia/builders/prod/clang-windows-x64/b8725790748165344833 Failure:
|
I don't understand how this change is related to that failure: I didn't modify anything related to resources, CMake/build system, or polly. Your builders also had the same failure on the 10th, which was before my change went in: https://luci-milo.appspot.com/ui/p/fuchsia/builders/prod/clang-windows-x64/b8726085201223378929/overview |
Thanks for the response. This was indeed unrelated to the patch. |
Adds support to objdump and readobj for reading the
UOP_Epilog
entries of Windows x64 unwind v2.UOP_Epilog
has a weird format:The first
UOP_Epilog
in the unwind data is the "header":OpInfo
is the "At End" flag, which signifies that there is an epilog at the very end of the associated function.CodeOffset
is the length each epilog described by the current unwind information (all epilogs have the same length).Any subsequent
UOP_Epilog
represents another epilog for the current function, whereOpInfo
andCodeOffset
are combined to a 12-bit value which is the offset of the beginning of the epilog from the end of the current function. If the offset is 0, then this entry is actually padding and can be ignored.