lldb::addr_t stack_frame_bottom,
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.
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
)
{
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)
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
{
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(),
}
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());
--- /dev/null
+"""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()