1146eb7a6SReid Kleckner //===--- COFFModuleDefinition.cpp - Simple DEF parser ---------------------===// 2146eb7a6SReid Kleckner // 3146eb7a6SReid Kleckner // The LLVM Compiler Infrastructure 4146eb7a6SReid Kleckner // 5146eb7a6SReid Kleckner // This file is distributed under the University of Illinois Open Source 6146eb7a6SReid Kleckner // License. See LICENSE.TXT for details. 7146eb7a6SReid Kleckner // 8146eb7a6SReid Kleckner //===----------------------------------------------------------------------===// 9146eb7a6SReid Kleckner // 10146eb7a6SReid Kleckner // Windows-specific. 11146eb7a6SReid Kleckner // A parser for the module-definition file (.def file). 12146eb7a6SReid Kleckner // 13146eb7a6SReid Kleckner // The format of module-definition files are described in this document: 14146eb7a6SReid Kleckner // https://msdn.microsoft.com/en-us/library/28d6s79h.aspx 15146eb7a6SReid Kleckner // 16146eb7a6SReid Kleckner //===----------------------------------------------------------------------===// 17146eb7a6SReid Kleckner 18146eb7a6SReid Kleckner #include "llvm/Object/COFFModuleDefinition.h" 19146eb7a6SReid Kleckner #include "llvm/ADT/StringRef.h" 20146eb7a6SReid Kleckner #include "llvm/ADT/StringSwitch.h" 21146eb7a6SReid Kleckner #include "llvm/Object/COFF.h" 22146eb7a6SReid Kleckner #include "llvm/Object/COFFImportFile.h" 23146eb7a6SReid Kleckner #include "llvm/Object/Error.h" 24146eb7a6SReid Kleckner #include "llvm/Support/Error.h" 25*e234901aSSaleem Abdulrasool #include "llvm/Support/Path.h" 26146eb7a6SReid Kleckner #include "llvm/Support/raw_ostream.h" 27146eb7a6SReid Kleckner 28146eb7a6SReid Kleckner using namespace llvm::COFF; 29146eb7a6SReid Kleckner using namespace llvm; 30146eb7a6SReid Kleckner 31146eb7a6SReid Kleckner namespace llvm { 32146eb7a6SReid Kleckner namespace object { 33146eb7a6SReid Kleckner 34146eb7a6SReid Kleckner enum Kind { 35146eb7a6SReid Kleckner Unknown, 36146eb7a6SReid Kleckner Eof, 37146eb7a6SReid Kleckner Identifier, 38146eb7a6SReid Kleckner Comma, 39146eb7a6SReid Kleckner Equal, 40146eb7a6SReid Kleckner KwBase, 41146eb7a6SReid Kleckner KwConstant, 42146eb7a6SReid Kleckner KwData, 43146eb7a6SReid Kleckner KwExports, 44146eb7a6SReid Kleckner KwHeapsize, 45146eb7a6SReid Kleckner KwLibrary, 46146eb7a6SReid Kleckner KwName, 47146eb7a6SReid Kleckner KwNoname, 48146eb7a6SReid Kleckner KwPrivate, 49146eb7a6SReid Kleckner KwStacksize, 50146eb7a6SReid Kleckner KwVersion, 51146eb7a6SReid Kleckner }; 52146eb7a6SReid Kleckner 53146eb7a6SReid Kleckner struct Token { 54146eb7a6SReid Kleckner explicit Token(Kind T = Unknown, StringRef S = "") : K(T), Value(S) {} 55146eb7a6SReid Kleckner Kind K; 56146eb7a6SReid Kleckner StringRef Value; 57146eb7a6SReid Kleckner }; 58146eb7a6SReid Kleckner 591079ef8dSMartell Malone static bool isDecorated(StringRef Sym, bool MingwDef) { 601079ef8dSMartell Malone // mingw does not prepend "_". 611079ef8dSMartell Malone return (!MingwDef && Sym.startswith("_")) || Sym.startswith("@") || 621079ef8dSMartell Malone Sym.startswith("?"); 63146eb7a6SReid Kleckner } 64146eb7a6SReid Kleckner 65146eb7a6SReid Kleckner static Error createError(const Twine &Err) { 66146eb7a6SReid Kleckner return make_error<StringError>(StringRef(Err.str()), 67146eb7a6SReid Kleckner object_error::parse_failed); 68146eb7a6SReid Kleckner } 69146eb7a6SReid Kleckner 70146eb7a6SReid Kleckner class Lexer { 71146eb7a6SReid Kleckner public: 72146eb7a6SReid Kleckner Lexer(StringRef S) : Buf(S) {} 73146eb7a6SReid Kleckner 74146eb7a6SReid Kleckner Token lex() { 75146eb7a6SReid Kleckner Buf = Buf.trim(); 76146eb7a6SReid Kleckner if (Buf.empty()) 77146eb7a6SReid Kleckner return Token(Eof); 78146eb7a6SReid Kleckner 79146eb7a6SReid Kleckner switch (Buf[0]) { 80146eb7a6SReid Kleckner case '\0': 81146eb7a6SReid Kleckner return Token(Eof); 82146eb7a6SReid Kleckner case ';': { 83146eb7a6SReid Kleckner size_t End = Buf.find('\n'); 84146eb7a6SReid Kleckner Buf = (End == Buf.npos) ? "" : Buf.drop_front(End); 85146eb7a6SReid Kleckner return lex(); 86146eb7a6SReid Kleckner } 87146eb7a6SReid Kleckner case '=': 88146eb7a6SReid Kleckner Buf = Buf.drop_front(); 891079ef8dSMartell Malone // GNU dlltool accepts both = and ==. 901079ef8dSMartell Malone if (Buf.startswith("=")) 911079ef8dSMartell Malone Buf = Buf.drop_front(); 92146eb7a6SReid Kleckner return Token(Equal, "="); 93146eb7a6SReid Kleckner case ',': 94146eb7a6SReid Kleckner Buf = Buf.drop_front(); 95146eb7a6SReid Kleckner return Token(Comma, ","); 96146eb7a6SReid Kleckner case '"': { 97146eb7a6SReid Kleckner StringRef S; 98146eb7a6SReid Kleckner std::tie(S, Buf) = Buf.substr(1).split('"'); 99146eb7a6SReid Kleckner return Token(Identifier, S); 100146eb7a6SReid Kleckner } 101146eb7a6SReid Kleckner default: { 102146eb7a6SReid Kleckner size_t End = Buf.find_first_of("=,\r\n \t\v"); 103146eb7a6SReid Kleckner StringRef Word = Buf.substr(0, End); 104146eb7a6SReid Kleckner Kind K = llvm::StringSwitch<Kind>(Word) 105146eb7a6SReid Kleckner .Case("BASE", KwBase) 106146eb7a6SReid Kleckner .Case("CONSTANT", KwConstant) 107146eb7a6SReid Kleckner .Case("DATA", KwData) 108146eb7a6SReid Kleckner .Case("EXPORTS", KwExports) 109146eb7a6SReid Kleckner .Case("HEAPSIZE", KwHeapsize) 110146eb7a6SReid Kleckner .Case("LIBRARY", KwLibrary) 111146eb7a6SReid Kleckner .Case("NAME", KwName) 112146eb7a6SReid Kleckner .Case("NONAME", KwNoname) 113146eb7a6SReid Kleckner .Case("PRIVATE", KwPrivate) 114146eb7a6SReid Kleckner .Case("STACKSIZE", KwStacksize) 115146eb7a6SReid Kleckner .Case("VERSION", KwVersion) 116146eb7a6SReid Kleckner .Default(Identifier); 117146eb7a6SReid Kleckner Buf = (End == Buf.npos) ? "" : Buf.drop_front(End); 118146eb7a6SReid Kleckner return Token(K, Word); 119146eb7a6SReid Kleckner } 120146eb7a6SReid Kleckner } 121146eb7a6SReid Kleckner } 122146eb7a6SReid Kleckner 123146eb7a6SReid Kleckner private: 124146eb7a6SReid Kleckner StringRef Buf; 125146eb7a6SReid Kleckner }; 126146eb7a6SReid Kleckner 127146eb7a6SReid Kleckner class Parser { 128146eb7a6SReid Kleckner public: 1291079ef8dSMartell Malone explicit Parser(StringRef S, MachineTypes M, bool B) 1301079ef8dSMartell Malone : Lex(S), Machine(M), MingwDef(B) {} 131146eb7a6SReid Kleckner 132146eb7a6SReid Kleckner Expected<COFFModuleDefinition> parse() { 133146eb7a6SReid Kleckner do { 134146eb7a6SReid Kleckner if (Error Err = parseOne()) 135146eb7a6SReid Kleckner return std::move(Err); 136146eb7a6SReid Kleckner } while (Tok.K != Eof); 137146eb7a6SReid Kleckner return Info; 138146eb7a6SReid Kleckner } 139146eb7a6SReid Kleckner 140146eb7a6SReid Kleckner private: 141146eb7a6SReid Kleckner void read() { 142146eb7a6SReid Kleckner if (Stack.empty()) { 143146eb7a6SReid Kleckner Tok = Lex.lex(); 144146eb7a6SReid Kleckner return; 145146eb7a6SReid Kleckner } 146146eb7a6SReid Kleckner Tok = Stack.back(); 147146eb7a6SReid Kleckner Stack.pop_back(); 148146eb7a6SReid Kleckner } 149146eb7a6SReid Kleckner 150146eb7a6SReid Kleckner Error readAsInt(uint64_t *I) { 151146eb7a6SReid Kleckner read(); 152146eb7a6SReid Kleckner if (Tok.K != Identifier || Tok.Value.getAsInteger(10, *I)) 153146eb7a6SReid Kleckner return createError("integer expected"); 154146eb7a6SReid Kleckner return Error::success(); 155146eb7a6SReid Kleckner } 156146eb7a6SReid Kleckner 157146eb7a6SReid Kleckner Error expect(Kind Expected, StringRef Msg) { 158146eb7a6SReid Kleckner read(); 159146eb7a6SReid Kleckner if (Tok.K != Expected) 160146eb7a6SReid Kleckner return createError(Msg); 161146eb7a6SReid Kleckner return Error::success(); 162146eb7a6SReid Kleckner } 163146eb7a6SReid Kleckner 164146eb7a6SReid Kleckner void unget() { Stack.push_back(Tok); } 165146eb7a6SReid Kleckner 166146eb7a6SReid Kleckner Error parseOne() { 167146eb7a6SReid Kleckner read(); 168146eb7a6SReid Kleckner switch (Tok.K) { 169146eb7a6SReid Kleckner case Eof: 170146eb7a6SReid Kleckner return Error::success(); 171146eb7a6SReid Kleckner case KwExports: 172146eb7a6SReid Kleckner for (;;) { 173146eb7a6SReid Kleckner read(); 174146eb7a6SReid Kleckner if (Tok.K != Identifier) { 175146eb7a6SReid Kleckner unget(); 176146eb7a6SReid Kleckner return Error::success(); 177146eb7a6SReid Kleckner } 178146eb7a6SReid Kleckner if (Error Err = parseExport()) 179146eb7a6SReid Kleckner return Err; 180146eb7a6SReid Kleckner } 181146eb7a6SReid Kleckner case KwHeapsize: 182146eb7a6SReid Kleckner return parseNumbers(&Info.HeapReserve, &Info.HeapCommit); 183146eb7a6SReid Kleckner case KwStacksize: 184146eb7a6SReid Kleckner return parseNumbers(&Info.StackReserve, &Info.StackCommit); 185146eb7a6SReid Kleckner case KwLibrary: 186146eb7a6SReid Kleckner case KwName: { 187146eb7a6SReid Kleckner bool IsDll = Tok.K == KwLibrary; // Check before parseName. 188146eb7a6SReid Kleckner std::string Name; 189146eb7a6SReid Kleckner if (Error Err = parseName(&Name, &Info.ImageBase)) 190146eb7a6SReid Kleckner return Err; 191146eb7a6SReid Kleckner // Append the appropriate file extension if not already present. 192*e234901aSSaleem Abdulrasool if (!sys::path::has_extension(Name)) 193*e234901aSSaleem Abdulrasool Name += IsDll ? ".dll" : ".exe"; 194146eb7a6SReid Kleckner 195146eb7a6SReid Kleckner // Set the output file, but don't override /out if it was already passed. 196146eb7a6SReid Kleckner if (Info.OutputFile.empty()) 197146eb7a6SReid Kleckner Info.OutputFile = Name; 198146eb7a6SReid Kleckner return Error::success(); 199146eb7a6SReid Kleckner } 200146eb7a6SReid Kleckner case KwVersion: 201146eb7a6SReid Kleckner return parseVersion(&Info.MajorImageVersion, &Info.MinorImageVersion); 202146eb7a6SReid Kleckner default: 203146eb7a6SReid Kleckner return createError("unknown directive: " + Tok.Value); 204146eb7a6SReid Kleckner } 205146eb7a6SReid Kleckner } 206146eb7a6SReid Kleckner 207146eb7a6SReid Kleckner Error parseExport() { 208146eb7a6SReid Kleckner COFFShortExport E; 209146eb7a6SReid Kleckner E.Name = Tok.Value; 210146eb7a6SReid Kleckner read(); 211146eb7a6SReid Kleckner if (Tok.K == Equal) { 212146eb7a6SReid Kleckner read(); 213146eb7a6SReid Kleckner if (Tok.K != Identifier) 214146eb7a6SReid Kleckner return createError("identifier expected, but got " + Tok.Value); 215146eb7a6SReid Kleckner E.ExtName = E.Name; 216146eb7a6SReid Kleckner E.Name = Tok.Value; 217146eb7a6SReid Kleckner } else { 218146eb7a6SReid Kleckner unget(); 219146eb7a6SReid Kleckner } 220146eb7a6SReid Kleckner 221146eb7a6SReid Kleckner if (Machine == IMAGE_FILE_MACHINE_I386) { 2221079ef8dSMartell Malone if (!isDecorated(E.Name, MingwDef)) 223146eb7a6SReid Kleckner E.Name = (std::string("_").append(E.Name)); 2241079ef8dSMartell Malone if (!E.ExtName.empty() && !isDecorated(E.ExtName, MingwDef)) 225146eb7a6SReid Kleckner E.ExtName = (std::string("_").append(E.ExtName)); 226146eb7a6SReid Kleckner } 227146eb7a6SReid Kleckner 228146eb7a6SReid Kleckner for (;;) { 229146eb7a6SReid Kleckner read(); 230146eb7a6SReid Kleckner if (Tok.K == Identifier && Tok.Value[0] == '@') { 231146eb7a6SReid Kleckner Tok.Value.drop_front().getAsInteger(10, E.Ordinal); 232146eb7a6SReid Kleckner read(); 233146eb7a6SReid Kleckner if (Tok.K == KwNoname) { 234146eb7a6SReid Kleckner E.Noname = true; 235146eb7a6SReid Kleckner } else { 236146eb7a6SReid Kleckner unget(); 237146eb7a6SReid Kleckner } 238146eb7a6SReid Kleckner continue; 239146eb7a6SReid Kleckner } 240146eb7a6SReid Kleckner if (Tok.K == KwData) { 241146eb7a6SReid Kleckner E.Data = true; 242146eb7a6SReid Kleckner continue; 243146eb7a6SReid Kleckner } 244146eb7a6SReid Kleckner if (Tok.K == KwConstant) { 245146eb7a6SReid Kleckner E.Constant = true; 246146eb7a6SReid Kleckner continue; 247146eb7a6SReid Kleckner } 248146eb7a6SReid Kleckner if (Tok.K == KwPrivate) { 249146eb7a6SReid Kleckner E.Private = true; 250146eb7a6SReid Kleckner continue; 251146eb7a6SReid Kleckner } 252146eb7a6SReid Kleckner unget(); 253146eb7a6SReid Kleckner Info.Exports.push_back(E); 254146eb7a6SReid Kleckner return Error::success(); 255146eb7a6SReid Kleckner } 256146eb7a6SReid Kleckner } 257146eb7a6SReid Kleckner 258146eb7a6SReid Kleckner // HEAPSIZE/STACKSIZE reserve[,commit] 259146eb7a6SReid Kleckner Error parseNumbers(uint64_t *Reserve, uint64_t *Commit) { 260146eb7a6SReid Kleckner if (Error Err = readAsInt(Reserve)) 261146eb7a6SReid Kleckner return Err; 262146eb7a6SReid Kleckner read(); 263146eb7a6SReid Kleckner if (Tok.K != Comma) { 264146eb7a6SReid Kleckner unget(); 265146eb7a6SReid Kleckner Commit = nullptr; 266146eb7a6SReid Kleckner return Error::success(); 267146eb7a6SReid Kleckner } 268146eb7a6SReid Kleckner if (Error Err = readAsInt(Commit)) 269146eb7a6SReid Kleckner return Err; 270146eb7a6SReid Kleckner return Error::success(); 271146eb7a6SReid Kleckner } 272146eb7a6SReid Kleckner 273146eb7a6SReid Kleckner // NAME outputPath [BASE=address] 274146eb7a6SReid Kleckner Error parseName(std::string *Out, uint64_t *Baseaddr) { 275146eb7a6SReid Kleckner read(); 276146eb7a6SReid Kleckner if (Tok.K == Identifier) { 277146eb7a6SReid Kleckner *Out = Tok.Value; 278146eb7a6SReid Kleckner } else { 279146eb7a6SReid Kleckner *Out = ""; 280146eb7a6SReid Kleckner unget(); 281146eb7a6SReid Kleckner return Error::success(); 282146eb7a6SReid Kleckner } 283146eb7a6SReid Kleckner read(); 284146eb7a6SReid Kleckner if (Tok.K == KwBase) { 285146eb7a6SReid Kleckner if (Error Err = expect(Equal, "'=' expected")) 286146eb7a6SReid Kleckner return Err; 287146eb7a6SReid Kleckner if (Error Err = readAsInt(Baseaddr)) 288146eb7a6SReid Kleckner return Err; 289146eb7a6SReid Kleckner } else { 290146eb7a6SReid Kleckner unget(); 291146eb7a6SReid Kleckner *Baseaddr = 0; 292146eb7a6SReid Kleckner } 293146eb7a6SReid Kleckner return Error::success(); 294146eb7a6SReid Kleckner } 295146eb7a6SReid Kleckner 296146eb7a6SReid Kleckner // VERSION major[.minor] 297146eb7a6SReid Kleckner Error parseVersion(uint32_t *Major, uint32_t *Minor) { 298146eb7a6SReid Kleckner read(); 299146eb7a6SReid Kleckner if (Tok.K != Identifier) 300146eb7a6SReid Kleckner return createError("identifier expected, but got " + Tok.Value); 301146eb7a6SReid Kleckner StringRef V1, V2; 302146eb7a6SReid Kleckner std::tie(V1, V2) = Tok.Value.split('.'); 303146eb7a6SReid Kleckner if (V1.getAsInteger(10, *Major)) 304146eb7a6SReid Kleckner return createError("integer expected, but got " + Tok.Value); 305146eb7a6SReid Kleckner if (V2.empty()) 306146eb7a6SReid Kleckner *Minor = 0; 307146eb7a6SReid Kleckner else if (V2.getAsInteger(10, *Minor)) 308146eb7a6SReid Kleckner return createError("integer expected, but got " + Tok.Value); 309146eb7a6SReid Kleckner return Error::success(); 310146eb7a6SReid Kleckner } 311146eb7a6SReid Kleckner 312146eb7a6SReid Kleckner Lexer Lex; 313146eb7a6SReid Kleckner Token Tok; 314146eb7a6SReid Kleckner std::vector<Token> Stack; 315146eb7a6SReid Kleckner MachineTypes Machine; 316146eb7a6SReid Kleckner COFFModuleDefinition Info; 3171079ef8dSMartell Malone bool MingwDef; 318146eb7a6SReid Kleckner }; 319146eb7a6SReid Kleckner 320146eb7a6SReid Kleckner Expected<COFFModuleDefinition> parseCOFFModuleDefinition(MemoryBufferRef MB, 3211079ef8dSMartell Malone MachineTypes Machine, 3221079ef8dSMartell Malone bool MingwDef) { 3231079ef8dSMartell Malone return Parser(MB.getBuffer(), Machine, MingwDef).parse(); 324146eb7a6SReid Kleckner } 325146eb7a6SReid Kleckner 326146eb7a6SReid Kleckner } // namespace object 327146eb7a6SReid Kleckner } // namespace llvm 328