blob: 64d4cf0efda2d2d2b61e145bb8041847b0324eeb [file] [log] [blame]
Reid Kleckner146eb7a2017-06-02 17:53:06 +00001//===--- COFFModuleDefinition.cpp - Simple DEF parser ---------------------===//
Martell Malone375dc902017-05-20 19:56:29 +00002//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
Martell Malone375dc902017-05-20 19:56:29 +00006//
7//===----------------------------------------------------------------------===//
8//
9// Windows-specific.
10// A parser for the module-definition file (.def file).
11//
12// The format of module-definition files are described in this document:
13// https://msdn.microsoft.com/en-us/library/28d6s79h.aspx
14//
15//===----------------------------------------------------------------------===//
16
Reid Kleckner146eb7a2017-06-02 17:53:06 +000017#include "llvm/Object/COFFModuleDefinition.h"
Martell Malone375dc902017-05-20 19:56:29 +000018#include "llvm/ADT/StringRef.h"
19#include "llvm/ADT/StringSwitch.h"
Reid Kleckner146eb7a2017-06-02 17:53:06 +000020#include "llvm/Object/COFF.h"
21#include "llvm/Object/COFFImportFile.h"
22#include "llvm/Object/Error.h"
23#include "llvm/Support/Error.h"
Saleem Abdulrasoole2349012017-07-18 22:11:00 +000024#include "llvm/Support/Path.h"
Martell Malone375dc902017-05-20 19:56:29 +000025#include "llvm/Support/raw_ostream.h"
26
Reid Kleckner146eb7a2017-06-02 17:53:06 +000027using namespace llvm::COFF;
Martell Malone375dc902017-05-20 19:56:29 +000028using namespace llvm;
29
Reid Kleckner146eb7a2017-06-02 17:53:06 +000030namespace llvm {
31namespace object {
Martell Malone375dc902017-05-20 19:56:29 +000032
33enum Kind {
34 Unknown,
35 Eof,
36 Identifier,
37 Comma,
38 Equal,
Martin Storsjo284ab802018-05-09 09:21:53 +000039 EqualEqual,
Martell Malone375dc902017-05-20 19:56:29 +000040 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();
Martin Storsjo284ab802018-05-09 09:21:53 +0000107 if (Buf.startswith("=")) {
Martell Malone1079ef82017-07-18 21:26:38 +0000108 Buf = Buf.drop_front();
Martin Storsjo284ab802018-05-09 09:21:53 +0000109 return Token(EqualEqual, "==");
110 }
Martell Malone375dc902017-05-20 19:56:29 +0000111 return Token(Equal, "=");
112 case ',':
113 Buf = Buf.drop_front();
114 return Token(Comma, ",");
115 case '"': {
116 StringRef S;
117 std::tie(S, Buf) = Buf.substr(1).split('"');
118 return Token(Identifier, S);
119 }
120 default: {
Rui Ueyamaefb50242017-12-06 19:18:24 +0000121 size_t End = Buf.find_first_of("=,;\r\n \t\v");
Martell Malone375dc902017-05-20 19:56:29 +0000122 StringRef Word = Buf.substr(0, End);
123 Kind K = llvm::StringSwitch<Kind>(Word)
124 .Case("BASE", KwBase)
125 .Case("CONSTANT", KwConstant)
126 .Case("DATA", KwData)
127 .Case("EXPORTS", KwExports)
128 .Case("HEAPSIZE", KwHeapsize)
129 .Case("LIBRARY", KwLibrary)
130 .Case("NAME", KwName)
131 .Case("NONAME", KwNoname)
132 .Case("PRIVATE", KwPrivate)
133 .Case("STACKSIZE", KwStacksize)
134 .Case("VERSION", KwVersion)
135 .Default(Identifier);
136 Buf = (End == Buf.npos) ? "" : Buf.drop_front(End);
137 return Token(K, Word);
138 }
139 }
140 }
141
142private:
143 StringRef Buf;
144};
145
146class Parser {
147public:
Martell Malone1079ef82017-07-18 21:26:38 +0000148 explicit Parser(StringRef S, MachineTypes M, bool B)
149 : Lex(S), Machine(M), MingwDef(B) {}
Martell Malone375dc902017-05-20 19:56:29 +0000150
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000151 Expected<COFFModuleDefinition> parse() {
Martell Malone375dc902017-05-20 19:56:29 +0000152 do {
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000153 if (Error Err = parseOne())
154 return std::move(Err);
Martell Malone375dc902017-05-20 19:56:29 +0000155 } while (Tok.K != Eof);
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000156 return Info;
Martell Malone375dc902017-05-20 19:56:29 +0000157 }
158
159private:
160 void read() {
161 if (Stack.empty()) {
162 Tok = Lex.lex();
163 return;
164 }
165 Tok = Stack.back();
166 Stack.pop_back();
167 }
168
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000169 Error readAsInt(uint64_t *I) {
Martell Malone375dc902017-05-20 19:56:29 +0000170 read();
171 if (Tok.K != Identifier || Tok.Value.getAsInteger(10, *I))
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000172 return createError("integer expected");
173 return Error::success();
Martell Malone375dc902017-05-20 19:56:29 +0000174 }
175
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000176 Error expect(Kind Expected, StringRef Msg) {
Martell Malone375dc902017-05-20 19:56:29 +0000177 read();
178 if (Tok.K != Expected)
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000179 return createError(Msg);
180 return Error::success();
Martell Malone375dc902017-05-20 19:56:29 +0000181 }
182
183 void unget() { Stack.push_back(Tok); }
184
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000185 Error parseOne() {
Martell Malone375dc902017-05-20 19:56:29 +0000186 read();
187 switch (Tok.K) {
188 case Eof:
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000189 return Error::success();
Martell Malone375dc902017-05-20 19:56:29 +0000190 case KwExports:
191 for (;;) {
192 read();
193 if (Tok.K != Identifier) {
194 unget();
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000195 return Error::success();
Martell Malone375dc902017-05-20 19:56:29 +0000196 }
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000197 if (Error Err = parseExport())
198 return Err;
Martell Malone375dc902017-05-20 19:56:29 +0000199 }
200 case KwHeapsize:
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000201 return parseNumbers(&Info.HeapReserve, &Info.HeapCommit);
Martell Malone375dc902017-05-20 19:56:29 +0000202 case KwStacksize:
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000203 return parseNumbers(&Info.StackReserve, &Info.StackCommit);
Martell Malone375dc902017-05-20 19:56:29 +0000204 case KwLibrary:
205 case KwName: {
206 bool IsDll = Tok.K == KwLibrary; // Check before parseName.
207 std::string Name;
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000208 if (Error Err = parseName(&Name, &Info.ImageBase))
209 return Err;
Saleem Abdulrasool08e5f682017-07-19 02:01:22 +0000210
211 Info.ImportName = Name;
Martell Malone375dc902017-05-20 19:56:29 +0000212
213 // Set the output file, but don't override /out if it was already passed.
Saleem Abdulrasool08e5f682017-07-19 02:01:22 +0000214 if (Info.OutputFile.empty()) {
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000215 Info.OutputFile = Name;
Saleem Abdulrasool08e5f682017-07-19 02:01:22 +0000216 // Append the appropriate file extension if not already present.
217 if (!sys::path::has_extension(Name))
218 Info.OutputFile += IsDll ? ".dll" : ".exe";
219 }
220
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000221 return Error::success();
Martell Malone375dc902017-05-20 19:56:29 +0000222 }
223 case KwVersion:
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000224 return parseVersion(&Info.MajorImageVersion, &Info.MinorImageVersion);
Martell Malone375dc902017-05-20 19:56:29 +0000225 default:
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000226 return createError("unknown directive: " + Tok.Value);
Martell Malone375dc902017-05-20 19:56:29 +0000227 }
228 }
229
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000230 Error parseExport() {
231 COFFShortExport E;
Martell Malone375dc902017-05-20 19:56:29 +0000232 E.Name = Tok.Value;
233 read();
234 if (Tok.K == Equal) {
235 read();
236 if (Tok.K != Identifier)
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000237 return createError("identifier expected, but got " + Tok.Value);
Martell Malone375dc902017-05-20 19:56:29 +0000238 E.ExtName = E.Name;
239 E.Name = Tok.Value;
240 } else {
241 unget();
242 }
243
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000244 if (Machine == IMAGE_FILE_MACHINE_I386) {
Martell Malone1079ef82017-07-18 21:26:38 +0000245 if (!isDecorated(E.Name, MingwDef))
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000246 E.Name = (std::string("_").append(E.Name));
Martell Malone1079ef82017-07-18 21:26:38 +0000247 if (!E.ExtName.empty() && !isDecorated(E.ExtName, MingwDef))
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000248 E.ExtName = (std::string("_").append(E.ExtName));
Martell Malone375dc902017-05-20 19:56:29 +0000249 }
250
251 for (;;) {
252 read();
253 if (Tok.K == Identifier && Tok.Value[0] == '@') {
Martin Storsjo6c1fd292017-10-26 20:11:32 +0000254 if (Tok.Value == "@") {
255 // "foo @ 10"
256 read();
257 Tok.Value.getAsInteger(10, E.Ordinal);
258 } else if (Tok.Value.drop_front().getAsInteger(10, E.Ordinal)) {
259 // "foo \n @bar" - Not an ordinal modifier at all, but the next
260 // export (fastcall decorated) - complete the current one.
Martin Storsjo58c95272017-08-16 05:18:36 +0000261 unget();
262 Info.Exports.push_back(E);
263 return Error::success();
264 }
Martin Storsjo6c1fd292017-10-26 20:11:32 +0000265 // "foo @10"
Martell Malone375dc902017-05-20 19:56:29 +0000266 read();
267 if (Tok.K == KwNoname) {
268 E.Noname = true;
269 } else {
270 unget();
271 }
272 continue;
273 }
274 if (Tok.K == KwData) {
275 E.Data = true;
276 continue;
277 }
278 if (Tok.K == KwConstant) {
279 E.Constant = true;
280 continue;
281 }
282 if (Tok.K == KwPrivate) {
283 E.Private = true;
284 continue;
285 }
Martin Storsjo284ab802018-05-09 09:21:53 +0000286 if (Tok.K == EqualEqual) {
287 read();
288 E.AliasTarget = Tok.Value;
289 if (Machine == IMAGE_FILE_MACHINE_I386 && !isDecorated(E.AliasTarget, MingwDef))
290 E.AliasTarget = std::string("_").append(E.AliasTarget);
291 continue;
292 }
Martell Malone375dc902017-05-20 19:56:29 +0000293 unget();
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000294 Info.Exports.push_back(E);
295 return Error::success();
Martell Malone375dc902017-05-20 19:56:29 +0000296 }
297 }
298
299 // HEAPSIZE/STACKSIZE reserve[,commit]
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000300 Error parseNumbers(uint64_t *Reserve, uint64_t *Commit) {
301 if (Error Err = readAsInt(Reserve))
302 return Err;
Martell Malone375dc902017-05-20 19:56:29 +0000303 read();
304 if (Tok.K != Comma) {
305 unget();
306 Commit = nullptr;
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000307 return Error::success();
Martell Malone375dc902017-05-20 19:56:29 +0000308 }
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000309 if (Error Err = readAsInt(Commit))
310 return Err;
311 return Error::success();
Martell Malone375dc902017-05-20 19:56:29 +0000312 }
313
314 // NAME outputPath [BASE=address]
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000315 Error parseName(std::string *Out, uint64_t *Baseaddr) {
Martell Malone375dc902017-05-20 19:56:29 +0000316 read();
317 if (Tok.K == Identifier) {
318 *Out = Tok.Value;
319 } else {
320 *Out = "";
321 unget();
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000322 return Error::success();
Martell Malone375dc902017-05-20 19:56:29 +0000323 }
324 read();
325 if (Tok.K == KwBase) {
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000326 if (Error Err = expect(Equal, "'=' expected"))
327 return Err;
328 if (Error Err = readAsInt(Baseaddr))
329 return Err;
Martell Malone375dc902017-05-20 19:56:29 +0000330 } else {
331 unget();
332 *Baseaddr = 0;
333 }
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000334 return Error::success();
Martell Malone375dc902017-05-20 19:56:29 +0000335 }
336
337 // VERSION major[.minor]
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000338 Error parseVersion(uint32_t *Major, uint32_t *Minor) {
Martell Malone375dc902017-05-20 19:56:29 +0000339 read();
340 if (Tok.K != Identifier)
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000341 return createError("identifier expected, but got " + Tok.Value);
Martell Malone375dc902017-05-20 19:56:29 +0000342 StringRef V1, V2;
343 std::tie(V1, V2) = Tok.Value.split('.');
344 if (V1.getAsInteger(10, *Major))
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000345 return createError("integer expected, but got " + Tok.Value);
Martell Malone375dc902017-05-20 19:56:29 +0000346 if (V2.empty())
347 *Minor = 0;
348 else if (V2.getAsInteger(10, *Minor))
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000349 return createError("integer expected, but got " + Tok.Value);
350 return Error::success();
Martell Malone375dc902017-05-20 19:56:29 +0000351 }
352
353 Lexer Lex;
354 Token Tok;
355 std::vector<Token> Stack;
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000356 MachineTypes Machine;
357 COFFModuleDefinition Info;
Martell Malone1079ef82017-07-18 21:26:38 +0000358 bool MingwDef;
Martell Malone375dc902017-05-20 19:56:29 +0000359};
360
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000361Expected<COFFModuleDefinition> parseCOFFModuleDefinition(MemoryBufferRef MB,
Martell Malone1079ef82017-07-18 21:26:38 +0000362 MachineTypes Machine,
363 bool MingwDef) {
364 return Parser(MB.getBuffer(), Machine, MingwDef).parse();
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000365}
Martell Malone375dc902017-05-20 19:56:29 +0000366
Reid Kleckner146eb7a2017-06-02 17:53:06 +0000367} // namespace object
368} // namespace llvm