github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/tools/syz-declextract/syz-declextract.cpp (about)

     1  // Copyright 2017 syzkaller project authors. All rights reserved.
     2  // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
     3  
     4  // This is a very rough prototype of an utility that extracts syscall descriptions from header files.
     5  // It needs to extract struct/union descriptions, better analyze types,
     6  // analyze pointer directions (in, out), figure out len types (usually marked with sal).
     7  // The easiest way to build it is to build it as part of clang. Add the following lines to CMakeLists.txt:
     8  //   +add_clang_executable(syz-declextract syz-declextract/syz-declextract.cpp)
     9  //   +target_link_libraries(syz-declextract clangTooling)
    10  // It was used to extract windows descriptions:
    11  //   syz-declextract -extra-arg="--driver-mode=cl" -extra-arg="-I/path/to/windows/headers" Windows.h
    12  
    13  #include "clang/AST/AST.h"
    14  #include "clang/AST/ASTConsumer.h"
    15  #include "clang/AST/ASTContext.h"
    16  #include "clang/AST/RecursiveASTVisitor.h"
    17  #include "clang/Driver/Options.h"
    18  #include "clang/Frontend/ASTConsumers.h"
    19  #include "clang/Frontend/CompilerInstance.h"
    20  #include "clang/Frontend/FrontendActions.h"
    21  #include "clang/Rewrite/Core/Rewriter.h"
    22  #include "clang/Tooling/CommonOptionsParser.h"
    23  #include "clang/Tooling/Tooling.h"
    24  
    25  using namespace clang;
    26  using namespace clang::tooling;
    27  
    28  std::string convertType(ASTContext &C, QualType T) {
    29    auto name = T.getAsString();
    30    if (name == "HANDLE")
    31      return name;
    32    if (T->isIntegralOrEnumerationType()) {
    33      int size = C.getTypeSize(T);
    34      char buf[10];
    35      sprintf(buf, "int%d", size);
    36      return buf;
    37    }
    38    if (T->isVoidPointerType()) {
    39      return "ptr[inout, array[int8]]";
    40    }
    41    if (T->isPointerType()) {
    42      auto inner = convertType(C, T->getPointeeType());
    43      if (inner == "")
    44        return "ptr[inout, array[int8]]";
    45      char buf[1024];
    46      sprintf(buf, "ptr[inout, %s]", inner.c_str());
    47      return buf;
    48    }
    49    return "intptr";
    50  }
    51  
    52  class DeclExtractCallVisitor : public RecursiveASTVisitor<DeclExtractCallVisitor> {
    53   public:
    54    explicit DeclExtractCallVisitor(ASTContext *Context)
    55        : Context(*Context) {}
    56  
    57    bool VisitFunctionDecl(const FunctionDecl *D) {
    58      if (D->doesThisDeclarationHaveABody())
    59        return true;
    60      // TODO(dvyukov): need to select only stdcall (WINAPI) functions.
    61      // But the following 2 approaches do not work.
    62      if (false) {
    63        if (auto *FPT = D->getType()->getAs<FunctionProtoType>()) {
    64          if (FPT->getExtInfo().getCC() != CC_X86StdCall)
    65            return true;
    66        }
    67      }
    68      if (false) {
    69        if (!D->hasAttr<StdCallAttr>())
    70          return true;
    71      }
    72      // Tons of functions are bulk ignored below because they cause
    73      // static/dynamic link failures, reboot machine, etc.
    74      auto fn = D->getNameInfo().getAsString();
    75      if (fn.empty()) return true;
    76      if (*fn.rbegin() == 'W') return true; // Unicode versions.
    77      const char *ignore_prefixes[] {
    78        "_",
    79        "Rtl",
    80        "IBind",
    81        "Ndr",
    82        "NDR",
    83        "SCard",
    84      };
    85      for (auto prefix: ignore_prefixes) {
    86        if (strncmp(fn.c_str(), prefix, strlen(prefix)) == 0) return true;
    87      }
    88      const char *ignore_functions[] {
    89        "IEnum",
    90        "IStream",
    91        "IType",
    92        "IService",
    93        "IProperty",
    94        "ISequential",
    95        "IDispatch",
    96        "I_RPC",
    97        "I_Rpc",
    98        "CLEANLOCAL",
    99        "WinMain",
   100        "PropertySheet",
   101        "LookupAccountNameLocalA",
   102        "LookupAccountSidLocalA",
   103        "WTSGetServiceSessionId",
   104        "WTSIsServerContainer",
   105        "GetDisplayAutoRotationPreferencesByProcessId",
   106        "LoadStringByReference",
   107        "IdnToNameprepUnicode",
   108        "VerFindFileA",
   109        "VerInstallFileA",
   110        "GetFileVersionInfoSizeA",
   111        "GetFileVersionInfoA",
   112        "GetFileVersionInfoSizeExA",
   113        "GetFileVersionInfoExA",
   114        "VerQueryValueA",
   115        "sndOpenSound",
   116        "Netbios",
   117        "RpcBindingGetTrainingContextHandle",
   118        "RpcAsyncCleanupThread",
   119        "ShellMessageBoxA",
   120        "SHEnumerateUnreadMailAccountsA",
   121        "SHGetUnreadMailCountA",
   122        "SHSetUnreadMailCountA",
   123        "GetEncSChannel",
   124        "CryptExportPKCS8Ex",
   125        "FindCertsByIssuer",
   126        "CryptCancelAsyncRetrieval",
   127        "CryptGetTimeValidObject",
   128        "CryptFlushTimeValidObject",
   129        "CryptProtectDataNoUI",
   130        "CryptUnprotectDataNoUI",
   131        "NsServerBindSearch",
   132        "NsClientBindSearch",
   133        "NsClientBindDone",
   134        "GetOpenCardNameA",
   135        "SubscribeServiceChangeNotifications",
   136        "UnsubscribeServiceChangeNotifications",
   137        "GetThreadDescription",
   138        "SetThreadDescription",
   139        "DialogControlDpi",
   140        "SetDialogDpiChangeBehavior",
   141        "GetDialogDpiChangeBehavior",
   142        "RpcServer",
   143        "DecodePointer",
   144        "DecodeRemotePointer",
   145        "DecodeSystemPointer",
   146        "EncodePointer",
   147        "EncodeRemotePointer",
   148        "EncodeSystemPointer",
   149        "UnmapViewOfFile2",
   150        "MapViewOfFileNuma2",
   151        "DeriveCapabilitySidsFromName",
   152        "QueryAuxiliaryCounterFrequency",
   153        "ConvertPerformanceCounterToAuxiliaryCounter",
   154        "ConvertAuxiliaryCounterToPerformanceCounter",
   155        "FreePropVariantArray",
   156        "PropVariantCopy",
   157        "PropVariantClear",
   158        "InitiateShutdown",
   159        "ExitWindowsEx",
   160        "LockWorkStation",
   161        "InitiateSystemShutdown",
   162        "InitiateSystemShutdownEx",
   163        "shutdown",
   164      };
   165      for (auto func: ignore_functions) {
   166        if (strstr(fn.c_str(), func)) return true;
   167      }
   168      // These are already described:
   169      const char *ignore_exact[] {
   170        "CreateFileA",
   171        "CloseHandle",
   172        "VirtualAlloc",
   173      };
   174      for (auto func: ignore_exact) {
   175        if (strcmp(fn.c_str(), func) == 0) return true;
   176      }
   177      const char *ignore_files[] {
   178        "/um/ole",
   179        "htiface.h",
   180        "objbase.h",
   181        "HLink.h",
   182        "urlmon.h",
   183        "HlGuids.h",
   184        "unknwn.h",
   185        "unknwnbase.h",
   186        "coguid.h",
   187        "MsHtmHst.h",
   188        "msime.h",
   189        "ComSvcs.h",
   190        "combaseapi.h",
   191        "WbemGlue.h",
   192        "OCIdl.h",
   193        "mfapi.h",
   194        "CompPkgSup.h",
   195        "ole2.h",
   196        "Ole2.h",
   197        "oleidl.h",
   198        "ObjIdl.h",
   199        "WabDefs.h",
   200        "objidl.h",
   201      };
   202      auto src = D->getSourceRange().getBegin().printToString(Context.getSourceManager());
   203      if (strstr(src.c_str(), "/um/") == 0) return true;
   204      for (auto file: ignore_files) {
   205        if (strstr(src.c_str(), file)) return true;
   206      }
   207      for (const ParmVarDecl *P : D->parameters()) {
   208        auto typ = convertType(Context, P->getType());
   209        if (typ == "") {
   210          llvm::outs() << D->getNameInfo().getAsString() << ": UNKNOWN TYPE: " <<
   211              QualType(P->getType()).getAsString() << "\n";
   212          return true;
   213        }
   214      }
   215      if (Generated[D->getNameInfo().getAsString()])
   216        return true;
   217      Generated[D->getNameInfo().getAsString()] = true;
   218  
   219      llvm::outs() << D->getNameInfo().getAsString() << "(";
   220      int i = 0;
   221      for (const ParmVarDecl *P : D->parameters()) {
   222        if (i)
   223          llvm::outs() << ", ";
   224        auto name = P->getNameAsString();
   225        if (name == "") {
   226          char buf[10];
   227          sprintf(buf, "arg%d", i);
   228          name = buf;
   229        }
   230        llvm::outs() << name << " " << convertType(Context, P->getType());
   231        i++;
   232        if (i == 9)
   233          break;
   234      }
   235      llvm::outs() << ")";
   236      auto ret = convertType(Context, D->getReturnType());
   237      if (ret == "HANDLE")
   238        llvm::outs() << " " << ret;
   239      llvm::outs() << "\n";
   240      return true;
   241    }
   242  
   243   private:
   244    ASTContext &Context;
   245    std::map<std::string, bool> Generated;
   246  };
   247  
   248  class DeclExtractCallConsumer : public clang::ASTConsumer {
   249   public:
   250    explicit DeclExtractCallConsumer(ASTContext *Context)
   251        : Visitor(Context) {}
   252  
   253    virtual void HandleTranslationUnit(clang::ASTContext &Context) {
   254      Visitor.TraverseDecl(Context.getTranslationUnitDecl());
   255    }
   256  
   257   private:
   258    DeclExtractCallVisitor Visitor;
   259  };
   260  
   261  class DeclExtractCallAction : public clang::ASTFrontendAction {
   262   public:
   263    DeclExtractCallAction() {}
   264  
   265    virtual std::unique_ptr<clang::ASTConsumer> CreateASTConsumer(
   266        clang::CompilerInstance &Compiler, llvm::StringRef InFile) {
   267      return std::unique_ptr<clang::ASTConsumer>(
   268          new DeclExtractCallConsumer(&Compiler.getASTContext()));
   269    }
   270  };
   271  
   272  static llvm::cl::OptionCategory MyToolCategory("my-tool options");
   273  
   274  int main(int argc, const char **argv) {
   275    CommonOptionsParser OptionsParser(argc, argv, MyToolCategory);
   276    ClangTool Tool(OptionsParser.getCompilations(),
   277                   OptionsParser.getSourcePathList());
   278    return Tool.run(newFrontendActionFactory<DeclExtractCallAction>().get());
   279  }