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 338