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

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