This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rG3256aa8fe6fd: [lldb] Add support for 
DW_AT_calling_convention to the DWARF parser (authored by teemperor).
Herald added a subscriber: lldb-commits.

Changed prior to commit:
  https://reviews.llvm.org/D108629?vs=368332&id=378623#toc

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D108629/new/

https://reviews.llvm.org/D108629

Files:
  lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
  lldb/test/API/lang/c/calling-conventions/Makefile
  lldb/test/API/lang/c/calling-conventions/TestCCallingConventions.py
  lldb/test/API/lang/c/calling-conventions/fastcall.c
  lldb/test/API/lang/c/calling-conventions/ms_abi.c
  lldb/test/API/lang/c/calling-conventions/pascal.c
  lldb/test/API/lang/c/calling-conventions/regcall.c
  lldb/test/API/lang/c/calling-conventions/stdcall.c
  lldb/test/API/lang/c/calling-conventions/sysv_abi.c
  lldb/test/API/lang/c/calling-conventions/vectorcall.c
  lldb/unittests/SymbolFile/DWARF/DWARFASTParserClangTests.cpp

Index: lldb/unittests/SymbolFile/DWARF/DWARFASTParserClangTests.cpp
===================================================================
--- lldb/unittests/SymbolFile/DWARF/DWARFASTParserClangTests.cpp
+++ lldb/unittests/SymbolFile/DWARF/DWARFASTParserClangTests.cpp
@@ -116,3 +116,159 @@
               testing::UnorderedElementsAre(decl_ctxs[0], decl_ctxs[3]));
 }
 
