Made the expression handle variables with
authorSean Callanan <scallanan@apple.com>
Fri, 18 Jan 2013 21:20:51 +0000 (21:20 +0000)
committerSean Callanan <scallanan@apple.com>
Fri, 18 Jan 2013 21:20:51 +0000 (21:20 +0000)
DW_AT_const_value instead of a location.  Also
added a testcase covering "frame variable," "expr"
using the IR interpreter, and "expr" using the
LLVM JIT.

<rdar://problem/12978195>

llvm-svn: 172848

lldb/include/lldb/Expression/ClangExpressionDeclMap.h
lldb/source/Expression/ClangExpressionDeclMap.cpp
lldb/test/lang/c/const_variables/Makefile [new file with mode: 0644]
lldb/test/lang/c/const_variables/TestConstVariables.py [new file with mode: 0644]
lldb/test/lang/c/const_variables/functions.c [new file with mode: 0644]
lldb/test/lang/c/const_variables/main.c [new file with mode: 0644]

index fb5d276..69ff134 100644 (file)
@@ -1104,6 +1104,51 @@ private:
                                         Error &err);
     
     //------------------------------------------------------------------
+    /// Create a temporary buffer in the target process to store the value
+    /// of a persistent variable that would otherwise not be accessible in
+    /// memory (e.g., register values or constants).
+    ///
+    /// @param[in] process
+    ///     The process to use when allocating the memory.
+    ///
+    /// @param[in] expr_var
+    ///     The variable whose live data will hold this buffer.
+    ///
+    /// @param[in] err
+    ///     An Error to populate with any messages related to
+    ///     allocating the memory.
+    ///
+    /// @return
+    ///     True on success; false otherwise.
+    //------------------------------------------------------------------
+    bool
+    CreateLiveMemoryForExpressionVariable (Process &process,
+                                           lldb::ClangExpressionVariableSP &expr_var,
+                                           Error &err);
+    
+    //------------------------------------------------------------------
+    /// Delete a temporary buffer created with
+    /// CreateLiveMemoryForExpressionVariable.
+    ///
+    /// @param[in] process
+    ///     The process to use when deallocating the memory.
+    ///
+    /// @param[in] expr_var
+    ///     The variable whose live data will hold this buffer.
+    ///
+    /// @param[in] err
+    ///     An Error to populate with any messages related to
+    ///     allocating the memory.
+    ///
+    /// @return
+    ///     True on success; false otherwise.
+    //------------------------------------------------------------------
+    bool
+    DeleteLiveMemoryForExpressionVariable (Process &process,
+                                           lldb::ClangExpressionVariableSP &expr_var,
+                                           Error &err);
+    
+    //------------------------------------------------------------------
     /// Actually do the task of materializing or dematerializing a 
     /// variable.
     ///
index f1ffb33..f11b73e 100644 (file)
@@ -1835,13 +1835,80 @@ ClangExpressionDeclMap::DoMaterializeOnePersistentVariable
     return true;
 }
 
