1 //===--- COFFModuleDefinition.cpp - Simple DEF parser ---------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
11 // A parser for the module-definition file (.def file).
13 // The format of module-definition files are described in this document:
14 // https://msdn.microsoft.com/en-us/library/28d6s79h.aspx
16 //===----------------------------------------------------------------------===//
18 #include "llvm/Object/COFFModuleDefinition.h"
19 #include "llvm/ADT/StringRef.h"
20 #include "llvm/ADT/StringSwitch.h"
21 #include "llvm/Object/COFF.h"
22 #include "llvm/Object/COFFImportFile.h"
23 #include "llvm/Object/Error.h"
24 #include "llvm/Support/Error.h"
25 #include "llvm/Support/Path.h"
26 #include "llvm/Support/raw_ostream.h"
28 using namespace llvm::COFF;
54 explicit Token(Kind T = Unknown, StringRef S = "") : K(T), Value(S) {}
59 static bool isDecorated(StringRef Sym, bool MingwDef) {
60 // mingw does not prepend "_".
61 return (!MingwDef && Sym.startswith("_")) || Sym.startswith("@") ||
65 static Error createError(const Twine &Err) {
66 return make_error<StringError>(StringRef(Err.str()),
67 object_error::parse_failed);
72 Lexer(StringRef S) : Buf(S) {}
83 size_t End = Buf.find('\n');
84 Buf = (End == Buf.npos) ? "" : Buf.drop_front(End);
88 Buf = Buf.drop_front();
89 // GNU dlltool accepts both = and ==.
90 if (Buf.startswith("="))
91 Buf = Buf.drop_front();
92 return Token(Equal, "=");
94 Buf = Buf.drop_front();
95 return Token(Comma, ",");
98 std::tie(S, Buf) = Buf.substr(1).split('"');
99 return Token(Identifier, S);
102 size_t End = Buf.find_first_of("=,\r\n \t\v");
103 StringRef Word = Buf.substr(0, End);
104 Kind K = llvm::StringSwitch<Kind>(Word)
105 .Case("BASE", KwBase)
106 .Case("CONSTANT", KwConstant)
107 .Case("DATA", KwData)
108 .Case("EXPORTS", KwExports)
109 .Case("HEAPSIZE", KwHeapsize)
110 .Case("LIBRARY", KwLibrary)
111 .Case("NAME", KwName)
112 .Case("NONAME", KwNoname)
113 .Case("PRIVATE", KwPrivate)
114 .Case("STACKSIZE", KwStacksize)
115 .Case("VERSION", KwVersion)
116 .Default(Identifier);
117 Buf = (End == Buf.npos) ? "" : Buf.drop_front(End);
118 return Token(K, Word);
129 explicit Parser(StringRef S, MachineTypes M, bool B)
130 : Lex(S), Machine(M), MingwDef(B) {}
132 Expected<COFFModuleDefinition> parse() {
134 if (Error Err = parseOne())
135 return std::move(Err);
136 } while (Tok.K != Eof);
150 Error readAsInt(uint64_t *I) {
152 if (Tok.K != Identifier || Tok.Value.getAsInteger(10, *I))
153 return createError("integer expected");
154 return Error::success();
157 Error expect(Kind Expected, StringRef Msg) {
159 if (Tok.K != Expected)
160 return createError(Msg);
161 return Error::success();
164 void unget() { Stack.push_back(Tok); }
170 return Error::success();
174 if (Tok.K != Identifier) {
176 return Error::success();
178 if (Error Err = parseExport())
182 return parseNumbers(&Info.HeapReserve, &Info.HeapCommit);
184 return parseNumbers(&Info.StackReserve, &Info.StackCommit);
187 bool IsDll = Tok.K == KwLibrary; // Check before parseName.
189 if (Error Err = parseName(&Name, &Info.ImageBase))
192 Info.ImportName = Name;
194 // Set the output file, but don't override /out if it was already passed.
195 if (Info.OutputFile.empty()) {
196 Info.OutputFile = Name;
197 // Append the appropriate file extension if not already present.
198 if (!sys::path::has_extension(Name))
199 Info.OutputFile += IsDll ? ".dll" : ".exe";
202 return Error::success();
205 return parseVersion(&Info.MajorImageVersion, &Info.MinorImageVersion);
207 return createError("unknown directive: " + Tok.Value);
211 Error parseExport() {
215 if (Tok.K == Equal) {
217 if (Tok.K != Identifier)
218 return createError("identifier expected, but got " + Tok.Value);
225 if (Machine == IMAGE_FILE_MACHINE_I386) {
226 if (!isDecorated(E.Name, MingwDef))
227 E.Name = (std::string("_").append(E.Name));
228 if (!E.ExtName.empty() && !isDecorated(E.ExtName, MingwDef))
229 E.ExtName = (std::string("_").append(E.ExtName));
234 if (Tok.K == Identifier && Tok.Value[0] == '@') {
235 if (Tok.Value.drop_front().getAsInteger(10, E.Ordinal)) {
236 // Not an ordinal modifier at all, but the next export (fastcall
237 // decorated) - complete the current one.
239 Info.Exports.push_back(E);
240 return Error::success();
243 if (Tok.K == KwNoname) {
250 if (Tok.K == KwData) {
254 if (Tok.K == KwConstant) {
258 if (Tok.K == KwPrivate) {
263 Info.Exports.push_back(E);
264 return Error::success();
268 // HEAPSIZE/STACKSIZE reserve[,commit]
269 Error parseNumbers(uint64_t *Reserve, uint64_t *Commit) {
270 if (Error Err = readAsInt(Reserve))
273 if (Tok.K != Comma) {
276 return Error::success();
278 if (Error Err = readAsInt(Commit))
280 return Error::success();
283 // NAME outputPath [BASE=address]
284 Error parseName(std::string *Out, uint64_t *Baseaddr) {
286 if (Tok.K == Identifier) {
291 return Error::success();
294 if (Tok.K == KwBase) {
295 if (Error Err = expect(Equal, "'=' expected"))
297 if (Error Err = readAsInt(Baseaddr))
303 return Error::success();
306 // VERSION major[.minor]
307 Error parseVersion(uint32_t *Major, uint32_t *Minor) {
309 if (Tok.K != Identifier)
310 return createError("identifier expected, but got " + Tok.Value);
312 std::tie(V1, V2) = Tok.Value.split('.');
313 if (V1.getAsInteger(10, *Major))
314 return createError("integer expected, but got " + Tok.Value);
317 else if (V2.getAsInteger(10, *Minor))
318 return createError("integer expected, but got " + Tok.Value);
319 return Error::success();
324 std::vector<Token> Stack;
325 MachineTypes Machine;
326 COFFModuleDefinition Info;
330 Expected<COFFModuleDefinition> parseCOFFModuleDefinition(MemoryBufferRef MB,
331 MachineTypes Machine,
333 return Parser(MB.getBuffer(), Machine, MingwDef).parse();
336 } // namespace object