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