OSDN Git Service

Revert "r364412 [ExpandMemCmp][MergeICmps] Move passes out of CodeGen into opt pipeline."
[android-x86/external-llvm.git] / tools / llvm-cvtres / llvm-cvtres.cpp
1 //===- llvm-cvtres.cpp - Serialize .res files into .obj ---------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Serialize .res files into .obj files.  This is intended to be a
10 // platform-independent port of Microsoft's cvtres.exe.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #include "llvm/ADT/StringSwitch.h"
15 #include "llvm/Object/Binary.h"
16 #include "llvm/Object/WindowsMachineFlag.h"
17 #include "llvm/Object/WindowsResource.h"
18 #include "llvm/Option/Arg.h"
19 #include "llvm/Option/ArgList.h"
20 #include "llvm/Option/Option.h"
21 #include "llvm/Support/BinaryStreamError.h"
22 #include "llvm/Support/Error.h"
23 #include "llvm/Support/InitLLVM.h"
24 #include "llvm/Support/ManagedStatic.h"
25 #include "llvm/Support/Path.h"
26 #include "llvm/Support/PrettyStackTrace.h"
27 #include "llvm/Support/Process.h"
28 #include "llvm/Support/ScopedPrinter.h"
29 #include "llvm/Support/Signals.h"
30 #include "llvm/Support/raw_ostream.h"
31
32 #include <system_error>
33
34 using namespace llvm;
35 using namespace object;
36
37 namespace {
38
39 enum ID {
40   OPT_INVALID = 0, // This is not an option ID.
41 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM,  \
42                HELPTEXT, METAVAR, VALUES)                                      \
43   OPT_##ID,
44 #include "Opts.inc"
45 #undef OPTION
46 };
47
48 #define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
49 #include "Opts.inc"
50 #undef PREFIX
51
52 static const opt::OptTable::Info InfoTable[] = {
53 #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM,  \
54                HELPTEXT, METAVAR, VALUES)                                      \
55   {                                                                            \
56       PREFIX,      NAME,      HELPTEXT,                                        \
57       METAVAR,     OPT_##ID,  opt::Option::KIND##Class,                        \
58       PARAM,       FLAGS,     OPT_##GROUP,                                     \
59       OPT_##ALIAS, ALIASARGS, VALUES},
60 #include "Opts.inc"
61 #undef OPTION
62 };
63
64 class CvtResOptTable : public opt::OptTable {
65 public:
66   CvtResOptTable() : OptTable(InfoTable, true) {}
67 };
68 }
69
70 LLVM_ATTRIBUTE_NORETURN void reportError(Twine Msg) {
71   errs() << Msg;
72   exit(1);
73 }
74
75 static void reportError(StringRef Input, std::error_code EC) {
76   reportError(Twine(Input) + ": " + EC.message() + ".\n");
77 }
78
79 void error(std::error_code EC) {
80   if (!EC)
81     return;
82   reportError(EC.message() + ".\n");
83 }
84
85 void error(Error EC) {
86   if (!EC)
87     return;
88   handleAllErrors(std::move(EC),
89                   [&](const ErrorInfoBase &EI) { reportError(EI.message()); });
90 }
91
92 static uint32_t getTime() {
93   std::time_t Now = time(nullptr);
94   if (Now < 0 || !isUInt<32>(Now))
95     return UINT32_MAX;
96   return static_cast<uint32_t>(Now);
97 }
98
99 template <typename T> T error(Expected<T> EC) {
100   if (!EC)
101     error(EC.takeError());
102   return std::move(EC.get());
103 }
104
105 int main(int Argc, const char **Argv) {
106   InitLLVM X(Argc, Argv);
107
108   CvtResOptTable T;
109   unsigned MAI, MAC;
110   ArrayRef<const char *> ArgsArr = makeArrayRef(Argv + 1, Argc - 1);
111   opt::InputArgList InputArgs = T.ParseArgs(ArgsArr, MAI, MAC);
112
113   if (InputArgs.hasArg(OPT_HELP)) {
114     T.PrintHelp(outs(), "llvm-cvtres [options] file...", "Resource Converter");
115     return 0;
116   }
117
118   bool Verbose = InputArgs.hasArg(OPT_VERBOSE);
119
120   COFF::MachineTypes MachineType;
121
122   if (opt::Arg *Arg = InputArgs.getLastArg(OPT_MACHINE)) {
123     MachineType = getMachineType(Arg->getValue());
124     if (MachineType == COFF::IMAGE_FILE_MACHINE_UNKNOWN) {
125       reportError(Twine("Unsupported machine architecture ") + Arg->getValue() +
126                   "\n");
127     }
128   } else {
129     if (Verbose)
130       outs() << "Machine architecture not specified; assumed X64.\n";
131     MachineType = COFF::IMAGE_FILE_MACHINE_AMD64;
132   }
133
134   std::vector<std::string> InputFiles = InputArgs.getAllArgValues(OPT_INPUT);
135
136   if (InputFiles.size() == 0) {
137     reportError("No input file specified.\n");
138   }
139
140   SmallString<128> OutputFile;
141
142   if (opt::Arg *Arg = InputArgs.getLastArg(OPT_OUT)) {
143     OutputFile = Arg->getValue();
144   } else {
145     OutputFile = sys::path::filename(StringRef(InputFiles[0]));
146     sys::path::replace_extension(OutputFile, ".obj");
147   }
148
149   uint32_t DateTimeStamp;
150   if (llvm::opt::Arg *Arg = InputArgs.getLastArg(OPT_TIMESTAMP)) {
151     StringRef Value(Arg->getValue());
152     if (Value.getAsInteger(0, DateTimeStamp))
153       reportError(Twine("invalid timestamp: ") + Value +
154             ".  Expected 32-bit integer\n");
155   } else {
156     DateTimeStamp = getTime();
157   }
158
159   if (Verbose)
160     outs() << "Machine: " << machineToStr(MachineType) << '\n';
161
162   WindowsResourceParser Parser;
163
164   for (const auto &File : InputFiles) {
165     Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(File);
166     if (!BinaryOrErr)
167       reportError(File, errorToErrorCode(BinaryOrErr.takeError()));
168
169     Binary &Binary = *BinaryOrErr.get().getBinary();
170
171     WindowsResource *RF = dyn_cast<WindowsResource>(&Binary);
172     if (!RF)
173       reportError(File + ": unrecognized file format.\n");
174
175     if (Verbose) {
176       int EntryNumber = 0;
177       ResourceEntryRef Entry = error(RF->getHeadEntry());
178       bool End = false;
179       while (!End) {
180         error(Entry.moveNext(End));
181         EntryNumber++;
182       }
183       outs() << "Number of resources: " << EntryNumber << "\n";
184     }
185
186     std::vector<std::string> Duplicates;
187     error(Parser.parse(RF, Duplicates));
188     for (const auto& DupeDiag : Duplicates)
189       reportError(DupeDiag);
190   }
191
192   if (Verbose) {
193     Parser.printTree(outs());
194   }
195
196   std::unique_ptr<MemoryBuffer> OutputBuffer =
197       error(llvm::object::writeWindowsResourceCOFF(MachineType, Parser,
198                                                    DateTimeStamp));
199   auto FileOrErr =
200       FileOutputBuffer::create(OutputFile, OutputBuffer->getBufferSize());
201   if (!FileOrErr)
202     reportError(OutputFile, errorToErrorCode(FileOrErr.takeError()));
203   std::unique_ptr<FileOutputBuffer> FileBuffer = std::move(*FileOrErr);
204   std::copy(OutputBuffer->getBufferStart(), OutputBuffer->getBufferEnd(),
205             FileBuffer->getBufferStart());
206   error(FileBuffer->commit());
207
208   if (Verbose) {
209     Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(OutputFile);
210     if (!BinaryOrErr)
211       reportError(OutputFile, errorToErrorCode(BinaryOrErr.takeError()));
212     Binary &Binary = *BinaryOrErr.get().getBinary();
213     ScopedPrinter W(errs());
214     W.printBinaryBlock("Output File Raw Data", Binary.getData());
215   }
216
217   return 0;
218 }