diff options
| author | Johnny Chen <johnny.chen@apple.com> | 2012-08-13 21:09:54 +0000 |
|---|---|---|
| committer | Johnny Chen <johnny.chen@apple.com> | 2012-08-13 21:09:54 +0000 |
| commit | 209bd65ea492d5ae713339314a52d9ae7421102d (patch) | |
| tree | 697d10d9c53df9b55856378c5c6e496dbface151 | |
| parent | d0af1d9657b5c2534f6e9f977d0d37be2a3beab4 (diff) | |
| download | bcm5719-llvm-209bd65ea492d5ae713339314a52d9ae7421102d.tar.gz bcm5719-llvm-209bd65ea492d5ae713339314a52d9ae7421102d.zip | |
rdar://problem/12007576
Record the snapshot of our watched value when the watchpoint is set or hit.
And report the old/new values when watchpoint is triggered. Add some test scenarios.
llvm-svn: 161785
9 files changed, 223 insertions, 34 deletions
diff --git a/lldb/include/lldb/Breakpoint/Watchpoint.h b/lldb/include/lldb/Breakpoint/Watchpoint.h index e033a2840fa..c5537d21e6c 100644 --- a/lldb/include/lldb/Breakpoint/Watchpoint.h +++ b/lldb/include/lldb/Breakpoint/Watchpoint.h @@ -53,10 +53,25 @@ public: uint32_t GetIgnoreCount () const; void SetIgnoreCount (uint32_t n); void SetWatchpointType (uint32_t type); - void SetDeclInfo (std::string &str); - void SetWatchSpec (std::string &str); + void SetDeclInfo (const std::string &str); + std::string GetWatchSpec(); + void SetWatchSpec (const std::string &str); + + // 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 GetDescription (Stream *s, lldb::DescriptionLevel level); void Dump (Stream *s) const; + void DumpSnapshots (const char * prefix, Stream *s) const; void DumpWithLevel (Stream *s, lldb::DescriptionLevel description_level) const; Target &GetTarget() { return *m_target; } const Error &GetError() { return m_error; } @@ -136,19 +151,23 @@ private: friend class WatchpointList; void SetTarget(Target *target_ptr) { m_target = target_ptr; } - std::string GetWatchSpec() { return m_watch_spec_str; } void ResetHitCount() { m_hit_count = 0; } 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_watch_read:1, // 1 if we stop when the watched data is read from m_watch_write:1, // 1 if we stop when the watched data is written to m_watch_was_read:1, // Set to 1 when watchpoint is hit for a read access m_watch_was_written:1; // Set to 1 when watchpoint is hit for a write access uint32_t m_ignore_count; // Number of times to ignore this breakpoint std::string m_decl_str; // Declaration information, if any. - std::string m_watch_spec_str; // Spec for the watchpoint (for future use). + 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. 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. diff --git a/lldb/lldb.xcodeproj/project.pbxproj b/lldb/lldb.xcodeproj/project.pbxproj index 34c46cf5e4c..cef11547a14 100644 --- a/lldb/lldb.xcodeproj/project.pbxproj +++ b/lldb/lldb.xcodeproj/project.pbxproj @@ -4407,7 +4407,7 @@ HEADER_SEARCH_PATHS = /usr/include/libxml2; LD_DYLIB_INSTALL_NAME = "$(DEVELOPER_DIR)/Library/PrivateFrameworks/LLDB.framework/Resources/lldb-core.a"; MACH_O_TYPE = staticlib; - MACOSX_DEPLOYMENT_TARGET = "10.7"; + MACOSX_DEPLOYMENT_TARGET = 10.7; OTHER_CPLUSPLUSFLAGS = ( "-fno-rtti", "-Wglobal-constructors", @@ -4438,7 +4438,7 @@ HEADER_SEARCH_PATHS = /usr/include/libxml2; LD_DYLIB_INSTALL_NAME = "$(DEVELOPER_DIR)/Library/PrivateFrameworks/LLDB.framework/Resources/lldb-core.a"; MACH_O_TYPE = staticlib; - MACOSX_DEPLOYMENT_TARGET = "10.7"; + MACOSX_DEPLOYMENT_TARGET = 10.7; OTHER_CPLUSPLUSFLAGS = ( "-fno-rtti", "-Wglobal-constructors", @@ -4469,7 +4469,7 @@ HEADER_SEARCH_PATHS = /usr/include/libxml2; LD_DYLIB_INSTALL_NAME = "$(DEVELOPER_DIR)/Library/PrivateFrameworks/LLDB.framework/Resources/lldb-core.a"; MACH_O_TYPE = staticlib; - MACOSX_DEPLOYMENT_TARGET = "10.7"; + MACOSX_DEPLOYMENT_TARGET = 10.7; OTHER_CPLUSPLUSFLAGS = ( "-fno-rtti", "-Wglobal-constructors", diff --git a/lldb/source/Breakpoint/Watchpoint.cpp b/lldb/source/Breakpoint/Watchpoint.cpp index 32c60a51238..60c47a9ad9b 100644 --- a/lldb/source/Breakpoint/Watchpoint.cpp +++ b/lldb/source/Breakpoint/Watchpoint.cpp @@ -28,6 +28,7 @@ Watchpoint::Watchpoint (lldb::addr_t addr, size_t size, bool hardware) : m_target(NULL), m_enabled(false), m_is_hardware(hardware), + m_is_watch_variable(false), m_watch_read(0), m_watch_write(0), m_watch_was_read(0), @@ -35,6 +36,10 @@ Watchpoint::Watchpoint (lldb::addr_t addr, size_t size, bool hardware) : m_ignore_count(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_error(), m_options () { @@ -70,19 +75,79 @@ Watchpoint::ClearCallback () } void -Watchpoint::SetDeclInfo (std::string &str) +Watchpoint::SetDeclInfo (const std::string &str) { m_decl_str = str; return; } +std::string +Watchpoint::GetWatchSpec() +{ + return m_watch_spec_str; +} + void -Watchpoint::SetWatchSpec (std::string &str) +Watchpoint::SetWatchSpec (const std::string &str) { m_watch_spec_str = str; return; } +std::string +Watchpoint::GetOldSnapshot() const +{ + return m_snapshot_old_str; +} + +void +Watchpoint::SetOldSnapshot (const std::string &str) +{ + m_snapshot_old_str = str; + return; +} + +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 = str; + return; +} + +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; +} + // Override default impl of StoppointLocation::IsHardware() since m_is_hardware // member field is more accurate. bool @@ -91,6 +156,18 @@ Watchpoint::IsHardware () const return m_is_hardware; } +bool +Watchpoint::IsWatchVariable() const +{ + return m_is_watch_variable; +} + +void +Watchpoint::SetWatchVariable(bool val) +{ + m_is_watch_variable = val; +} + // RETURNS - true if we should stop at this breakpoint, false if we // should continue. @@ -122,6 +199,24 @@ Watchpoint::Dump(Stream *s) const } void +Watchpoint::DumpSnapshots(const char *prefix, Stream *s) const +{ + if (IsWatchVariable()) + { + if (!m_snapshot_old_str.empty()) + s->Printf("\n%swatchpoint old value:\n\t%s", prefix, m_snapshot_old_str.c_str()); + if (!m_snapshot_new_str.empty()) + s->Printf("\n%swatchpoint new value:\n\t%s", prefix, m_snapshot_new_str.c_str()); + } + else + { + uint32_t num_hex_digits = GetByteSize() * 2; + s->Printf("\n%swatchpoint old value:0x%0*.*llx", prefix, num_hex_digits, num_hex_digits, m_snapshot_old_val); + s->Printf("\n%swatchpoint new value:0x%0*.*llx", prefix, num_hex_digits, num_hex_digits, m_snapshot_new_val); + } +} + +void Watchpoint::DumpWithLevel(Stream *s, lldb::DescriptionLevel description_level) const { if (s == NULL) @@ -142,7 +237,11 @@ Watchpoint::DumpWithLevel(Stream *s, lldb::DescriptionLevel description_level) c if (!m_decl_str.empty()) s->Printf("\n declare @ '%s'", m_decl_str.c_str()); if (!m_watch_spec_str.empty()) - s->Printf("\n static watchpoint spec = '%s'", m_watch_spec_str.c_str()); + s->Printf("\n watchpoint spec = '%s'", m_watch_spec_str.c_str()); + + // Dump the snapshots we have taken. + DumpSnapshots(" ", s); + if (GetConditionText()) s->Printf("\n condition = '%s'", GetConditionText()); m_options.GetCallbackDescription(s, description_level); diff --git a/lldb/source/Breakpoint/WatchpointOptions.cpp b/lldb/source/Breakpoint/WatchpointOptions.cpp index 931b7a85e5a..86ea411e4af 100644 --- a/lldb/source/Breakpoint/WatchpointOptions.cpp +++ b/lldb/source/Breakpoint/WatchpointOptions.cpp @@ -168,11 +168,8 @@ WatchpointOptions::GetCallbackDescription (Stream *s, lldb::DescriptionLevel lev { if (m_callback_baton_sp.get()) { - if (level != eDescriptionLevelBrief) - { - s->EOL(); - m_callback_baton_sp->GetDescription (s, level); - } + s->EOL(); + m_callback_baton_sp->GetDescription (s, level); } } void @@ -222,7 +219,7 @@ WatchpointOptions::CommandBaton::GetDescription (Stream *s, lldb::DescriptionLev } s->IndentMore (); - s->Indent("Watchpoint commands:\n"); + s->Indent("watchpoint commands:\n"); s->IndentMore (); if (data && data->user_source.GetSize() > 0) diff --git a/lldb/source/Commands/CommandObjectWatchpoint.cpp b/lldb/source/Commands/CommandObjectWatchpoint.cpp index b545d3ebd27..ff59e318d8d 100644 --- a/lldb/source/Commands/CommandObjectWatchpoint.cpp +++ b/lldb/source/Commands/CommandObjectWatchpoint.cpp @@ -1047,6 +1047,8 @@ protected: error.Clear(); Watchpoint *wp = target->CreateWatchpoint(addr, size, watch_type, error).get(); if (wp) { + wp->SetWatchSpec(command.GetArgumentAtIndex(0)); + wp->SetWatchVariable(true); if (var_sp && var_sp->GetDeclaration().GetFile()) { StreamString ss; // True to show fullpath for declaration file. @@ -1054,13 +1056,15 @@ protected: 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(); result.SetStatus(eReturnStatusSuccessFinishResult); } else { - result.AppendErrorWithFormat("Watchpoint creation failed (addr=0x%llx, size=%lu).\n", - addr, size); + result.AppendErrorWithFormat("Watchpoint creation failed (addr=0x%llx, size=%lu, variable expression='%s').\n", + addr, size, command.GetArgumentAtIndex(0)); if (error.AsCString(NULL)) result.AppendError(error.AsCString()); result.SetStatus(eReturnStatusFailed); @@ -1238,8 +1242,12 @@ protected: var_sp->GetDeclaration().DumpStopContext(&ss, true); wp->SetDeclInfo(ss.GetString()); } - StreamString ss; 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); diff --git a/lldb/source/Target/StopInfo.cpp b/lldb/source/Target/StopInfo.cpp index 96c17394073..a902ee8e9b2 100644 --- a/lldb/source/Target/StopInfo.cpp +++ b/lldb/source/Target/StopInfo.cpp @@ -451,7 +451,7 @@ public: virtual void PerformAction (Event *event_ptr) { - LogSP log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS); + LogSP log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS); // We're going to calculate if we should stop or not in some way during the course of // this code. Also by default we're going to stop, so set that here. m_should_stop = true; @@ -461,11 +461,11 @@ public: if (wp_sp) { ExecutionContext exe_ctx (m_thread.GetStackFrameAtIndex(0)); + Process* process = exe_ctx.GetProcessPtr(); { // check if this process is running on an architecture where watchpoints trigger // before the associated instruction runs. if so, disable the WP, single-step and then // re-enable the watchpoint - Process* process = exe_ctx.GetProcessPtr(); if (process) { uint32_t num; bool wp_triggers_after; @@ -491,7 +491,62 @@ public: } } } - StoppointCallbackContext context (event_ptr, exe_ctx, false); + + // Record the snapshot of our watchpoint. + VariableSP var_sp; + ValueObjectSP valobj_sp; + StackFrame *frame = exe_ctx.GetFramePtr(); + if (frame) + { + if (!wp_sp->IsWatchVariable()) + { + 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()) + { + // Things have checked out ok... + 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 + wp_sp->SetNewSnapshot("snapshot attempt failed."); + + if (log) + log->Printf("Watchpoint snapshot taken: '%s'\n", wp_sp->GetNewSnapshot().c_str()); + } + + // Now dump the snapshots we have 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) { @@ -564,6 +619,7 @@ public: // If the condition says to stop, we run the callback to further decide whether to stop. if (m_should_stop) { + StoppointCallbackContext context (event_ptr, exe_ctx, false); bool stop_requested = wp_sp->InvokeCallback (&context); // Also make sure that the callback hasn't continued the target. // If it did, when we'll set m_should_stop to false and get out of here. diff --git a/lldb/test/functionalities/watchpoint/watchpoint_commands/command/TestWatchpointCommandLLDB.py b/lldb/test/functionalities/watchpoint/watchpoint_commands/command/TestWatchpointCommandLLDB.py index 4f8963b305d..782f04cab92 100644 --- a/lldb/test/functionalities/watchpoint/watchpoint_commands/command/TestWatchpointCommandLLDB.py +++ b/lldb/test/functionalities/watchpoint/watchpoint_commands/command/TestWatchpointCommandLLDB.py @@ -63,11 +63,11 @@ class WatchpointLLDBCommandTestCase(TestBase): substrs = ['Watchpoint created', 'size = 4', 'type = w', '%s:%d' % (self.source, self.decl)]) - self.runCmd('watchpoint command add 1 -o "expr -- global = 777"') + self.runCmd('watchpoint command add 1 -o "expr -- cookie = 777"') # List the watchpoint command we just added. self.expect("watchpoint command list 1", - substrs = ['expr -- global = 777']) + substrs = ['expr -- cookie = 777']) # Use the '-v' option to do verbose listing of the watchpoint. # The hit count should be 0 initially. @@ -81,9 +81,14 @@ class WatchpointLLDBCommandTestCase(TestBase): self.expect("thread backtrace", STOPPED_DUE_TO_WATCHPOINT, substrs = ['stop reason = watchpoint']) - # The watchpoint command "forced" our global variable to become 777. - self.expect("frame variable -g global", - substrs = ['(int32_t)', 'global = 777']) + # Check that the watchpoint snapshoting mechanism is working. + self.expect("watchpoint list -v", + substrs = ['watchpoint old value:', 'global = 0', + 'watchpoint new value:', 'global = 1']) + + # The watchpoint command "forced" our global variable 'cookie' to become 777. + self.expect("frame variable -g cookie", + substrs = ['(int32_t)', 'cookie = 777']) if __name__ == '__main__': diff --git a/lldb/test/functionalities/watchpoint/watchpoint_commands/command/TestWatchpointCommandPython.py b/lldb/test/functionalities/watchpoint/watchpoint_commands/command/TestWatchpointCommandPython.py index 995819e5f2e..3a4cafe5872 100644 --- a/lldb/test/functionalities/watchpoint/watchpoint_commands/command/TestWatchpointCommandPython.py +++ b/lldb/test/functionalities/watchpoint/watchpoint_commands/command/TestWatchpointCommandPython.py @@ -63,11 +63,11 @@ class WatchpointPythonCommandTestCase(TestBase): substrs = ['Watchpoint created', 'size = 4', 'type = w', '%s:%d' % (self.source, self.decl)]) - self.runCmd('watchpoint command add -s python 1 -o \'frame.EvaluateExpression("global = 777")\'') + self.runCmd('watchpoint command add -s python 1 -o \'frame.EvaluateExpression("cookie = 777")\'') # List the watchpoint command we just added. self.expect("watchpoint command list 1", - substrs = ['frame.EvaluateExpression', 'global = 777']) + substrs = ['frame.EvaluateExpression', 'cookie = 777']) # Use the '-v' option to do verbose listing of the watchpoint. # The hit count should be 0 initially. @@ -81,9 +81,14 @@ class WatchpointPythonCommandTestCase(TestBase): self.expect("thread backtrace", STOPPED_DUE_TO_WATCHPOINT, substrs = ['stop reason = watchpoint']) - # The watchpoint command "forced" our global variable to become 777. - self.expect("frame variable -g global", - substrs = ['(int32_t)', 'global = 777']) + # Check that the watchpoint snapshoting mechanism is working. + self.expect("watchpoint list -v", + substrs = ['watchpoint old value:', 'global = 0', + 'watchpoint new value:', 'global = 1']) + + # The watchpoint command "forced" our global variable 'cookie' to become 777. + self.expect("frame variable -g cookie", + substrs = ['(int32_t)', 'cookie = 777']) if __name__ == '__main__': diff --git a/lldb/test/functionalities/watchpoint/watchpoint_commands/command/main.cpp b/lldb/test/functionalities/watchpoint/watchpoint_commands/command/main.cpp index f4c3527f8af..6cb80c62217 100644 --- a/lldb/test/functionalities/watchpoint/watchpoint_commands/command/main.cpp +++ b/lldb/test/functionalities/watchpoint/watchpoint_commands/command/main.cpp @@ -10,6 +10,7 @@ #include <stdint.h> int32_t global = 0; // Watchpoint variable declaration. +int32_t cookie = 0; static void modify(int32_t &var) { ++var; @@ -19,10 +20,9 @@ int main(int argc, char** argv) { int local = 0; printf("&global=%p\n", &global); printf("about to write to 'global'...\n"); // Set break point at this line. - // When stopped, watch 'global', - // for the condition "global == 5". for (int i = 0; i < 10; ++i) modify(global); printf("global=%d\n", global); + printf("cookie=%d\n", cookie); } |

