From 7b5805d0d1cba7d5a0f0a3ca7867f63cbde5cda8 Mon Sep 17 00:00:00 2001 From: Sean Callanan Date: Fri, 18 Jan 2013 21:20:51 +0000 Subject: [PATCH] Made the expression handle variables with 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. llvm-svn: 172848 --- .../lldb/Expression/ClangExpressionDeclMap.h | 45 +++++ lldb/source/Expression/ClangExpressionDeclMap.cpp | 189 ++++++++++++++++----- lldb/test/lang/c/const_variables/Makefile | 7 + .../lang/c/const_variables/TestConstVariables.py | 66 +++++++ lldb/test/lang/c/const_variables/functions.c | 18 ++ lldb/test/lang/c/const_variables/main.c | 19 +++ 6 files changed, 306 insertions(+), 38 deletions(-) create mode 100644 lldb/test/lang/c/const_variables/Makefile create mode 100644 lldb/test/lang/c/const_variables/TestConstVariables.py create mode 100644 lldb/test/lang/c/const_variables/functions.c create mode 100644 lldb/test/lang/c/const_variables/main.c diff --git a/lldb/include/lldb/Expression/ClangExpressionDeclMap.h b/lldb/include/lldb/Expression/ClangExpressionDeclMap.h index fb5d276..69ff134 100644 --- a/lldb/include/lldb/Expression/ClangExpressionDeclMap.h +++ b/lldb/include/lldb/Expression/ClangExpressionDeclMap.h @@ -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. /// diff --git a/lldb/source/Expression/ClangExpressionDeclMap.cpp b/lldb/source/Expression/ClangExpressionDeclMap.cpp index f1ffb33..f11b73e 100644 --- a/lldb/source/Expression/ClangExpressionDeclMap.cpp +++ b/lldb/source/Expression/ClangExpressionDeclMap.cpp @@ -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 ®_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 index 0000000..923a0d6 --- /dev/null +++ b/lldb/test/lang/c/const_variables/Makefile @@ -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 index 0000000..e3ea90c --- /dev/null +++ b/lldb/test/lang/c/const_variables/TestConstVariables.py @@ -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 index 0000000..c9ea638 --- /dev/null +++ b/lldb/test/lang/c/const_variables/functions.c @@ -0,0 +1,18 @@ +#include + +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 index 0000000..086fa6f --- /dev/null +++ b/lldb/test/lang/c/const_variables/main.c @@ -0,0 +1,19 @@ +#include + +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); +} -- 2.7.4