+TEST_F(DWARFASTParserClangTests, TestCallingConventionParsing) {
+  // Tests parsing DW_AT_calling_convention values.
+
+  // The DWARF below just declares a list of function types with
+  // DW_AT_calling_convention on them.
+  const char *yamldata = R"(
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS32
+  Data:    ELFDATA2LSB
+  Type:    ET_EXEC
+  Machine: EM_386
+DWARF:
+  debug_str:
+    - func1
+    - func2
+    - func3
+    - func4
+    - func5
+    - func6
+    - func7
+    - func8
+    - func9
+  debug_abbrev:
+    - ID:              0
+      Table:
+        - Code:            0x1
+          Tag:             DW_TAG_compile_unit
+          Children:        DW_CHILDREN_yes
+          Attributes:
+            - Attribute:       DW_AT_language
+              Form:            DW_FORM_data2
+        - Code:            0x2
+          Tag:             DW_TAG_subprogram
+          Children:        DW_CHILDREN_no
+          Attributes:
+            - Attribute:       DW_AT_low_pc
+              Form:            DW_FORM_addr
+            - Attribute:       DW_AT_high_pc
+              Form:            DW_FORM_data4
+            - Attribute:       DW_AT_name
+              Form:            DW_FORM_strp
+            - Attribute:       DW_AT_calling_convention
+              Form:            DW_FORM_data1
+            - Attribute:       DW_AT_external
+              Form:            DW_FORM_flag_present
+  debug_info:
+    - Version:         4
+      AddrSize:        4
+      Entries:
+        - AbbrCode:        0x1
+          Values:
+            - Value:           0xC
+        - AbbrCode:        0x2
+          Values:
+            - Value:           0x0
+            - Value:           0x5
+            - Value:           0x00
+            - Value:           0xCB
+            - Value:           0x1
+        - AbbrCode:        0x2
+          Values:
+            - Value:           0x10
+            - Value:           0x5
+            - Value:           0x06
+            - Value:           0xB3
+            - Value:           0x1
+        - AbbrCode:        0x2
+          Values:
+            - Value:           0x20
+            - Value:           0x5
+            - Value:           0x0C
+            - Value:           0xB1
+            - Value:           0x1
+        - AbbrCode:        0x2
+          Values:
+            - Value:           0x30
+            - Value:           0x5
+            - Value:           0x12
+            - Value:           0xC0
+            - Value:           0x1
+        - AbbrCode:        0x2
+          Values:
+            - Value:           0x40
+            - Value:           0x5
+            - Value:           0x18
+            - Value:           0xB2
+            - Value:           0x1
+        - AbbrCode:        0x2
+          Values:
+            - Value:           0x50
+            - Value:           0x5
+            - Value:           0x1E
+            - Value:           0xC1
+            - Value:           0x1
+        - AbbrCode:        0x2
+          Values:
+            - Value:           0x60
+            - Value:           0x5
+            - Value:           0x24
+            - Value:           0xC2
+            - Value:           0x1
+        - AbbrCode:        0x2
+          Values:
+            - Value:           0x70
+            - Value:           0x5
+            - Value:           0x2a
+            - Value:           0xEE
+            - Value:           0x1
+        - AbbrCode:        0x2
+          Values:
+            - Value:           0x80
+            - Value:           0x5
+            - Value:           0x30
+            - Value:           0x01
+            - Value:           0x1
+        - AbbrCode:        0x0
+...
+)";
+  YAMLModuleTester t(yamldata);
+
+  DWARFUnit *unit = t.GetDwarfUnit();
+  ASSERT_NE(unit, nullptr);
+  const DWARFDebugInfoEntry *cu_entry = unit->DIE().GetDIE();
+  ASSERT_EQ(cu_entry->Tag(), DW_TAG_compile_unit);
+  DWARFDIE cu_die(unit, cu_entry);
+
+  TypeSystemClang ast_ctx("dummy ASTContext", HostInfoBase::GetTargetTriple());
+  DWARFASTParserClangStub ast_parser(ast_ctx);
+
+  std::vector<std::string> found_function_types;
+  // The DWARF above is just a list of functions. Parse all of them to
+  // extract the function types and their calling convention values.
+  for (DWARFDIE func : cu_die.children()) {
+    ASSERT_EQ(func.Tag(), DW_TAG_subprogram);
+    SymbolContext sc;
+    bool new_type = false;
+    lldb::TypeSP type = ast_parser.ParseTypeFromDWARF(sc, func, &new_type);
+    found_function_types.push_back(
+        type->GetForwardCompilerType().GetTypeName().AsCString());
+  }
+
+  // Compare the parsed function types against the expected list of types.
+  const std::vector<std::string> expected_function_types = {
+      "void () __attribute__((regcall))",
+      "void () __attribute__((fastcall))",
+      "void () __attribute__((stdcall))",
+      "void () __attribute__((vectorcall))",
+      "void () __attribute__((pascal))",
+      "void () __attribute__((ms_abi))",
+      "void () __attribute__((sysv_abi))",
+      "void ()", // invalid calling convention.
+      "void ()", // DW_CC_normal -> no attribute
+  };
+  ASSERT_EQ(found_function_types, expected_function_types);
+}
Index: lldb/test/API/lang/c/calling-conventions/vectorcall.c
===================================================================
--- /dev/null
+++ lldb/test/API/lang/c/calling-conventions/vectorcall.c
@@ -0,0 +1,7 @@
+int __attribute__((vectorcall)) func(double a) {
+  return (int)a;
+}
+
+int main() {
+  return func(1.0); // break here
+}
Index: lldb/test/API/lang/c/calling-conventions/sysv_abi.c
===================================================================
--- /dev/null
+++ lldb/test/API/lang/c/calling-conventions/sysv_abi.c
@@ -0,0 +1,7 @@
+int __attribute__((sysv_abi)) func(int a, int b, int c, int d) {
+  return a + b + c + d;
+}
+
+int main() {
+  return func(1, 2, 3, 4); // break here
+}
Index: lldb/test/API/lang/c/calling-conventions/stdcall.c
===================================================================
--- /dev/null
+++ lldb/test/API/lang/c/calling-conventions/stdcall.c
@@ -0,0 +1,7 @@
+int __attribute__((stdcall)) func(int a, int b, int c, int d) {
+  return a + b + c + d;
+}
+
+int main() {
+  return func(1, 2, 3, 4); // break here
+}
Index: lldb/test/API/lang/c/calling-conventions/regcall.c
===================================================================
--- /dev/null
+++ lldb/test/API/lang/c/calling-conventions/regcall.c
@@ -0,0 +1,7 @@
+int __attribute__((regcall)) func(int a, int b, int c, int d) {
+  return a + b + c + d;
+}
+
+int main() {
+  return func(1, 2, 3, 4); // break here
+}
Index: lldb/test/API/lang/c/calling-conventions/pascal.c
===================================================================
--- /dev/null
+++ lldb/test/API/lang/c/calling-conventions/pascal.c
@@ -0,0 +1,7 @@
+int __attribute__((pascal)) func(int a, int b, int c, int d) {
+  return a + b + c + d;
+}
+
+int main() {
+  return func(1, 2, 3, 4); // break here
+}
Index: lldb/test/API/lang/c/calling-conventions/ms_abi.c
===================================================================
--- /dev/null
+++ lldb/test/API/lang/c/calling-conventions/ms_abi.c
@@ -0,0 +1,7 @@
+int __attribute__((ms_abi)) func(int a, int b, int c, int d) {
+  return a + b + c + d;
+}
+
+int main() {
+  return func(1, 2, 3, 4); // break here
+}
Index: lldb/test/API/lang/c/calling-conventions/fastcall.c
===================================================================
--- /dev/null
+++ lldb/test/API/lang/c/calling-conventions/fastcall.c
@@ -0,0 +1,7 @@
+int __attribute__((fastcall)) func(int a, int b, int c, int d) {
+  return a + b + c + d;
+}
+
+int main() {
+  return func(1, 2, 3, 4); // break here
+}
Index: lldb/test/API/lang/c/calling-conventions/TestCCallingConventions.py
===================================================================
--- /dev/null
+++ lldb/test/API/lang/c/calling-conventions/TestCCallingConventions.py
@@ -0,0 +1,78 @@
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+from lldbsuite.test_event.build_exception import BuildError
+
+class TestCase(TestBase):
+
+    mydir = TestBase.compute_mydir(__file__)
+
+    NO_DEBUG_INFO_TESTCASE = True
+
+    def build_and_run(self, test_file):
+        """
+        Tries building the given test source and runs to the first breakpoint.
+        Returns false if the file fails to build due to an unsupported calling
+        convention on the current test target. Returns true if building and
+        running to the breakpoint succeeded.
+        """
+        try:
+            self.build(dictionary={
+                "C_SOURCES" : test_file,
+                "CFLAGS_EXTRAS" : "-Werror"
+            })
+        except BuildError as e:
+             # Test source failed to build. Check if it failed because the
+             # calling convention argument is unsupported/unknown in which case
+             # the test should be skipped.
+             error_msg = str(e)
+             # Clang gives an explicit error when a calling convention is
+             # not supported.
+             if "calling convention is not supported for this target" in error_msg:
+               return False
+             # GCC's has two different generic warnings it can emit.
+             if "attribute ignored" in error_msg:
+               return False
+             if "attribute directive ignored " in error_msg:
+               return False
+             # We got a different build error, so raise it again to fail the
+             # test.
+             raise
+        lldbutil.run_to_source_breakpoint(self, "// break here", lldb.SBFileSpec(test_file))
+        return True
+
+    def test_regcall(self):
+        if not self.build_and_run("regcall.c"):
+            return
+        self.expect_expr("func(1, 2, 3, 4)", result_type="int", result_value="10")
+
+    def test_ms_abi(self):
+        if not self.build_and_run("ms_abi.c"):
+            return
+        self.expect_expr("func(1, 2, 3, 4)", result_type="int", result_value="10")
+
+    def test_stdcall(self):
+        if not self.build_and_run("stdcall.c"):
+            return
+        self.expect_expr("func(1, 2, 3, 4)", result_type="int", result_value="10")
+
+    def test_vectorcall(self):
+        if not self.build_and_run("vectorcall.c"):
+            return
+        self.expect_expr("func(1.0)", result_type="int", result_value="1")
+
+    def test_fastcall(self):
+        if not self.build_and_run("fastcall.c"):
+            return
+        self.expect_expr("func(1, 2, 3, 4)", result_type="int", result_value="10")
+
+    def test_pascal(self):
+        if not self.build_and_run("pascal.c"):
+            return
+        self.expect_expr("func(1, 2, 3, 4)", result_type="int", result_value="10")
+
+    def test_sysv_abi(self):
+        if not self.build_and_run("sysv_abi.c"):
+            return
+        self.expect_expr("func(1, 2, 3, 4)", result_type="int", result_value="10")
Index: lldb/test/API/lang/c/calling-conventions/Makefile
===================================================================
--- /dev/null
+++ lldb/test/API/lang/c/calling-conventions/Makefile
@@ -0,0 +1 @@
+include Makefile.rules
Index: lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
===================================================================
--- lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
+++ lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -876,6 +876,37 @@
   return type_sp;
 }
 