-bool 
+bool
+ClangExpressionDeclMap::CreateLiveMemoryForExpressionVariable
+(
+    Process &process,
+    ClangExpressionVariableSP &expr_var,
+    Error &err
+)
+{
+    Error allocate_error;
+    TypeFromUser type(expr_var->GetTypeFromUser());
+    const ConstString &name(expr_var->GetName());
+    
+    size_t value_bit_size = ClangASTType::GetClangTypeBitWidth(type.GetASTContext(), type.GetOpaqueQualType());
+    size_t value_byte_size = value_bit_size % 8 ? ((value_bit_size + 8) / 8) : (value_bit_size / 8);
+
+    Scalar val_addr (process.AllocateMemory (value_byte_size,
+                                             lldb::ePermissionsReadable | lldb::ePermissionsWritable,
+                                             allocate_error));
+    
+    if (val_addr.ULongLong() == LLDB_INVALID_ADDRESS)
+    {
+        err.SetErrorStringWithFormat ("Couldn't allocate a memory area to store %s: %s",
+                                      name.GetCString(),
+                                      allocate_error.AsCString());
+        return false;
+    }
+    
+    // Put the location of the spare memory into the live data of the ValueObject.
+    
+    expr_var->m_live_sp = ValueObjectConstResult::Create (m_parser_vars->m_exe_ctx.GetBestExecutionContextScope(),
+                                                          type.GetASTContext(),
+                                                          type.GetOpaqueQualType(),
+                                                          name,
+                                                          val_addr.ULongLong(),
+                                                          eAddressTypeLoad,
+                                                          value_byte_size);
+    
+    return true;
+}
+
+bool
+ClangExpressionDeclMap::DeleteLiveMemoryForExpressionVariable
+(
+    Process &process,
+    ClangExpressionVariableSP &expr_var,
+    Error &err
+)
+{
+    const ConstString &name(expr_var->GetName());
+    
+    Scalar &val_addr = expr_var->m_live_sp->GetValue().GetScalar();
+    
+    Error deallocate_error = process.DeallocateMemory(val_addr.ULongLong());
+    
+    if (!deallocate_error.Success())
+    {
+        err.SetErrorStringWithFormat ("Couldn't deallocate spare memory area for %s: %s",
+                                      name.GetCString(),
+                                      deallocate_error.AsCString());
+        return false;
+    }
+    
+    expr_var->m_live_sp.reset();
+    
+    return true;
+}
+
+bool
 ClangExpressionDeclMap::DoMaterializeOneVariable
 (
     bool dematerialize,
     const SymbolContext &sym_ctx,
     ClangExpressionVariableSP &expr_var,
-    lldb::addr_t addr, 
+    lldb::addr_t addr,
     Error &err
 )
 {
@@ -1939,6 +2006,66 @@ ClangExpressionDeclMap::DoMaterializeOneVariable
             return false;
         }
         break;
+    case Value::eValueTypeHostAddress:
+        {
+            if (dematerialize)
+            {
+                if (!DeleteLiveMemoryForExpressionVariable(*process, expr_var, err))
+                    return false;
+            }
+            else
+            {                
+                DataExtractor value_data_extractor;
+                
+                if (location_value->GetData(value_data_extractor))
+                {
+                    if (value_byte_size != value_data_extractor.GetByteSize())
+                    {
+                        err.SetErrorStringWithFormat ("Size mismatch for %s: %llu versus %llu",
+                                                      name.GetCString(),
+                                                      (uint64_t)value_data_extractor.GetByteSize(),
+                                                      (uint64_t)value_byte_size);
+                        return false;
+                    }
+                    
+                    if (!CreateLiveMemoryForExpressionVariable(*process, expr_var, err))
+                        return false;
+                    
+                    Scalar &buf_addr = expr_var->m_live_sp->GetValue().GetScalar();
+
+                    Error write_error;
+                    
+                    if (!process->WriteMemory(buf_addr.ULongLong(),
+                                              value_data_extractor.GetDataStart(),
+                                              value_data_extractor.GetByteSize(),
+                                              write_error))
+                    {
+                        err.SetErrorStringWithFormat ("Couldn't write %s to the target: %s",
+                                                      name.GetCString(),
+                                                      write_error.AsCString());
+                        return false;
+                    }
+                    
+                    if (!process->WriteScalarToMemory(addr,
+                                                      buf_addr,
+                                                      process->GetAddressByteSize(),
+                                                      write_error))
+                    {
+                        err.SetErrorStringWithFormat ("Couldn't write the address of %s to the target: %s",
+                                                      name.GetCString(),
+                                                      write_error.AsCString());
+                        return false;
+                    }
+                }
+                else
+                {
+                    err.SetErrorStringWithFormat ("%s is marked as a host address but doesn't contain any data",
+                                                  name.GetCString());
+                    return false;
+                }
+            }
+        }
+        break;
     case Value::eValueTypeLoadAddress:
         {
             if (!dematerialize)
@@ -2057,19 +2184,8 @@ ClangExpressionDeclMap::DoMaterializeOneVariable
                     return false;
                 }
                 
