Line data Source code
1 : //===--- COFFModuleDefinition.cpp - Simple DEF parser ---------------------===//
2 : //
3 : // The LLVM Compiler Infrastructure
4 : //
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 :
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"
27 :
28 : using namespace llvm::COFF;
29 : using namespace llvm;
30 :
31 : namespace llvm {
32 : namespace object {
33 :
34 : enum Kind {
35 : Unknown,
36 : Eof,
37 : Identifier,
38 : Comma,
39 : Equal,
40 : EqualEqual,
41 : KwBase,
42 : KwConstant,
43 : KwData,
44 : KwExports,
45 : KwHeapsize,
46 : KwLibrary,
47 : KwName,
48 : KwNoname,
49 : KwPrivate,
50 : KwStacksize,
51 : KwVersion,
52 : };
53 :
54 : struct Token {
55 186 : explicit Token(Kind T = Unknown, StringRef S = "") : K(T), Value(S) {}
56 : Kind K;
57 : StringRef Value;
58 : };
59 :
60 25 : static bool isDecorated(StringRef Sym, bool MingwDef) {
61 : // 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 38 : return Sym.startswith("@") || Sym.contains("@@") || Sym.startswith("?") ||
81 11 : (!MingwDef && Sym.contains('@'));
82 : }
83 :
84 0 : static Error createError(const Twine &Err) {
85 0 : return make_error<StringError>(StringRef(Err.str()),
86 0 : object_error::parse_failed);
87 : }
88 :
89 : class Lexer {
90 : public:
91 32 : Lexer(StringRef S) : Buf(S) {}
92 :
93 260 : Token lex() {
94 260 : Buf = Buf.trim();
95 260 : if (Buf.empty())
96 : return Token(Eof);
97 :
98 227 : switch (Buf[0]) {
99 : case '\0':
100 : return Token(Eof);
101 69 : case ';': {
102 4 : size_t End = Buf.find('\n');
103 134 : Buf = (End == Buf.npos) ? "" : Buf.drop_front(End);
104 69 : return lex();
105 : }
106 10 : case '=':
107 10 : Buf = Buf.drop_front();
108 : if (Buf.startswith("=")) {
109 3 : Buf = Buf.drop_front();
110 : return Token(EqualEqual, "==");
111 : }
112 : return Token(Equal, "=");
113 2 : case ',':
114 2 : Buf = Buf.drop_front();
115 : return Token(Comma, ",");
116 0 : case '"': {
117 : StringRef S;
118 0 : std::tie(S, Buf) = Buf.substr(1).split('"');
119 : return Token(Identifier, S);
120 : }
121 146 : default: {
122 146 : size_t End = Buf.find_first_of("=,;\r\n \t\v");
123 146 : StringRef Word = Buf.substr(0, End);
124 146 : Kind K = llvm::StringSwitch<Kind>(Word)
125 146 : .Case("BASE", KwBase)
126 146 : .Case("CONSTANT", KwConstant)
127 146 : .Case("DATA", KwData)
128 146 : .Case("EXPORTS", KwExports)
129 146 : .Case("HEAPSIZE", KwHeapsize)
130 146 : .Case("LIBRARY", KwLibrary)
131 146 : .Case("NAME", KwName)
132 146 : .Case("NONAME", KwNoname)
133 146 : .Case("PRIVATE", KwPrivate)
134 146 : .Case("STACKSIZE", KwStacksize)
135 146 : .Case("VERSION", KwVersion)
136 : .Default(Identifier);
137 264 : Buf = (End == Buf.npos) ? "" : Buf.drop_front(End);
138 : return Token(K, Word);
139 : }
140 : }
141 : }
142 :
143 : private:
144 : StringRef Buf;
145 : };
146 :
147 : class Parser {
148 : public:
149 : explicit Parser(StringRef S, MachineTypes M, bool B)
150 32 : : Lex(S), Machine(M), MingwDef(B) {}
151 :
152 32 : Expected<COFFModuleDefinition> parse() {
153 : do {
154 102 : if (Error Err = parseOne())
155 : return std::move(Err);
156 51 : } while (Tok.K != Eof);
157 32 : return Info;
158 : }
159 :
160 : private:
161 306 : void read() {
162 306 : if (Stack.empty()) {
163 191 : Tok = Lex.lex();
164 191 : return;
165 : }
166 115 : Tok = Stack.back();
167 : Stack.pop_back();
168 : }
169 :
170 6 : Error readAsInt(uint64_t *I) {
171 6 : read();
172 12 : if (Tok.K != Identifier || Tok.Value.getAsInteger(10, *I))
173 0 : return createError("integer expected");
174 : return Error::success();
175 : }
176 :
177 0 : Error expect(Kind Expected, StringRef Msg) {
178 0 : read();
179 0 : if (Tok.K != Expected)
180 0 : return createError(Msg);
181 : return Error::success();
182 : }
183 :
184 145 : void unget() { Stack.push_back(Tok); }
185 :
186 51 : Error parseOne() {
187 51 : read();
188 51 : switch (Tok.K) {
189 : case Eof:
190 : return Error::success();
191 73 : case KwExports:
192 : for (;;) {
193 73 : read();
194 73 : if (Tok.K != Identifier) {
195 : unget();
196 : return Error::success();
197 : }
198 98 : if (Error Err = parseExport())
199 : return Err;
200 : }
201 2 : case KwHeapsize:
202 2 : return parseNumbers(&Info.HeapReserve, &Info.HeapCommit);
203 2 : case KwStacksize:
204 2 : return parseNumbers(&Info.StackReserve, &Info.StackCommit);
205 21 : case KwLibrary:
206 : case KwName: {
207 : bool IsDll = Tok.K == KwLibrary; // Check before parseName.
208 : std::string Name;
209 42 : if (Error Err = parseName(&Name, &Info.ImageBase))
210 : return Err;
211 :
212 21 : Info.ImportName = Name;
213 :
214 : // Set the output file, but don't override /out if it was already passed.
215 21 : if (Info.OutputFile.empty()) {
216 21 : Info.OutputFile = Name;
217 : // Append the appropriate file extension if not already present.
218 21 : if (!sys::path::has_extension(Name))
219 14 : Info.OutputFile += IsDll ? ".dll" : ".exe";
220 : }
221 :
222 : return Error::success();
223 : }
224 0 : case KwVersion:
225 0 : return parseVersion(&Info.MajorImageVersion, &Info.MinorImageVersion);
226 0 : default:
227 0 : return createError("unknown directive: " + Tok.Value);
228 : }
229 : }
230 :
231 49 : Error parseExport() {
232 49 : COFFShortExport E;
233 49 : E.Name = Tok.Value;
234 49 : read();
235 49 : if (Tok.K == Equal) {
236 7 : read();
237 7 : if (Tok.K != Identifier)
238 0 : return createError("identifier expected, but got " + Tok.Value);
239 : E.ExtName = E.Name;
240 14 : E.Name = Tok.Value;
241 : } else {
242 : unget();
243 : }
244 :
245 49 : if (Machine == IMAGE_FILE_MACHINE_I386) {
246 44 : if (!isDecorated(E.Name, MingwDef))
247 26 : E.Name = (std::string("_").append(E.Name));
248 22 : if (!E.ExtName.empty() && !isDecorated(E.ExtName, MingwDef))
249 4 : E.ExtName = (std::string("_").append(E.ExtName));
250 : }
251 :
252 : for (;;) {
253 61 : read();
254 61 : if (Tok.K == Identifier && Tok.Value[0] == '@') {
255 : if (Tok.Value == "@") {
256 : // "foo @ 10"
257 3 : read();
258 3 : Tok.Value.getAsInteger(10, E.Ordinal);
259 8 : } 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.
262 : unget();
263 4 : Info.Exports.push_back(E);
264 : return Error::success();
265 : }
266 : // "foo @10"
267 7 : read();
268 7 : if (Tok.K == KwNoname) {
269 0 : E.Noname = true;
270 : } else {
271 : unget();
272 : }
273 7 : continue;
274 : }
275 50 : if (Tok.K == KwData) {
276 1 : E.Data = true;
277 1 : continue;
278 : }
279 49 : if (Tok.K == KwConstant) {
280 1 : E.Constant = true;
281 1 : continue;
282 : }
283 48 : if (Tok.K == KwPrivate) {
284 0 : E.Private = true;
285 0 : continue;
286 : }
287 48 : if (Tok.K == EqualEqual) {
288 3 : read();
289 3 : E.AliasTarget = Tok.Value;
290 3 : if (Machine == IMAGE_FILE_MACHINE_I386 && !isDecorated(E.AliasTarget, MingwDef))
291 2 : E.AliasTarget = std::string("_").append(E.AliasTarget);
292 3 : continue;
293 : }
294 : unget();
295 45 : Info.Exports.push_back(E);
296 : return Error::success();
297 : }
298 : }
299 :
300 : // HEAPSIZE/STACKSIZE reserve[,commit]
301 4 : Error parseNumbers(uint64_t *Reserve, uint64_t *Commit) {
302 8 : if (Error Err = readAsInt(Reserve))
303 : return Err;
304 4 : read();
305 4 : if (Tok.K != Comma) {
306 : unget();
307 : Commit = nullptr;
308 : return Error::success();
309 : }
310 4 : if (Error Err = readAsInt(Commit))
311 : return Err;
312 : return Error::success();
313 : }
314 :
315 : // NAME outputPath [BASE=address]
316 21 : Error parseName(std::string *Out, uint64_t *Baseaddr) {
317 21 : read();
318 21 : if (Tok.K == Identifier) {
319 21 : *Out = Tok.Value;
320 : } else {
321 : *Out = "";
322 : unget();
323 : return Error::success();
324 : }
325 21 : read();
326 21 : if (Tok.K == KwBase) {
327 0 : if (Error Err = expect(Equal, "'=' expected"))
328 : return Err;
329 0 : if (Error Err = readAsInt(Baseaddr))
330 : return Err;
331 : } else {
332 : unget();
333 21 : *Baseaddr = 0;
334 : }
335 : return Error::success();
336 : }
337 :
338 : // VERSION major[.minor]
339 0 : Error parseVersion(uint32_t *Major, uint32_t *Minor) {
340 0 : read();
341 0 : if (Tok.K != Identifier)
342 0 : return createError("identifier expected, but got " + Tok.Value);
343 : StringRef V1, V2;
344 0 : std::tie(V1, V2) = Tok.Value.split('.');
345 0 : if (V1.getAsInteger(10, *Major))
346 0 : return createError("integer expected, but got " + Tok.Value);
347 0 : if (V2.empty())
348 0 : *Minor = 0;
349 0 : else if (V2.getAsInteger(10, *Minor))
350 0 : return createError("integer expected, but got " + Tok.Value);
351 : return Error::success();
352 : }
353 :
354 : Lexer Lex;
355 : Token Tok;
356 : std::vector<Token> Stack;
357 : MachineTypes Machine;
358 : COFFModuleDefinition Info;
359 : bool MingwDef;
360 : };
361 :
362 32 : Expected<COFFModuleDefinition> parseCOFFModuleDefinition(MemoryBufferRef MB,
363 : MachineTypes Machine,
364 : bool MingwDef) {
365 32 : return Parser(MB.getBuffer(), Machine, MingwDef).parse();
366 : }
367 :
368 : } // namespace object
369 : } // namespace llvm
|