Skip to content

Commit d5ef37a

Browse files
llvm-beanzbogner
authored andcommitted
[ObjCopy][DX] Support for -dump-section flag (llvm#159999)
This adds support for the `-dump-section=<section>=<file>` flag for the DXContainer file format. This flag dumps the contents of a named section to the specified file. This flag is particularly handy for ripping DXIL bitcode out of the object files so that we can use LLVM tools to inspect and operate on the bitcode. To facilitate that workflow this flag also strips the program headers from parts containing DXIL so that the resulting file is a valid bitcode file. --------- Co-authored-by: Justin Bogner <[email protected]>
1 parent 1dcfdd9 commit d5ef37a

File tree

4 files changed

+355
-8
lines changed

4 files changed

+355
-8
lines changed

llvm/lib/ObjCopy/ConfigManager.cpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -122,14 +122,14 @@ ConfigManager::getDXContainerConfig() const {
122122
if (!Common.AddGnuDebugLink.empty() || !Common.SplitDWO.empty() ||
123123
!Common.AllocSectionsPrefix.empty() ||
124124
Common.DiscardMode != DiscardType::None || !Common.AddSection.empty() ||
125-
!Common.DumpSection.empty() || !Common.KeepSection.empty() ||
126-
!Common.SectionsToRename.empty() || !Common.SetSectionAlignment.empty() ||
127-
!Common.SetSectionFlags.empty() || !Common.SetSectionType.empty() ||
128-
Common.ExtractDWO || Common.OnlyKeepDebug || Common.StripAllGNU ||
129-
Common.StripDWO || Common.StripDebug || Common.StripNonAlloc ||
130-
Common.StripSections || Common.StripUnneeded ||
131-
Common.DecompressDebugSections || Common.GapFill != 0 ||
132-
Common.PadTo != 0 || Common.ChangeSectionLMAValAll != 0 ||
125+
!Common.KeepSection.empty() || !Common.SectionsToRename.empty() ||
126+
!Common.SetSectionAlignment.empty() || !Common.SetSectionFlags.empty() ||
127+
!Common.SetSectionType.empty() || Common.ExtractDWO ||
128+
Common.OnlyKeepDebug || Common.StripAllGNU || Common.StripDWO ||
129+
Common.StripDebug || Common.StripNonAlloc || Common.StripSections ||
130+
Common.StripUnneeded || Common.DecompressDebugSections ||
131+
Common.GapFill != 0 || Common.PadTo != 0 ||
132+
Common.ChangeSectionLMAValAll != 0 ||
133133
!Common.ChangeSectionAddress.empty()) {
134134
return createStringError(llvm::errc::invalid_argument,
135135
"option is not supported for DXContainer");

llvm/lib/ObjCopy/DXContainer/DXContainerObjcopy.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@
99
#include "llvm/ObjCopy/DXContainer/DXContainerObjcopy.h"
1010
#include "DXContainerReader.h"
1111
#include "DXContainerWriter.h"
12+
#include "llvm/BinaryFormat/DXContainer.h"
1213
#include "llvm/ObjCopy/CommonConfig.h"
1314
#include "llvm/ObjCopy/DXContainer/DXContainerConfig.h"
15+
#include "llvm/Support/FileOutputBuffer.h"
1416
#include "llvm/Support/raw_ostream.h"
1517

1618
namespace llvm {
@@ -42,7 +44,47 @@ static Error extractPartAsObject(StringRef PartName, StringRef OutFilename,
4244
"part '%s' not found", PartName.str().c_str());
4345
}
4446

47+
static Error dumpPartToFile(StringRef PartName, StringRef Filename,
48+
StringRef InputFilename, Object &Obj) {
49+
auto PartIter = llvm::find_if(
50+
Obj.Parts, [&PartName](const Part &P) { return P.Name == PartName; });
51+
if (PartIter == Obj.Parts.end())
52+
return createFileError(Filename,
53+
std::make_error_code(std::errc::invalid_argument),
54+
"part '%s' not found", PartName.str().c_str());
55+
ArrayRef<uint8_t> Contents = PartIter->Data;
56+
// The DXContainer format is a bit odd because the part-specific headers are
57+
// contained inside the part data itself. For parts that contain LLVM bitcode
58+
// when we dump the part we want to skip the part-specific header so that we
59+
// get a valid .bc file that we can inspect. All the data contained inside the
60+
// program header is pulled out of the bitcode, so the header can be
61+
// reconstructed if needed from the bitcode itself. More comprehensive
62+
// documentation on the DXContainer format can be found at
63+
// https://llvm.org/docs/DirectX/DXContainer.html.
64+
65+
if (PartName == "DXIL" || PartName == "STAT")
66+
Contents = Contents.drop_front(sizeof(llvm::dxbc::ProgramHeader));
67+
if (Contents.empty())
68+
return createFileError(Filename, object_error::parse_failed,
69+
"part '%s' is empty", PartName.str().c_str());
70+
Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
71+
FileOutputBuffer::create(Filename, Contents.size());
72+
if (!BufferOrErr)
73+
return createFileError(Filename, BufferOrErr.takeError());
74+
std::unique_ptr<FileOutputBuffer> Buf = std::move(*BufferOrErr);
75+
llvm::copy(Contents, Buf->getBufferStart());
76+
if (Error E = Buf->commit())
77+
return createFileError(Filename, std::move(E));
78+
return Error::success();
79+
}
80+
4581
static Error handleArgs(const CommonConfig &Config, Object &Obj) {
82+
for (StringRef Flag : Config.DumpSection) {
83+
auto [SecName, FileName] = Flag.split("=");
84+
if (Error E = dumpPartToFile(SecName, FileName, Config.InputFilename, Obj))
85+
return E;
86+
}
87+
4688
// Extract all sections before any modifications.
4789
for (StringRef Flag : Config.ExtractSection) {
4890
StringRef SectionName;
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# RUN: yaml2obj %s -o %t.dxbc
2+
# RUN: not llvm-objcopy --dump-section=FKE0=%t.fek0 %t.dxbc 2>&1 | FileCheck %s --check-prefix=CHECK-ZEROSIZE -DFILE=%t.fek0
3+
# RUN: not llvm-objcopy --dump-section=FKE3=%t.fek1 %t.dxbc 2>&1 | FileCheck %s --check-prefix=CHECK-MISSING -DFILE=%t.fek1
4+
# RUN: not llvm-objcopy --dump-section=FKE2=%t/does_not_exist/.fek2 %t.dxbc 2>&1 | FileCheck %s --check-prefix=CHECK-BAD-PATH -DFILE=%t/does_not_exist/.fek2 -DMSG=%errc_ENOENT
5+
6+
# CHECK-ZEROSIZE: error: '[[FILE]]': part 'FKE0' is empty
7+
# CHECK-MISSING: error: '[[FILE]]': part 'FKE3' not found
8+
# CHECK-BAD-PATH: error: '[[FILE]]': [[MSG]]
9+
10+
--- !dxcontainer
11+
Header:
12+
Hash: [ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
13+
0x0, 0x0, 0x0, 0x0, 0x0, 0x0 ]
14+
Version:
15+
Major: 1
16+
Minor: 0
17+
FileSize: 108
18+
PartCount: 3
19+
PartOffsets: [ 60, 68, 76 ]
20+
Parts:
21+
- Name: FKE0
22+
Size: 0
23+
- Name: FKE1
24+
Size: 0
25+
- Name: FKE2
26+
Size: 8
27+
...

0 commit comments

Comments
 (0)