diff options
Diffstat (limited to 'tools/syz-declextract/syz-declextract.cpp')
| -rw-r--r-- | tools/syz-declextract/syz-declextract.cpp | 329 |
1 files changed, 71 insertions, 258 deletions
diff --git a/tools/syz-declextract/syz-declextract.cpp b/tools/syz-declextract/syz-declextract.cpp index cb29175b1..78162f648 100644 --- a/tools/syz-declextract/syz-declextract.cpp +++ b/tools/syz-declextract/syz-declextract.cpp @@ -1,279 +1,92 @@ -// Copyright 2017 syzkaller project authors. All rights reserved. -// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. - -// This is a very rough prototype of an utility that extracts syscall descriptions from header files. -// It needs to extract struct/union descriptions, better analyze types, -// analyze pointer directions (in, out), figure out len types (usually marked with sal). -// The easiest way to build it is to build it as part of clang. Add the following lines to CMakeLists.txt: -// +add_clang_executable(syz-declextract syz-declextract/syz-declextract.cpp) -// +target_link_libraries(syz-declextract clangTooling) -// It was used to extract windows descriptions: -// syz-declextract -extra-arg="--driver-mode=cl" -extra-arg="-I/path/to/windows/headers" Windows.h - -#include "clang/AST/AST.h" -#include "clang/AST/ASTConsumer.h" -#include "clang/AST/ASTContext.h" -#include "clang/AST/RecursiveASTVisitor.h" -#include "clang/Driver/Options.h" -#include "clang/Frontend/ASTConsumers.h" -#include "clang/Frontend/CompilerInstance.h" -#include "clang/Frontend/FrontendActions.h" -#include "clang/Rewrite/Core/Rewriter.h" +#include "clang/AST/APValue.h" +#include "clang/AST/Decl.h" +#include "clang/AST/Expr.h" +#include "clang/AST/Stmt.h" +#include "clang/AST/Type.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/ASTMatchers/ASTMatchersInternal.h" +#include "clang/Basic/LLVM.h" +#include "clang/Sema/Ownership.h" #include "clang/Tooling/CommonOptionsParser.h" #include "clang/Tooling/Tooling.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/raw_ostream.h" +#include <stdio.h> +#include <string> +#include <vector> using namespace clang; -using namespace clang::tooling; +using namespace clang::ast_matchers; -std::string convertType(ASTContext &C, QualType T) { - auto name = T.getAsString(); - if (name == "HANDLE") - return name; - if (T->isIntegralOrEnumerationType()) { - int size = C.getTypeSize(T); - char buf[10]; - sprintf(buf, "int%d", size); - return buf; - } - if (T->isVoidPointerType()) { - return "ptr[inout, array[int8]]"; - } - if (T->isPointerType()) { - auto inner = convertType(C, T->getPointeeType()); - if (inner == "") - return "ptr[inout, array[int8]]"; - char buf[1024]; - sprintf(buf, "ptr[inout, %s]", inner.c_str()); - return buf; - } - return "intptr"; -} +struct Param { + std::string type; + std::string name; +}; -class DeclExtractCallVisitor : public RecursiveASTVisitor<DeclExtractCallVisitor> { - public: - explicit DeclExtractCallVisitor(ASTContext *Context) - : Context(*Context) {} +class Printer : public MatchFinder::MatchCallback { +public: + virtual void run(const MatchFinder::MatchResult &Result) override { + const auto *varDecl = Result.Nodes.getNodeAs<VarDecl>("Struct"); + auto *context = Result.Context; + if (!varDecl || !varDecl->getInit()) + return; - bool VisitFunctionDecl(const FunctionDecl *D) { - if (D->doesThisDeclarationHaveABody()) - return true; - // TODO(dvyukov): need to select only stdcall (WINAPI) functions. - // But the following 2 approaches do not work. - if (false) { - if (auto *FPT = D->getType()->getAs<FunctionProtoType>()) { - if (FPT->getExtInfo().getCC() != CC_X86StdCall) - return true; + // values contains the initializer list for the struct `syscall_metadata` + auto values = llvm::dyn_cast<InitListExpr>(varDecl->getInit())->inits(); + if (values.empty()) + return; + + int argc = *values[2]->getIntegerConstantExpr(*context).value().getRawData(); + + std::vector<Param> args(argc); + if (argc) { + int i = 0; + for (const auto *type : // get parameter types + llvm::dyn_cast<InitListExpr>( + llvm::dyn_cast<VarDecl>(values[3]->getAsBuiltinConstantDeclRef(*context)->getUnderlyingDecl()) + ->getInit()) + ->inits()) { + args[i++].type = std::move(*type->tryEvaluateString(*context)); } - } - if (false) { - if (!D->hasAttr<StdCallAttr>()) - return true; - } - // Tons of functions are bulk ignored below because they cause - // static/dynamic link failures, reboot machine, etc. - auto fn = D->getNameInfo().getAsString(); - if (fn.empty()) return true; - if (*fn.rbegin() == 'W') return true; // Unicode versions. - const char *ignore_prefixes[] { - "_", - "Rtl", - "IBind", - "Ndr", - "NDR", - "SCard", - }; - for (auto prefix: ignore_prefixes) { - if (strncmp(fn.c_str(), prefix, strlen(prefix)) == 0) return true; - } - const char *ignore_functions[] { - "IEnum", - "IStream", - "IType", - "IService", - "IProperty", - "ISequential", - "IDispatch", - "I_RPC", - "I_Rpc", - "CLEANLOCAL", - "WinMain", - "PropertySheet", - "LookupAccountNameLocalA", - "LookupAccountSidLocalA", - "WTSGetServiceSessionId", - "WTSIsServerContainer", - "GetDisplayAutoRotationPreferencesByProcessId", - "LoadStringByReference", - "IdnToNameprepUnicode", - "VerFindFileA", - "VerInstallFileA", - "GetFileVersionInfoSizeA", - "GetFileVersionInfoA", - "GetFileVersionInfoSizeExA", - "GetFileVersionInfoExA", - "VerQueryValueA", - "sndOpenSound", - "Netbios", - "RpcBindingGetTrainingContextHandle", - "RpcAsyncCleanupThread", - "ShellMessageBoxA", - "SHEnumerateUnreadMailAccountsA", - "SHGetUnreadMailCountA", - "SHSetUnreadMailCountA", - "GetEncSChannel", - "CryptExportPKCS8Ex", - "FindCertsByIssuer", - "CryptCancelAsyncRetrieval", - "CryptGetTimeValidObject", - "CryptFlushTimeValidObject", - "CryptProtectDataNoUI", - "CryptUnprotectDataNoUI", - "NsServerBindSearch", - "NsClientBindSearch", - "NsClientBindDone", - "GetOpenCardNameA", - "SubscribeServiceChangeNotifications", - "UnsubscribeServiceChangeNotifications", - "GetThreadDescription", - "SetThreadDescription", - "DialogControlDpi", - "SetDialogDpiChangeBehavior", - "GetDialogDpiChangeBehavior", - "RpcServer", - "DecodePointer", - "DecodeRemotePointer", - "DecodeSystemPointer", - "EncodePointer", - "EncodeRemotePointer", - "EncodeSystemPointer", - "UnmapViewOfFile2", - "MapViewOfFileNuma2", - "DeriveCapabilitySidsFromName", - "QueryAuxiliaryCounterFrequency", - "ConvertPerformanceCounterToAuxiliaryCounter", - "ConvertAuxiliaryCounterToPerformanceCounter", - "FreePropVariantArray", - "PropVariantCopy", - "PropVariantClear", - "InitiateShutdown", - "ExitWindowsEx", - "LockWorkStation", - "InitiateSystemShutdown", - "InitiateSystemShutdownEx", - "shutdown", - }; - for (auto func: ignore_functions) { - if (strstr(fn.c_str(), func)) return true; - } - // These are already described: - const char *ignore_exact[] { - "CreateFileA", - "CloseHandle", - "VirtualAlloc", - }; - for (auto func: ignore_exact) { - if (strcmp(fn.c_str(), func) == 0) return true; - } - const char *ignore_files[] { - "/um/ole", - "htiface.h", - "objbase.h", - "HLink.h", - "urlmon.h", - "HlGuids.h", - "unknwn.h", - "unknwnbase.h", - "coguid.h", - "MsHtmHst.h", - "msime.h", - "ComSvcs.h", - "combaseapi.h", - "WbemGlue.h", - "OCIdl.h", - "mfapi.h", - "CompPkgSup.h", - "ole2.h", - "Ole2.h", - "oleidl.h", - "ObjIdl.h", - "WabDefs.h", - "objidl.h", - }; - auto src = D->getSourceRange().getBegin().printToString(Context.getSourceManager()); - if (strstr(src.c_str(), "/um/") == 0) return true; - for (auto file: ignore_files) { - if (strstr(src.c_str(), file)) return true; - } - for (const ParmVarDecl *P : D->parameters()) { - auto typ = convertType(Context, P->getType()); - if (typ == "") { - llvm::outs() << D->getNameInfo().getAsString() << ": UNKNOWN TYPE: " << - QualType(P->getType()).getAsString() << "\n"; - return true; + + i = 0; + for (const auto *name : // get parameter names + llvm::dyn_cast<InitListExpr>( + llvm::dyn_cast<VarDecl>(values[4]->getAsBuiltinConstantDeclRef(*context)->getUnderlyingDecl()) + ->getInit()) + ->inits()) { + args[i++].name = std::move(*name->tryEvaluateString(*context)); } } - if (Generated[D->getNameInfo().getAsString()]) - return true; - Generated[D->getNameInfo().getAsString()] = true; - llvm::outs() << D->getNameInfo().getAsString() << "("; - int i = 0; - for (const ParmVarDecl *P : D->parameters()) { - if (i) - llvm::outs() << ", "; - auto name = P->getNameAsString(); - if (name == "") { - char buf[10]; - sprintf(buf, "arg%d", i); - name = buf; - } - llvm::outs() << name << " " << convertType(Context, P->getType()); - i++; - if (i == 9) - break; + printf("==========SYSCALL Found==========\n"); + printf("%s\n", values[0]->tryEvaluateString(*context).value().c_str()); + for (const auto &arg : args) { + printf("%s %s\n", arg.type.c_str(), arg.name.c_str()); } - llvm::outs() << ")"; - auto ret = convertType(Context, D->getReturnType()); - if (ret == "HANDLE") - llvm::outs() << " " << ret; - llvm::outs() << "\n"; - return true; } - - private: - ASTContext &Context; - std::map<std::string, bool> Generated; }; -class DeclExtractCallConsumer : public clang::ASTConsumer { - public: - explicit DeclExtractCallConsumer(ASTContext *Context) - : Visitor(Context) {} +int main(int argc, const char **argv) { + llvm::cl::OptionCategory SyzDeclExtractOptionCategory("SyzDeclExtract options"); + auto ExpectedParser = clang::tooling::CommonOptionsParser::create(argc, argv, SyzDeclExtractOptionCategory); - virtual void HandleTranslationUnit(clang::ASTContext &Context) { - Visitor.TraverseDecl(Context.getTranslationUnitDecl()); + if (!ExpectedParser) { + llvm::errs() << ExpectedParser.takeError(); + return 1; } - private: - DeclExtractCallVisitor Visitor; -}; - -class DeclExtractCallAction : public clang::ASTFrontendAction { - public: - DeclExtractCallAction() {} - - virtual std::unique_ptr<clang::ASTConsumer> CreateASTConsumer( - clang::CompilerInstance &Compiler, llvm::StringRef InFile) { - return std::unique_ptr<clang::ASTConsumer>( - new DeclExtractCallConsumer(&Compiler.getASTContext())); - } -}; + clang::tooling::CommonOptionsParser &OptionsParser = ExpectedParser.get(); + clang::tooling::ClangTool Tool(OptionsParser.getCompilations(), OptionsParser.getSourcePathList()); -static llvm::cl::OptionCategory MyToolCategory("my-tool options"); + DeclarationMatcher MetaDataMatcher = + varDecl(isExpandedFromMacro("SYSCALL_METADATA"), hasType(recordDecl(hasName("syscall_metadata")))).bind("Struct"); -int main(int argc, const char **argv) { - CommonOptionsParser OptionsParser(argc, argv, MyToolCategory); - ClangTool Tool(OptionsParser.getCompilations(), - OptionsParser.getSourcePathList()); - return Tool.run(newFrontendActionFactory<DeclExtractCallAction>().get()); + Printer Printer; + MatchFinder Finder; + Finder.addMatcher(MetaDataMatcher, &Printer); + return Tool.run(clang::tooling::newFrontendActionFactory(&Finder).get()); } |
