blob: a571354648d6557b04aed3ea49ebf1e06a877f9d [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) {
Martin Storsjo843cbbd2017-10-23 09:08:13 +000060 // In def files, the symbols can either be listed decorated or undecorated.
61 //
62 // - For cdecl symbols, only the undecorated form is allowed.
63 // - For fastcall and vectorcall symbols, both fully decorated or
64 // undecorated forms can be present.
65 // - For stdcall symbols in non-MinGW environments, the decorated form is
66 // fully decorated with leading underscore and trailing stack argument
67 // size - like "_Func@0".
68 // - In MinGW def files, a decorated stdcall symbol does not include the
69 // leading underscore though, like "Func@0".
70
71 // This function controls whether a leading underscore should be added to
72 // the given symbol name or not. For MinGW, treat a stdcall symbol name such
73 // as "Func@0" as undecorated, i.e. a leading underscore must be added.
74 // For non-MinGW, look for '@' in the whole string and consider "_Func@0"
75 // as decorated, i.e. don't add any more leading underscores.
76 // We can't check for a leading underscore here, since function names
77 // themselves can start with an underscore, while a second one still needs
78 // to be added.
79 return Sym.startswith("@") || Sym.contains("@@") || Sym.startswith("?") ||
80 (!MingwDef && Sym.contains('@'));
Martell Malone375dc902017-05-20 19:56:29 +000081}
82
Reid Kleckner146eb7a2017-06-02 17:53:06 +000083static Error createError(const Twine &Err) {
84 return make_error<StringError>(StringRef(Err.str()),
85 object_error::parse_failed);
86}
87
Martell Malone375dc902017-05-20 19:56:29 +000088class Lexer {
89public:
Reid Kleckner146eb7a2017-06-02 17:53:06 +000090 Lexer(StringRef S) : Buf(S) {}
Martell Malone375dc902017-05-20 19:56:29 +000091
92 Token lex() {
93 Buf = Buf.trim();
94 if (Buf.empty())
95 return Token(Eof);
96
97 switch (Buf[0]) {
98 case '\0':
99 return Token(Eof);
100 case ';': {
101 size_t End = Buf.find('\n');
102 Buf = (End == Buf.npos) ? "" : Buf.drop_front(End);
103 return lex();
104 }
105 case '=':
106 Buf = Buf.drop_front();
Martell Malone1079ef82017-07-18 21:26:38 +0000107 // GNU dlltool accepts both = and ==.
108 if (Buf.startswith("="))
109 Buf = Buf.drop_front();
Martell Malone375dc902017-05-20 19:56:29 +0000110 return Token(Equal, "=");
111 case ',':
112 Buf = Buf.drop_front();
113 return Token(Comma, ",");
114 case '"': {
115 StringRef S;
116 std::tie(S, Buf) = Buf.substr(1).split('"');
117 return Token(Identifier, S);
118 }
119 default: {
Rui Ueyamaefb50242017-12-06 19:18:24 +0000120 size_t End = Buf.find_first_of("=,;\r\n \t\v");
Martell Malone375dc902017-05-20 19:56:29 +0000121 StringRef Word = Buf.substr(0, End);
122 Kind K = llvm::StringSwitch<Kind>(Word)
123 .Case("BASE", KwBase)
124 .Case("CONSTANT", KwConstant)
125 .Case("DATA", KwData)
126 .Case("EXPORTS", KwExports)
127 .Case("HEAPSIZE", KwHeapsize)
128 .Case("LIBRARY", KwLibrary)
129 .Case("NAME", KwName)
130 .Case("NONAME", KwNoname)
131 .Case("PRIVATE", KwPrivate)
132 .Case("STACKSIZE", KwStacksize)
133 .Case("VERSION", KwVersion)
134 .Default(Identifier);
135 Buf = (End == Buf.npos) ? "" : Buf.drop_front(End);
136 return Token(K, Word);
137 }
138 }
139 }
140
141private:
142 StringRef Buf;
143};
144
145class Parser {
146public:
Martell Malone1079ef82017-07-18 21:26:38 +0000147 explicit Parser(StringRef S, MachineTypes M, bool B)
148 : Lex(S), Machine(M), MingwDef(B) {}
Martell Malone375dc902017-05-20 19:56:29 +0000149
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000150 Expected<COFFModuleDefinition> parse() {
Martell Malone375dc902017-05-20 19:56:29 +0000151 do {
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000152 if (Error Err = parseOne())
153 return std::move(Err);
Martell Malone375dc902017-05-20 19:56:29 +0000154 } while (Tok.K != Eof);
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000155 return Info;
Martell Malone375dc902017-05-20 19:56:29 +0000156 }
157
158private:
159 void read() {
160 if (Stack.empty()) {
161 Tok = Lex.lex();
162 return;
163 }
164 Tok = Stack.back();
165 Stack.pop_back();
166 }
167
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000168 Error readAsInt(uint64_t *I) {
Martell Malone375dc902017-05-20 19:56:29 +0000169 read();
170 if (Tok.K != Identifier || Tok.Value.getAsInteger(10, *I))
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000171 return createError("integer expected");
172 return Error::success();
Martell Malone375dc902017-05-20 19:56:29 +0000173 }
174
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000175 Error expect(Kind Expected, StringRef Msg) {
Martell Malone375dc902017-05-20 19:56:29 +0000176 read();
177 if (Tok.K != Expected)
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000178 return createError(Msg);
179 return Error::success();
Martell Malone375dc902017-05-20 19:56:29 +0000180 }
181
182 void unget() { Stack.push_back(Tok); }
183
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000184 Error parseOne() {
Martell Malone375dc902017-05-20 19:56:29 +0000185 read();
186 switch (Tok.K) {
187 case Eof:
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000188 return Error::success();
Martell Malone375dc902017-05-20 19:56:29 +0000189 case KwExports:
190 for (;;) {
191 read();
192 if (Tok.K != Identifier) {
193 unget();
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000194 return Error::success();
Martell Malone375dc902017-05-20 19:56:29 +0000195 }
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000196 if (Error Err = parseExport())
197 return Err;
Martell Malone375dc902017-05-20 19:56:29 +0000198 }
199 case KwHeapsize:
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000200 return parseNumbers(&Info.HeapReserve, &Info.HeapCommit);
Martell Malone375dc902017-05-20 19:56:29 +0000201 case KwStacksize:
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000202 return parseNumbers(&Info.StackReserve, &Info.StackCommit);
Martell Malone375dc902017-05-20 19:56:29 +0000203 case KwLibrary:
204 case KwName: {
205 bool IsDll = Tok.K == KwLibrary; // Check before parseName.
206 std::string Name;
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000207 if (Error Err = parseName(&Name, &Info.ImageBase))
208 return Err;
Saleem Abdulrasool08e5f682017-07-19 02:01:22 +0000209
210 Info.ImportName = Name;
Martell Malone375dc902017-05-20 19:56:29 +0000211
212 // Set the output file, but don't override /out if it was already passed.
Saleem Abdulrasool08e5f682017-07-19 02:01:22 +0000213 if (Info.OutputFile.empty()) {
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000214 Info.OutputFile = Name;
Saleem Abdulrasool08e5f682017-07-19 02:01:22 +0000215 // Append the appropriate file extension if not already present.
216 if (!sys::path::has_extension(Name))
217 Info.OutputFile += IsDll ? ".dll" : ".exe";
218 }
219
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000220 return Error::success();
Martell Malone375dc902017-05-20 19:56:29 +0000221 }
222 case KwVersion:
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000223 return parseVersion(&Info.MajorImageVersion, &Info.MinorImageVersion);
Martell Malone375dc902017-05-20 19:56:29 +0000224 default:
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000225 return createError("unknown directive: " + Tok.Value);
Martell Malone375dc902017-05-20 19:56:29 +0000226 }
227 }
228
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000229 Error parseExport() {
230 COFFShortExport E;
Martell Malone375dc902017-05-20 19:56:29 +0000231 E.Name = Tok.Value;
232 read();
233 if (Tok.K == Equal) {
234 read();
235 if (Tok.K != Identifier)
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000236 return createError("identifier expected, but got " + Tok.Value);
Martell Malone375dc902017-05-20 19:56:29 +0000237 E.ExtName = E.Name;
238 E.Name = Tok.Value;
239 } else {
240 unget();
241 }
242
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000243 if (Machine == IMAGE_FILE_MACHINE_I386) {
Martell Malone1079ef82017-07-18 21:26:38 +0000244 if (!isDecorated(E.Name, MingwDef))
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000245 E.Name = (std::string("_").append(E.Name));
Martell Malone1079ef82017-07-18 21:26:38 +0000246 if (!E.ExtName.empty() && !isDecorated(E.ExtName, MingwDef))
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000247 E.ExtName = (std::string("_").append(E.ExtName));
Martell Malone375dc902017-05-20 19:56:29 +0000248 }
249
250 for (;;) {
251 read();
252 if (Tok.K == Identifier && Tok.Value[0] == '@') {
Martin Storsjo6c1fd292017-10-26 20:11:32 +0000253 if (Tok.Value == "@") {
254 // "foo @ 10"
255 read();
256 Tok.Value.getAsInteger(10, E.Ordinal);
257 } else if (Tok.Value.drop_front().getAsInteger(10, E.Ordinal)) {
258 // "foo \n @bar" - Not an ordinal modifier at all, but the next
259 // export (fastcall decorated) - complete the current one.
Martin Storsjo58c95272017-08-16 05:18:36 +0000260 unget();
261 Info.Exports.push_back(E);
262 return Error::success();
263 }
Martin Storsjo6c1fd292017-10-26 20:11:32 +0000264 // "foo @10"
Martell Malone375dc902017-05-20 19:56:29 +0000265 read();
266 if (Tok.K == KwNoname) {
267 E.Noname = true;
268 } else {
269 unget();
270 }
271 continue;
272 }
273 if (Tok.K == KwData) {
274 E.Data = true;
275 continue;
276 }
277 if (Tok.K == KwConstant) {
278 E.Constant = true;
279 continue;
280 }
281 if (Tok.K == KwPrivate) {
282 E.Private = true;
283 continue;
284 }
285 unget();
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000286 Info.Exports.push_back(E);
287 return Error::success();
Martell Malone375dc902017-05-20 19:56:29 +0000288 }
289 }
290
291 // HEAPSIZE/STACKSIZE reserve[,commit]
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000292 Error parseNumbers(uint64_t *Reserve, uint64_t *Commit) {
293 if (Error Err = readAsInt(Reserve))
294 return Err;
Martell Malone375dc902017-05-20 19:56:29 +0000295 read();
296 if (Tok.K != Comma) {
297 unget();
298 Commit = nullptr;
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000299 return Error::success();
Martell Malone375dc902017-05-20 19:56:29 +0000300 }
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000301 if (Error Err = readAsInt(Commit))
302 return Err;
303 return Error::success();
Martell Malone375dc902017-05-20 19:56:29 +0000304 }
305
306 // NAME outputPath [BASE=address]
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000307 Error parseName(std::string *Out, uint64_t *Baseaddr) {
Martell Malone375dc902017-05-20 19:56:29 +0000308 read();
309 if (Tok.K == Identifier) {
310 *Out = Tok.Value;
311 } else {
312 *Out = "";
313 unget();
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000314 return Error::success();
Martell Malone375dc902017-05-20 19:56:29 +0000315 }
316 read();
317 if (Tok.K == KwBase) {
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000318 if (Error Err = expect(Equal, "'=' expected"))
319 return Err;
320 if (Error Err = readAsInt(Baseaddr))
321 return Err;
Martell Malone375dc902017-05-20 19:56:29 +0000322 } else {
323 unget();
324 *Baseaddr = 0;
325 }
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000326 return Error::success();
Martell Malone375dc902017-05-20 19:56:29 +0000327 }
328
329 // VERSION major[.minor]
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000330 Error parseVersion(uint32_t *Major, uint32_t *Minor) {
Martell Malone375dc902017-05-20 19:56:29 +0000331 read();
332 if (Tok.K != Identifier)
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000333 return createError("identifier expected, but got " + Tok.Value);
Martell Malone375dc902017-05-20 19:56:29 +0000334 StringRef V1, V2;
335 std::tie(V1, V2) = Tok.Value.split('.');
336 if (V1.getAsInteger(10, *Major))
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000337 return createError("integer expected, but got " + Tok.Value);
Martell Malone375dc902017-05-20 19:56:29 +0000338 if (V2.empty())
339 *Minor = 0;
340 else if (V2.getAsInteger(10, *Minor))
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000341 return createError("integer expected, but got " + Tok.Value);
342 return Error::success();
Martell Malone375dc902017-05-20 19:56:29 +0000343 }
344
345 Lexer Lex;
346 Token Tok;
347 std::vector<Token> Stack;
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000348 MachineTypes Machine;
349 COFFModuleDefinition Info;
Martell Malone1079ef82017-07-18 21:26:38 +0000350 bool MingwDef;
Martell Malone375dc902017-05-20 19:56:29 +0000351};
352
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000353Expected<COFFModuleDefinition> parseCOFFModuleDefinition(MemoryBufferRef MB,
Martell Malone1079ef82017-07-18 21:26:38 +0000354 MachineTypes Machine,
355 bool MingwDef) {
356 return Parser(MB.getBuffer(), Machine, MingwDef).parse();
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000357}
Martell Malone375dc902017-05-20 19:56:29 +0000358
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000359} // namespace object
360} // namespace llvm