LCOV - code coverage report
Current view: top level - lib/Object - COFFModuleDefinition.cpp (source / functions) Hit Total Coverage
Test: llvm-toolchain.info Lines: 134 180 74.4 %
Date: 2017-09-14 15:23:50 Functions: 11 14 78.6 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13