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 Tok.Value.drop_front().getAsInteger(10, E.Ordinal); 236 read(); 237 if (Tok.K == KwNoname) { 238 E.Noname = true; 239 } else { 240 unget(); 241 } 242 continue; 243 } 244 if (Tok.K == KwData) { 245 E.Data = true; 246 continue; 247 } 248 if (Tok.K == KwConstant) { 249 E.Constant = true; 250 continue; 251 } 252 if (Tok.K == KwPrivate) { 253 E.Private = true; 254 continue; 255 } 256 unget(); 257 Info.Exports.push_back(E); 258 return Error::success(); 259 } 260 } 261 262 // HEAPSIZE/STACKSIZE reserve[,commit] 263 Error parseNumbers(uint64_t *Reserve, uint64_t *Commit) { 264 if (Error Err = readAsInt(Reserve)) 265 return Err; 266 read(); 267 if (Tok.K != Comma) { 268 unget(); 269 Commit = nullptr; 270 return Error::success(); 271 } 272 if (Error Err = readAsInt(Commit)) 273 return Err; 274 return Error::success(); 275 } 276 277 // NAME outputPath [BASE=address] 278 Error parseName(std::string *Out, uint64_t *Baseaddr) { 279 read(); 280 if (Tok.K == Identifier) { 281 *Out = Tok.Value; 282 } else { 283 *Out = ""; 284 unget(); 285 return Error::success(); 286 } 287 read(); 288 if (Tok.K == KwBase) { 289 if (Error Err = expect(Equal, "'=' expected")) 290 return Err; 291 if (Error Err = readAsInt(Baseaddr)) 292 return Err; 293 } else { 294 unget(); 295 *Baseaddr = 0; 296 } 297 return Error::success(); 298 } 299 300 // VERSION major[.minor] 301 Error parseVersion(uint32_t *Major, uint32_t *Minor) { 302 read(); 303 if (Tok.K != Identifier) 304 return createError("identifier expected, but got " + Tok.Value); 305 StringRef V1, V2; 306 std::tie(V1, V2) = Tok.Value.split('.'); 307 if (V1.getAsInteger(10, *Major)) 308 return createError("integer expected, but got " + Tok.Value); 309 if (V2.empty()) 310 *Minor = 0; 311 else if (V2.getAsInteger(10, *Minor)) 312 return createError("integer expected, but got " + Tok.Value); 313 return Error::success(); 314 } 315 316 Lexer Lex; 317 Token Tok; 318 std::vector<Token> Stack; 319 MachineTypes Machine; 320 COFFModuleDefinition Info; 321 bool MingwDef; 322 }; 323 324 Expected<COFFModuleDefinition> parseCOFFModuleDefinition(MemoryBufferRef MB, 325 MachineTypes Machine, 326 bool MingwDef) { 327 return Parser(MB.getBuffer(), Machine, MingwDef).parse(); 328 } 329 330 } // namespace object 331 } // namespace llvm 332