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"
25e234901aSSaleem Abdulrasool #include "llvm/Support/Path.h"
26146eb7a6SReid Kleckner #include "llvm/Support/raw_ostream.h"
27146eb7a6SReid Kleckner 
28146eb7a6SReid Kleckner using namespace llvm::COFF;
29146eb7a6SReid Kleckner using namespace llvm;
30146eb7a6SReid Kleckner 
31146eb7a6SReid Kleckner namespace llvm {
32146eb7a6SReid Kleckner namespace object {
33146eb7a6SReid Kleckner 
34146eb7a6SReid Kleckner enum Kind {
35146eb7a6SReid Kleckner   Unknown,
36146eb7a6SReid Kleckner   Eof,
37146eb7a6SReid Kleckner   Identifier,
38146eb7a6SReid Kleckner   Comma,
39146eb7a6SReid Kleckner   Equal,
40146eb7a6SReid Kleckner   KwBase,
41146eb7a6SReid Kleckner   KwConstant,
42146eb7a6SReid Kleckner   KwData,
43146eb7a6SReid Kleckner   KwExports,
44146eb7a6SReid Kleckner   KwHeapsize,
45146eb7a6SReid Kleckner   KwLibrary,
46146eb7a6SReid Kleckner   KwName,
47146eb7a6SReid Kleckner   KwNoname,
48146eb7a6SReid Kleckner   KwPrivate,
49146eb7a6SReid Kleckner   KwStacksize,
50146eb7a6SReid Kleckner   KwVersion,
51146eb7a6SReid Kleckner };
52146eb7a6SReid Kleckner 
53146eb7a6SReid Kleckner struct Token {
54146eb7a6SReid Kleckner   explicit Token(Kind T = Unknown, StringRef S = "") : K(T), Value(S) {}
55146eb7a6SReid Kleckner   Kind K;
56146eb7a6SReid Kleckner   StringRef Value;
57146eb7a6SReid Kleckner };
58146eb7a6SReid Kleckner 
591079ef8dSMartell Malone static bool isDecorated(StringRef Sym, bool MingwDef) {
601079ef8dSMartell Malone   // mingw does not prepend "_".
611079ef8dSMartell Malone   return (!MingwDef && Sym.startswith("_")) || Sym.startswith("@") ||
621079ef8dSMartell Malone          Sym.startswith("?");
63146eb7a6SReid Kleckner }
64146eb7a6SReid Kleckner 
65146eb7a6SReid Kleckner static Error createError(const Twine &Err) {
66146eb7a6SReid Kleckner   return make_error<StringError>(StringRef(Err.str()),
67146eb7a6SReid Kleckner                                  object_error::parse_failed);
68146eb7a6SReid Kleckner }
69146eb7a6SReid Kleckner 
70146eb7a6SReid Kleckner class Lexer {
71146eb7a6SReid Kleckner public:
72146eb7a6SReid Kleckner   Lexer(StringRef S) : Buf(S) {}
73146eb7a6SReid Kleckner 
74146eb7a6SReid Kleckner   Token lex() {
75146eb7a6SReid Kleckner     Buf = Buf.trim();
76146eb7a6SReid Kleckner     if (Buf.empty())
77146eb7a6SReid Kleckner       return Token(Eof);
78146eb7a6SReid Kleckner 
79146eb7a6SReid Kleckner     switch (Buf[0]) {
80146eb7a6SReid Kleckner     case '\0':
81146eb7a6SReid Kleckner       return Token(Eof);
82146eb7a6SReid Kleckner     case ';': {
83146eb7a6SReid Kleckner       size_t End = Buf.find('\n');
84146eb7a6SReid Kleckner       Buf = (End == Buf.npos) ? "" : Buf.drop_front(End);
85146eb7a6SReid Kleckner       return lex();
86146eb7a6SReid Kleckner     }
87146eb7a6SReid Kleckner     case '=':
88146eb7a6SReid Kleckner       Buf = Buf.drop_front();
891079ef8dSMartell Malone       // GNU dlltool accepts both = and ==.
901079ef8dSMartell Malone       if (Buf.startswith("="))
911079ef8dSMartell Malone         Buf = Buf.drop_front();
92146eb7a6SReid Kleckner       return Token(Equal, "=");
93146eb7a6SReid Kleckner     case ',':
94146eb7a6SReid Kleckner       Buf = Buf.drop_front();
95146eb7a6SReid Kleckner       return Token(Comma, ",");
96146eb7a6SReid Kleckner     case '"': {
97146eb7a6SReid Kleckner       StringRef S;
98146eb7a6SReid Kleckner       std::tie(S, Buf) = Buf.substr(1).split('"');
99146eb7a6SReid Kleckner       return Token(Identifier, S);
100146eb7a6SReid Kleckner     }
101146eb7a6SReid Kleckner     default: {
102146eb7a6SReid Kleckner       size_t End = Buf.find_first_of("=,\r\n \t\v");
103146eb7a6SReid Kleckner       StringRef Word = Buf.substr(0, End);
104146eb7a6SReid Kleckner       Kind K = llvm::StringSwitch<Kind>(Word)
105146eb7a6SReid Kleckner                    .Case("BASE", KwBase)
106146eb7a6SReid Kleckner                    .Case("CONSTANT", KwConstant)
107146eb7a6SReid Kleckner                    .Case("DATA", KwData)
108146eb7a6SReid Kleckner                    .Case("EXPORTS", KwExports)
109146eb7a6SReid Kleckner                    .Case("HEAPSIZE", KwHeapsize)
110146eb7a6SReid Kleckner                    .Case("LIBRARY", KwLibrary)
111146eb7a6SReid Kleckner                    .Case("NAME", KwName)
112146eb7a6SReid Kleckner                    .Case("NONAME", KwNoname)
113146eb7a6SReid Kleckner                    .Case("PRIVATE", KwPrivate)
114146eb7a6SReid Kleckner                    .Case("STACKSIZE", KwStacksize)
115146eb7a6SReid Kleckner                    .Case("VERSION", KwVersion)
116146eb7a6SReid Kleckner                    .Default(Identifier);
117146eb7a6SReid Kleckner       Buf = (End == Buf.npos) ? "" : Buf.drop_front(End);
118146eb7a6SReid Kleckner       return Token(K, Word);
119146eb7a6SReid Kleckner     }
120146eb7a6SReid Kleckner     }
121146eb7a6SReid Kleckner   }
122146eb7a6SReid Kleckner 
123146eb7a6SReid Kleckner private:
124146eb7a6SReid Kleckner   StringRef Buf;
125146eb7a6SReid Kleckner };
126146eb7a6SReid Kleckner 
127146eb7a6SReid Kleckner class Parser {
128146eb7a6SReid Kleckner public:
1291079ef8dSMartell Malone   explicit Parser(StringRef S, MachineTypes M, bool B)
1301079ef8dSMartell Malone       : Lex(S), Machine(M), MingwDef(B) {}
131146eb7a6SReid Kleckner 
132146eb7a6SReid Kleckner   Expected<COFFModuleDefinition> parse() {
133146eb7a6SReid Kleckner     do {
134146eb7a6SReid Kleckner       if (Error Err = parseOne())
135146eb7a6SReid Kleckner         return std::move(Err);
136146eb7a6SReid Kleckner     } while (Tok.K != Eof);
137146eb7a6SReid Kleckner     return Info;
138146eb7a6SReid Kleckner   }
139146eb7a6SReid Kleckner 
140146eb7a6SReid Kleckner private:
141146eb7a6SReid Kleckner   void read() {
142146eb7a6SReid Kleckner     if (Stack.empty()) {
143146eb7a6SReid Kleckner       Tok = Lex.lex();
144146eb7a6SReid Kleckner       return;
145146eb7a6SReid Kleckner     }
146146eb7a6SReid Kleckner     Tok = Stack.back();
147146eb7a6SReid Kleckner     Stack.pop_back();
148146eb7a6SReid Kleckner   }
149146eb7a6SReid Kleckner 
150146eb7a6SReid Kleckner   Error readAsInt(uint64_t *I) {
151146eb7a6SReid Kleckner     read();
152146eb7a6SReid Kleckner     if (Tok.K != Identifier || Tok.Value.getAsInteger(10, *I))
153146eb7a6SReid Kleckner       return createError("integer expected");
154146eb7a6SReid Kleckner     return Error::success();
155146eb7a6SReid Kleckner   }
156146eb7a6SReid Kleckner 
157146eb7a6SReid Kleckner   Error expect(Kind Expected, StringRef Msg) {
158146eb7a6SReid Kleckner     read();
159146eb7a6SReid Kleckner     if (Tok.K != Expected)
160146eb7a6SReid Kleckner       return createError(Msg);
161146eb7a6SReid Kleckner     return Error::success();
162146eb7a6SReid Kleckner   }
163146eb7a6SReid Kleckner 
164146eb7a6SReid Kleckner   void unget() { Stack.push_back(Tok); }
165146eb7a6SReid Kleckner 
166146eb7a6SReid Kleckner   Error parseOne() {
167146eb7a6SReid Kleckner     read();
168146eb7a6SReid Kleckner     switch (Tok.K) {
169146eb7a6SReid Kleckner     case Eof:
170146eb7a6SReid Kleckner       return Error::success();
171146eb7a6SReid Kleckner     case KwExports:
172146eb7a6SReid Kleckner       for (;;) {
173146eb7a6SReid Kleckner         read();
174146eb7a6SReid Kleckner         if (Tok.K != Identifier) {
175146eb7a6SReid Kleckner           unget();
176146eb7a6SReid Kleckner           return Error::success();
177146eb7a6SReid Kleckner         }
178146eb7a6SReid Kleckner         if (Error Err = parseExport())
179146eb7a6SReid Kleckner           return Err;
180146eb7a6SReid Kleckner       }
181146eb7a6SReid Kleckner     case KwHeapsize:
182146eb7a6SReid Kleckner       return parseNumbers(&Info.HeapReserve, &Info.HeapCommit);
183146eb7a6SReid Kleckner     case KwStacksize:
184146eb7a6SReid Kleckner       return parseNumbers(&Info.StackReserve, &Info.StackCommit);
185146eb7a6SReid Kleckner     case KwLibrary:
186146eb7a6SReid Kleckner     case KwName: {
187146eb7a6SReid Kleckner       bool IsDll = Tok.K == KwLibrary; // Check before parseName.
188146eb7a6SReid Kleckner       std::string Name;
189146eb7a6SReid Kleckner       if (Error Err = parseName(&Name, &Info.ImageBase))
190146eb7a6SReid Kleckner         return Err;
191*08e5f685SSaleem Abdulrasool 
192*08e5f685SSaleem Abdulrasool       Info.ImportName = Name;
193146eb7a6SReid Kleckner 
194146eb7a6SReid Kleckner       // Set the output file, but don't override /out if it was already passed.
195*08e5f685SSaleem Abdulrasool       if (Info.OutputFile.empty()) {
196146eb7a6SReid Kleckner         Info.OutputFile = Name;
197*08e5f685SSaleem Abdulrasool         // Append the appropriate file extension if not already present.
198*08e5f685SSaleem Abdulrasool         if (!sys::path::has_extension(Name))
199*08e5f685SSaleem Abdulrasool           Info.OutputFile += IsDll ? ".dll" : ".exe";
200*08e5f685SSaleem Abdulrasool       }
201*08e5f685SSaleem Abdulrasool 
202146eb7a6SReid Kleckner       return Error::success();
203146eb7a6SReid Kleckner     }
204146eb7a6SReid Kleckner     case KwVersion:
205146eb7a6SReid Kleckner       return parseVersion(&Info.MajorImageVersion, &Info.MinorImageVersion);
206146eb7a6SReid Kleckner     default:
207146eb7a6SReid Kleckner       return createError("unknown directive: " + Tok.Value);
208146eb7a6SReid Kleckner     }
209146eb7a6SReid Kleckner   }
210146eb7a6SReid Kleckner 
211146eb7a6SReid Kleckner   Error parseExport() {
212146eb7a6SReid Kleckner     COFFShortExport E;
213146eb7a6SReid Kleckner     E.Name = Tok.Value;
214146eb7a6SReid Kleckner     read();
215146eb7a6SReid Kleckner     if (Tok.K == Equal) {
216146eb7a6SReid Kleckner       read();
217146eb7a6SReid Kleckner       if (Tok.K != Identifier)
218146eb7a6SReid Kleckner         return createError("identifier expected, but got " + Tok.Value);
219146eb7a6SReid Kleckner       E.ExtName = E.Name;
220146eb7a6SReid Kleckner       E.Name = Tok.Value;
221146eb7a6SReid Kleckner     } else {
222146eb7a6SReid Kleckner       unget();
223146eb7a6SReid Kleckner     }
224146eb7a6SReid Kleckner 
225146eb7a6SReid Kleckner     if (Machine == IMAGE_FILE_MACHINE_I386) {
2261079ef8dSMartell Malone       if (!isDecorated(E.Name, MingwDef))
227146eb7a6SReid Kleckner         E.Name = (std::string("_").append(E.Name));
2281079ef8dSMartell Malone       if (!E.ExtName.empty() && !isDecorated(E.ExtName, MingwDef))
229146eb7a6SReid Kleckner         E.ExtName = (std::string("_").append(E.ExtName));
230146eb7a6SReid Kleckner     }
231146eb7a6SReid Kleckner 
232146eb7a6SReid Kleckner     for (;;) {
233146eb7a6SReid Kleckner       read();
234146eb7a6SReid Kleckner       if (Tok.K == Identifier && Tok.Value[0] == '@') {
235146eb7a6SReid Kleckner         Tok.Value.drop_front().getAsInteger(10, E.Ordinal);
236146eb7a6SReid Kleckner         read();
237146eb7a6SReid Kleckner         if (Tok.K == KwNoname) {
238146eb7a6SReid Kleckner           E.Noname = true;
239146eb7a6SReid Kleckner         } else {
240146eb7a6SReid Kleckner           unget();
241146eb7a6SReid Kleckner         }
242146eb7a6SReid Kleckner         continue;
243146eb7a6SReid Kleckner       }
244146eb7a6SReid Kleckner       if (Tok.K == KwData) {
245146eb7a6SReid Kleckner         E.Data = true;
246146eb7a6SReid Kleckner         continue;
247146eb7a6SReid Kleckner       }
248146eb7a6SReid Kleckner       if (Tok.K == KwConstant) {
249146eb7a6SReid Kleckner         E.Constant = true;
250146eb7a6SReid Kleckner         continue;
251146eb7a6SReid Kleckner       }
252146eb7a6SReid Kleckner       if (Tok.K == KwPrivate) {
253146eb7a6SReid Kleckner         E.Private = true;
254146eb7a6SReid Kleckner         continue;
255146eb7a6SReid Kleckner       }
256146eb7a6SReid Kleckner       unget();
257146eb7a6SReid Kleckner       Info.Exports.push_back(E);
258146eb7a6SReid Kleckner       return Error::success();
259146eb7a6SReid Kleckner     }
260146eb7a6SReid Kleckner   }
261146eb7a6SReid Kleckner 
262146eb7a6SReid Kleckner   // HEAPSIZE/STACKSIZE reserve[,commit]
263146eb7a6SReid Kleckner   Error parseNumbers(uint64_t *Reserve, uint64_t *Commit) {
264146eb7a6SReid Kleckner     if (Error Err = readAsInt(Reserve))
265146eb7a6SReid Kleckner       return Err;
266146eb7a6SReid Kleckner     read();
267146eb7a6SReid Kleckner     if (Tok.K != Comma) {
268146eb7a6SReid Kleckner       unget();
269146eb7a6SReid Kleckner       Commit = nullptr;
270146eb7a6SReid Kleckner       return Error::success();
271146eb7a6SReid Kleckner     }
272146eb7a6SReid Kleckner     if (Error Err = readAsInt(Commit))
273146eb7a6SReid Kleckner       return Err;
274146eb7a6SReid Kleckner     return Error::success();
275146eb7a6SReid Kleckner   }
276146eb7a6SReid Kleckner 
277146eb7a6SReid Kleckner   // NAME outputPath [BASE=address]
278146eb7a6SReid Kleckner   Error parseName(std::string *Out, uint64_t *Baseaddr) {
279146eb7a6SReid Kleckner     read();
280146eb7a6SReid Kleckner     if (Tok.K == Identifier) {
281146eb7a6SReid Kleckner       *Out = Tok.Value;
282146eb7a6SReid Kleckner     } else {
283146eb7a6SReid Kleckner       *Out = "";
284146eb7a6SReid Kleckner       unget();
285146eb7a6SReid Kleckner       return Error::success();
286146eb7a6SReid Kleckner     }
287146eb7a6SReid Kleckner     read();
288146eb7a6SReid Kleckner     if (Tok.K == KwBase) {
289146eb7a6SReid Kleckner       if (Error Err = expect(Equal, "'=' expected"))
290146eb7a6SReid Kleckner         return Err;
291146eb7a6SReid Kleckner       if (Error Err = readAsInt(Baseaddr))
292146eb7a6SReid Kleckner         return Err;
293146eb7a6SReid Kleckner     } else {
294146eb7a6SReid Kleckner       unget();
295146eb7a6SReid Kleckner       *Baseaddr = 0;
296146eb7a6SReid Kleckner     }
297146eb7a6SReid Kleckner     return Error::success();
298146eb7a6SReid Kleckner   }
299146eb7a6SReid Kleckner 
300146eb7a6SReid Kleckner   // VERSION major[.minor]
301146eb7a6SReid Kleckner   Error parseVersion(uint32_t *Major, uint32_t *Minor) {
302146eb7a6SReid Kleckner     read();
303146eb7a6SReid Kleckner     if (Tok.K != Identifier)
304146eb7a6SReid Kleckner       return createError("identifier expected, but got " + Tok.Value);
305146eb7a6SReid Kleckner     StringRef V1, V2;
306146eb7a6SReid Kleckner     std::tie(V1, V2) = Tok.Value.split('.');
307146eb7a6SReid Kleckner     if (V1.getAsInteger(10, *Major))
308146eb7a6SReid Kleckner       return createError("integer expected, but got " + Tok.Value);
309146eb7a6SReid Kleckner     if (V2.empty())
310146eb7a6SReid Kleckner       *Minor = 0;
311146eb7a6SReid Kleckner     else if (V2.getAsInteger(10, *Minor))
312146eb7a6SReid Kleckner       return createError("integer expected, but got " + Tok.Value);
313146eb7a6SReid Kleckner     return Error::success();
314146eb7a6SReid Kleckner   }
315146eb7a6SReid Kleckner 
316146eb7a6SReid Kleckner   Lexer Lex;
317146eb7a6SReid Kleckner   Token Tok;
318146eb7a6SReid Kleckner   std::vector<Token> Stack;
319146eb7a6SReid Kleckner   MachineTypes Machine;
320146eb7a6SReid Kleckner   COFFModuleDefinition Info;
3211079ef8dSMartell Malone   bool MingwDef;
322146eb7a6SReid Kleckner };
323146eb7a6SReid Kleckner 
324146eb7a6SReid Kleckner Expected<COFFModuleDefinition> parseCOFFModuleDefinition(MemoryBufferRef MB,
3251079ef8dSMartell Malone                                                          MachineTypes Machine,
3261079ef8dSMartell Malone                                                          bool MingwDef) {
3271079ef8dSMartell Malone   return Parser(MB.getBuffer(), Machine, MingwDef).parse();
328146eb7a6SReid Kleckner }
329146eb7a6SReid Kleckner 
330146eb7a6SReid Kleckner } // namespace object
331146eb7a6SReid Kleckner } // namespace llvm
332