-                // Deallocate the spare area and clear the variable's live data.
-                
-                Error deallocate_error = process->DeallocateMemory(reg_addr.ULongLong());
-                
-                if (!deallocate_error.Success())
-                {
-                    err.SetErrorStringWithFormat ("Couldn't deallocate spare memory area for %s: %s", 
-                                                  name.GetCString(), 
-                                                  deallocate_error.AsCString());
+                if (!DeleteLiveMemoryForExpressionVariable(*process, expr_var, err))
                     return false;
-                }
-                
-                expr_var->m_live_sp.reset();
             }
             else
             {
@@ -2103,36 +2219,17 @@ ClangExpressionDeclMap::DoMaterializeOneVariable
                     
                     return true;
                 }
-
+                
                 // Allocate a spare memory area to place the register's contents into.  This memory area will be pointed to by the slot in the
                 // struct.
                 
-                Error allocate_error;
-                
-                Scalar reg_addr (process->AllocateMemory (value_byte_size, 
-                                                          lldb::ePermissionsReadable | lldb::ePermissionsWritable, 
-                                                          allocate_error));
-                
-                if (reg_addr.ULongLong() == LLDB_INVALID_ADDRESS)
-                {
-                    err.SetErrorStringWithFormat ("Couldn't allocate a memory area to store %s: %s", 
-                                                  name.GetCString(), 
-                                                  allocate_error.AsCString());
+                if (!CreateLiveMemoryForExpressionVariable (*process, expr_var, err))
                     return false;
-                }
                 
-                // Put the location of the spare memory into the live data of the ValueObject.
+                // Now write the location of the area into the struct.
                 
-                expr_var->m_live_sp = ValueObjectConstResult::Create (m_parser_vars->m_exe_ctx.GetBestExecutionContextScope(),
-                                                                      type.GetASTContext(),
-                                                                      type.GetOpaqueQualType(),
-                                                                      name,
-                                                                      reg_addr.ULongLong(),
-                                                                      eAddressTypeLoad,
-                                                                      value_byte_size);
+                Scalar &reg_addr = expr_var->m_live_sp->GetValue().GetScalar();
                 
