it to print the old and new values.
Temporarily disable the "out of scope" checking since it didn't work correctly, and was
not what people generally expected watchpoints to be doing.
llvm-svn: 166472
{
public:
- Watchpoint (lldb::addr_t addr, size_t size, bool hardware = true);
-
+ Watchpoint (Target& target, lldb::addr_t addr, size_t size, const ClangASTType *type, bool hardware = true);
~Watchpoint ();
void
// Snapshot management interface.
bool IsWatchVariable() const;
void SetWatchVariable(bool val);
- std::string GetOldSnapshot() const;
- void SetOldSnapshot (const std::string &str);
- std::string GetNewSnapshot() const;
- void SetNewSnapshot (const std::string &str);
- uint64_t GetOldSnapshotVal() const;
- void SetOldSnapshotVal (uint64_t val);
- uint64_t GetNewSnapshotVal() const;
- void SetNewSnapshotVal (uint64_t val);
- void ClearSnapshots();
+ bool CaptureWatchedValue (const ExecutionContext &exe_ctx);
void GetDescription (Stream *s, lldb::DescriptionLevel level);
void Dump (Stream *s) const;
void DumpSnapshots (Stream *s, const char * prefix = NULL) const;
void DumpWithLevel (Stream *s, lldb::DescriptionLevel description_level) const;
- Target &GetTarget() { return *m_target; }
+ Target &GetTarget() { return m_target; }
const Error &GetError() { return m_error; }
//------------------------------------------------------------------
bool
IsDisabledDuringEphemeralMode();
+
+ const ClangASTType &
+ GetClangASTType()
+ {
+ return m_type;
+ }
+
private:
friend class Target;
friend class WatchpointList;
- void SetTarget(Target *target_ptr) { m_target = target_ptr; }
void ResetHitCount() { m_hit_count = 0; }
- Target *m_target;
+ Target &m_target;
bool m_enabled; // Is this watchpoint enabled
bool m_is_hardware; // Is this a hardware watchpoint
bool m_is_watch_variable; // True if set via 'watchpoint set variable'.
uint32_t m_false_alarms; // Number of false alarms.
std::string m_decl_str; // Declaration information, if any.
std::string m_watch_spec_str; // Spec for the watchpoint.
- std::string m_snapshot_old_str; // Old snapshot for the watchpoint value as by ValueObject::DumpValueObject().
- std::string m_snapshot_new_str; // New Snapshot for the watchpoint value as by ValueObject::DumpValueObject().
- uint64_t m_snapshot_old_val; // Old snapshot for the watchpoint bytes.
- uint64_t m_snapshot_new_val; // New Snapshot for the watchpoint bytes.
+ lldb::ValueObjectSP m_old_value_sp;
+ lldb::ValueObjectSP m_new_value_sp;
+ ClangASTType m_type;
Error m_error; // An error object describing errors associated with this watchpoint.
WatchpointOptions m_options; // Settable watchpoint options, which is a delegate to handle
// the callback machinery.
lldb::WatchpointSP
CreateWatchpoint (lldb::addr_t addr,
size_t size,
- uint32_t type,
+ const ClangASTType *type,
+ uint32_t kind,
Error &error);
lldb::WatchpointSP
26BC7CFB10F1B71400F91463 /* StoppointLocation.h */,
26BC7E1710F1B83100F91463 /* StoppointLocation.cpp */,
26BC7CFC10F1B71400F91463 /* Watchpoint.h */,
- B27318431416AC43006039C8 /* WatchpointList.h */,
26BC7E1810F1B83100F91463 /* Watchpoint.cpp */,
+ B27318431416AC43006039C8 /* WatchpointList.h */,
B27318411416AC12006039C8 /* WatchpointList.cpp */,
B2B7CCED15D1BFB700EEFB57 /* WatchpointOptions.h */,
B2B7CCEF15D1C20F00EEFB57 /* WatchpointOptions.cpp */,
watch_type |= LLDB_WATCH_TYPE_WRITE;
// Target::CreateWatchpoint() is thread safe.
Error cw_error;
- watchpoint_sp = target_sp->CreateWatchpoint(addr, size, watch_type, cw_error);
+ // This API doesn't take in a type, so we can't figure out what it is.
+ ClangASTType *type = NULL;
+ watchpoint_sp = target_sp->CreateWatchpoint(addr, size, type, watch_type, cw_error);
error.SetError(cw_error);
sb_watchpoint.SetSP (watchpoint_sp);
}
watch_type |= LLDB_WATCH_TYPE_WRITE;
Error rc;
- WatchpointSP watchpoint_sp = target_sp->CreateWatchpoint(addr, byte_size, watch_type, rc);
+ ClangASTType type (value_sp->GetClangAST(), value_sp->GetClangType());
+ WatchpointSP watchpoint_sp = target_sp->CreateWatchpoint(addr, byte_size, &type, watch_type, rc);
error.SetError(rc);
if (watchpoint_sp)
// Project includes
#include "lldb/Breakpoint/StoppointCallbackContext.h"
#include "lldb/Core/Stream.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Core/ValueObjectMemory.h"
+#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/ThreadSpec.h"
using namespace lldb;
using namespace lldb_private;
-Watchpoint::Watchpoint (lldb::addr_t addr, size_t size, bool hardware) :
+Watchpoint::Watchpoint (Target& target, lldb::addr_t addr, size_t size, const ClangASTType *type, bool hardware) :
StoppointLocation (0, addr, size, hardware),
- m_target(NULL),
+ m_target(target),
m_enabled(false),
m_is_hardware(hardware),
m_is_watch_variable(false),
m_false_alarms(0),
m_decl_str(),
m_watch_spec_str(),
- m_snapshot_old_str(),
- m_snapshot_new_str(),
- m_snapshot_old_val(0),
- m_snapshot_new_val(0),
+ m_type(),
m_error(),
m_options ()
{
+ if (type && type->IsValid())
+ m_type = *type;
+ else
+ {
+ // If we don't have a known type, then we force it to unsigned int of the right size.
+ ClangASTContext *ast_context = target.GetScratchClangASTContext();
+ clang_type_t clang_type = ast_context->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, size);
+ m_type.SetClangType(ast_context->getASTContext(), clang_type);
+ }
+
+ // Set the initial value of the watched variable:
+ if (m_target.GetProcessSP())
+ {
+ ExecutionContext exe_ctx;
+ m_target.GetProcessSP()->CalculateExecutionContext(exe_ctx);
+ CaptureWatchedValue (exe_ctx);
+ }
}
Watchpoint::~Watchpoint()
return;
}
-// Strip at most one character from the end of the string.
-static inline std::string
-RStripOnce(const std::string &str, const char c)
-{
- std::string res = str;
- size_t len = res.length();
- if (len && res.at(len - 1) == '\n')
- res.resize(len - 1);
- return res;
-}
-
-std::string
-Watchpoint::GetOldSnapshot() const
-{
- return m_snapshot_old_str;
-}
-
-void
-Watchpoint::SetOldSnapshot (const std::string &str)
-{
- m_snapshot_old_str = RStripOnce(str, '\n');
-}
-
-std::string
-Watchpoint::GetNewSnapshot() const
-{
- return m_snapshot_new_str;
-}
-
-void
-Watchpoint::SetNewSnapshot (const std::string &str)
-{
- m_snapshot_old_str = m_snapshot_new_str;
- m_snapshot_new_str = RStripOnce(str, '\n');
-}
-
-uint64_t
-Watchpoint::GetOldSnapshotVal() const
-{
- return m_snapshot_old_val;
-}
-
-void
-Watchpoint::SetOldSnapshotVal (uint64_t val)
-{
- m_snapshot_old_val = val;
- return;
-}
-
-uint64_t
-Watchpoint::GetNewSnapshotVal() const
-{
- return m_snapshot_new_val;
-}
-
-void
-Watchpoint::SetNewSnapshotVal (uint64_t val)
-{
- m_snapshot_old_val = m_snapshot_new_val;
- m_snapshot_new_val = val;
- return;
-}
-
-void
-Watchpoint::ClearSnapshots()
-{
- m_snapshot_old_str.clear();
- m_snapshot_new_str.clear();
- m_snapshot_old_val = 0;
- m_snapshot_new_val = 0;
-}
-
// Override default impl of StoppointLocation::IsHardware() since m_is_hardware
// member field is more accurate.
bool
m_is_watch_variable = val;
}
+bool
+Watchpoint::CaptureWatchedValue (const ExecutionContext &exe_ctx)
+{
+ ConstString watch_name("$__lldb__watch_value");
+ m_old_value_sp = m_new_value_sp;
+ Address watch_address(GetLoadAddress());
+ m_new_value_sp = ValueObjectMemory::Create (exe_ctx.GetBestExecutionContextScope(), watch_name.AsCString(), watch_address, m_type);
+ m_new_value_sp = m_new_value_sp->CreateConstantValue(watch_name);
+ if (m_new_value_sp && m_new_value_sp->GetError().Success())
+ return true;
+ else
+ return false;
+}
+
void
Watchpoint::IncrementFalseAlarmsAndReviseHitCount()
{
s->Printf("\nWatchpoint %u hit:", GetID());
prefix = "";
}
-
- if (IsWatchVariable())
+
+ if (m_old_value_sp)
{
- if (!m_snapshot_old_str.empty())
- s->Printf("\n%sold value: %s", prefix, m_snapshot_old_str.c_str());
- if (!m_snapshot_new_str.empty())
- s->Printf("\n%snew value: %s", prefix, m_snapshot_new_str.c_str());
+ s->Printf("\n%sold value: %s", prefix, m_old_value_sp->GetValueAsCString());
}
- else
+ if (m_new_value_sp)
{
- uint32_t num_hex_digits = GetByteSize() * 2;
- s->Printf("\n%sold value: 0x%0*.*llx", prefix, num_hex_digits, num_hex_digits, m_snapshot_old_val);
- s->Printf("\n%snew value: 0x%0*.*llx", prefix, num_hex_digits, num_hex_digits, m_snapshot_new_val);
+ s->Printf("\n%snew value: %s", prefix, m_new_value_sp->GetValueAsCString());
}
}
// Don't clear the snapshots for now.
// Within StopInfo.cpp, we purposely do disable/enable watchpoint while performing watchpoint actions.
- //ClearSnapshots();
}
m_enabled = enabled;
}
valobj_sp = valobj_list.GetValueObjectAtIndex(0);
}
+ ClangASTType type;
+
if (valobj_sp) {
AddressType addr_type;
addr = valobj_sp->GetAddressOf(false, &addr_type);
size = m_option_watchpoint.watch_size == 0 ? valobj_sp->GetByteSize()
: m_option_watchpoint.watch_size;
}
+ type.SetClangType(valobj_sp->GetClangAST(), valobj_sp->GetClangType());
} else {
const char *error_cstr = error.AsCString(NULL);
if (error_cstr)
// Now it's time to create the watchpoint.
uint32_t watch_type = m_option_watchpoint.watch_type;
error.Clear();
- Watchpoint *wp = target->CreateWatchpoint(addr, size, watch_type, error).get();
+ Watchpoint *wp = target->CreateWatchpoint(addr, size, &type, watch_type, error).get();
if (wp) {
wp->SetWatchSpec(command.GetArgumentAtIndex(0));
wp->SetWatchVariable(true);
var_sp->GetDeclaration().DumpStopContext(&ss, true);
wp->SetDeclInfo(ss.GetString());
}
- StreamString ss;
- ValueObject::DumpValueObject(ss, valobj_sp.get());
- wp->SetNewSnapshot(ss.GetString());
output_stream.Printf("Watchpoint created: ");
wp->GetDescription(&output_stream, lldb::eDescriptionLevelFull);
output_stream.EOL();
// Now it's time to create the watchpoint.
uint32_t watch_type = m_option_watchpoint.watch_type;
+
+ // Fetch the type from the value object, the type of the watched object is the pointee type
+ /// of the expression, so convert to that if we found a valid type.
+ ClangASTType type(valobj_sp->GetClangAST(), valobj_sp->GetClangType());
+ if (type.IsValid())
+ type.SetClangType(type.GetASTContext(), type.GetPointeeType());
+
Error error;
- Watchpoint *wp = target->CreateWatchpoint(addr, size, watch_type, error).get();
+ Watchpoint *wp = target->CreateWatchpoint(addr, size, &type, watch_type, error).get();
if (wp) {
if (var_sp && var_sp->GetDeclaration().GetFile()) {
StreamString ss;
wp->SetDeclInfo(ss.GetString());
}
output_stream.Printf("Watchpoint created: ");
- uint64_t val = target->GetProcessSP()->ReadUnsignedIntegerFromMemory(addr, size, 0, error);
- if (error.Success())
- wp->SetNewSnapshotVal(val);
- else
- output_stream.Printf("watchpoint snapshot failed: %s", error.AsCString());
wp->GetDescription(&output_stream, lldb::eDescriptionLevelFull);
output_stream.EOL();
result.SetStatus(eReturnStatusSuccessFinishResult);
}
}
- // Record the snapshot of our watchpoint.
- VariableSP var_sp;
- ValueObjectSP valobj_sp;
- StackFrame *frame = exe_ctx.GetFramePtr();
- if (frame)
- {
- bool snapshot_taken = true;
- if (!wp_sp->IsWatchVariable())
- {
- // We are not watching a variable, just read from the process memory for the watched location.
- assert (process);
- Error error;
- uint64_t val = process->ReadUnsignedIntegerFromMemory(wp_sp->GetLoadAddress(),
- wp_sp->GetByteSize(),
- 0,
- error);
- if (log)
- {
- if (error.Success())
- log->Printf("Watchpoint snapshot val taken: 0x%llx\n", val);
- else
- log->Printf("Watchpoint snapshot val taking failed.\n");
- }
- wp_sp->SetNewSnapshotVal(val);
- }
- else if (!wp_sp->GetWatchSpec().empty())
- {
- // Use our frame to evaluate the variable expression.
- Error error;
- uint32_t expr_path_options = StackFrame::eExpressionPathOptionCheckPtrVsMember |
- StackFrame::eExpressionPathOptionsAllowDirectIVarAccess;
- valobj_sp = frame->GetValueForVariableExpressionPath (wp_sp->GetWatchSpec().c_str(),
- eNoDynamicValues,
- expr_path_options,
- var_sp,
- error);
- if (valobj_sp)
- {
- // We're in business.
- StreamString ss;
- ValueObject::DumpValueObject(ss, valobj_sp.get());
- wp_sp->SetNewSnapshot(ss.GetString());
- }
- else
- {
- // The variable expression has become out of scope?
- // Let us forget about this stop info.
- if (log)
- log->Printf("Snapshot attempt failed. Variable expression has become out of scope?");
- snapshot_taken = false;
- m_should_stop = false;
- wp_sp->IncrementFalseAlarmsAndReviseHitCount();
- }
-
- if (log && snapshot_taken)
- log->Printf("Watchpoint snapshot taken: '%s'\n", wp_sp->GetNewSnapshot().c_str());
- }
-
- // Now dump the snapshots we have taken.
- if (snapshot_taken)
- {
- Debugger &debugger = exe_ctx.GetTargetRef().GetDebugger();
- StreamSP output_sp = debugger.GetAsyncOutputStream ();
- wp_sp->DumpSnapshots(output_sp.get());
- output_sp->EOL();
- output_sp->Flush();
- }
- }
-
if (m_should_stop && wp_sp->GetConditionText() != NULL)
{
// We need to make sure the user sees any parse errors in their condition, so we'll hook the
m_should_stop = false;
}
}
+ // Finally, if we are going to stop, print out the new & old values:
+ if (m_should_stop)
+ {
+ wp_sp->CaptureWatchedValue(exe_ctx);
+
+ Debugger &debugger = exe_ctx.GetTargetRef().GetDebugger();
+ StreamSP output_sp = debugger.GetAsyncOutputStream ();
+ wp_sp->DumpSnapshots(output_sp.get());
+ output_sp->EOL();
+ output_sp->Flush();
+ }
+
}
else
{
}
if (log)
log->Printf ("Process::%s returning from action with m_should_stop: %d.", __FUNCTION__, m_should_stop);
+
}
virtual const char *
// See also Watchpoint::SetWatchpointType(uint32_t type) and
// the OptionGroupWatchpoint::WatchType enum type.
WatchpointSP
-Target::CreateWatchpoint(lldb::addr_t addr, size_t size, uint32_t type, Error &error)
+Target::CreateWatchpoint(lldb::addr_t addr, size_t size, const ClangASTType *type, uint32_t kind, Error &error)
{
LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
if (log)
log->Printf("Target::%s (addr = 0x%8.8llx size = %llu type = %u)\n",
- __FUNCTION__, addr, (uint64_t)size, type);
+ __FUNCTION__, addr, (uint64_t)size, kind);
WatchpointSP wp_sp;
if (!ProcessIsValid())
(matched_sp->WatchpointRead() ? LLDB_WATCH_TYPE_READ : 0) |
(matched_sp->WatchpointWrite() ? LLDB_WATCH_TYPE_WRITE : 0);
// Return the existing watchpoint if both size and type match.
- if (size == old_size && type == old_type) {
+ if (size == old_size && kind == old_type) {
wp_sp = matched_sp;
wp_sp->SetEnabled(false);
} else {
}
if (!wp_sp) {
- Watchpoint *new_wp = new Watchpoint(addr, size);
+ Watchpoint *new_wp = new Watchpoint(*this, addr, size, type);
if (!new_wp) {
printf("Watchpoint ctor failed, out of memory?\n");
return wp_sp;
}
- new_wp->SetWatchpointType(type);
- new_wp->SetTarget(this);
+ new_wp->SetWatchpointType(kind);
wp_sp.reset(new_wp);
m_watchpoint_list.Add(wp_sp);
}
mydir = os.path.join("functionalities", "watchpoint", "variable_out_of_scope")
+ #
+ # This test depends on not tracking watchpoint expression hits if we have
+ # left the watchpoint scope. We will provide such an ability at some point
+ # but the way this was done was incorrect, and it is unclear that for the
+ # most part that's not what folks mostly want, so we have to provide a
+ # clearer API to express this.
+ #
+
+ @unittest2.expectedFailure
@dsym_test
def test_watched_var_should_only_hit_when_in_scope_with_dsym(self):
"""Test that a variable watchpoint should only hit when in scope."""
self.setTearDownCleanup(dictionary=self.d)
self.watched_var()
+ @unittest2.expectedFailure
@dwarf_test
def test_watched_var_should_only_hit_when_in_scope_with_dwarf(self):
"""Test that a variable watchpoint should only hit when in scope."""
# Check that the watchpoint snapshoting mechanism is working.
self.expect("watchpoint list -v",
- substrs = ['old value:', 'global = 0',
- 'new value:', 'global = 1'])
+ substrs = ['old value:', ' = 0',
+ 'new value:', ' = 1'])
# The watchpoint command "forced" our global variable 'cookie' to become 777.
self.expect("frame variable -g cookie",
# Check that the watchpoint snapshoting mechanism is working.
self.expect("watchpoint list -v",
- substrs = ['old value:', 'global = 0',
- 'new value:', 'global = 1'])
+ substrs = ['old value:', ' = 0',
+ 'new value:', ' = 1'])
# The watchpoint command "forced" our global variable 'cookie' to become 777.
self.expect("frame variable -g cookie",