1146eb7a6SReid Kleckner //===--- COFFModuleDefinition.cpp - Simple DEF parser ---------------------===//
2146eb7a6SReid Kleckner //
3146eb7a6SReid Kleckner //                     The LLVM Compiler Infrastructure
4146eb7a6SReid Kleckner //
5146eb7a6SReid Kleckner // This file is distributed under the University of Illinois Open Source
6146eb7a6SReid Kleckner // License. See LICENSE.TXT for details.
7146eb7a6SReid Kleckner //
8146eb7a6SReid Kleckner //===----------------------------------------------------------------------===//
9146eb7a6SReid Kleckner //
10146eb7a6SReid Kleckner // Windows-specific.
11146eb7a6SReid Kleckner // A parser for the module-definition file (.def file).
12146eb7a6SReid Kleckner //
13146eb7a6SReid Kleckner // The format of module-definition files are described in this document:
14146eb7a6SReid Kleckner // https://msdn.microsoft.com/en-us/library/28d6s79h.aspx
15146eb7a6SReid Kleckner //
16146eb7a6SReid Kleckner //===----------------------------------------------------------------------===//
17146eb7a6SReid Kleckner 
18146eb7a6SReid Kleckner #include "llvm/Object/COFFModuleDefinition.h"
19146eb7a6SReid Kleckner #include "llvm/ADT/StringRef.h"
20146eb7a6SReid Kleckner #include "llvm/ADT/StringSwitch.h"
21146eb7a6SReid Kleckner #include "llvm/Object/COFF.h"
22146eb7a6SReid Kleckner #include "llvm/Object/COFFImportFile.h"
23146eb7a6SReid Kleckner #include "llvm/Object/Error.h"
24146eb7a6SReid Kleckner #include "llvm/Support/Error.h"
25146eb7a6SReid Kleckner #include "llvm/Support/raw_ostream.h"
26146eb7a6SReid Kleckner 
27146eb7a6SReid Kleckner using namespace llvm::COFF;
28146eb7a6SReid Kleckner using namespace llvm;
29146eb7a6SReid Kleckner 
30146eb7a6SReid Kleckner namespace llvm {
31146eb7a6SReid Kleckner namespace object {
32146eb7a6SReid Kleckner 
33146eb7a6SReid Kleckner enum Kind {
34146eb7a6SReid Kleckner   Unknown,
35146eb7a6SReid Kleckner   Eof,
36146eb7a6SReid Kleckner   Identifier,
37146eb7a6SReid Kleckner   Comma,
38146eb7a6SReid Kleckner   Equal,
39146eb7a6SReid Kleckner   KwBase,
40146eb7a6SReid Kleckner   KwConstant,
41146eb7a6SReid Kleckner   KwData,
42146eb7a6SReid Kleckner   KwExports,
43146eb7a6SReid Kleckner   KwHeapsize,
44146eb7a6SReid Kleckner   KwLibrary,
45146eb7a6SReid Kleckner   KwName,
46146eb7a6SReid Kleckner   KwNoname,
47146eb7a6SReid Kleckner   KwPrivate,
48146eb7a6SReid Kleckner   KwStacksize,
49146eb7a6SReid Kleckner   KwVersion,
50146eb7a6SReid Kleckner };
51146eb7a6SReid Kleckner 
52146eb7a6SReid Kleckner struct Token {
53146eb7a6SReid Kleckner   explicit Token(Kind T = Unknown, StringRef S = "") : K(T), Value(S) {}
54146eb7a6SReid Kleckner   Kind K;
55146eb7a6SReid Kleckner   StringRef Value;
56146eb7a6SReid Kleckner };
57146eb7a6SReid Kleckner 
58*1079ef8dSMartell Malone static bool isDecorated(StringRef Sym, bool MingwDef) {
59*1079ef8dSMartell Malone   // mingw does not prepend "_".
60*1079ef8dSMartell Malone   return (!MingwDef && Sym.startswith("_")) || Sym.startswith("@") ||
61*1079ef8dSMartell Malone          Sym.startswith("?");
62146eb7a6SReid Kleckner }
63146eb7a6SReid Kleckner 
64146eb7a6SReid Kleckner static Error createError(const Twine &Err) {
65146eb7a6SReid Kleckner   return make_error<StringError>(StringRef(Err.str()),
66146eb7a6SReid Kleckner                                  object_error::parse_failed);
67146eb7a6SReid Kleckner }
68146eb7a6SReid Kleckner 
69146eb7a6SReid Kleckner class Lexer {
70146eb7a6SReid Kleckner public:
71146eb7a6SReid Kleckner   Lexer(StringRef S) : Buf(S) {}
72146eb7a6SReid Kleckner 
73146eb7a6SReid Kleckner   Token lex() {
74146eb7a6SReid Kleckner     Buf = Buf.trim();
75146eb7a6SReid Kleckner     if (Buf.empty())
76146eb7a6SReid Kleckner       return Token(Eof);
77146eb7a6SReid Kleckner 
78146eb7a6SReid Kleckner     switch (Buf[0]) {
79146eb7a6SReid Kleckner     case '\0':
80146eb7a6SReid Kleckner       return Token(Eof);
81146eb7a6SReid Kleckner     case ';': {
82146eb7a6SReid Kleckner       size_t End = Buf.find('\n');
83146eb7a6SReid Kleckner       Buf = (End == Buf.npos) ? "" : Buf.drop_front(End);
84146eb7a6SReid Kleckner       return lex();
85146eb7a6SReid Kleckner     }
86146eb7a6SReid Kleckner     case '=':
87146eb7a6SReid Kleckner       Buf = Buf.drop_front();
88*1079ef8dSMartell Malone       // GNU dlltool accepts both = and ==.
89*1079ef8dSMartell Malone       if (Buf.startswith("="))
90*1079ef8dSMartell Malone         Buf = Buf.drop_front();
91146eb7a6SReid Kleckner       return Token(Equal, "=");
92146eb7a6SReid Kleckner     case ',':
93146eb7a6SReid Kleckner       Buf = Buf.drop_front();
94146eb7a6SReid Kleckner       return Token(Comma, ",");
95146eb7a6SReid Kleckner     case '"': {
96146eb7a6SReid Kleckner       StringRef S;
97146eb7a6SReid Kleckner       std::tie(S, Buf) = Buf.substr(1).split('"');
98146eb7a6SReid Kleckner       return Token(Identifier, S);
99146eb7a6SReid Kleckner     }
100146eb7a6SReid Kleckner     default: {
101146eb7a6SReid Kleckner       size_t End = Buf.find_first_of("=,\r\n \t\v");
102146eb7a6SReid Kleckner       StringRef Word = Buf.substr(0, End);
103146eb7a6SReid Kleckner       Kind K = llvm::StringSwitch<Kind>(Word)
104146eb7a6SReid Kleckner                    .Case("BASE", KwBase)
105146eb7a6SReid Kleckner                    .Case("CONSTANT", KwConstant)
106146eb7a6SReid Kleckner                    .Case("DATA", KwData)
107146eb7a6SReid Kleckner                    .Case("EXPORTS", KwExports)
108146eb7a6SReid Kleckner                    .Case("HEAPSIZE", KwHeapsize)
109146eb7a6SReid Kleckner                    .Case("LIBRARY", KwLibrary)
110146eb7a6SReid Kleckner                    .Case("NAME", KwName)
111146eb7a6SReid Kleckner                    .Case("NONAME", KwNoname)
112146eb7a6SReid Kleckner                    .Case("PRIVATE", KwPrivate)
113146eb7a6SReid Kleckner                    .Case("STACKSIZE", KwStacksize)
114146eb7a6SReid Kleckner                    .Case("VERSION", KwVersion)
115146eb7a6SReid Kleckner                    .Default(Identifier);
116146eb7a6SReid Kleckner       Buf = (End == Buf.npos) ? "" : Buf.drop_front(End);
117146eb7a6SReid Kleckner       return Token(K, Word);
118146eb7a6SReid Kleckner     }
119146eb7a6SReid Kleckner     }
120146eb7a6SReid Kleckner   }
121146eb7a6SReid Kleckner 
122146eb7a6SReid Kleckner private:
123146eb7a6SReid Kleckner   StringRef Buf;
124146eb7a6SReid Kleckner };
125146eb7a6SReid Kleckner 
126146eb7a6SReid Kleckner class Parser {
127146eb7a6SReid Kleckner public:
128*1079ef8dSMartell Malone   explicit Parser(StringRef S, MachineTypes M, bool B)
129*1079ef8dSMartell Malone       : Lex(S), Machine(M), MingwDef(B) {}
130146eb7a6SReid Kleckner 
131146eb7a6SReid Kleckner   Expected<COFFModuleDefinition> parse() {
132146eb7a6SReid Kleckner     do {
133146eb7a6SReid Kleckner       if (Error Err = parseOne())
134146eb7a6SReid Kleckner         return std::move(Err);
135146eb7a6SReid Kleckner     } while (Tok.K != Eof);
136146eb7a6SReid Kleckner     return Info;
137146eb7a6SReid Kleckner   }
138146eb7a6SReid Kleckner 
139146eb7a6SReid Kleckner private:
140146eb7a6SReid Kleckner   void read() {
141146eb7a6SReid Kleckner     if (Stack.empty()) {
142146eb7a6SReid Kleckner       Tok = Lex.lex();
143146eb7a6SReid Kleckner       return;
144146eb7a6SReid Kleckner     }
145146eb7a6SReid Kleckner     Tok = Stack.back();
146146eb7a6SReid Kleckner     Stack.pop_back();
147146eb7a6SReid Kleckner   }
148146eb7a6SReid Kleckner 
149146eb7a6SReid Kleckner   Error readAsInt(uint64_t *I) {
150146eb7a6SReid Kleckner     read();
151146eb7a6SReid Kleckner     if (Tok.K != Identifier || Tok.Value.getAsInteger(10, *I))
152146eb7a6SReid Kleckner       return createError("integer expected");
153146eb7a6SReid Kleckner     return Error::success();
154146eb7a6SReid Kleckner   }
155146eb7a6SReid Kleckner 
156146eb7a6SReid Kleckner   Error expect(Kind Expected, StringRef Msg) {
157146eb7a6SReid Kleckner     read();
158146eb7a6SReid Kleckner     if (Tok.K != Expected)
159146eb7a6SReid Kleckner       return createError(Msg);
160146eb7a6SReid Kleckner     return Error::success();
161146eb7a6SReid Kleckner   }
162146eb7a6SReid Kleckner 
163146eb7a6SReid Kleckner   void unget() { Stack.push_back(Tok); }
164146eb7a6SReid Kleckner 
165146eb7a6SReid Kleckner   Error parseOne() {
166146eb7a6SReid Kleckner     read();
167146eb7a6SReid Kleckner     switch (Tok.K) {
168146eb7a6SReid Kleckner     case Eof:
169146eb7a6SReid Kleckner       return Error::success();
170146eb7a6SReid Kleckner     case KwExports:
171146eb7a6SReid Kleckner       for (;;) {
172146eb7a6SReid Kleckner         read();
173146eb7a6SReid Kleckner         if (Tok.K != Identifier) {
174146eb7a6SReid Kleckner           unget();
175146eb7a6SReid Kleckner           return Error::success();
176146eb7a6SReid Kleckner         }
177146eb7a6SReid Kleckner         if (Error Err = parseExport())
178146eb7a6SReid Kleckner           return Err;
179146eb7a6SReid Kleckner       }
180146eb7a6SReid Kleckner     case KwHeapsize:
181146eb7a6SReid Kleckner       return parseNumbers(&Info.HeapReserve, &Info.HeapCommit);
182146eb7a6SReid Kleckner     case KwStacksize:
183146eb7a6SReid Kleckner       return parseNumbers(&Info.StackReserve, &Info.StackCommit);
184146eb7a6SReid Kleckner     case KwLibrary:
185146eb7a6SReid Kleckner     case KwName: {
186146eb7a6SReid Kleckner       bool IsDll = Tok.K == KwLibrary; // Check before parseName.
187146eb7a6SReid Kleckner       std::string Name;
188146eb7a6SReid Kleckner       if (Error Err = parseName(&Name, &Info.ImageBase))
189146eb7a6SReid Kleckner         return Err;
190146eb7a6SReid Kleckner       // Append the appropriate file extension if not already present.
191146eb7a6SReid Kleckner       StringRef Ext = IsDll ? ".dll" : ".exe";
192146eb7a6SReid Kleckner       if (!StringRef(Name).endswith_lower(Ext))
193146eb7a6SReid Kleckner         Name += Ext;
194146eb7a6SReid Kleckner 
195146eb7a6SReid Kleckner       // Set the output file, but don't override /out if it was already passed.
196146eb7a6SReid Kleckner       if (Info.OutputFile.empty())
197146eb7a6SReid Kleckner         Info.OutputFile = Name;
198146eb7a6SReid Kleckner       return Error::success();
199146eb7a6SReid Kleckner     }
200146eb7a6SReid Kleckner     case KwVersion:
201146eb7a6SReid Kleckner       return parseVersion(&Info.MajorImageVersion, &Info.MinorImageVersion);
202146eb7a6SReid Kleckner     default:
203146eb7a6SReid Kleckner       return createError("unknown directive: " + Tok.Value);
204146eb7a6SReid Kleckner     }
205146eb7a6SReid Kleckner   }
206146eb7a6SReid Kleckner 
207146eb7a6SReid Kleckner   Error parseExport() {
208146eb7a6SReid Kleckner     COFFShortExport E;
209146eb7a6SReid Kleckner     E.Name = Tok.Value;
210146eb7a6SReid Kleckner     read();
211146eb7a6SReid Kleckner     if (Tok.K == Equal) {
212146eb7a6SReid Kleckner       read();
213146eb7a6SReid Kleckner       if (Tok.K != Identifier)
214146eb7a6SReid Kleckner         return createError("identifier expected, but got " + Tok.Value);
215146eb7a6SReid Kleckner       E.ExtName = E.Name;
216146eb7a6SReid Kleckner       E.Name = Tok.Value;
217146eb7a6SReid Kleckner     } else {
218146eb7a6SReid Kleckner       unget();
219146eb7a6SReid Kleckner     }
220146eb7a6SReid Kleckner 
221146eb7a6SReid Kleckner     if (Machine == IMAGE_FILE_MACHINE_I386) {
222*1079ef8dSMartell Malone       if (!isDecorated(E.Name, MingwDef))
223146eb7a6SReid Kleckner         E.Name = (std::string("_").append(E.Name));
224*1079ef8dSMartell Malone       if (!E.ExtName.empty() && !isDecorated(E.ExtName, MingwDef))
225146eb7a6SReid Kleckner         E.ExtName = (std::string("_").append(E.ExtName));
226146eb7a6SReid Kleckner     }
227146eb7a6SReid Kleckner 
228146eb7a6SReid Kleckner     for (;;) {
229146eb7a6SReid Kleckner       read();
230146eb7a6SReid Kleckner       if (Tok.K == Identifier && Tok.Value[0] == '@') {
231146eb7a6SReid Kleckner         Tok.Value.drop_front().getAsInteger(10, E.Ordinal);
232146eb7a6SReid Kleckner         read();
233146eb7a6SReid Kleckner         if (Tok.K == KwNoname) {
234146eb7a6SReid Kleckner           E.Noname = true;
235146eb7a6SReid Kleckner         } else {
236146eb7a6SReid Kleckner           unget();
237146eb7a6SReid Kleckner         }
238146eb7a6SReid Kleckner         continue;
239146eb7a6SReid Kleckner       }
240146eb7a6SReid Kleckner       if (Tok.K == KwData) {
241146eb7a6SReid Kleckner         E.Data = true;
242146eb7a6SReid Kleckner         continue;
243146eb7a6SReid Kleckner       }
244146eb7a6SReid Kleckner       if (Tok.K == KwConstant) {
245146eb7a6SReid Kleckner         E.Constant = true;
246146eb7a6SReid Kleckner         continue;
247146eb7a6SReid Kleckner       }
248146eb7a6SReid Kleckner       if (Tok.K == KwPrivate) {
249146eb7a6SReid Kleckner         E.Private = true;
250146eb7a6SReid Kleckner         continue;
251146eb7a6SReid Kleckner       }
252146eb7a6SReid Kleckner       unget();
253146eb7a6SReid Kleckner       Info.Exports.push_back(E);
254146eb7a6SReid Kleckner       return Error::success();
255146eb7a6SReid Kleckner     }
256146eb7a6SReid Kleckner   }
257146eb7a6SReid Kleckner 
258146eb7a6SReid Kleckner   // HEAPSIZE/STACKSIZE reserve[,commit]
259146eb7a6SReid Kleckner   Error parseNumbers(uint64_t *Reserve, uint64_t *Commit) {
260146eb7a6SReid Kleckner     if (Error Err = readAsInt(Reserve))
261146eb7a6SReid Kleckner       return Err;
262146eb7a6SReid Kleckner     read();
263146eb7a6SReid Kleckner     if (Tok.K != Comma) {
264146eb7a6SReid Kleckner       unget();
265146eb7a6SReid Kleckner       Commit = nullptr;
266146eb7a6SReid Kleckner       return Error::success();
267146eb7a6SReid Kleckner     }
268146eb7a6SReid Kleckner     if (Error Err = readAsInt(Commit))
269146eb7a6SReid Kleckner       return Err;
270146eb7a6SReid Kleckner     return Error::success();
271146eb7a6SReid Kleckner   }
272146eb7a6SReid Kleckner 
273146eb7a6SReid Kleckner   // NAME outputPath [BASE=address]
274146eb7a6SReid Kleckner   Error parseName(std::string *Out, uint64_t *Baseaddr) {
275146eb7a6SReid Kleckner     read();
276146eb7a6SReid Kleckner     if (Tok.K == Identifier) {
277146eb7a6SReid Kleckner       *Out = Tok.Value;
278146eb7a6SReid Kleckner     } else {
279146eb7a6SReid Kleckner       *Out = "";
280146eb7a6SReid Kleckner       unget();
281146eb7a6SReid Kleckner       return Error::success();
282146eb7a6SReid Kleckner     }
283146eb7a6SReid Kleckner     read();
284146eb7a6SReid Kleckner     if (Tok.K == KwBase) {
285146eb7a6SReid Kleckner       if (Error Err = expect(Equal, "'=' expected"))
286146eb7a6SReid Kleckner         return Err;
287146eb7a6SReid Kleckner       if (Error Err = readAsInt(Baseaddr))
288146eb7a6SReid Kleckner         return Err;
289146eb7a6SReid Kleckner     } else {
290146eb7a6SReid Kleckner       unget();
291146eb7a6SReid Kleckner       *Baseaddr = 0;
292146eb7a6SReid Kleckner     }
293146eb7a6SReid Kleckner     return Error::success();
294146eb7a6SReid Kleckner   }
295146eb7a6SReid Kleckner 
296146eb7a6SReid Kleckner   // VERSION major[.minor]
297146eb7a6SReid Kleckner   Error parseVersion(uint32_t *Major, uint32_t *Minor) {
298146eb7a6SReid Kleckner     read();
299146eb7a6SReid Kleckner     if (Tok.K != Identifier)
300146eb7a6SReid Kleckner       return createError("identifier expected, but got " + Tok.Value);
301146eb7a6SReid Kleckner     StringRef V1, V2;
302146eb7a6SReid Kleckner     std::tie(V1, V2) = Tok.Value.split('.');
303146eb7a6SReid Kleckner     if (V1.getAsInteger(10, *Major))
304146eb7a6SReid Kleckner       return createError("integer expected, but got " + Tok.Value);
305146eb7a6SReid Kleckner     if (V2.empty())
306146eb7a6SReid Kleckner       *Minor = 0;
307146eb7a6SReid Kleckner     else if (V2.getAsInteger(10, *Minor))
308146eb7a6SReid Kleckner       return createError("integer expected, but got " + Tok.Value);
309146eb7a6SReid Kleckner     return Error::success();
310146eb7a6SReid Kleckner   }
311146eb7a6SReid Kleckner 
312146eb7a6SReid Kleckner   Lexer Lex;
313146eb7a6SReid Kleckner   Token Tok;
314146eb7a6SReid Kleckner   std::vector<Token> Stack;
315146eb7a6SReid Kleckner   MachineTypes Machine;
316146eb7a6SReid Kleckner   COFFModuleDefinition Info;
317*1079ef8dSMartell Malone   bool MingwDef;
318146eb7a6SReid Kleckner };
319146eb7a6SReid Kleckner 
320146eb7a6SReid Kleckner Expected<COFFModuleDefinition> parseCOFFModuleDefinition(MemoryBufferRef MB,
321*1079ef8dSMartell Malone                                                          MachineTypes Machine,
322*1079ef8dSMartell Malone                                                          bool MingwDef) {
323*1079ef8dSMartell Malone   return Parser(MB.getBuffer(), Machine, MingwDef).parse();
324146eb7a6SReid Kleckner }
325146eb7a6SReid Kleckner 
326146eb7a6SReid Kleckner } // namespace object
327146eb7a6SReid Kleckner } // namespace llvm
328