[Lldb-commits] [lldb] 188b074 - Support dereferencing a DWARF scalar stack value

Adrian Prantl via lldb-commits lldb-commits at lists.llvm.org
Fri Feb 12 16:12:43 PST 2021


Author: Adrian Prantl
Date: 2021-02-12T16:12:32-08:00
New Revision: 188b0747c1664d962e94f00b5e3caac529fa1e26

URL: https://github.com/llvm/llvm-project/commit/188b0747c1664d962e94f00b5e3caac529fa1e26
DIFF: https://github.com/llvm/llvm-project/commit/188b0747c1664d962e94f00b5e3caac529fa1e26.diff

LOG: Support dereferencing a DWARF scalar stack value

Swift async functions receive function arguments inside a
heap-allocated data structure, similar to how ObjC block captures or
C++ coroutine arguments are implement. In DWARF they are described
relative to an entry value that produces a pointer into that heap
object. At typical location looks like

DW_OP_entry_value [ DW_OP_reg14 ] DW_OP_deref DW_OP_plus_uconst 32 DW_OP_deref

This allows the unwinder (which has special ABI knowledge to restore
the contents of r14) to push the base address onto the stack thus
allowing the deref/offset operations to continue. The result of the
entry value is a scalar, because DW_OP_reg14 is a register location —
as it should be since we want to restore the pointer value contained
in r14 at the beginning of the function and not the historical memory
contents it was pointing to. The entry value should restore the
address, which is still valid, not the contents at function entry.

To make this work, we need to allow LLDB to dereference Scalar stack
results like load addresses, which is what this patch
does. Unfortunately it is difficult to test this in isolation, since
the DWARFExpression unit test doesn't have a process.

Differential Revision: https://reviews.llvm.org/D96549

Added: 
    

Modified: 
    lldb/source/Expression/DWARFExpression.cpp
    lldb/unittests/Expression/CMakeLists.txt
    lldb/unittests/Expression/DWARFExpressionTest.cpp

Removed: 
    


################################################################################
diff  --git a/lldb/source/Expression/DWARFExpression.cpp b/lldb/source/Expression/DWARFExpression.cpp
index 08dd1e2c929c..6e78b9aa841a 100644
--- a/lldb/source/Expression/DWARFExpression.cpp
+++ b/lldb/source/Expression/DWARFExpression.cpp
@@ -1067,6 +1067,7 @@ bool DWARFExpression::Evaluate(
         stack.back().SetValueType(Value::ValueType::LoadAddress);
         // Fall through to load address code below...
       } LLVM_FALLTHROUGH;