+static clang::CallingConv
+ConvertDWARFCallingConventionToClang(const ParsedDWARFTypeAttributes &attrs) {
+  switch (attrs.calling_convention) {
+  case llvm::dwarf::DW_CC_normal:
+    return clang::CC_C;
+  case llvm::dwarf::DW_CC_BORLAND_stdcall:
+    return clang::CC_X86StdCall;
+  case llvm::dwarf::DW_CC_BORLAND_msfastcall:
+    return clang::CC_X86FastCall;
+  case llvm::dwarf::DW_CC_LLVM_vectorcall:
+    return clang::CC_X86VectorCall;
+  case llvm::dwarf::DW_CC_BORLAND_pascal:
+    return clang::CC_X86Pascal;
+  case llvm::dwarf::DW_CC_LLVM_Win64:
+    return clang::CC_Win64;
+  case llvm::dwarf::DW_CC_LLVM_X86_64SysV:
+    return clang::CC_X86_64SysV;
+  case llvm::dwarf::DW_CC_LLVM_X86RegCall:
+    return clang::CC_X86RegCall;
+  default:
+    break;
+  }
+
+  Log *log(LogChannelDWARF::GetLogIfAny(DWARF_LOG_TYPE_COMPLETION |
+                                        DWARF_LOG_LOOKUPS));
+  LLDB_LOG(log, "Unsupported DW_AT_calling_convention value: {0}",
+           attrs.calling_convention);
+  // Use the default calling convention as a fallback.
+  return clang::CC_C;
+}
+
 TypeSP DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die,
                            ParsedDWARFTypeAttributes &attrs) {
   Log *log(LogChannelDWARF::GetLogIfAny(DWARF_LOG_TYPE_COMPLETION |
@@ -954,11 +985,14 @@
     is_cxx_method = false;
   }
 
+  clang::CallingConv calling_convention =
+      ConvertDWARFCallingConventionToClang(attrs);
+
   // clang_type will get the function prototype clang type after this
   // call
   CompilerType clang_type = m_ast.CreateFunctionType(
       return_clang_type, function_param_types.data(),
-      function_param_types.size(), is_variadic, type_quals);
+      function_param_types.size(), is_variadic, type_quals, calling_convention);
 
   if (attrs.name) {
     bool type_handled = false;
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to