blob: 510eac8b239ba93d0808acec02aa5f867c8d5fb5 [file] [log] [blame]
Reid Kleckner146eb7a2017-06-02 17:53:06 +00001//===--- COFFModuleDefinition.cpp - Simple DEF parser ---------------------===//
Martell Malone375dc902017-05-20 19:56:29 +00002//
Reid Kleckner146eb7a2017-06-02 17:53:06 +00003// The LLVM Compiler Infrastructure
Martell Malone375dc902017-05-20 19:56:29 +00004//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// Windows-specific.
11// A parser for the module-definition file (.def file).
12//
13// The format of module-definition files are described in this document:
14// https://msdn.microsoft.com/en-us/library/28d6s79h.aspx
15//
16//===----------------------------------------------------------------------===//
17
Reid Kleckner146eb7a2017-06-02 17:53:06 +000018#include "llvm/Object/COFFModuleDefinition.h"
Martell Malone375dc902017-05-20 19:56:29 +000019#include "llvm/ADT/StringRef.h"
20#include "llvm/ADT/StringSwitch.h"
Reid Kleckner146eb7a2017-06-02 17:53:06 +000021#include "llvm/Object/COFF.h"
22#include "llvm/Object/COFFImportFile.h"
23#include "llvm/Object/Error.h"
24#include "llvm/Support/Error.h"
Saleem Abdulrasoole2349012017-07-18 22:11:00 +000025#include "llvm/Support/Path.h"
Martell Malone375dc902017-05-20 19:56:29 +000026#include "llvm/Support/raw_ostream.h"
27
Reid Kleckner146eb7a2017-06-02 17:53:06 +000028using namespace llvm::COFF;
Martell Malone375dc902017-05-20 19:56:29 +000029using namespace llvm;
30
Reid Kleckner146eb7a2017-06-02 17:53:06 +000031namespace llvm {
32namespace object {
Martell Malone375dc902017-05-20 19:56:29 +000033
34enum Kind {
35 Unknown,
36 Eof,
37 Identifier,
38 Comma,
39 Equal,
40 KwBase,
41 KwConstant,
42 KwData,
43 KwExports,
44 KwHeapsize,
45 KwLibrary,
46 KwName,
47 KwNoname,
48 KwPrivate,
49 KwStacksize,
50 KwVersion,
51};
52
53struct Token {
54 explicit Token(Kind T = Unknown, StringRef S = "") : K(T), Value(S) {}
55 Kind K;
56 StringRef Value;
57};
58
Martell Malone1079ef82017-07-18 21:26:38 +000059static bool isDecorated(StringRef Sym, bool MingwDef) {
60 // mingw does not prepend "_".
61 return (!MingwDef && Sym.startswith("_")) || Sym.startswith("@") ||
62 Sym.startswith("?");
Martell Malone375dc902017-05-20 19:56:29 +000063}
64
Reid Kleckner146eb7a2017-06-02 17:53:06 +000065static Error createError(const Twine &Err) {
66 return make_error<StringError>(StringRef(Err.str()),
67 object_error::parse_failed);
68}
69
Martell Malone375dc902017-05-20 19:56:29 +000070class Lexer {
71public:
Reid Kleckner146eb7a2017-06-02 17:53:06 +000072 Lexer(StringRef S) : Buf(S) {}
Martell Malone375dc902017-05-20 19:56:29 +000073
74 Token lex() {
75 Buf = Buf.trim();
76 if (Buf.empty())
77 return Token(Eof);
78
79 switch (Buf[0]) {
80 case '\0':
81 return Token(Eof);
82 case ';': {
83 size_t End = Buf.find('\n');
84 Buf = (End == Buf.npos) ? "" : Buf.drop_front(End);
85 return lex();
86 }
87 case '=':
88 Buf = Buf.drop_front();
Martell Malone1079ef82017-07-18 21:26:38 +000089 // GNU dlltool accepts both = and ==.
90 if (Buf.startswith("="))
91 Buf = Buf.drop_front();
Martell Malone375dc902017-05-20 19:56:29 +000092 return Token(Equal, "=");
93 case ',':
94 Buf = Buf.drop_front();
95 return Token(Comma, ",");
96 case '"': {
97 StringRef S;
98 std::tie(S, Buf) = Buf.substr(1).split('"');
99 return Token(Identifier, S);
100 }
101 default: {
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);
119 }
120 }
121 }
122
123private:
124 StringRef Buf;
125};
126
127class Parser {
128public:
Martell Malone1079ef82017-07-18 21:26:38 +0000129 explicit Parser(StringRef S, MachineTypes M, bool B)
130 : Lex(S), Machine(M), MingwDef(B) {}
Martell Malone375dc902017-05-20 19:56:29 +0000131
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000132 Expected<COFFModuleDefinition> parse() {
Martell Malone375dc902017-05-20 19:56:29 +0000133 do {
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000134 if (Error Err = parseOne())
135 return std::move(Err);
Martell Malone375dc902017-05-20 19:56:29 +0000136 } while (Tok.K != Eof);
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000137 return Info;
Martell Malone375dc902017-05-20 19:56:29 +0000138 }
139
140private:
141 void read() {
142 if (Stack.empty()) {
143 Tok = Lex.lex();
144 return;
145 }
146 Tok = Stack.back();
147 Stack.pop_back();
148 }
149
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000150 Error readAsInt(uint64_t *I) {
Martell Malone375dc902017-05-20 19:56:29 +0000151 read();
152 if (Tok.K != Identifier || Tok.Value.getAsInteger(10, *I))
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000153 return createError("integer expected");
154 return Error::success();
Martell Malone375dc902017-05-20 19:56:29 +0000155 }
156
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000157 Error expect(Kind Expected, StringRef Msg) {
Martell Malone375dc902017-05-20 19:56:29 +0000158 read();
159 if (Tok.K != Expected)
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000160 return createError(Msg);
161 return Error::success();
Martell Malone375dc902017-05-20 19:56:29 +0000162 }
163
164 void unget() { Stack.push_back(Tok); }
165
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000166 Error parseOne() {
Martell Malone375dc902017-05-20 19:56:29 +0000167 read();
168 switch (Tok.K) {
169 case Eof:
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000170 return Error::success();
Martell Malone375dc902017-05-20 19:56:29 +0000171 case KwExports:
172 for (;;) {
173 read();
174 if (Tok.K != Identifier) {
175 unget();
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000176 return Error::success();
Martell Malone375dc902017-05-20 19:56:29 +0000177 }
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000178 if (Error Err = parseExport())
179 return Err;
Martell Malone375dc902017-05-20 19:56:29 +0000180 }
181 case KwHeapsize:
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000182 return parseNumbers(&Info.HeapReserve, &Info.HeapCommit);
Martell Malone375dc902017-05-20 19:56:29 +0000183 case KwStacksize:
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000184 return parseNumbers(&Info.StackReserve, &Info.StackCommit);
Martell Malone375dc902017-05-20 19:56:29 +0000185 case KwLibrary:
186 case KwName: {
187 bool IsDll = Tok.K == KwLibrary; // Check before parseName.
188 std::string Name;
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000189 if (Error Err = parseName(&Name, &Info.ImageBase))
190 return Err;
Saleem Abdulrasool08e5f682017-07-19 02:01:22 +0000191
192 Info.ImportName = Name;
Martell Malone375dc902017-05-20 19:56:29 +0000193
194 // Set the output file, but don't override /out if it was already passed.
Saleem Abdulrasool08e5f682017-07-19 02:01:22 +0000195 if (Info.OutputFile.empty()) {
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000196 Info.OutputFile = Name;
Saleem Abdulrasool08e5f682017-07-19 02:01:22 +0000197 // Append the appropriate file extension if not already present.
198 if (!sys::path::has_extension(Name))
199 Info.OutputFile += IsDll ? ".dll" : ".exe";
200 }
201
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000202 return Error::success();
Martell Malone375dc902017-05-20 19:56:29 +0000203 }
204 case KwVersion:
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000205 return parseVersion(&Info.MajorImageVersion, &Info.MinorImageVersion);
Martell Malone375dc902017-05-20 19:56:29 +0000206 default:
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000207 return createError("unknown directive: " + Tok.Value);
Martell Malone375dc902017-05-20 19:56:29 +0000208 }
209 }
210
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000211 Error parseExport() {
212 COFFShortExport E;
Martell Malone375dc902017-05-20 19:56:29 +0000213 E.Name = Tok.Value;
214 read();
215 if (Tok.K == Equal) {
216 read();
217 if (Tok.K != Identifier)
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000218 return createError("identifier expected, but got " + Tok.Value);
Martell Malone375dc902017-05-20 19:56:29 +0000219 E.ExtName = E.Name;
220 E.Name = Tok.Value;
221 } else {
222 unget();
223 }
224
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000225 if (Machine == IMAGE_FILE_MACHINE_I386) {
Martell Malone1079ef82017-07-18 21:26:38 +0000226 if (!isDecorated(E.Name, MingwDef))
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000227 E.Name = (std::string("_").append(E.Name));
Martell Malone1079ef82017-07-18 21:26:38 +0000228 if (!E.ExtName.empty() && !isDecorated(E.ExtName, MingwDef))
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000229 E.ExtName = (std::string("_").append(E.ExtName));
Martell Malone375dc902017-05-20 19:56:29 +0000230 }
231
232 for (;;) {
233 read();
234 if (Tok.K == Identifier && Tok.Value[0] == '@') {
Martin Storsjo58c95272017-08-16 05:18:36 +0000235 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.
238 unget();
239 Info.Exports.push_back(E);
240 return Error::success();
241 }
Martell Malone375dc902017-05-20 19:56:29 +0000242 read();
243 if (Tok.K == KwNoname) {
244 E.Noname = true;
245 } else {
246 unget();
247 }
248 continue;
249 }
250 if (Tok.K == KwData) {
251 E.Data = true;
252 continue;
253 }
254 if (Tok.K == KwConstant) {
255 E.Constant = true;
256 continue;
257 }
258 if (Tok.K == KwPrivate) {
259 E.Private = true;
260 continue;
261 }
262 unget();
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000263 Info.Exports.push_back(E);
264 return Error::success();
Martell Malone375dc902017-05-20 19:56:29 +0000265 }
266 }
267
268 // HEAPSIZE/STACKSIZE reserve[,commit]
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000269 Error parseNumbers(uint64_t *Reserve, uint64_t *Commit) {
270 if (Error Err = readAsInt(Reserve))
271 return Err;
Martell Malone375dc902017-05-20 19:56:29 +0000272 read();
273 if (Tok.K != Comma) {
274 unget();
275 Commit = nullptr;
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000276 return Error::success();
Martell Malone375dc902017-05-20 19:56:29 +0000277 }
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000278 if (Error Err = readAsInt(Commit))
279 return Err;
280 return Error::success();
Martell Malone375dc902017-05-20 19:56:29 +0000281 }
282
283 // NAME outputPath [BASE=address]
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000284 Error parseName(std::string *Out, uint64_t *Baseaddr) {
Martell Malone375dc902017-05-20 19:56:29 +0000285 read();
286 if (Tok.K == Identifier) {
287 *Out = Tok.Value;
288 } else {
289 *Out = "";
290 unget();
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000291 return Error::success();
Martell Malone375dc902017-05-20 19:56:29 +0000292 }
293 read();
294 if (Tok.K == KwBase) {
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000295 if (Error Err = expect(Equal, "'=' expected"))
296 return Err;
297 if (Error Err = readAsInt(Baseaddr))
298 return Err;
Martell Malone375dc902017-05-20 19:56:29 +0000299 } else {
300 unget();
301 *Baseaddr = 0;
302 }
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000303 return Error::success();
Martell Malone375dc902017-05-20 19:56:29 +0000304 }
305
306 // VERSION major[.minor]
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000307 Error parseVersion(uint32_t *Major, uint32_t *Minor) {
Martell Malone375dc902017-05-20 19:56:29 +0000308 read();
309 if (Tok.K != Identifier)
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000310 return createError("identifier expected, but got " + Tok.Value);
Martell Malone375dc902017-05-20 19:56:29 +0000311 StringRef V1, V2;
312 std::tie(V1, V2) = Tok.Value.split('.');
313 if (V1.getAsInteger(10, *Major))
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000314 return createError("integer expected, but got " + Tok.Value);
Martell Malone375dc902017-05-20 19:56:29 +0000315 if (V2.empty())
316 *Minor = 0;
317 else if (V2.getAsInteger(10, *Minor))
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000318 return createError("integer expected, but got " + Tok.Value);
319 return Error::success();
Martell Malone375dc902017-05-20 19:56:29 +0000320 }
321
322 Lexer Lex;
323 Token Tok;
324 std::vector<Token> Stack;
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000325 MachineTypes Machine;
326 COFFModuleDefinition Info;
Martell Malone1079ef82017-07-18 21:26:38 +0000327 bool MingwDef;
Martell Malone375dc902017-05-20 19:56:29 +0000328};
329
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000330Expected<COFFModuleDefinition> parseCOFFModuleDefinition(MemoryBufferRef MB,
Martell Malone1079ef82017-07-18 21:26:38 +0000331 MachineTypes Machine,
332 bool MingwDef) {
333 return Parser(MB.getBuffer(), Machine, MingwDef).parse();
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000334}
Martell Malone375dc902017-05-20 19:56:29 +0000335
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000336} // namespace object
337} // namespace llvm