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