Blame SOURCES/bpftrace-0.9-clang_parser-fix-clang_parser-for-LLVM-8.patch

05649e
From acb0ee316d5ed776253b6d7bfccfb21e0005919b Mon Sep 17 00:00:00 2001
05649e
From: Jerome Marchand <jmarchan@redhat.com>
05649e
Date: Thu, 16 May 2019 14:56:50 +0200
05649e
Subject: [PATCH] fix clang_parser for LLVM 8+
05649e
05649e
LLVM changed the behavior of clang_Cursor_isAnonymous in [1]. The old
05649e
behavior would returned false for direct-acccess anonymous structs
05649e
within other structs, whereas LLVM 8 returns true. To circumvent this
05649e
behavior change among LLVM versions, we keep track of all structs
05649e
defined within a struct. We don't parse the substruct recursively (if we
05649e
do it might be parsed multiple times, and since we don't know yet if
05649e
this is a direct or indirect strucutre, we might parse it incorrectly),
05649e
instead we keep the cursor saved in a map. If this substruct is later
05649e
declared as an attribute of the supersctruct, that means we have a
05649e
direct-accessible struct. We remove it from our map, and we parse
05649e
recursively (parsing recursively the cursor pointing to the declaration
05649e
will effectively parse the struct definition).
05649e
05649e
After the first parse, any struct left in our map is an indirect struct.
05649e
Since we skipped the parsing stage for those, we need to run
05649e
`clang_visitChildren` again for each struct cursor we have saved. We
05649e
repeat this until there's no unvisited structs in the map. Keep in mind
05649e
that while visiting a new struct we might find more indirect structs.
05649e
05649e
Also add Travis jobs to test against LLVM and clang 8 on Ubuntu.
05649e
05649e
[1]: llvm/llvm-project@c05e6f4
05649e
---
05649e
 .travis.yml                    |  4 ++
05649e
 docker/Dockerfile.bionic-llvm8 | 36 ++++++++++++++
05649e
 src/bpforc.h                   |  9 ++++
05649e
 src/clang_parser.cpp           | 87 +++++++++++++++++++++++-----------
05649e
 4 files changed, 108 insertions(+), 28 deletions(-)
05649e
 create mode 100644 docker/Dockerfile.bionic-llvm8
05649e
05649e
diff --git a/.travis.yml b/.travis.yml
05649e
index 7fbff63..b539868 100644
05649e
--- a/.travis.yml
05649e
+++ b/.travis.yml
05649e
@@ -20,6 +20,10 @@ sudo: required
05649e
       env: BASE=fedora29 TYPE=Debug
05649e
     - name: "LLVM 7 Release"
05649e
       env: BASE=fedora29 TYPE=Release
05649e
+    - name: "LLVM 8 Debug"
05649e
+      env: BASE=bionic-llvm8 TYPE=Debug
05649e
+    - name: "LLVM 8 Release"
05649e
+      env: BASE=bionic-llvm8 TYPE=Release
05649e
   allow_failures:
05649e
     - name: "Static LLVM 5 Debug"
05649e
       env: BASE=alpine TYPE=Debug STATIC_LINKING=ON TEST_ARGS="--gtest_filter=-codegen.string_equal_comparison:codegen.string_not_equal_comparison"
05649e
diff --git a/docker/Dockerfile.bionic-llvm8 b/docker/Dockerfile.bionic-llvm8
05649e
new file mode 100644
05649e
index 0000000..ebf10d3
05649e
--- /dev/null
05649e
+++ b/docker/Dockerfile.bionic-llvm8
05649e
@@ -0,0 +1,36 @@
05649e
+FROM ubuntu:bionic
05649e
+
05649e
+ENV llvmVersion=8
05649e
+
05649e
+RUN apt-get update && apt-get install -y curl gnupg &&\
05649e
+    llvmRepository='\n\
05649e
+deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic main\n\
05649e
+deb-src http://apt.llvm.org/bionic/ llvm-toolchain-bionic main\n\
05649e
+# 8\n\
05649e
+deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-8 main\n\
05649e
+deb-src http://apt.llvm.org/bionic/ llvm-toolchain-bionic-8 main' && \
05649e
+    echo $llvmRepository >> /etc/apt/sources.list && \
05649e
+    curl -L https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add - && \
05649e
+    apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 4052245BD4284CDD && \
05649e
+    echo "deb https://repo.iovisor.org/apt/bionic bionic main" | tee /etc/apt/sources.list.d/iovisor.list
05649e
+
05649e
+RUN apt-get update && apt-get install -y \
05649e
+      bison \
05649e
+      cmake \
05649e
+      flex \
05649e
+      g++ \
05649e
+      git \
05649e
+      libelf-dev \
05649e
+      zlib1g-dev \
05649e
+      libbcc \
05649e
+      clang-${llvmVersion} \
05649e
+      libclang-${llvmVersion}-dev \
05649e
+      libclang-common-${llvmVersion}-dev \
05649e
+      libclang1-${llvmVersion} \
05649e
+      llvm-${llvmVersion} \
05649e
+      llvm-${llvmVersion}-dev \
05649e
+      llvm-${llvmVersion}-runtime \
05649e
+      libllvm${llvmVersion}
05649e
+
05649e
+COPY build.sh /build.sh
05649e
+ENTRYPOINT ["bash", "/build.sh"]
05649e
diff --git a/src/bpforc.h b/src/bpforc.h
05649e
index 1c134d0..8eede31 100644
05649e
--- a/src/bpforc.h
05649e
+++ b/src/bpforc.h
05649e
@@ -80,8 +80,13 @@ class BpfOrc
05649e
   ExecutionSession ES;
