1*0b57cec5SDimitry Andric //===--- COFFModuleDefinition.cpp - Simple DEF parser ---------------------===//
2*0b57cec5SDimitry Andric //
3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric //
7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric //
9*0b57cec5SDimitry Andric // Windows-specific.
10*0b57cec5SDimitry Andric // A parser for the module-definition file (.def file).
11*0b57cec5SDimitry Andric //
12*0b57cec5SDimitry Andric // The format of module-definition files are described in this document:
13*0b57cec5SDimitry Andric // https://msdn.microsoft.com/en-us/library/28d6s79h.aspx
14*0b57cec5SDimitry Andric //
15*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
16*0b57cec5SDimitry Andric 
17*0b57cec5SDimitry Andric #include "llvm/Object/COFFModuleDefinition.h"
18*0b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h"
19*0b57cec5SDimitry Andric #include "llvm/ADT/StringSwitch.h"
20*0b57cec5SDimitry Andric #include "llvm/Object/COFF.h"
21*0b57cec5SDimitry Andric #include "llvm/Object/COFFImportFile.h"
22*0b57cec5SDimitry Andric #include "llvm/Object/Error.h"
23*0b57cec5SDimitry Andric #include "llvm/Support/Error.h"
24*0b57cec5SDimitry Andric #include "llvm/Support/Path.h"
25*0b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
26*0b57cec5SDimitry Andric 
27*0b57cec5SDimitry Andric using namespace llvm::COFF;
28*0b57cec5SDimitry Andric using namespace llvm;
29*0b57cec5SDimitry Andric 
30*0b57cec5SDimitry Andric namespace llvm {
31*0b57cec5SDimitry Andric namespace object {
32*0b57cec5SDimitry Andric 
33*0b57cec5SDimitry Andric enum Kind {
34*0b57cec5SDimitry Andric   Unknown,
35*0b57cec5SDimitry Andric   Eof,
36*0b57cec5SDimitry Andric   Identifier,
37*0b57cec5SDimitry Andric   Comma,
38*0b57cec5SDimitry Andric   Equal,
39*0b57cec5SDimitry Andric   EqualEqual,
40*0b57cec5SDimitry Andric   KwBase,
41*0b57cec5SDimitry Andric   KwConstant,
42*0b57cec5SDimitry Andric   KwData,
43*0b57cec5SDimitry Andric   KwExports,
44*0b57cec5SDimitry Andric   KwHeapsize,
45*0b57cec5SDimitry Andric   KwLibrary,
46*0b57cec5SDimitry Andric   KwName,
47*0b57cec5SDimitry Andric   KwNoname,
48*0b57cec5SDimitry Andric   KwPrivate,
49*0b57cec5SDimitry Andric   KwStacksize,
50*0b57cec5SDimitry Andric   KwVersion,
51*0b57cec5SDimitry Andric };
52*0b57cec5SDimitry Andric 
53*0b57cec5SDimitry Andric struct Token {
Tokenllvm::object::Token54*0b57cec5SDimitry Andric   explicit Token(Kind T = Unknown, StringRef S = "") : K(T), Value(S) {}
55*0b57cec5SDimitry Andric   Kind K;
56*0b57cec5SDimitry Andric   StringRef Value;
57*0b57cec5SDimitry Andric };
58*0b57cec5SDimitry Andric 
isDecorated(StringRef Sym,bool MingwDef)59*0b57cec5SDimitry Andric static bool isDecorated(StringRef Sym, bool MingwDef) {
60*0b57cec5SDimitry Andric   // In def files, the symbols can either be listed decorated or undecorated.
61*0b57cec5SDimitry Andric   //
62*0b57cec5SDimitry Andric   // - For cdecl symbols, only the undecorated form is allowed.
63*0b57cec5SDimitry Andric   // - For fastcall and vectorcall symbols, both fully decorated or
64*0b57cec5SDimitry Andric   //   undecorated forms can be present.
65*0b57cec5SDimitry Andric   // - For stdcall symbols in non-MinGW environments, the decorated form is
66*0b57cec5SDimitry Andric   //   fully decorated with leading underscore and trailing stack argument
67*0b57cec5SDimitry Andric   //   size - like "_Func@0".
68*0b57cec5SDimitry Andric   // - In MinGW def files, a decorated stdcall symbol does not include the
69*0b57cec5SDimitry Andric   //   leading underscore though, like "Func@0".
70*0b57cec5SDimitry Andric 
71*0b57cec5SDimitry Andric   // This function controls whether a leading underscore should be added to
72*0b57cec5SDimitry Andric   // the given symbol name or not. For MinGW, treat a stdcall symbol name such
73*0b57cec5SDimitry Andric   // as "Func@0" as undecorated, i.e. a leading underscore must be added.
74*0b57cec5SDimitry Andric   // For non-MinGW, look for '@' in the whole string and consider "_Func@0"
75*0b57cec5SDimitry Andric   // as decorated, i.e. don't add any more leading underscores.
76*0b57cec5SDimitry Andric   // We can't check for a leading underscore here, since function names
77*0b57cec5SDimitry Andric   // themselves can start with an underscore, while a second one still needs
78*0b57cec5SDimitry Andric   // to be added.
79*0b57cec5SDimitry Andric   return Sym.startswith("@") || Sym.contains("@@") || Sym.startswith("?") ||
80*0b57cec5SDimitry Andric          (!MingwDef && Sym.contains('@'));
81*0b57cec5SDimitry Andric }
82*0b57cec5SDimitry Andric 
createError(const Twine & Err)83*0b57cec5SDimitry Andric static Error createError(const Twine &Err) {
84*0b57cec5SDimitry Andric   return make_error<StringError>(StringRef(Err.str()),
85*0b57cec5SDimitry Andric                                  object_error::parse_failed);
86*0b57cec5SDimitry Andric }
87*0b57cec5SDimitry Andric 
88*0b57cec5SDimitry Andric class Lexer {
89*0b57cec5SDimitry Andric public:
Lexer(StringRef S)90*0b57cec5SDimitry Andric   Lexer(StringRef S) : Buf(S) {}
91*0b57cec5SDimitry Andric 
lex()92*0b57cec5SDimitry Andric   Token lex() {
93*0b57cec5SDimitry Andric     Buf = Buf.trim();
94*0b57cec5SDimitry Andric     if (Buf.empty())
95*0b57cec5SDimitry Andric       return Token(Eof);
96*0b57cec5SDimitry Andric 
97*0b57cec5SDimitry Andric     switch (Buf[0]) {
98*0b57cec5SDimitry Andric     case '\0':
99*0b57cec5SDimitry Andric       return Token(Eof);
100*0b57cec5SDimitry Andric     case ';': {
101*0b57cec5SDimitry Andric       size_t End = Buf.find('\n');
102*0b57cec5SDimitry Andric       Buf = (End == Buf.npos) ? "" : Buf.drop_front(End);
103*0b57cec5SDimitry Andric       return lex();
104*0b57cec5SDimitry Andric     }
105*0b57cec5SDimitry Andric     case '=':
106*0b57cec5SDimitry Andric       Buf = Buf.drop_front();
107*0b57cec5SDimitry Andric       if (Buf.startswith("=")) {
108*0b57cec5SDimitry Andric         Buf = Buf.drop_front();
109*0b57cec5SDimitry Andric         return Token(EqualEqual, "==");
110*0b57cec5SDimitry Andric       }
111*0b57cec5SDimitry Andric       return Token(Equal, "=");
112*0b57cec5SDimitry Andric     case ',':
113*0b57cec5SDimitry Andric       Buf = Buf.drop_front();
114*0b57cec5SDimitry Andric       return Token(Comma, ",");
115*0b57cec5SDimitry Andric     case '"': {
116*0b57cec5SDimitry Andric       StringRef S;
117*0b57cec5SDimitry Andric       std::tie(S, Buf) = Buf.substr(1).split('"');
118*0b57cec5SDimitry Andric       return Token(Identifier, S);
119*0b57cec5SDimitry Andric     }
120*0b57cec5SDimitry Andric     default: {
121*0b57cec5SDimitry Andric       size_t End = Buf.find_first_of("=,;\r\n \t\v");
122*0b57cec5SDimitry Andric       StringRef Word = Buf.substr(0, End);
123*0b57cec5SDimitry Andric       Kind K = llvm::StringSwitch<Kind>(Word)
124*0b57cec5SDimitry Andric                    .Case("BASE", KwBase)
125*0b57cec5SDimitry Andric                    .Case("CONSTANT", KwConstant)
126*0b57cec5SDimitry Andric                    .Case("DATA", KwData)
127*0b57cec5SDimitry Andric                    .Case("EXPORTS", KwExports)
128*0b57cec5SDimitry Andric                    .Case("HEAPSIZE", KwHeapsize)
129*0b57cec5SDimitry Andric                    .Case("LIBRARY", KwLibrary)
130*0b57cec5SDimitry Andric                    .Case("NAME", KwName)
131*0b57cec5SDimitry Andric                    .Case("NONAME", KwNoname)
132*0b57cec5SDimitry Andric                    .Case("PRIVATE", KwPrivate)
133*0b57cec5SDimitry Andric                    .Case("STACKSIZE", KwStacksize)
134*0b57cec5SDimitry Andric                    .Case("VERSION", KwVersion)
135*0b57cec5SDimitry Andric                    .Default(Identifier);
136*0b57cec5SDimitry Andric       Buf = (End == Buf.npos) ? "" : Buf.drop_front(End);
137*0b57cec5SDimitry Andric       return Token(K, Word);
138*0b57cec5SDimitry Andric     }
139*0b57cec5SDimitry Andric     }
140*0b57cec5SDimitry Andric   }
141*0b57cec5SDimitry Andric 
142*0b57cec5SDimitry Andric private:
143*0b57cec5SDimitry Andric   StringRef Buf;
144*0b57cec5SDimitry Andric };
145*0b57cec5SDimitry Andric 
146*0b57cec5SDimitry Andric class Parser {
147*0b57cec5SDimitry Andric public:
Parser(StringRef S,MachineTypes M,bool B)148*0b57cec5SDimitry Andric   explicit Parser(StringRef S, MachineTypes M, bool B)
149*0b57cec5SDimitry Andric       : Lex(S), Machine(M), MingwDef(B) {}
150*0b57cec5SDimitry Andric 
parse()151*0b57cec5SDimitry Andric   Expected<COFFModuleDefinition> parse() {
152*0b57cec5SDimitry Andric     do {
153*0b57cec5SDimitry Andric       if (Error Err = parseOne())
154*0b57cec5SDimitry Andric         return std::move(Err);
155*0b57cec5SDimitry Andric     } while (Tok.K != Eof);
156*0b57cec5SDimitry Andric     return Info;
157*0b57cec5SDimitry Andric   }
158*0b57cec5SDimitry Andric 
159*0b57cec5SDimitry Andric private:
read()160*0b57cec5SDimitry Andric   void read() {
161*0b57cec5SDimitry Andric     if (Stack.empty()) {
162*0b57cec5SDimitry Andric       Tok = Lex.lex();
163*0b57cec5SDimitry Andric       return;
164*0b57cec5SDimitry Andric     }
165*0b57cec5SDimitry Andric     Tok = Stack.back();
166*0b57cec5SDimitry Andric     Stack.pop_back();
167*0b57cec5SDimitry Andric   }
168*0b57cec5SDimitry Andric 
readAsInt(uint64_t * I)169*0b57cec5SDimitry Andric   Error readAsInt(uint64_t *I) {
170*0b57cec5SDimitry Andric     read();
171*0b57cec5SDimitry Andric     if (Tok.K != Identifier || Tok.Value.getAsInteger(10, *I))
172*0b57cec5SDimitry Andric       return createError("integer expected");
173*0b57cec5SDimitry Andric     return Error::success();
174*0b57cec5SDimitry Andric   }
175*0b57cec5SDimitry Andric 
expect(Kind Expected,StringRef Msg)176*0b57cec5SDimitry Andric   Error expect(Kind Expected, StringRef Msg) {
177*0b57cec5SDimitry Andric     read();
178*0b57cec5SDimitry Andric     if (Tok.K != Expected)
179*0b57cec5SDimitry Andric       return createError(Msg);
180*0b57cec5SDimitry Andric     return Error::success();
181*0b57cec5SDimitry Andric   }
182*0b57cec5SDimitry Andric 
unget()183*0b57cec5SDimitry Andric   void unget() { Stack.push_back(Tok); }
184*0b57cec5SDimitry Andric 
parseOne()185*0b57cec5SDimitry Andric   Error parseOne() {
186*0b57cec5SDimitry Andric     read();
187*0b57cec5SDimitry Andric     switch (Tok.K) {
188*0b57cec5SDimitry Andric     case Eof:
189*0b57cec5SDimitry Andric       return Error::success();
190*0b57cec5SDimitry Andric     case KwExports:
191*0b57cec5SDimitry Andric       for (;;) {
192*0b57cec5SDimitry Andric         read();
193*0b57cec5SDimitry Andric         if (Tok.K != Identifier) {
194*0b57cec5SDimitry Andric           unget();
195*0b57cec5SDimitry Andric           return Error::success();
196*0b57cec5SDimitry Andric         }
197*0b57cec5SDimitry Andric         if (Error Err = parseExport())
198*0b57cec5SDimitry Andric           return Err;
199*0b57cec5SDimitry Andric       }
200*0b57cec5SDimitry Andric     case KwHeapsize:
201*0b57cec5SDimitry Andric       return parseNumbers(&Info.HeapReserve, &Info.HeapCommit);
202*0b57cec5SDimitry Andric     case KwStacksize:
203*0b57cec5SDimitry Andric       return parseNumbers(&Info.StackReserve, &Info.StackCommit);
204*0b57cec5SDimitry Andric     case KwLibrary:
205*0b57cec5SDimitry Andric     case KwName: {
206*0b57cec5SDimitry Andric       bool IsDll = Tok.K == KwLibrary; // Check before parseName.
207*0b57cec5SDimitry Andric       std::string Name;
208*0b57cec5SDimitry Andric       if (Error Err = parseName(&Name, &Info.ImageBase))
209*0b57cec5SDimitry Andric         return Err;
210*0b57cec5SDimitry Andric 
211*0b57cec5SDimitry Andric       Info.ImportName = Name;
212*0b57cec5SDimitry Andric 
213*0b57cec5SDimitry Andric       // Set the output file, but don't override /out if it was already passed.
214*0b57cec5SDimitry Andric       if (Info.OutputFile.empty()) {
215*0b57cec5SDimitry Andric         Info.OutputFile = Name;
216*0b57cec5SDimitry Andric         // Append the appropriate file extension if not already present.
217*0b57cec5SDimitry Andric         if (!sys::path::has_extension(Name))
218*0b57cec5SDimitry Andric           Info.OutputFile += IsDll ? ".dll" : ".exe";
219*0b57cec5SDimitry Andric       }
220*0b57cec5SDimitry Andric 
221*0b57cec5SDimitry Andric       return Error::success();
222*0b57cec5SDimitry Andric     }
223*0b57cec5SDimitry Andric     case KwVersion:
224*0b57cec5SDimitry Andric       return parseVersion(&Info.MajorImageVersion, &Info.MinorImageVersion);
225*0b57cec5SDimitry Andric     default:
226*0b57cec5SDimitry Andric       return createError("unknown directive: " + Tok.Value);
227*0b57cec5SDimitry Andric     }
228*0b57cec5SDimitry Andric   }
229*0b57cec5SDimitry Andric 
parseExport()230*0b57cec5SDimitry Andric   Error parseExport() {
231*0b57cec5SDimitry Andric     COFFShortExport E;
232*0b57cec5SDimitry Andric     E.Name = std::string(Tok.Value);
233*0b57cec5SDimitry Andric     read();
234*0b57cec5SDimitry Andric     if (Tok.K == Equal) {
235*0b57cec5SDimitry Andric       read();
236*0b57cec5SDimitry Andric       if (Tok.K != Identifier)
237*0b57cec5SDimitry Andric         return createError("identifier expected, but got " + Tok.Value);
238*0b57cec5SDimitry Andric       E.ExtName = E.Name;
239*0b57cec5SDimitry Andric       E.Name = std::string(Tok.Value);
240*0b57cec5SDimitry Andric     } else {
241*0b57cec5SDimitry Andric       unget();
242*0b57cec5SDimitry Andric     }
243*0b57cec5SDimitry Andric 
244*0b57cec5SDimitry Andric     if (Machine == IMAGE_FILE_MACHINE_I386) {
245*0b57cec5SDimitry Andric       if (!isDecorated(E.Name, MingwDef))
246*0b57cec5SDimitry Andric         E.Name = (std::string("_").append(E.Name));
247*0b57cec5SDimitry Andric       if (!E.ExtName.empty() && !isDecorated(E.ExtName, MingwDef))
248*0b57cec5SDimitry Andric         E.ExtName = (std::string("_").append(E.ExtName));
249*0b57cec5SDimitry Andric     }
250*0b57cec5SDimitry Andric 
251*0b57cec5SDimitry Andric     for (;;) {
252*0b57cec5SDimitry Andric       read();
253*0b57cec5SDimitry Andric       if (Tok.K == Identifier && Tok.Value[0] == '@') {
254*0b57cec5SDimitry Andric         if (Tok.Value == "@") {
255*0b57cec5SDimitry Andric           // "foo @ 10"
256*0b57cec5SDimitry Andric           read();
257*0b57cec5SDimitry Andric           Tok.Value.getAsInteger(10, E.Ordinal);
258*0b57cec5SDimitry Andric         } else if (Tok.Value.drop_front().getAsInteger(10, E.Ordinal)) {
259*0b57cec5SDimitry Andric           // "foo \n @bar" - Not an ordinal modifier at all, but the next
260*0b57cec5SDimitry Andric           // export (fastcall decorated) - complete the current one.
261*0b57cec5SDimitry Andric           unget();
262*0b57cec5SDimitry Andric           Info.Exports.push_back(E);
263*0b57cec5SDimitry Andric           return Error::success();
264*0b57cec5SDimitry Andric         }
265*0b57cec5SDimitry Andric         // "foo @10"
266*0b57cec5SDimitry Andric         read();
267*0b57cec5SDimitry Andric         if (Tok.K == KwNoname) {
268*0b57cec5SDimitry Andric           E.Noname = true;
269*0b57cec5SDimitry Andric         } else {
270*0b57cec5SDimitry Andric           unget();
271*0b57cec5SDimitry Andric         }
272*0b57cec5SDimitry Andric         continue;
273*0b57cec5SDimitry Andric       }
274*0b57cec5SDimitry Andric       if (Tok.K == KwData) {
275*0b57cec5SDimitry Andric         E.Data = true;
276*0b57cec5SDimitry Andric         continue;
277*0b57cec5SDimitry Andric       }
278*0b57cec5SDimitry Andric       if (Tok.K == KwConstant) {
279*0b57cec5SDimitry Andric         E.Constant = true;
280*0b57cec5SDimitry Andric         continue;
281*0b57cec5SDimitry Andric       }
282*0b57cec5SDimitry Andric       if (Tok.K == KwPrivate) {
283*0b57cec5SDimitry Andric         E.Private = true;
284*0b57cec5SDimitry Andric         continue;
285*0b57cec5SDimitry Andric       }
286*0b57cec5SDimitry Andric       if (Tok.K == EqualEqual) {
287*0b57cec5SDimitry Andric         read();
288*0b57cec5SDimitry Andric         E.AliasTarget = std::string(Tok.Value);
289*0b57cec5SDimitry Andric         if (Machine == IMAGE_FILE_MACHINE_I386 && !isDecorated(E.AliasTarget, MingwDef))
290*0b57cec5SDimitry Andric           E.AliasTarget = std::string("_").append(E.AliasTarget);
291*0b57cec5SDimitry Andric         continue;
292*0b57cec5SDimitry Andric       }
293*0b57cec5SDimitry Andric       unget();
294*0b57cec5SDimitry Andric       Info.Exports.push_back(E);
295*0b57cec5SDimitry Andric       return Error::success();
296*0b57cec5SDimitry Andric     }
297*0b57cec5SDimitry Andric   }
298*0b57cec5SDimitry Andric 
299*0b57cec5SDimitry Andric   // HEAPSIZE/STACKSIZE reserve[,commit]
parseNumbers(uint64_t * Reserve,uint64_t * Commit)300*0b57cec5SDimitry Andric   Error parseNumbers(uint64_t *Reserve, uint64_t *Commit) {
301*0b57cec5SDimitry Andric     if (Error Err = readAsInt(Reserve))
302*0b57cec5SDimitry Andric       return Err;
303*0b57cec5SDimitry Andric     read();
304*0b57cec5SDimitry Andric     if (Tok.K != Comma) {
305*0b57cec5SDimitry Andric       unget();
306*0b57cec5SDimitry Andric       Commit = nullptr;
307*0b57cec5SDimitry Andric       return Error::success();
308*0b57cec5SDimitry Andric     }
309*0b57cec5SDimitry Andric     if (Error Err = readAsInt(Commit))
310*0b57cec5SDimitry Andric       return Err;
311*0b57cec5SDimitry Andric     return Error::success();
312*0b57cec5SDimitry Andric   }
313*0b57cec5SDimitry Andric 
314*0b57cec5SDimitry Andric   // NAME outputPath [BASE=address]
parseName(std::string * Out,uint64_t * Baseaddr)315*0b57cec5SDimitry Andric   Error parseName(std::string *Out, uint64_t *Baseaddr) {
316*0b57cec5SDimitry Andric     read();
317*0b57cec5SDimitry Andric     if (Tok.K == Identifier) {
318*0b57cec5SDimitry Andric       *Out = std::string(Tok.Value);
319*0b57cec5SDimitry Andric     } else {
320*0b57cec5SDimitry Andric       *Out = "";
321*0b57cec5SDimitry Andric       unget();
322*0b57cec5SDimitry Andric       return Error::success();
323*0b57cec5SDimitry Andric     }
324*0b57cec5SDimitry Andric     read();
325*0b57cec5SDimitry Andric     if (Tok.K == KwBase) {
326*0b57cec5SDimitry Andric       if (Error Err = expect(Equal, "'=' expected"))
327*0b57cec5SDimitry Andric         return Err;
328*0b57cec5SDimitry Andric       if (Error Err = readAsInt(Baseaddr))
329*0b57cec5SDimitry Andric         return Err;
330*0b57cec5SDimitry Andric     } else {
331*0b57cec5SDimitry Andric       unget();
332*0b57cec5SDimitry Andric       *Baseaddr = 0;
333*0b57cec5SDimitry Andric     }
334*0b57cec5SDimitry Andric     return Error::success();
335*0b57cec5SDimitry Andric   }
336*0b57cec5SDimitry Andric 
337*0b57cec5SDimitry Andric   // VERSION major[.minor]
parseVersion(uint32_t * Major,uint32_t * Minor)338*0b57cec5SDimitry Andric   Error parseVersion(uint32_t *Major, uint32_t *Minor) {
339*0b57cec5SDimitry Andric     read();
340*0b57cec5SDimitry Andric     if (Tok.K != Identifier)
341*0b57cec5SDimitry Andric       return createError("identifier expected, but got " + Tok.Value);
342*0b57cec5SDimitry Andric     StringRef V1, V2;
343*0b57cec5SDimitry Andric     std::tie(V1, V2) = Tok.Value.split('.');
344*0b57cec5SDimitry Andric     if (V1.getAsInteger(10, *Major))
345*0b57cec5SDimitry Andric       return createError("integer expected, but got " + Tok.Value);
346*0b57cec5SDimitry Andric     if (V2.empty())
347*0b57cec5SDimitry Andric       *Minor = 0;
348*0b57cec5SDimitry Andric     else if (V2.getAsInteger(10, *Minor))
349*0b57cec5SDimitry Andric       return createError("integer expected, but got " + Tok.Value);
350*0b57cec5SDimitry Andric     return Error::success();
351*0b57cec5SDimitry Andric   }
352*0b57cec5SDimitry Andric 
353*0b57cec5SDimitry Andric   Lexer Lex;
354*0b57cec5SDimitry Andric   Token Tok;
355*0b57cec5SDimitry Andric   std::vector<Token> Stack;
356*0b57cec5SDimitry Andric   MachineTypes Machine;
357*0b57cec5SDimitry Andric   COFFModuleDefinition Info;
358*0b57cec5SDimitry Andric   bool MingwDef;
359*0b57cec5SDimitry Andric };
360*0b57cec5SDimitry Andric 
parseCOFFModuleDefinition(MemoryBufferRef MB,MachineTypes Machine,bool MingwDef)361*0b57cec5SDimitry Andric Expected<COFFModuleDefinition> parseCOFFModuleDefinition(MemoryBufferRef MB,
362*0b57cec5SDimitry Andric                                                          MachineTypes Machine,
363*0b57cec5SDimitry Andric                                                          bool MingwDef) {
364*0b57cec5SDimitry Andric   return Parser(MB.getBuffer(), Machine, MingwDef).parse();
365*0b57cec5SDimitry Andric }
366*0b57cec5SDimitry Andric 
367*0b57cec5SDimitry Andric } // namespace object
368*0b57cec5SDimitry Andric } // namespace llvm
369