28
28
#include " llvm/Support/raw_ostream.h"
29
29
30
30
#define IMAGE_INFO_SECTION_NAME " .tgtimg"
31
+ #define IMAGE_SECTION_NAME_PREFIX " __CLANG_OFFLOAD_BUNDLE__"
32
+ // Windows truncates the names of sections to 8 bytes
33
+ #define IMAGE_SECTION_NAME_PREFIX_COFF " __CLANG_"
34
+
35
+ #define DEBUG_TYPE " clang-offload-extract"
31
36
32
37
using namespace llvm ;
33
38
using namespace llvm ::object;
34
39
40
+ // Command-line parsing
35
41
// Create a category to label utility-specific options; This will allow
36
42
// us to distinguish those specific options from generic options and
37
43
// irrelevant options
38
44
static cl::OptionCategory
39
45
ClangOffloadExtractCategory (" Utility-specific options" );
40
46
41
- // Create options for the input and output files, each with an
42
- // appropriate default when not specified
47
+ // Create options for the input (fat binary) and output (target images)
48
+ // files, each with an appropriate default when not specified
43
49
static cl::opt<std::string> Input (cl::Positional, cl::init(" a.out" ),
44
50
cl::desc(" <input file>" ),
45
51
cl::cat(ClangOffloadExtractCategory));
@@ -61,10 +67,8 @@ static cl::alias FileNameStemAlias(
61
67
" output" , cl::desc(" Deprecated option, replaced by option '--stem'" ),
62
68
cl::aliasopt(FileNameStem), cl::cat(ClangOffloadExtractCategory));
63
69
64
- // Path to the current binary
65
- static std::string ToolPath;
66
-
67
70
// Report error (and handle any deferred errors)
71
+ // This is the main diagnostic used by the utility
68
72
static void reportError (Error E, Twine message = " \n " ) {
69
73
std::string S;
70
74
raw_string_ostream OSS (S);
@@ -80,7 +84,6 @@ static void reportError(Error E, Twine message = "\n") {
80
84
81
85
int main (int argc, const char **argv) {
82
86
sys::PrintStackTraceOnErrorSignal (argv[0 ]);
83
- ToolPath = argv[0 ];
84
87
85
88
// Hide non-generic options that are not in this utility's explicit
86
89
// category;
@@ -138,105 +141,144 @@ linked fat binary, and store them in separate files.
138
141
}
139
142
140
143
// We are dealing with an appropriate fat binary;
141
- // Locate the section IMAGE_INFO_SECTION_NAME (which contains the
142
- // metadata on the embedded binaries)
143
- unsigned FileNum = 0 ;
144
-
144
+ // * Create an array all the sections that have
145
+ // IMAGE_SECTION_NAME in the section name:
146
+ auto OffloadSections = SmallVector<SectionRef>();
147
+ // * Locate the section that starts with IMAGE_INFO_SECTION_NAME_PREFIX
148
+ // and extract the index for all the embedded binaries:
149
+ auto OffloadIndex = SmallVector<SectionRef>();
145
150
for (const auto &Section : Binary->sections ()) {
146
- Expected<StringRef> NameOrErr = Section.getName ();
147
- if (auto E = NameOrErr .takeError ()) {
151
+ Expected<StringRef> InfoSecNameOrErr = Section.getName ();
152
+ if (auto E = InfoSecNameOrErr .takeError ()) {
148
153
reportError (std::move (E), " Input File: '" + Input + " '\n " );
149
154
}
150
- if (*NameOrErr != IMAGE_INFO_SECTION_NAME)
151
- continue ;
155
+ LLVM_DEBUG (dbgs () << " Section: " << *InfoSecNameOrErr << " \n " );
152
156
153
- // This is the section we are looking for;
154
- // Extract the meta information:
155
- // The IMAGE_INFO_SECTION_NAME section contains packed <address,
156
- // size> pairs describing target images that are stored in the fat
157
- // binary.
158
- Expected<StringRef> DataOrErr = Section.getContents ();
159
- if (auto E = DataOrErr.takeError ()) {
160
- reportError (std::move (E), " Input File: '" + Input + " '\n " );
157
+ // We have a valid section name
158
+ std::string SectionNameToCompare = isa<COFFObjectFile>(Binary)
159
+ ? IMAGE_SECTION_NAME_PREFIX_COFF
160
+ : IMAGE_SECTION_NAME_PREFIX;
161
+ if (InfoSecNameOrErr->find (SectionNameToCompare) != std::string::npos) {
162
+ // This section contains embedded binaries
163
+ OffloadSections.push_back (Section);
164
+ } else if (*InfoSecNameOrErr == IMAGE_INFO_SECTION_NAME) {
165
+ // This section is the index
166
+ OffloadIndex.push_back (Section);
161
167
}
162
- // Data type to store the metadata for an individual target image
163
- struct ImgInfoType {
164
- uintptr_t Addr;
165
- uintptr_t Size;
166
- };
167
-
168
- // Store the metadata for all target images in an array of target
169
- // image information descriptors
170
- auto ImgInfo =
171
- ArrayRef (reinterpret_cast <const ImgInfoType *>(DataOrErr->data ()),
172
- DataOrErr->size () / sizeof (ImgInfoType));
173
-
174
- // Loop over the image information descriptors to extract each
175
- // target image.
176
- for (const auto &Img : ImgInfo) {
177
- // Ignore zero padding that can be inserted by the linker.
178
- if (!Img.Addr )
179
- continue ;
180
-
181
- // Find section which contains this image.
182
- // TODO: can use more efficient algorithm than linear search. For
183
- // example sections and images could be sorted by address then one pass
184
- // performed through both at the same time.
185
- // std::find_if
186
- // * searches for a true predicate in [first,last] =~ [first,end)
187
- // * returns end if no predicate is true
188
- // It is probably faster to track success through a bool (ImgFound)
189
- bool ImgFound = false ;
190
- auto ImgSec =
191
- find_if (Binary->sections (), [&Img, &ImgFound](SectionRef Sec) {
192
- bool pred = ( //
193
- Sec.isData () //
194
- && (Img.Addr == Sec.getAddress ()) //
195
- && (Img.Size == Sec.getSize ()) //
196
- );
197
- ImgFound = ImgFound || pred;
198
- return pred;
199
- });
200
- if (!ImgFound) {
201
-
202
- reportError (
203
- createStringError (
204
- inconvertibleErrorCode (),
205
- " cannot find section containing <0x%lx, 0x%lx> target image" ,
206
- Img.Addr , Img.Size ),
207
- " Input File: '" + Input + " '\n " );
208
- }
209
-
210
- Expected<StringRef> SecDataOrErr = ImgSec->getContents ();
211
- if (auto E = SecDataOrErr.takeError ()) {
212
- reportError (std::move (E), " Input File: '" + Input + " '\n " );
213
- }
214
-
215
- // Output file name is composed from the name prefix provided by the
216
- // user and the image number which is appended to the prefix
217
- std::string FileName = FileNameStem + " ." + std::to_string (FileNum++);
218
-
219
- // Tell user that we are saving an image.
220
- outs () << " Saving target image to '" << FileName << " '\n " ;
221
-
222
- // Write image data to the output
223
- std::error_code EC;
224
- raw_fd_ostream OS (FileName, EC);
225
- if (EC) {
226
- reportError (createFileError (FileName, EC),
227
- " Specify a different Output File ('--stem' option)\n " );
228
- }
229
-
230
- OS << SecDataOrErr->substr (Img.Addr - ImgSec->getAddress (), Img.Size );
231
- if (OS.has_error ()) {
232
- reportError (createFileError (FileName, OS.error ()),
233
- " Try a different Output File ('--stem' option)" );
234
- }
235
- } // &Img: ImgInfo
236
-
237
- // Fat binary is not expected to have more than one .tgtimg section.
238
- break ;
239
168
}
240
169
170
+ // Check if there are any sections with embedded binaries
171
+ if (OffloadSections.size () == 0 ) {
172
+ reportError (
173
+ createStringError (inconvertibleErrorCode (),
174
+ " Could not locate sections with offload binaries" ),
175
+ " Fat Binary: '" + Input + " '\n " );
176
+ }
177
+ // Check if we found the index section
178
+ if (OffloadIndex.size () == 0 ) {
179
+ reportError (
180
+ createStringError (inconvertibleErrorCode (),
181
+ " Could not locate index for embedded binaries" ),
182
+ " Fat Binary: '" + Input + " '\n " );
183
+ }
184
+ // Check if we have a valid index section
185
+ Expected<StringRef> DataOrErr = OffloadIndex[0 ].getContents ();
186
+ if (auto E = DataOrErr.takeError ()) {
187
+ reportError (std::move (E), " Input File: '" + Input + " '\n " );
188
+ }
189
+
190
+ // The input binary contains embedded offload binaries
191
+ // The index section contains packed <address, size> pairs describing
192
+ // target images that are stored in the fat binary.
193
+ // Data type to store the index for an individual target image
194
+ struct ImgInfoType {
195
+ uintptr_t Addr;
196
+ uintptr_t Size;
197
+ };
198
+
199
+ // Store the metadata for all target images in an array of target
200
+ // image information descriptors
201
+ // This can be done by reinterpreting the content of the section
202
+ auto ImgInfo =
203
+ ArrayRef (reinterpret_cast <const ImgInfoType *>(DataOrErr->data ()),
204
+ DataOrErr->size () / sizeof (ImgInfoType));
205
+
206
+ // Loop over the image information descriptors to extract each
207
+ // target image the object file data
208
+ unsigned FileNum = 0 ;
209
+ unsigned ImgCnt = 1 ;
210
+
211
+ for (const auto &Img : ImgInfo) {
212
+ // Ignore zero padding that can be inserted by the linker.
213
+ if (!Img.Addr )
214
+ continue ;
215
+
216
+ // Find section which contains this image.
217
+ // /!\ There might be multiple images in a section
218
+ // std::find_if
219
+ // * searches for a true predicate in [first,last] =~ [first,end)
220
+ // * returns end if no predicate is true
221
+ // It is probably faster to track success through a bool (ImgFound)
222
+ bool ImgFound = false ;
223
+ auto ImgSec = find_if (OffloadSections, [&Img, &ImgFound](auto Sec) {
224
+ bool pred = ( //
225
+ Sec.isData () //
226
+ && (Img.Addr >= Sec.getAddress ()) //
227
+ && ((Img.Addr + Img.Size ) <= (Sec.getAddress () + Sec.getSize ())) //
228
+ );
229
+ ImgFound = ImgFound || pred;
230
+ return pred;
231
+ });
232
+ if (!ImgFound) {
233
+
234
+ reportError (
235
+ createStringError (inconvertibleErrorCode (),
236
+ " Target image (Address:0x%lx, Size:0x%lx>) is "
237
+ " not contained in any section" ,
238
+ Img.Addr , Img.Size ),
239
+ " Fat Binary: '" + Input + " '\n " );
240
+ }
241
+
242
+ Expected<StringRef> ImgSecNameOrErr = ImgSec->getName ();
243
+ if (auto E = ImgSecNameOrErr.takeError ()) {
244
+ reportError (std::move (E),
245
+ " Can not determine section name in Fat Binary '" + Input +
246
+ " '\n " );
247
+ }
248
+ Expected<StringRef> SecDataOrErr = ImgSec->getContents ();
249
+ if (auto E = SecDataOrErr.takeError ()) {
250
+ reportError (std::move (E), " Can not extract contents for section '" +
251
+ *ImgSecNameOrErr + " ' in Fat Binary '" +
252
+ Input + " '\n " );
253
+ }
254
+
255
+ // Output file name is composed from the name prefix provided by the
256
+ // user and the image number which is appended to the prefix
257
+ std::string FileName = FileNameStem + " ." + std::to_string (FileNum++);
258
+ std::string OffloadName = ImgSecNameOrErr->data ();
259
+ std::string OffloadPrefix = isa<COFFObjectFile>(Binary)
260
+ ? IMAGE_SECTION_NAME_PREFIX_COFF
261
+ : IMAGE_SECTION_NAME_PREFIX;
262
+ OffloadName.erase (0 , OffloadPrefix.length ());
263
+
264
+ // Tell user that we are saving an image.
265
+ outs () << " Section '" + OffloadName + " ': Image " << ImgCnt++
266
+ << " '-> File '" + FileName + " '\n " ;
267
+
268
+ // Write image data to the output
269
+ std::error_code EC;
270
+ raw_fd_ostream OS (FileName, EC);
271
+ if (EC) {
272
+ reportError (createFileError (FileName, EC),
273
+ " Specify a different Output File ('--stem' option)\n " );
274
+ }
275
+
276
+ OS << SecDataOrErr->substr (Img.Addr - ImgSec->getAddress (), Img.Size );
277
+ if (OS.has_error ()) {
278
+ reportError (createFileError (FileName, OS.error ()),
279
+ " Try a different Output File ('--stem' option)" );
280
+ }
281
+ } // &Img: ImgInfo
282
+
241
283
return 0 ;
242
284
}
0 commit comments