1*146eb7a6SReid Kleckner //===--- COFFModuleDefinition.cpp - Simple DEF parser ---------------------===//
2*146eb7a6SReid Kleckner //
3*146eb7a6SReid Kleckner //                     The LLVM Compiler Infrastructure
4*146eb7a6SReid Kleckner //
5*146eb7a6SReid Kleckner // This file is distributed under the University of Illinois Open Source
6*146eb7a6SReid Kleckner // License. See LICENSE.TXT for details.
7*146eb7a6SReid Kleckner //
8*146eb7a6SReid Kleckner //===----------------------------------------------------------------------===//
9*146eb7a6SReid Kleckner //
10*146eb7a6SReid Kleckner // Windows-specific.
11*146eb7a6SReid Kleckner // A parser for the module-definition file (.def file).
12*146eb7a6SReid Kleckner //
13*146eb7a6SReid Kleckner // The format of module-definition files are described in this document:
14*146eb7a6SReid Kleckner // https://msdn.microsoft.com/en-us/library/28d6s79h.aspx
15*146eb7a6SReid Kleckner //
16*146eb7a6SReid Kleckner //===----------------------------------------------------------------------===//
17*146eb7a6SReid Kleckner 
18*146eb7a6SReid Kleckner #include "llvm/Object/COFFModuleDefinition.h"
19*146eb7a6SReid Kleckner #include "llvm/ADT/StringRef.h"
20*146eb7a6SReid Kleckner #include "llvm/ADT/StringSwitch.h"
21*146eb7a6SReid Kleckner #include "llvm/Object/COFF.h"
22*146eb7a6SReid Kleckner #include "llvm/Object/COFFImportFile.h"
23*146eb7a6SReid Kleckner #include "llvm/Object/Error.h"
24*146eb7a6SReid Kleckner #include "llvm/Support/Error.h"
25*146eb7a6SReid Kleckner #include "llvm/Support/raw_ostream.h"
26*146eb7a6SReid Kleckner 
27*146eb7a6SReid Kleckner using namespace llvm::COFF;
28*146eb7a6SReid Kleckner using namespace llvm;
29*146eb7a6SReid Kleckner 
30*146eb7a6SReid Kleckner namespace llvm {
31*146eb7a6SReid Kleckner namespace object {
32*146eb7a6SReid Kleckner 
33*146eb7a6SReid Kleckner enum Kind {
34*146eb7a6SReid Kleckner   Unknown,
35*146eb7a6SReid Kleckner   Eof,
36*146eb7a6SReid Kleckner   Identifier,
37*146eb7a6SReid Kleckner   Comma,
38*146eb7a6SReid Kleckner   Equal,
39*146eb7a6SReid Kleckner   KwBase,
40*146eb7a6SReid Kleckner   KwConstant,
41*146eb7a6SReid Kleckner   KwData,
42*146eb7a6SReid Kleckner   KwExports,
43*146eb7a6SReid Kleckner   KwHeapsize,
44*146eb7a6SReid Kleckner   KwLibrary,
45*146eb7a6SReid Kleckner   KwName,
46*146eb7a6SReid Kleckner   KwNoname,
47*146eb7a6SReid Kleckner   KwPrivate,
48*146eb7a6SReid Kleckner   KwStacksize,
49*146eb7a6SReid Kleckner   KwVersion,
50*146eb7a6SReid Kleckner };
51*146eb7a6SReid Kleckner 
52*146eb7a6SReid Kleckner struct Token {
53*146eb7a6SReid Kleckner   explicit Token(Kind T = Unknown, StringRef S = "") : K(T), Value(S) {}
54*146eb7a6SReid Kleckner   Kind K;
55*146eb7a6SReid Kleckner   StringRef Value;
56*146eb7a6SReid Kleckner };
57*146eb7a6SReid Kleckner 
58*146eb7a6SReid Kleckner static bool isDecorated(StringRef Sym) {
59*146eb7a6SReid Kleckner   return Sym.startswith("_") || Sym.startswith("@") || Sym.startswith("?");
60*146eb7a6SReid Kleckner }
61*146eb7a6SReid Kleckner 
62*146eb7a6SReid Kleckner static Error createError(const Twine &Err) {
63*146eb7a6SReid Kleckner   return make_error<StringError>(StringRef(Err.str()),
64*146eb7a6SReid Kleckner                                  object_error::parse_failed);
65*146eb7a6SReid Kleckner }
66*146eb7a6SReid Kleckner 
67*146eb7a6SReid Kleckner class Lexer {
68*146eb7a6SReid Kleckner public:
69*146eb7a6SReid Kleckner   Lexer(StringRef S) : Buf(S) {}
70*146eb7a6SReid Kleckner 
71*146eb7a6SReid Kleckner   Token lex() {
72*146eb7a6SReid Kleckner     Buf = Buf.trim();
73*146eb7a6SReid Kleckner     if (Buf.empty())
74*146eb7a6SReid Kleckner       return Token(Eof);
75*146eb7a6SReid Kleckner 
76*146eb7a6SReid Kleckner     switch (Buf[0]) {
77*146eb7a6SReid Kleckner     case '\0':
78*146eb7a6SReid Kleckner       return Token(Eof);
79*146eb7a6SReid Kleckner     case ';': {
80*146eb7a6SReid Kleckner       size_t End = Buf.find('\n');
81*146eb7a6SReid Kleckner       Buf = (End == Buf.npos) ? "" : Buf.drop_front(End);
82*146eb7a6SReid Kleckner       return lex();
83*146eb7a6SReid Kleckner     }
84*146eb7a6SReid Kleckner     case '=':
85*146eb7a6SReid Kleckner       Buf = Buf.drop_front();
86*146eb7a6SReid Kleckner       return Token(Equal, "=");
87*146eb7a6SReid Kleckner     case ',':
88*146eb7a6SReid Kleckner       Buf = Buf.drop_front();
89*146eb7a6SReid Kleckner       return Token(Comma, ",");
90*146eb7a6SReid Kleckner     case '"': {
91*146eb7a6SReid Kleckner       StringRef S;
92*146eb7a6SReid Kleckner       std::tie(S, Buf) = Buf.substr(1).split('"');
93*146eb7a6SReid Kleckner       return Token(Identifier, S);
94*146eb7a6SReid Kleckner     }
95*146eb7a6SReid Kleckner     default: {
96*146eb7a6SReid Kleckner       size_t End = Buf.find_first_of("=,\r\n \t\v");
97*146eb7a6SReid Kleckner       StringRef Word = Buf.substr(0, End);
98*146eb7a6SReid Kleckner       Kind K = llvm::StringSwitch<Kind>(Word)
99*146eb7a6SReid Kleckner                    .Case("BASE", KwBase)
100*146eb7a6SReid Kleckner                    .Case("CONSTANT", KwConstant)
101*146eb7a6SReid Kleckner                    .Case("DATA", KwData)
102*146eb7a6SReid Kleckner                    .Case("EXPORTS", KwExports)
103*146eb7a6SReid Kleckner                    .Case("HEAPSIZE", KwHeapsize)
104*146eb7a6SReid Kleckner                    .Case("LIBRARY", KwLibrary)
105*146eb7a6SReid Kleckner                    .Case("NAME", KwName)
106*146eb7a6SReid Kleckner                    .Case("NONAME", KwNoname)
107*146eb7a6SReid Kleckner                    .Case("PRIVATE", KwPrivate)
108*146eb7a6SReid Kleckner                    .Case("STACKSIZE", KwStacksize)
109*146eb7a6SReid Kleckner                    .Case("VERSION", KwVersion)
110*146eb7a6SReid Kleckner                    .Default(Identifier);
111*146eb7a6SReid Kleckner       Buf = (End == Buf.npos) ? "" : Buf.drop_front(End);
112*146eb7a6SReid Kleckner       return Token(K, Word);
113*146eb7a6SReid Kleckner     }
114*146eb7a6SReid Kleckner     }
115*146eb7a6SReid Kleckner   }
116*146eb7a6SReid Kleckner 
117*146eb7a6SReid Kleckner private:
118*146eb7a6SReid Kleckner   StringRef Buf;
119*146eb7a6SReid Kleckner };
120*146eb7a6SReid Kleckner 
121*146eb7a6SReid Kleckner class Parser {
122*146eb7a6SReid Kleckner public:
123*146eb7a6SReid Kleckner   explicit Parser(StringRef S, MachineTypes M) : Lex(S), Machine(M) {}
124*146eb7a6SReid Kleckner 
125*146eb7a6SReid Kleckner   Expected<COFFModuleDefinition> parse() {
126*146eb7a6SReid Kleckner     do {
127*146eb7a6SReid Kleckner       if (Error Err = parseOne())
128*146eb7a6SReid Kleckner         return std::move(Err);
129*146eb7a6SReid Kleckner     } while (Tok.K != Eof);
130*146eb7a6SReid Kleckner     return Info;
131*146eb7a6SReid Kleckner   }
132*146eb7a6SReid Kleckner 
133*146eb7a6SReid Kleckner private:
134*146eb7a6SReid Kleckner   void read() {
135*146eb7a6SReid Kleckner     if (Stack.empty()) {
136*146eb7a6SReid Kleckner       Tok = Lex.lex();
137*146eb7a6SReid Kleckner       return;
138*146eb7a6SReid Kleckner     }
139*146eb7a6SReid Kleckner     Tok = Stack.back();
140*146eb7a6SReid Kleckner     Stack.pop_back();
141*146eb7a6SReid Kleckner   }
142*146eb7a6SReid Kleckner 
143*146eb7a6SReid Kleckner   Error readAsInt(uint64_t *I) {
144*146eb7a6SReid Kleckner     read();
145*146eb7a6SReid Kleckner     if (Tok.K != Identifier || Tok.Value.getAsInteger(10, *I))
146*146eb7a6SReid Kleckner       return createError("integer expected");
147*146eb7a6SReid Kleckner     return Error::success();
148*146eb7a6SReid Kleckner   }
149*146eb7a6SReid Kleckner 
150*146eb7a6SReid Kleckner   Error expect(Kind Expected, StringRef Msg) {
151*146eb7a6SReid Kleckner     read();
152*146eb7a6SReid Kleckner     if (Tok.K != Expected)
153*146eb7a6SReid Kleckner       return createError(Msg);
154*146eb7a6SReid Kleckner     return Error::success();
155*146eb7a6SReid Kleckner   }
156*146eb7a6SReid Kleckner 
157*146eb7a6SReid Kleckner   void unget() { Stack.push_back(Tok); }
158*146eb7a6SReid Kleckner 
159*146eb7a6SReid Kleckner   Error parseOne() {
160*146eb7a6SReid Kleckner     read();
161*146eb7a6SReid Kleckner     switch (Tok.K) {
162*146eb7a6SReid Kleckner     case Eof:
163*146eb7a6SReid Kleckner       return Error::success();
164*146eb7a6SReid Kleckner     case KwExports:
165*146eb7a6SReid Kleckner       for (;;) {
166*146eb7a6SReid Kleckner         read();
167*146eb7a6SReid Kleckner         if (Tok.K != Identifier) {
168*146eb7a6SReid Kleckner           unget();
169*146eb7a6SReid Kleckner           return Error::success();
170*146eb7a6SReid Kleckner         }
171*146eb7a6SReid Kleckner         if (Error Err = parseExport())
172*146eb7a6SReid Kleckner           return Err;
173*146eb7a6SReid Kleckner       }
174*146eb7a6SReid Kleckner     case KwHeapsize:
175*146eb7a6SReid Kleckner       return parseNumbers(&Info.HeapReserve, &Info.HeapCommit);
176*146eb7a6SReid Kleckner     case KwStacksize:
177*146eb7a6SReid Kleckner       return parseNumbers(&Info.StackReserve, &Info.StackCommit);
178*146eb7a6SReid Kleckner     case KwLibrary:
179*146eb7a6SReid Kleckner     case KwName: {
180*146eb7a6SReid Kleckner       bool IsDll = Tok.K == KwLibrary; // Check before parseName.
181*146eb7a6SReid Kleckner       std::string Name;
182*146eb7a6SReid Kleckner       if (Error Err = parseName(&Name, &Info.ImageBase))
183*146eb7a6SReid Kleckner         return Err;
184*146eb7a6SReid Kleckner       // Append the appropriate file extension if not already present.
185*146eb7a6SReid Kleckner       StringRef Ext = IsDll ? ".dll" : ".exe";
186*146eb7a6SReid Kleckner       if (!StringRef(Name).endswith_lower(Ext))
187*146eb7a6SReid Kleckner         Name += Ext;
188*146eb7a6SReid Kleckner 
189*146eb7a6SReid Kleckner       // Set the output file, but don't override /out if it was already passed.
190*146eb7a6SReid Kleckner       if (Info.OutputFile.empty())
191*146eb7a6SReid Kleckner         Info.OutputFile = Name;
192*146eb7a6SReid Kleckner       return Error::success();
193*146eb7a6SReid Kleckner     }
194*146eb7a6SReid Kleckner     case KwVersion:
195*146eb7a6SReid Kleckner       return parseVersion(&Info.MajorImageVersion, &Info.MinorImageVersion);
196*146eb7a6SReid Kleckner     default:
197*146eb7a6SReid Kleckner       return createError("unknown directive: " + Tok.Value);
198*146eb7a6SReid Kleckner     }
199*146eb7a6SReid Kleckner   }
200*146eb7a6SReid Kleckner 
201*146eb7a6SReid Kleckner   Error parseExport() {
202*146eb7a6SReid Kleckner     COFFShortExport E;
203*146eb7a6SReid Kleckner     E.Name = Tok.Value;
204*146eb7a6SReid Kleckner     read();
205*146eb7a6SReid Kleckner     if (Tok.K == Equal) {
206*146eb7a6SReid Kleckner       read();
207*146eb7a6SReid Kleckner       if (Tok.K != Identifier)
208*146eb7a6SReid Kleckner         return createError("identifier expected, but got " + Tok.Value);
209*146eb7a6SReid Kleckner       E.ExtName = E.Name;
210*146eb7a6SReid Kleckner       E.Name = Tok.Value;
211*146eb7a6SReid Kleckner     } else {
212*146eb7a6SReid Kleckner       unget();
213*146eb7a6SReid Kleckner     }
214*146eb7a6SReid Kleckner 
215*146eb7a6SReid Kleckner     if (Machine == IMAGE_FILE_MACHINE_I386) {
216*146eb7a6SReid Kleckner       if (!isDecorated(E.Name))
217*146eb7a6SReid Kleckner         E.Name = (std::string("_").append(E.Name));
218*146eb7a6SReid Kleckner       if (!E.ExtName.empty() && !isDecorated(E.ExtName))
219*146eb7a6SReid Kleckner         E.ExtName = (std::string("_").append(E.ExtName));
220*146eb7a6SReid Kleckner     }
221*146eb7a6SReid Kleckner 
222*146eb7a6SReid Kleckner     for (;;) {
223*146eb7a6SReid Kleckner       read();
224*146eb7a6SReid Kleckner       if (Tok.K == Identifier && Tok.Value[0] == '@') {
225*146eb7a6SReid Kleckner         Tok.Value.drop_front().getAsInteger(10, E.Ordinal);
226*146eb7a6SReid Kleckner         read();
227*146eb7a6SReid Kleckner         if (Tok.K == KwNoname) {
228*146eb7a6SReid Kleckner           E.Noname = true;
229*146eb7a6SReid Kleckner         } else {
230*146eb7a6SReid Kleckner           unget();
231*146eb7a6SReid Kleckner         }
232*146eb7a6SReid Kleckner         continue;
233*146eb7a6SReid Kleckner       }
234*146eb7a6SReid Kleckner       if (Tok.K == KwData) {
235*146eb7a6SReid Kleckner         E.Data = true;
236*146eb7a6SReid Kleckner         continue;
237*146eb7a6SReid Kleckner       }
238*146eb7a6SReid Kleckner       if (Tok.K == KwConstant) {
239*146eb7a6SReid Kleckner         E.Constant = true;
240*146eb7a6SReid Kleckner         continue;
241*146eb7a6SReid Kleckner       }
242*146eb7a6SReid Kleckner       if (Tok.K == KwPrivate) {
243*146eb7a6SReid Kleckner         E.Private = true;
244*146eb7a6SReid Kleckner         continue;
245*146eb7a6SReid Kleckner       }
246*146eb7a6SReid Kleckner       unget();
247*146eb7a6SReid Kleckner       Info.Exports.push_back(E);
248*146eb7a6SReid Kleckner       return Error::success();
249*146eb7a6SReid Kleckner     }
250*146eb7a6SReid Kleckner   }
251*146eb7a6SReid Kleckner 
252*146eb7a6SReid Kleckner   // HEAPSIZE/STACKSIZE reserve[,commit]
253*146eb7a6SReid Kleckner   Error parseNumbers(uint64_t *Reserve, uint64_t *Commit) {
254*146eb7a6SReid Kleckner     if (Error Err = readAsInt(Reserve))
255*146eb7a6SReid Kleckner       return Err;
256*146eb7a6SReid Kleckner     read();
257*146eb7a6SReid Kleckner     if (Tok.K != Comma) {
258*146eb7a6SReid Kleckner       unget();
259*146eb7a6SReid Kleckner       Commit = nullptr;
260*146eb7a6SReid Kleckner       return Error::success();
261*146eb7a6SReid Kleckner     }
262*146eb7a6SReid Kleckner     if (Error Err = readAsInt(Commit))
263*146eb7a6SReid Kleckner       return Err;
264*146eb7a6SReid Kleckner     return Error::success();
265*146eb7a6SReid Kleckner   }
266*146eb7a6SReid Kleckner 
267*146eb7a6SReid Kleckner   // NAME outputPath [BASE=address]
268*146eb7a6SReid Kleckner   Error parseName(std::string *Out, uint64_t *Baseaddr) {
269*146eb7a6SReid Kleckner     read();
270*146eb7a6SReid Kleckner     if (Tok.K == Identifier) {
271*146eb7a6SReid Kleckner       *Out = Tok.Value;
272*146eb7a6SReid Kleckner     } else {
273*146eb7a6SReid Kleckner       *Out = "";
274*146eb7a6SReid Kleckner       unget();
275*146eb7a6SReid Kleckner       return Error::success();
276*146eb7a6SReid Kleckner     }
277*146eb7a6SReid Kleckner     read();
278*146eb7a6SReid Kleckner     if (Tok.K == KwBase) {
279*146eb7a6SReid Kleckner       if (Error Err = expect(Equal, "'=' expected"))
280*146eb7a6SReid Kleckner         return Err;
281*146eb7a6SReid Kleckner       if (Error Err = readAsInt(Baseaddr))
282*146eb7a6SReid Kleckner         return Err;
283*146eb7a6SReid Kleckner     } else {
284*146eb7a6SReid Kleckner       unget();
285*146eb7a6SReid Kleckner       *Baseaddr = 0;
286*146eb7a6SReid Kleckner     }
287*146eb7a6SReid Kleckner     return Error::success();
288*146eb7a6SReid Kleckner   }
289*146eb7a6SReid Kleckner 
290*146eb7a6SReid Kleckner   // VERSION major[.minor]
291*146eb7a6SReid Kleckner   Error parseVersion(uint32_t *Major, uint32_t *Minor) {
292*146eb7a6SReid Kleckner     read();
293*146eb7a6SReid Kleckner     if (Tok.K != Identifier)
294*146eb7a6SReid Kleckner       return createError("identifier expected, but got " + Tok.Value);
295*146eb7a6SReid Kleckner     StringRef V1, V2;
296*146eb7a6SReid Kleckner     std::tie(V1, V2) = Tok.Value.split('.');
297*146eb7a6SReid Kleckner     if (V1.getAsInteger(10, *Major))
298*146eb7a6SReid Kleckner       return createError("integer expected, but got " + Tok.Value);
299*146eb7a6SReid Kleckner     if (V2.empty())
300*146eb7a6SReid Kleckner       *Minor = 0;
301*146eb7a6SReid Kleckner     else if (V2.getAsInteger(10, *Minor))
302*146eb7a6SReid Kleckner       return createError("integer expected, but got " + Tok.Value);
303*146eb7a6SReid Kleckner     return Error::success();
304*146eb7a6SReid Kleckner   }
305*146eb7a6SReid Kleckner 
306*146eb7a6SReid Kleckner   Lexer Lex;
307*146eb7a6SReid Kleckner   Token Tok;
308*146eb7a6SReid Kleckner   std::vector<Token> Stack;
309*146eb7a6SReid Kleckner   MachineTypes Machine;
310*146eb7a6SReid Kleckner   COFFModuleDefinition Info;
311*146eb7a6SReid Kleckner };
312*146eb7a6SReid Kleckner 
313*146eb7a6SReid Kleckner Expected<COFFModuleDefinition> parseCOFFModuleDefinition(MemoryBufferRef MB,
314*146eb7a6SReid Kleckner                                                          MachineTypes Machine) {
315*146eb7a6SReid Kleckner   return Parser(MB.getBuffer(), Machine).parse();
316*146eb7a6SReid Kleckner }
317*146eb7a6SReid Kleckner 
318*146eb7a6SReid Kleckner } // namespace object
319*146eb7a6SReid Kleckner } // namespace llvm
320