]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/lib/Object/COFFModuleDefinition.cpp
MFV r325605: 8713 Buffer overflow in dsl_dataset_name()
[FreeBSD/FreeBSD.git] / contrib / llvm / lib / Object / COFFModuleDefinition.cpp
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   KwBase,
41   KwConstant,
42   KwData,
43   KwExports,
44   KwHeapsize,
45   KwLibrary,
46   KwName,
47   KwNoname,
48   KwPrivate,
49   KwStacksize,
50   KwVersion,
51 };
52
53 struct Token {
54   explicit Token(Kind T = Unknown, StringRef S = "") : K(T), Value(S) {}
55   Kind K;
56   StringRef Value;
57 };
58
59 static bool isDecorated(StringRef Sym, bool MingwDef) {
60   // mingw does not prepend "_".
61   return (!MingwDef && Sym.startswith("_")) || Sym.startswith("@") ||
62          Sym.startswith("?");
63 }
64
65 static Error createError(const Twine &Err) {
66   return make_error<StringError>(StringRef(Err.str()),
67                                  object_error::parse_failed);
68 }
69
70 class Lexer {
71 public:
72   Lexer(StringRef S) : Buf(S) {}
73
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();
89       // GNU dlltool accepts both = and ==.
90       if (Buf.startswith("="))
91         Buf = Buf.drop_front();
92       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
123 private:
124   StringRef Buf;
125 };
126
127 class Parser {
128 public:
129   explicit Parser(StringRef S, MachineTypes M, bool B)
130       : Lex(S), Machine(M), MingwDef(B) {}
131
132   Expected<COFFModuleDefinition> parse() {
133     do {
134       if (Error Err = parseOne())
135         return std::move(Err);
136     } while (Tok.K != Eof);
137     return Info;
138   }
139
140 private:
141   void read() {
142     if (Stack.empty()) {
143       Tok = Lex.lex();
144       return;
145     }
146     Tok = Stack.back();
147     Stack.pop_back();
148   }
149
150   Error readAsInt(uint64_t *I) {
151     read();
152     if (Tok.K != Identifier || Tok.Value.getAsInteger(10, *I))
153       return createError("integer expected");
154     return Error::success();
155   }
156
157   Error expect(Kind Expected, StringRef Msg) {
158     read();
159     if (Tok.K != Expected)
160       return createError(Msg);
161     return Error::success();
162   }
163
164   void unget() { Stack.push_back(Tok); }
165
166   Error parseOne() {
167     read();
168     switch (Tok.K) {
169     case Eof:
170       return Error::success();
171     case KwExports:
172       for (;;) {
173         read();
174         if (Tok.K != Identifier) {
175           unget();
176           return Error::success();
177         }
178         if (Error Err = parseExport())
179           return Err;
180       }
181     case KwHeapsize:
182       return parseNumbers(&Info.HeapReserve, &Info.HeapCommit);
183     case KwStacksize:
184       return parseNumbers(&Info.StackReserve, &Info.StackCommit);
185     case KwLibrary:
186     case KwName: {
187       bool IsDll = Tok.K == KwLibrary; // Check before parseName.
188       std::string Name;
189       if (Error Err = parseName(&Name, &Info.ImageBase))
190         return Err;
191
192       Info.ImportName = Name;
193
194       // Set the output file, but don't override /out if it was already passed.
195       if (Info.OutputFile.empty()) {
196         Info.OutputFile = Name;
197         // Append the appropriate file extension if not already present.
198         if (!sys::path::has_extension(Name))
199           Info.OutputFile += IsDll ? ".dll" : ".exe";
200       }
201
202       return Error::success();
203     }
204     case KwVersion:
205       return parseVersion(&Info.MajorImageVersion, &Info.MinorImageVersion);
206     default:
207       return createError("unknown directive: " + Tok.Value);
208     }
209   }
210
211   Error parseExport() {
212     COFFShortExport E;
213     E.Name = Tok.Value;
214     read();
215     if (Tok.K == Equal) {
216       read();
217       if (Tok.K != Identifier)
218         return createError("identifier expected, but got " + Tok.Value);
219       E.ExtName = E.Name;
220       E.Name = Tok.Value;
221     } else {
222       unget();
223     }
224
225     if (Machine == IMAGE_FILE_MACHINE_I386) {
226       if (!isDecorated(E.Name, MingwDef))
227         E.Name = (std::string("_").append(E.Name));
228       if (!E.ExtName.empty() && !isDecorated(E.ExtName, MingwDef))
229         E.ExtName = (std::string("_").append(E.ExtName));
230     }
231
232     for (;;) {
233       read();
234       if (Tok.K == Identifier && Tok.Value[0] == '@') {
235         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         }
242         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();
263       Info.Exports.push_back(E);
264       return Error::success();
265     }
266   }
267
268   // HEAPSIZE/STACKSIZE reserve[,commit]
269   Error parseNumbers(uint64_t *Reserve, uint64_t *Commit) {
270     if (Error Err = readAsInt(Reserve))
271       return Err;
272     read();
273     if (Tok.K != Comma) {
274       unget();
275       Commit = nullptr;
276       return Error::success();
277     }
278     if (Error Err = readAsInt(Commit))
279       return Err;
280     return Error::success();
281   }
282
283   // NAME outputPath [BASE=address]
284   Error parseName(std::string *Out, uint64_t *Baseaddr) {
285     read();
286     if (Tok.K == Identifier) {
287       *Out = Tok.Value;
288     } else {
289       *Out = "";
290       unget();
291       return Error::success();
292     }
293     read();
294     if (Tok.K == KwBase) {
295       if (Error Err = expect(Equal, "'=' expected"))
296         return Err;
297       if (Error Err = readAsInt(Baseaddr))
298         return Err;
299     } else {
300       unget();
301       *Baseaddr = 0;
302     }
303     return Error::success();
304   }
305
306   // VERSION major[.minor]
307   Error parseVersion(uint32_t *Major, uint32_t *Minor) {
308     read();
309     if (Tok.K != Identifier)
310       return createError("identifier expected, but got " + Tok.Value);
311     StringRef V1, V2;
312     std::tie(V1, V2) = Tok.Value.split('.');
313     if (V1.getAsInteger(10, *Major))
314       return createError("integer expected, but got " + Tok.Value);
315     if (V2.empty())
316       *Minor = 0;
317     else if (V2.getAsInteger(10, *Minor))
318       return createError("integer expected, but got " + Tok.Value);
319     return Error::success();
320   }
321
322   Lexer Lex;
323   Token Tok;
324   std::vector<Token> Stack;
325   MachineTypes Machine;
326   COFFModuleDefinition Info;
327   bool MingwDef;
328 };
329
330 Expected<COFFModuleDefinition> parseCOFFModuleDefinition(MemoryBufferRef MB,
331                                                          MachineTypes Machine,
332                                                          bool MingwDef) {
333   return Parser(MB.getBuffer(), Machine, MingwDef).parse();
334 }
335
336 } // namespace object
337 } // namespace llvm