05649e
   std::unique_ptr<TargetMachine> TM;
05649e
   std::shared_ptr<SymbolResolver> Resolver;
05649e
+#if LLVM_VERSION_MAJOR >= 8
05649e
+  LegacyRTDyldObjectLinkingLayer ObjectLayer;
05649e
+  LegacyIRCompileLayer<decltype(ObjectLayer), SimpleCompiler> CompileLayer;
05649e
+#else
05649e
   RTDyldObjectLinkingLayer ObjectLayer;
05649e
   IRCompileLayer<decltype(ObjectLayer), SimpleCompiler> CompileLayer;
05649e
+#endif
05649e
 
05649e
 public:
05649e
   std::map<std::string, std::tuple<uint8_t *, uintptr_t>> sections_;
05649e
@@ -91,7 +96,11 @@ class BpfOrc
05649e
       Resolver(createLegacyLookupResolver(ES,
05649e
         [](const std::string &Name __attribute__((unused))) -> JITSymbol { return nullptr; },
05649e
         [](Error Err) { cantFail(std::move(Err), "lookup failed"); })),
05649e
+#if LLVM_VERSION_MAJOR >= 8
05649e
+      ObjectLayer(ES, [this](VModuleKey) { return LegacyRTDyldObjectLinkingLayer::Resources{std::make_shared<MemoryManager>(sections_), Resolver}; }),
05649e
+#else
05649e
       ObjectLayer(ES, [this](VModuleKey) { return RTDyldObjectLinkingLayer::Resources{std::make_shared<MemoryManager>(sections_), Resolver}; }),
05649e
+#endif
05649e
       CompileLayer(ObjectLayer, SimpleCompiler(*TM)) {}
05649e
 