+      case Value::ValueType::Scalar:
       case Value::ValueType::LoadAddress:
         if (exe_ctx) {
           if (process) {
@@ -1099,7 +1100,6 @@ bool DWARFExpression::Evaluate(
         }
         break;
 
-      case Value::ValueType::Scalar:
       case Value::ValueType::Invalid:
         if (error_ptr)
           error_ptr->SetErrorString("Invalid value type for DW_OP_deref.\n");
@@ -1170,6 +1170,7 @@ bool DWARFExpression::Evaluate(
         stack.back().GetScalar() = ptr;
         stack.back().ClearContext();
       } break;
+      case Value::ValueType::Scalar:
       case Value::ValueType::LoadAddress:
         if (exe_ctx) {
           if (process) {
@@ -1221,7 +1222,6 @@ bool DWARFExpression::Evaluate(
         }
         break;
 
-      case Value::ValueType::Scalar:
       case Value::ValueType::FileAddress:
       case Value::ValueType::Invalid:
         if (error_ptr)

diff  --git a/lldb/unittests/Expression/CMakeLists.txt b/lldb/unittests/Expression/CMakeLists.txt
index 0e8230d19bad..185b19f84cae 100644
--- a/lldb/unittests/Expression/CMakeLists.txt
+++ b/lldb/unittests/Expression/CMakeLists.txt
@@ -7,6 +7,8 @@ add_lldb_unittest(ExpressionTests
 
   LINK_LIBS
     lldbCore
+    lldbPluginObjectFileELF
+    lldbPluginPlatformLinux
     lldbPluginExpressionParserClang
     lldbPluginTypeSystemClang
     lldbUtility

diff  --git a/lldb/unittests/Expression/DWARFExpressionTest.cpp b/lldb/unittests/Expression/DWARFExpressionTest.cpp
index ef89749ba7f8..ad56207659d2 100644
--- a/lldb/unittests/Expression/DWARFExpressionTest.cpp
+++ b/lldb/unittests/Expression/DWARFExpressionTest.cpp
@@ -7,11 +7,15 @@
 //===----------------------------------------------------------------------===//
 
 #include "lldb/Expression/DWARFExpression.h"
+#include "Plugins/Platform/Linux/PlatformLinux.h"
 #include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
 #include "TestingSupport/Symbol/YAMLModuleTester.h"
 #include "lldb/Core/Value.h"
+#include "lldb/Core/Debugger.h"
 #include "lldb/Core/dwarf.h"
+#include "lldb/Host/HostInfo.h"
 #include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Utility/Reproducer.h"
 #include "lldb/Utility/StreamString.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/Testing/Support/Error.h"
@@ -21,16 +25,17 @@ using namespace lldb_private;
 
 static llvm::Expected<Scalar> Evaluate(llvm::ArrayRef<uint8_t> expr,
                                        lldb::ModuleSP module_sp = {},
-                                       DWARFUnit *unit = nullptr) {
+                                       DWARFUnit *unit = nullptr,
+                                       ExecutionContext *exe_ctx = nullptr) {
   DataExtractor extractor(expr.data(), expr.size(), lldb::eByteOrderLittle,
                           /*addr_size*/ 4);
   Value result;
   Status status;
-  if (!DWARFExpression::Evaluate(
-          /*exe_ctx*/ nullptr, /*reg_ctx*/ nullptr, module_sp, extractor, unit,
-          lldb::eRegisterKindLLDB,
-          /*initial_value_ptr*/ nullptr,
-          /*object_address_ptr*/ nullptr, result, &status))
+  if (!DWARFExpression::Evaluate(exe_ctx, /*reg_ctx*/ nullptr, module_sp,
+                                 extractor, unit, lldb::eRegisterKindLLDB,
+                                 /*initial_value_ptr*/ nullptr,
+                                 /*object_address_ptr*/ nullptr, result,
+                                 &status))
     return status.ToError();
 
   switch (result.GetValueType()) {
@@ -66,6 +71,23 @@ static Scalar GetScalar(unsigned bits, uint64_t value, bool sign) {
   return scalar;
 }
 
+/// This is needed for the tests that use a mock process.
+class DWARFExpressionMockProcessTest : public ::testing::Test {
+public:
+  void SetUp() override {
+    llvm::cantFail(repro::Reproducer::Initialize(repro::ReproducerMode::Off, {}));
+    FileSystem::Initialize();
+    HostInfo::Initialize();
+    platform_linux::PlatformLinux::Initialize();
+  }
+  void TearDown() override {
+    platform_linux::PlatformLinux::Terminate();
+    HostInfo::Terminate();
+    FileSystem::Terminate();
+    repro::Reproducer::Terminate();
+  }
+};
+
 TEST(DWARFExpression, DW_OP_pick) {
   EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit1, DW_OP_lit0, DW_OP_pick, 0}),
                        llvm::HasValue(0));
@@ -277,6 +299,51 @@ TEST(DWARFExpression, DW_OP_unknown) {
           "Unhandled opcode DW_OP_unknown_ff in DWARFExpression"));
 }
 
-TEST(DWARFExpression, DW_OP_deref) {
+TEST_F(DWARFExpressionMockProcessTest, DW_OP_deref) {
   EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit0, DW_OP_deref}), llvm::Failed());
+
+  struct MockProcess : Process {
+    using Process::Process;
+    ConstString GetPluginName() override { return ConstString("mock process"); }
+    uint32_t GetPluginVersion() override { return 0; }
+    bool CanDebug(lldb::TargetSP target,
+                  bool plugin_specified_by_name) override {
+      return false;
+    };
+    Status DoDestroy() override { return {}; }
+    void RefreshStateAfterStop() override {}
+    bool DoUpdateThreadList(ThreadList &old_thread_list,
+                            ThreadList &new_thread_list) override {
+      return false;
+    };
+    size_t DoReadMemory(lldb::addr_t vm_addr, void *buf, size_t size,
+                        Status &error) override {
+      for (size_t i = 0; i < size; ++i)
+        ((char *)buf)[i] = (vm_addr + i) & 0xff;
+      error.Clear();
+      return size;
+    }
+  };
+
+  // Set up a mock process.
+  ArchSpec arch("i386-pc-linux");
+  Platform::SetHostPlatform(
+      platform_linux::PlatformLinux::CreateInstance(true, &arch));
+  lldb::DebuggerSP debugger_sp = Debugger::CreateInstance();
+  ASSERT_TRUE(debugger_sp);
+  lldb::TargetSP target_sp;
+  lldb::PlatformSP platform_sp;
+  debugger_sp->GetTargetList().CreateTarget(
+      *debugger_sp, "", arch, eLoadDependentsNo, platform_sp, target_sp);
+  ASSERT_TRUE(target_sp);
+  ASSERT_TRUE(target_sp->GetArchitecture().IsValid());
+  ASSERT_TRUE(platform_sp);
+  lldb::ListenerSP listener_sp(Listener::MakeListener("dummy"));
+  lldb::ProcessSP process_sp =
+      std::make_shared<MockProcess>(target_sp, listener_sp);
+  ASSERT_TRUE(process_sp);
+
+  ExecutionContext exe_ctx(process_sp);
+  EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit4, DW_OP_deref}, {}, {}, &exe_ctx),
+                       llvm::HasValue(GetScalar(32, 0x07060504, false)));
 }


        


More information about the lldb-commits mailing list