blob: c703071b86e06447024eb40b6c14bd106b939b33 [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,
Martin Storsjo284ab802018-05-09 09:21:53 +000040 EqualEqual,
Martell Malone375dc902017-05-20 19:56:29 +000041 KwBase,
42 KwConstant,
43 KwData,
44 KwExports,
45 KwHeapsize,
46 KwLibrary,
47 KwName,
48 KwNoname,
49 KwPrivate,
50 KwStacksize,
51 KwVersion,
52};
53
54struct Token {
55 explicit Token(Kind T = Unknown, StringRef S = "") : K(T), Value(S) {}
56 Kind K;
57 StringRef Value;
58};
59
Martell Malone1079ef82017-07-18 21:26:38 +000060static bool isDecorated(StringRef Sym, bool MingwDef) {
Martin Storsjo843cbbd2017-10-23 09:08:13 +000061 // In def files, the symbols can either be listed decorated or undecorated.
62 //
63 // - For cdecl symbols, only the undecorated form is allowed.
64 // - For fastcall and vectorcall symbols, both fully decorated or
65 // undecorated forms can be present.
66 // - For stdcall symbols in non-MinGW environments, the decorated form is
67 // fully decorated with leading underscore and trailing stack argument
68 // size - like "_Func@0".
69 // - In MinGW def files, a decorated stdcall symbol does not include the
70 // leading underscore though, like "Func@0".
71
72 // This function controls whether a leading underscore should be added to
73 // the given symbol name or not. For MinGW, treat a stdcall symbol name such
74 // as "Func@0" as undecorated, i.e. a leading underscore must be added.
75 // For non-MinGW, look for '@' in the whole string and consider "_Func@0"
76 // as decorated, i.e. don't add any more leading underscores.
77 // We can't check for a leading underscore here, since function names
78 // themselves can start with an underscore, while a second one still needs
79 // to be added.
80 return Sym.startswith("@") || Sym.contains("@@") || Sym.startswith("?") ||
81 (!MingwDef && Sym.contains('@'));
Martell Malone375dc902017-05-20 19:56:29 +000082}
83
Reid Kleckner146eb7a2017-06-02 17:53:06 +000084static Error createError(const Twine &Err) {
85 return make_error<StringError>(StringRef(Err.str()),
86 object_error::parse_failed);
87}
88
Martell Malone375dc902017-05-20 19:56:29 +000089class Lexer {
90public:
Reid Kleckner146eb7a2017-06-02 17:53:06 +000091 Lexer(StringRef S) : Buf(S) {}
Martell Malone375dc902017-05-20 19:56:29 +000092
93 Token lex() {
94 Buf = Buf.trim();
95 if (Buf.empty())
96 return Token(Eof);
97
98 switch (Buf[0]) {
99 case '\0':
100 return Token(Eof);
101 case ';': {
102 size_t End = Buf.find('\n');
103 Buf = (End == Buf.npos) ? "" : Buf.drop_front(End);
104 return lex();
105 }
106 case '=':
107 Buf = Buf.drop_front();
Martin Storsjo284ab802018-05-09 09:21:53 +0000108 if (Buf.startswith("=")) {
Martell Malone1079ef82017-07-18 21:26:38 +0000109 Buf = Buf.drop_front();
Martin Storsjo284ab802018-05-09 09:21:53 +0000110 return Token(EqualEqual, "==");
111 }
Martell Malone375dc902017-05-20 19:56:29 +0000112 return Token(Equal, "=");
113 case ',':
114 Buf = Buf.drop_front();
115 return Token(Comma, ",");
116 case '"': {
117 StringRef S;
118 std::tie(S, Buf) = Buf.substr(1).split('"');
119 return Token(Identifier, S);
120 }
121 default: {
Rui Ueyamaefb50242017-12-06 19:18:24 +0000122 size_t End = Buf.find_first_of("=,;\r\n \t\v");
Martell Malone375dc902017-05-20 19:56:29 +0000123 StringRef Word = Buf.substr(0, End);
124 Kind K = llvm::StringSwitch<Kind>(Word)
125 .Case("BASE", KwBase)
126 .Case("CONSTANT", KwConstant)
127 .Case("DATA", KwData)
128 .Case("EXPORTS", KwExports)
129 .Case("HEAPSIZE", KwHeapsize)
130 .Case("LIBRARY", KwLibrary)
131 .Case("NAME", KwName)
132 .Case("NONAME", KwNoname)
133 .Case("PRIVATE", KwPrivate)
134 .Case("STACKSIZE", KwStacksize)
135 .Case("VERSION", KwVersion)
136 .Default(Identifier);
137 Buf = (End == Buf.npos) ? "" : Buf.drop_front(End);
138 return Token(K, Word);
139 }
140 }
141 }
142
143private:
144 StringRef Buf;
145};
146
147class Parser {
148public:
Martell Malone1079ef82017-07-18 21:26:38 +0000149 explicit Parser(StringRef S, MachineTypes M, bool B)
150 : Lex(S), Machine(M), MingwDef(B) {}
Martell Malone375dc902017-05-20 19:56:29 +0000151
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000152 Expected<COFFModuleDefinition> parse() {
Martell Malone375dc902017-05-20 19:56:29 +0000153 do {
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000154 if (Error Err = parseOne())
155 return std::move(Err);
Martell Malone375dc902017-05-20 19:56:29 +0000156 } while (Tok.K != Eof);
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000157 return Info;
Martell Malone375dc902017-05-20 19:56:29 +0000158 }
159
160private:
161 void read() {
162 if (Stack.empty()) {
163 Tok = Lex.lex();
164 return;
165 }
166 Tok = Stack.back();
167 Stack.pop_back();
168 }
169
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000170 Error readAsInt(uint64_t *I) {
Martell Malone375dc902017-05-20 19:56:29 +0000171 read();
172 if (Tok.K != Identifier || Tok.Value.getAsInteger(10, *I))
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000173 return createError("integer expected");
174 return Error::success();
Martell Malone375dc902017-05-20 19:56:29 +0000175 }
176
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000177 Error expect(Kind Expected, StringRef Msg) {
Martell Malone375dc902017-05-20 19:56:29 +0000178 read();
179 if (Tok.K != Expected)
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000180 return createError(Msg);
181 return Error::success();
Martell Malone375dc902017-05-20 19:56:29 +0000182 }
183
184 void unget() { Stack.push_back(Tok); }
185
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000186 Error parseOne() {
Martell Malone375dc902017-05-20 19:56:29 +0000187 read();
188 switch (Tok.K) {
189 case Eof:
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000190 return Error::success();
Martell Malone375dc902017-05-20 19:56:29 +0000191 case KwExports:
192 for (;;) {
193 read();
194 if (Tok.K != Identifier) {
195 unget();
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000196 return Error::success();
Martell Malone375dc902017-05-20 19:56:29 +0000197 }
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000198 if (Error Err = parseExport())
199 return Err;
Martell Malone375dc902017-05-20 19:56:29 +0000200 }
201 case KwHeapsize:
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000202 return parseNumbers(&Info.HeapReserve, &Info.HeapCommit);
Martell Malone375dc902017-05-20 19:56:29 +0000203 case KwStacksize:
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000204 return parseNumbers(&Info.StackReserve, &Info.StackCommit);
Martell Malone375dc902017-05-20 19:56:29 +0000205 case KwLibrary:
206 case KwName: {
207 bool IsDll = Tok.K == KwLibrary; // Check before parseName.
208 std::string Name;
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000209 if (Error Err = parseName(&Name, &Info.ImageBase))
210 return Err;
Saleem Abdulrasool08e5f682017-07-19 02:01:22 +0000211
212 Info.ImportName = Name;
Martell Malone375dc902017-05-20 19:56:29 +0000213
214 // Set the output file, but don't override /out if it was already passed.
Saleem Abdulrasool08e5f682017-07-19 02:01:22 +0000215 if (Info.OutputFile.empty()) {
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000216 Info.OutputFile = Name;
Saleem Abdulrasool08e5f682017-07-19 02:01:22 +0000217 // Append the appropriate file extension if not already present.
218 if (!sys::path::has_extension(Name))
219 Info.OutputFile += IsDll ? ".dll" : ".exe";
220 }
221
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000222 return Error::success();
Martell Malone375dc902017-05-20 19:56:29 +0000223 }
224 case KwVersion:
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000225 return parseVersion(&Info.MajorImageVersion, &Info.MinorImageVersion);
Martell Malone375dc902017-05-20 19:56:29 +0000226 default:
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000227 return createError("unknown directive: " + Tok.Value);
Martell Malone375dc902017-05-20 19:56:29 +0000228 }
229 }
230
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000231 Error parseExport() {
232 COFFShortExport E;
Martell Malone375dc902017-05-20 19:56:29 +0000233 E.Name = Tok.Value;
234 read();
235 if (Tok.K == Equal) {
236 read();
237 if (Tok.K != Identifier)
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000238 return createError("identifier expected, but got " + Tok.Value);
Martell Malone375dc902017-05-20 19:56:29 +0000239 E.ExtName = E.Name;
240 E.Name = Tok.Value;
241 } else {
242 unget();
243 }
244
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000245 if (Machine == IMAGE_FILE_MACHINE_I386) {
Martell Malone1079ef82017-07-18 21:26:38 +0000246 if (!isDecorated(E.Name, MingwDef))
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000247 E.Name = (std::string("_").append(E.Name));
Martell Malone1079ef82017-07-18 21:26:38 +0000248 if (!E.ExtName.empty() && !isDecorated(E.ExtName, MingwDef))
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000249 E.ExtName = (std::string("_").append(E.ExtName));
Martell Malone375dc902017-05-20 19:56:29 +0000250 }
251
252 for (;;) {
253 read();
254 if (Tok.K == Identifier && Tok.Value[0] == '@') {
Martin Storsjo6c1fd292017-10-26 20:11:32 +0000255 if (Tok.Value == "@") {
256 // "foo @ 10"
257 read();
258 Tok.Value.getAsInteger(10, E.Ordinal);
259 } else if (Tok.Value.drop_front().getAsInteger(10, E.Ordinal)) {
260 // "foo \n @bar" - Not an ordinal modifier at all, but the next
261 // export (fastcall decorated) - complete the current one.
Martin Storsjo58c95272017-08-16 05:18:36 +0000262 unget();
263 Info.Exports.push_back(E);
264 return Error::success();
265 }
Martin Storsjo6c1fd292017-10-26 20:11:32 +0000266 // "foo @10"
Martell Malone375dc902017-05-20 19:56:29 +0000267 read();
268 if (Tok.K == KwNoname) {
269 E.Noname = true;
270 } else {
271 unget();
272 }
273 continue;
274 }
275 if (Tok.K == KwData) {
276 E.Data = true;
277 continue;
278 }
279 if (Tok.K == KwConstant) {
280 E.Constant = true;
281 continue;
282 }
283 if (Tok.K == KwPrivate) {
284 E.Private = true;
285 continue;
286 }
Martin Storsjo284ab802018-05-09 09:21:53 +0000287 if (Tok.K == EqualEqual) {
288 read();
289 E.AliasTarget = Tok.Value;
290 if (Machine == IMAGE_FILE_MACHINE_I386 && !isDecorated(E.AliasTarget, MingwDef))
291 E.AliasTarget = std::string("_").append(E.AliasTarget);
292 continue;
293 }
Martell Malone375dc902017-05-20 19:56:29 +0000294 unget();
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000295 Info.Exports.push_back(E);
296 return Error::success();
Martell Malone375dc902017-05-20 19:56:29 +0000297 }
298 }
299
300 // HEAPSIZE/STACKSIZE reserve[,commit]
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000301 Error parseNumbers(uint64_t *Reserve, uint64_t *Commit) {
302 if (Error Err = readAsInt(Reserve))
303 return Err;
Martell Malone375dc902017-05-20 19:56:29 +0000304 read();
305 if (Tok.K != Comma) {
306 unget();
307 Commit = nullptr;
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000308 return Error::success();
Martell Malone375dc902017-05-20 19:56:29 +0000309 }
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000310 if (Error Err = readAsInt(Commit))
311 return Err;
312 return Error::success();
Martell Malone375dc902017-05-20 19:56:29 +0000313 }
314
315 // NAME outputPath [BASE=address]
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000316 Error parseName(std::string *Out, uint64_t *Baseaddr) {
Martell Malone375dc902017-05-20 19:56:29 +0000317 read();
318 if (Tok.K == Identifier) {
319 *Out = Tok.Value;
320 } else {
321 *Out = "";
322 unget();
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000323 return Error::success();
Martell Malone375dc902017-05-20 19:56:29 +0000324 }
325 read();
326 if (Tok.K == KwBase) {
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000327 if (Error Err = expect(Equal, "'=' expected"))
328 return Err;
329 if (Error Err = readAsInt(Baseaddr))
330 return Err;
Martell Malone375dc902017-05-20 19:56:29 +0000331 } else {
332 unget();
333 *Baseaddr = 0;
334 }
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000335 return Error::success();
Martell Malone375dc902017-05-20 19:56:29 +0000336 }
337
338 // VERSION major[.minor]
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000339 Error parseVersion(uint32_t *Major, uint32_t *Minor) {
Martell Malone375dc902017-05-20 19:56:29 +0000340 read();
341 if (Tok.K != Identifier)
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000342 return createError("identifier expected, but got " + Tok.Value);
Martell Malone375dc902017-05-20 19:56:29 +0000343 StringRef V1, V2;
344 std::tie(V1, V2) = Tok.Value.split('.');
345 if (V1.getAsInteger(10, *Major))
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000346 return createError("integer expected, but got " + Tok.Value);
Martell Malone375dc902017-05-20 19:56:29 +0000347 if (V2.empty())
348 *Minor = 0;
349 else if (V2.getAsInteger(10, *Minor))
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000350 return createError("integer expected, but got " + Tok.Value);
351 return Error::success();
Martell Malone375dc902017-05-20 19:56:29 +0000352 }
353
354 Lexer Lex;
355 Token Tok;
356 std::vector<Token> Stack;
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000357 MachineTypes Machine;
358 COFFModuleDefinition Info;
Martell Malone1079ef82017-07-18 21:26:38 +0000359 bool MingwDef;
Martell Malone375dc902017-05-20 19:56:29 +0000360};
361
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000362Expected<COFFModuleDefinition> parseCOFFModuleDefinition(MemoryBufferRef MB,
Martell Malone1079ef82017-07-18 21:26:38 +0000363 MachineTypes Machine,
364 bool MingwDef) {
365 return Parser(MB.getBuffer(), Machine, MingwDef).parse();
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000366}
Martell Malone375dc902017-05-20 19:56:29 +0000367
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000368} // namespace object
369} // namespace llvm