05649e
   void compileModule(std::unique_ptr<Module> M) {
05649e
diff --git a/src/clang_parser.cpp b/src/clang_parser.cpp
05649e
index 4bb8f87..7bb8d6a 100644
05649e
--- a/src/clang_parser.cpp
05649e
+++ b/src/clang_parser.cpp
05649e
@@ -1,5 +1,7 @@
05649e
 #include <clang-c/Index.h>
05649e
 #include <iostream>
05649e
+#include <unordered_map>
05649e
+#include <unordered_set>
05649e
 #include <string.h>
05649e
 #include <sys/utsname.h>
05649e
 #include <sys/stat.h>
05649e
@@ -13,6 +15,9 @@
05649e
 
05649e
 namespace bpftrace {
05649e
 
05649e
+std::unordered_map<std::string, CXCursor> indirect_structs;
05649e
+std::unordered_set<std::string> unvisited_indirect_structs;
05649e
+
05649e
 static std::string get_clang_string(CXString string)
05649e
 {
05649e
   std::string str = clang_getCString(string);
05649e
@@ -30,8 +35,9 @@ static CXCursor get_indirect_field_parent_struct(CXCursor c)
05649e
 {
05649e
   CXCursor parent = clang_getCursorSemanticParent(c);
05649e
 
05649e
-  while (!clang_Cursor_isNull(parent) && clang_Cursor_isAnonymous(parent))
05649e
-     parent = clang_getCursorSemanticParent(parent);
05649e
+  while (!clang_Cursor_isNull(parent) && indirect_structs.count(get_clang_string(clang_getTypeSpelling(clang_getCanonicalType(clang_getCursorType(parent))))) > 0) {
05649e
+    parent = clang_getCursorSemanticParent(parent);
05649e
+  }
05649e
 
05649e
   return parent;
05649e
 }
05649e
@@ -253,44 +259,69 @@ void ClangParser::parse(ast::Program *program, BPFtrace &bpftrace)
05649e
     std::cerr << "Input (" << input.size() << "): " << input << std::endl;
05649e
   }
05649e
 
05649e
-  CXCursor cursor = clang_getTranslationUnitCursor(translation_unit);
05649e
+  indirect_structs.clear();
05649e
+  unvisited_indirect_structs.clear();
05649e
 
05649e
-  clang_visitChildren(
05649e
-      cursor,
05649e
-      [](CXCursor c, CXCursor parent, CXClientData client_data)
05649e
-      {
05649e
+  CXCursor cursor = clang_getTranslationUnitCursor(translation_unit);
05649e
 
05649e
-        if (clang_getCursorKind(parent) != CXCursor_StructDecl &&
05649e
-            clang_getCursorKind(parent) != CXCursor_UnionDecl)
05649e
-          return CXChildVisit_Recurse;
05649e
+  bool iterate = true;
05649e
 
05649e
-        if (clang_getCursorKind(c) == CXCursor_FieldDecl)
05649e
+  do {
05649e
+    clang_visitChildren(
05649e
+        cursor,
05649e
+        [](CXCursor c, CXCursor parent, CXClientData client_data)
05649e
         {
05649e
-          auto &structs = static_cast<BPFtrace*>(client_data)->structs_;
05649e
-          auto struct_name = get_parent_struct_name(c);
05649e
-          auto ident = get_clang_string(clang_getCursorSpelling(c));
05649e
-          auto offset = clang_Cursor_getOffsetOfField(c) / 8;
05649e
-          auto type = clang_getCanonicalType(clang_getCursorType(c));
05649e
+          if (clang_getCursorKind(parent) != CXCursor_StructDecl &&
05649e
+              clang_getCursorKind(parent) != CXCursor_UnionDecl)
05649e
+            return CXChildVisit_Recurse;
05649e
 
05649e
           auto ptype = clang_getCanonicalType(clang_getCursorType(parent));
05649e
           auto ptypestr = get_clang_string(clang_getTypeSpelling(ptype));
05649e
           auto ptypesize = clang_Type_getSizeOf(ptype);
05649e
 
05649e
-          if(clang_Cursor_isAnonymous(parent))
05649e
-            offset = get_indirect_field_offset(c);
05649e
+          if (clang_getCursorKind(c) == CXCursor_StructDecl ||
05649e
+              clang_getCursorKind(c) == CXCursor_UnionDecl) {
05649e
+            auto struct_name = get_clang_string(clang_getTypeSpelling(clang_getCanonicalType(clang_getCursorType(c))));
05649e
+            indirect_structs[struct_name] = c;
05649e
+            unvisited_indirect_structs.insert(struct_name);
05649e
 
05649e
-          if (struct_name == "")
05649e
-            struct_name = ptypestr;
05649e
-          remove_struct_prefix(struct_name);
05649e
+            return CXChildVisit_Continue;
05649e
+          }
05649e
 
05649e
-          structs[struct_name].fields[ident].offset = offset;
05649e
-          structs[struct_name].fields[ident].type = get_sized_type(type);
05649e
-          structs[struct_name].size = ptypesize;
05649e
-        }
05649e
+          if (clang_getCursorKind(c) == CXCursor_FieldDecl)
05649e
+          {
05649e
+            auto &structs = static_cast<BPFtrace*>(client_data)->structs_;
05649e
+            auto struct_name = get_parent_struct_name(c);
05649e
+            auto ident = get_clang_string(clang_getCursorSpelling(c));
05649e
+            auto offset = clang_Cursor_getOffsetOfField(c) / 8;
05649e
+            auto type = clang_getCanonicalType(clang_getCursorType(c));
05649e
+            auto typestr = get_clang_string(clang_getTypeSpelling(type));
05649e
 
05649e
-        return CXChildVisit_Recurse;
05649e
-      },
05649e
-      &bpftrace);
05649e
+            if (indirect_structs.count(typestr))
05649e
+              indirect_structs.erase(typestr);
05649e
+
05649e
+            if(indirect_structs.count(ptypestr))
05649e
+              offset = get_indirect_field_offset(c);
05649e
+
05649e
+            if (struct_name == "")
05649e
+              struct_name = ptypestr;
05649e
+            remove_struct_prefix(struct_name);
05649e
+
05649e
+            structs[struct_name].fields[ident].offset = offset;
05649e
+            structs[struct_name].fields[ident].type = get_sized_type(type);
05649e
+            structs[struct_name].size = ptypesize;
05649e
+          }
05649e
+
05649e
+          return CXChildVisit_Recurse;
05649e
+        },
05649e
+        &bpftrace);
05649e
+    if (unvisited_indirect_structs.size()) {
05649e
+      cursor = indirect_structs[*unvisited_indirect_structs.begin()];
05649e
+      unvisited_indirect_structs.erase(unvisited_indirect_structs.begin());
05649e
+    } else {
05649e
+      iterate = false;
05649e
+    }
05649e
+  } while (iterate);
05649e
 
05649e
   clang_disposeTranslationUnit(translation_unit);
05649e
   clang_disposeIndex(index);
05649e
-- 
05649e
2.20.1
05649e