-                // Now write the location of the area into the struct.
-                                
                 if (!process->WriteScalarToMemory (addr, 
                                                    reg_addr, 
                                                    process->GetAddressByteSize(), 
@@ -3055,7 +3152,23 @@ ClangExpressionDeclMap::GetVariableValue
     }
     Error err;
     
-    if (!var_location_expr.Evaluate(&m_parser_vars->m_exe_ctx, ast, NULL, NULL, NULL, loclist_base_load_addr, NULL, *var_location.get(), &err))
+    if (var->GetLocationIsConstantValueData())
+    {
+        DataExtractor const_value_extractor;
+        
+        if (var_location_expr.GetExpressionData(const_value_extractor))
+        {
+            var_location->operator=(Value(const_value_extractor.GetDataStart(), const_value_extractor.GetByteSize()));
+            var_location->SetValueType(Value::eValueTypeHostAddress);
+        }
+        else
+        {
+            if (log)
+                log->Printf("Error evaluating constant variable: %s", err.AsCString());
+            return NULL;
+        }
+    }
+    else if (!var_location_expr.Evaluate(&m_parser_vars->m_exe_ctx, ast, NULL, NULL, NULL, loclist_base_load_addr, NULL, *var_location.get(), &err))
     {
         if (log)
             log->Printf("Error evaluating location: %s", err.AsCString());
diff --git a/lldb/test/lang/c/const_variables/Makefile b/lldb/test/lang/c/const_variables/Makefile
new file mode 100644 (file)
index 0000000..923a0d6
--- /dev/null
@@ -0,0 +1,7 @@
+LEVEL = ../../../make
+
+C_SOURCES := main.c functions.c
+
+CFLAGS ?= -arch $(ARCH) -gdwarf-2 -O3
+
+include $(LEVEL)/Makefile.rules
diff --git a/lldb/test/lang/c/const_variables/TestConstVariables.py b/lldb/test/lang/c/const_variables/TestConstVariables.py
new file mode 100644 (file)
index 0000000..e3ea90c
--- /dev/null
@@ -0,0 +1,66 @@
+"""Check that compiler-generated constant values work correctly"""
+
+import os, time
+import unittest2
+import lldb
+from lldbtest import *
+import lldbutil
+
+class ConstVariableTestCase(TestBase):
+
+    mydir = os.path.join("lang", "c", "const_variables")
+
+    @dsym_test
+    def test_with_dsym_and_run_command(self):
+        """Test interpreted and JITted expressions on constant values."""
+        self.buildDsym()
+        self.const_variable()
+
+    @dwarf_test
+    def test_with_dwarf_and_run_command(self):
+        """Test interpreted and JITted expressions on constant values."""
+        self.buildDwarf()
+        self.const_variable()
+
+    def setUp(self):
+        # Call super's setUp().
+        TestBase.setUp(self)
+
+    def const_variable(self):
+        """Test interpreted and JITted expressions on constant values."""
+        exe = os.path.join(os.getcwd(), "a.out")
+        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
+
+        # Break inside the main.
+        lldbutil.run_break_set_by_symbol (self, "main", num_expected_locations=1)
+
+        self.runCmd("run", RUN_SUCCEEDED)
+
+        # The stop reason of the thread should be breakpoint.
+        self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
+            substrs = ['stopped',
+                       'stop reason = breakpoint'])
+
+        # The breakpoint should have a hit count of 1.
+        self.expect("breakpoint list -f", BREAKPOINT_HIT_ONCE,
+            substrs = [' resolved, hit count = 1'])
+
+        # Try frame variable.
+        self.expect("frame variable index", VARIABLES_DISPLAYED_CORRECTLY,
+            substrs = ['(int32_t) index = 512'])
+
+        # Try an interpreted expression.
+        self.expect("expr (index + 512)", VARIABLES_DISPLAYED_CORRECTLY,
+            substrs = ['(int) $0 = 1024'])
+
+        # Try a JITted expression.
+        self.expect("expr (int)getpid(); (index - 256)", VARIABLES_DISPLAYED_CORRECTLY,
+            substrs = ['(int) $1 = 256'])
+
+        self.runCmd("kill")
+
+if __name__ == '__main__':
+    import atexit
+    lldb.SBDebugger.Initialize()
+    atexit.register(lambda: lldb.SBDebugger.Terminate())
+    unittest2.main()
diff --git a/lldb/test/lang/c/const_variables/functions.c b/lldb/test/lang/c/const_variables/functions.c
new file mode 100644 (file)
index 0000000..c9ea638
--- /dev/null
@@ -0,0 +1,18 @@
+#include <stdio.h>
+
+void foo()
+{
+  printf("foo()\n");
+}
+
+int bar()
+{
+  int ret = 3;
+  printf("bar()->%d\n", ret);
+  return ret;
+}
+
+void baaz(int i)
+{
+  printf("baaz(%d)\n", i);
+}
diff --git a/lldb/test/lang/c/const_variables/main.c b/lldb/test/lang/c/const_variables/main.c
new file mode 100644 (file)
index 0000000..086fa6f
--- /dev/null
@@ -0,0 +1,19 @@
+#include <stdint.h>
+
+extern int foo();
+extern int bar();
+extern int baaz(int i);
+
+int main()
+{
+  int32_t index;
+
+  foo();
+
+  index = 512;
+
+  if (bar())
+    index = 256;
+
+  baaz(index);
+}