diff options
author | Johnny Chen <johnny.chen@apple.com> | 2011-09-22 18:04:58 +0000 |
---|---|---|
committer | Johnny Chen <johnny.chen@apple.com> | 2011-09-22 18:04:58 +0000 |
commit | f04ee930a039e5710ca44997f14ddfb96a0ba7e0 (patch) | |
tree | d5fe7a4b782bbc837f122cdf579caa1914414c9e | |
parent | 0542df51982242e98a0f320e8277cad13e201251 (diff) | |
download | bcm5719-llvm-f04ee930a039e5710ca44997f14ddfb96a0ba7e0.tar.gz bcm5719-llvm-f04ee930a039e5710ca44997f14ddfb96a0ba7e0.zip |
Add initial implementation of watchpoint commands for list, enable, disable, and delete.
Test cases to be added later.
llvm-svn: 140322
-rw-r--r-- | lldb/include/lldb/Breakpoint/StoppointLocation.h | 2 | ||||
-rw-r--r-- | lldb/include/lldb/Breakpoint/WatchpointLocation.h | 6 | ||||
-rw-r--r-- | lldb/include/lldb/Breakpoint/WatchpointLocationList.h | 2 | ||||
-rw-r--r-- | lldb/lldb.xcodeproj/project.pbxproj | 6 | ||||
-rw-r--r-- | lldb/source/Breakpoint/WatchpointLocation.cpp | 41 | ||||
-rw-r--r-- | lldb/source/Breakpoint/WatchpointLocationList.cpp | 51 | ||||
-rw-r--r-- | lldb/source/Commands/CommandObjectWatchpoint.cpp | 557 | ||||
-rw-r--r-- | lldb/source/Commands/CommandObjectWatchpoint.h | 145 | ||||
-rw-r--r-- | lldb/source/Interpreter/CommandInterpreter.cpp | 2 | ||||
-rw-r--r-- | lldb/source/Target/Target.cpp | 16 | ||||
-rw-r--r-- | lldb/test/functionalities/watchpoint/hello_watchpoint/TestMyFirstWatchpoint.py | 10 |
11 files changed, 773 insertions, 65 deletions
diff --git a/lldb/include/lldb/Breakpoint/StoppointLocation.h b/lldb/include/lldb/Breakpoint/StoppointLocation.h index 871bb464346..c42ea9f2b97 100644 --- a/lldb/include/lldb/Breakpoint/StoppointLocation.h +++ b/lldb/include/lldb/Breakpoint/StoppointLocation.h @@ -85,7 +85,7 @@ public: return m_hw_preferred; } - bool + virtual bool IsHardware () const { return m_hw_index != LLDB_INVALID_INDEX32; diff --git a/lldb/include/lldb/Breakpoint/WatchpointLocation.h b/lldb/include/lldb/Breakpoint/WatchpointLocation.h index 9362d4ca679..e1f4cdc5203 100644 --- a/lldb/include/lldb/Breakpoint/WatchpointLocation.h +++ b/lldb/include/lldb/Breakpoint/WatchpointLocation.h @@ -41,6 +41,9 @@ public: SetEnabled (bool enabled); virtual bool + IsHardware () const; + + virtual bool ShouldStop (StoppointCallbackContext *context); bool WatchpointRead () const; @@ -55,7 +58,8 @@ public: void DumpWithLevel (Stream *s, lldb::DescriptionLevel description_level) const; private: - bool m_enabled; // Is this breakpoint enabled + bool m_enabled; // Is this watchpoint enabled + bool m_is_hardware; // Is this a hardware watchpoint 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 diff --git a/lldb/include/lldb/Breakpoint/WatchpointLocationList.h b/lldb/include/lldb/Breakpoint/WatchpointLocationList.h index 32ad0998784..16e865c5c7d 100644 --- a/lldb/include/lldb/Breakpoint/WatchpointLocationList.h +++ b/lldb/include/lldb/Breakpoint/WatchpointLocationList.h @@ -224,7 +224,6 @@ public: GetListMutex (lldb_private::Mutex::Locker &locker); protected: - typedef std::vector<lldb::WatchpointLocationSP> collection; typedef std::map<lldb::addr_t, lldb::WatchpointLocationSP> addr_map; addr_map::iterator @@ -233,7 +232,6 @@ protected: addr_map::const_iterator GetIDConstIterator(lldb::watch_id_t watchID) const; - collection m_locations; addr_map m_address_to_location; mutable Mutex m_mutex; }; diff --git a/lldb/lldb.xcodeproj/project.pbxproj b/lldb/lldb.xcodeproj/project.pbxproj index 166b0a4ce51..6308f5a9644 100644 --- a/lldb/lldb.xcodeproj/project.pbxproj +++ b/lldb/lldb.xcodeproj/project.pbxproj @@ -442,6 +442,7 @@ 9AC70390117675270086C050 /* SBInstructionList.h in Headers */ = {isa = PBXBuildFile; fileRef = 9AC7038F117675270086C050 /* SBInstructionList.h */; settings = {ATTRIBUTES = (Public, ); }; }; 9AC703AF117675410086C050 /* SBInstruction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9AC703AE117675410086C050 /* SBInstruction.cpp */; }; 9AC703B1117675490086C050 /* SBInstructionList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9AC703B0117675490086C050 /* SBInstructionList.cpp */; }; + B207C4931429607D00F36E4E /* CommandObjectWatchpoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B207C4921429607D00F36E4E /* CommandObjectWatchpoint.cpp */; }; B2462247141AD37D00F3D409 /* OptionGroupWatchpoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B2462246141AD37D00F3D409 /* OptionGroupWatchpoint.cpp */; }; B271B11413D6139300C3FEDB /* FormatClasses.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94A9112D13D5DF210046D8A6 /* FormatClasses.cpp */; }; B27318421416AC12006039C8 /* WatchpointLocationList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B27318411416AC12006039C8 /* WatchpointLocationList.cpp */; }; @@ -1304,6 +1305,8 @@ AF68D32F1255A110002FF25B /* UnwindLLDB.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = UnwindLLDB.cpp; path = Utility/UnwindLLDB.cpp; sourceTree = "<group>"; }; AF68D3301255A110002FF25B /* UnwindLLDB.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = UnwindLLDB.h; path = Utility/UnwindLLDB.h; sourceTree = "<group>"; }; AF94005711C03F6500085DB9 /* SymbolVendor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SymbolVendor.cpp; path = source/Symbol/SymbolVendor.cpp; sourceTree = "<group>"; }; + B207C4921429607D00F36E4E /* CommandObjectWatchpoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommandObjectWatchpoint.cpp; path = source/Commands/CommandObjectWatchpoint.cpp; sourceTree = "<group>"; }; + B207C4941429609C00F36E4E /* CommandObjectWatchpoint.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = CommandObjectWatchpoint.h; path = source/Commands/CommandObjectWatchpoint.h; sourceTree = "<group>"; }; B23DD24F12EDFAC1000C3894 /* ARMUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ARMUtils.h; path = Utility/ARMUtils.h; sourceTree = "<group>"; }; B2462246141AD37D00F3D409 /* OptionGroupWatchpoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = OptionGroupWatchpoint.cpp; path = source/Interpreter/OptionGroupWatchpoint.cpp; sourceTree = "<group>"; }; B2462248141AD39B00F3D409 /* OptionGroupWatchpoint.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = OptionGroupWatchpoint.h; path = include/lldb/Interpreter/OptionGroupWatchpoint.h; sourceTree = "<group>"; }; @@ -2257,6 +2260,8 @@ 9463D4CC13B1798800C230D4 /* CommandObjectType.cpp */, B296983512C2FB2B002D92C3 /* CommandObjectVersion.h */, B296983412C2FB2B002D92C3 /* CommandObjectVersion.cpp */, + B207C4941429609C00F36E4E /* CommandObjectWatchpoint.h */, + B207C4921429607D00F36E4E /* CommandObjectWatchpoint.cpp */, ); name = Commands; sourceTree = "<group>"; @@ -3384,6 +3389,7 @@ B2462247141AD37D00F3D409 /* OptionGroupWatchpoint.cpp in Sources */, 49A71FE7141FFA5C00D59478 /* IRInterpreter.cpp in Sources */, 49A71FE8141FFACF00D59478 /* DataEncoder.cpp in Sources */, + B207C4931429607D00F36E4E /* CommandObjectWatchpoint.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/lldb/source/Breakpoint/WatchpointLocation.cpp b/lldb/source/Breakpoint/WatchpointLocation.cpp index e0c14edfff2..a0bbc037d5c 100644 --- a/lldb/source/Breakpoint/WatchpointLocation.cpp +++ b/lldb/source/Breakpoint/WatchpointLocation.cpp @@ -21,6 +21,7 @@ using namespace lldb_private; WatchpointLocation::WatchpointLocation (lldb::addr_t addr, size_t size, bool hardware) : StoppointLocation (GetNextID(), addr, size, hardware), m_enabled(0), + m_is_hardware(hardware), m_watch_read(0), m_watch_write(0), m_watch_was_read(0), @@ -58,28 +59,36 @@ WatchpointLocation::SetDeclInfo (std::string &str) } +bool +WatchpointLocation::IsHardware () const +{ + return m_is_hardware; +} + // RETURNS - true if we should stop at this breakpoint, false if we // should continue. bool WatchpointLocation::ShouldStop (StoppointCallbackContext *context) { - m_hit_count++; - - if (m_hit_count > m_ignore_count) - { - uint32_t access = 0; - if (m_watch_was_read) - access |= LLDB_WATCH_TYPE_READ; - if (m_watch_was_written) - access |= LLDB_WATCH_TYPE_WRITE; - - if (m_callback) - return m_callback(m_callback_baton, context, GetID(), access); - else - return true; - } - return false; + ++m_hit_count; + + if (!IsEnabled()) + return false; + + if (m_hit_count <= GetIgnoreCount()) + return false; + + uint32_t access = 0; + if (m_watch_was_read) + access |= LLDB_WATCH_TYPE_READ; + if (m_watch_was_written) + access |= LLDB_WATCH_TYPE_WRITE; + + if (m_callback) + return m_callback(m_callback_baton, context, GetID(), access); + else + return true; } void diff --git a/lldb/source/Breakpoint/WatchpointLocationList.cpp b/lldb/source/Breakpoint/WatchpointLocationList.cpp index 4e6dbb782a3..ac466fa4f02 100644 --- a/lldb/source/Breakpoint/WatchpointLocationList.cpp +++ b/lldb/source/Breakpoint/WatchpointLocationList.cpp @@ -20,7 +20,6 @@ using namespace lldb; using namespace lldb_private; WatchpointLocationList::WatchpointLocationList() : - m_locations (), m_address_to_location (), m_mutex (Mutex::eMutexTypeRecursive) { @@ -41,21 +40,10 @@ WatchpointLocationList::Add (const WatchpointLocationSP &wp_loc_sp) addr_map::iterator iter = m_address_to_location.find(wp_addr); if (iter == m_address_to_location.end()) - { m_address_to_location.insert(iter, addr_map::value_type(wp_addr, wp_loc_sp)); - } else - { m_address_to_location[wp_addr] = wp_loc_sp; - collection::iterator pos, end = m_locations.end(); - for (pos = m_locations.begin(); pos != end; ++pos) - if ((*pos)->GetLoadAddress() == wp_addr) - { - m_locations.erase(pos); - break; - } - } - m_locations.push_back(wp_loc_sp); + return wp_loc_sp->GetID(); } @@ -154,9 +142,12 @@ WatchpointLocationList::GetByIndex (uint32_t i) { Mutex::Locker locker (m_mutex); WatchpointLocationSP wp_loc_sp; - if (i < m_locations.size()) - wp_loc_sp = m_locations[i]; - + if (i < m_address_to_location.size()) + { + addr_map::const_iterator pos = m_address_to_location.begin(); + std::advance(pos, i); + wp_loc_sp = pos->second; + } return wp_loc_sp; } @@ -165,9 +156,12 @@ WatchpointLocationList::GetByIndex (uint32_t i) const { Mutex::Locker locker (m_mutex); WatchpointLocationSP wp_loc_sp; - if (i < m_locations.size()) - wp_loc_sp = m_locations[i]; - + if (i < m_address_to_location.size()) + { + addr_map::const_iterator pos = m_address_to_location.begin(); + std::advance(pos, i); + wp_loc_sp = pos->second; + } return wp_loc_sp; } @@ -175,17 +169,10 @@ bool WatchpointLocationList::Remove (lldb::watch_id_t watch_id) { Mutex::Locker locker (m_mutex); - addr_map::iterator pos = GetIDIterator(watch_id); // Predicate + addr_map::iterator pos = GetIDIterator(watch_id); if (pos != m_address_to_location.end()) { m_address_to_location.erase(pos); - collection::iterator pos, end = m_locations.end(); - for (pos = m_locations.begin(); pos != end; ++pos) - if ((*pos)->GetID() == watch_id) - { - m_locations.erase(pos); - break; - } return true; } return false; @@ -205,6 +192,7 @@ WatchpointLocationList::GetHitCount () const bool WatchpointLocationList::ShouldStop (StoppointCallbackContext *context, lldb::watch_id_t watch_id) { + WatchpointLocationSP wp_loc_sp = FindByID (watch_id); if (wp_loc_sp) { @@ -245,14 +233,7 @@ void WatchpointLocationList::RemoveAll () { Mutex::Locker locker(m_mutex); - - addr_map::iterator pos, end = m_address_to_location.end(); - for (pos = m_address_to_location.begin(); pos != end; ++pos) - m_address_to_location.erase(pos); - - collection::iterator p, e = m_locations.end(); - for (p = m_locations.begin(); p != e; ++pos) - m_locations.erase(p); + m_address_to_location.clear(); } void diff --git a/lldb/source/Commands/CommandObjectWatchpoint.cpp b/lldb/source/Commands/CommandObjectWatchpoint.cpp new file mode 100644 index 00000000000..aa3c8e82ddd --- /dev/null +++ b/lldb/source/Commands/CommandObjectWatchpoint.cpp @@ -0,0 +1,557 @@ +//===-- CommandObjectWatchpoint.cpp -----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "CommandObjectWatchpoint.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Breakpoint/WatchpointLocation.h" +#include "lldb/Breakpoint/WatchpointLocationList.h" +#include "lldb/Core/StreamString.h" +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Target/Target.h" +#include "lldb/Interpreter/CommandCompletions.h" + +#include <vector> + +using namespace lldb; +using namespace lldb_private; + +static void +AddWatchpointDescription(Stream *s, WatchpointLocation *wp_loc, lldb::DescriptionLevel level) +{ + s->IndentMore(); + wp_loc->GetDescription(s, level); + s->IndentLess(); + s->EOL(); +} + +static bool +CheckTargetForWatchpointOperations(Target *target, CommandReturnObject &result) +{ + if (target == NULL) + { + result.AppendError ("Invalid target. No existing target or watchpoints."); + result.SetStatus (eReturnStatusFailed); + return false; + } + bool process_is_valid = target->GetProcessSP() && target->GetProcessSP()->IsAlive(); + if (!process_is_valid) + { + result.AppendError ("Thre's no process or it is not alive."); + result.SetStatus (eReturnStatusFailed); + return false; + } + // Target passes our checks, return true. + return true; +} + +#include "llvm/ADT/StringRef.h" + +// Equivalent class: {"-", "to", "To", "TO"} of range specifier array. +static const char* RSA[4] = { "-", "to", "To", "TO" }; + +// Return the index to RSA if found; otherwise -1 is returned. +static int32_t +WithRSAIndex(llvm::StringRef &Arg) +{ + + uint32_t i; + for (i = 0; i < 4; ++i) + if (Arg.find(RSA[i]) != llvm::StringRef::npos) + return i; + return -1; +} + +// Return true if wp_ids is successfully populated with the watch ids. +// False otherwise. +static bool +VerifyWatchpointIDs(Args &args, std::vector<uint32_t> &wp_ids) +{ + // Pre-condition: args.GetArgumentCount() > 0. + assert(args.GetArgumentCount() > 0); + + llvm::StringRef Minus("-"); + std::vector<llvm::StringRef> StrRefArgs; + std::pair<llvm::StringRef, llvm::StringRef> Pair; + size_t i; + int32_t idx; + // Go through the argments and make a canonical form of arg list containing + // only numbers with possible "-" in between. + for (i = 0; i < args.GetArgumentCount(); ++i) { + llvm::StringRef Arg(args.GetArgumentAtIndex(i)); + if ((idx = WithRSAIndex(Arg)) == -1) { + StrRefArgs.push_back(Arg); + continue; + } + // The Arg contains the range specifier, split it, then. + Pair = Arg.split(RSA[idx]); + if (!Pair.first.empty()) + StrRefArgs.push_back(Pair.first); + StrRefArgs.push_back(Minus); + if (!Pair.second.empty()) + StrRefArgs.push_back(Pair.second); + } + // Now process the canonical list and fill in the vector of uint32_t's. + // If there is any error, return false and the client should ignore wp_ids. + uint32_t beg, end, id; + size_t size = StrRefArgs.size(); + bool in_range = false; + for (i = 0; i < size; ++i) { + llvm::StringRef Arg = StrRefArgs[i]; + if (in_range) { + // Look for the 'end' of the range. Note StringRef::getAsInteger() + // returns true to signify error while parsing. + if (Arg.getAsInteger(0, end)) + return false; + // Found a range! Now append the elements. + for (id = beg; id <= end; ++id) + wp_ids.push_back(id); + in_range = false; + continue; + } + if (i < (size - 1) && StrRefArgs[i+1] == Minus) { + if (Arg.getAsInteger(0, beg)) + return false; + // Turn on the in_range flag, we are looking for end of range next. + ++i; in_range = true; + continue; + } + // Otherwise, we have a simple ID. Just append it. + if (Arg.getAsInteger(0, beg)) + return false; + wp_ids.push_back(beg); + } + // It is an error if after the loop, we're still in_range. + if (in_range) + return false; + + return true; // Success! +} + +//------------------------------------------------------------------------- +// CommandObjectMultiwordWatchpoint +//------------------------------------------------------------------------- +#pragma mark MultiwordWatchpoint + +CommandObjectMultiwordWatchpoint::CommandObjectMultiwordWatchpoint(CommandInterpreter &interpreter) : + CommandObjectMultiword (interpreter, + "watchpoint", + "A set of commands for operating on watchpoints.", + "watchpoint <command> [<command-options>]") +{ + bool status; + + CommandObjectSP list_command_object (new CommandObjectWatchpointList (interpreter)); + CommandObjectSP enable_command_object (new CommandObjectWatchpointEnable (interpreter)); + CommandObjectSP disable_command_object (new CommandObjectWatchpointDisable (interpreter)); + CommandObjectSP delete_command_object (new CommandObjectWatchpointDelete (interpreter)); + + list_command_object->SetCommandName ("watchpoint list"); + enable_command_object->SetCommandName("watchpoint enable"); + disable_command_object->SetCommandName("watchpoint disable"); + delete_command_object->SetCommandName("watchpoint delete"); + + status = LoadSubCommand ("list", list_command_object); + status = LoadSubCommand ("enable", enable_command_object); + status = LoadSubCommand ("disable", disable_command_object); + status = LoadSubCommand ("delete", delete_command_object); +} + +CommandObjectMultiwordWatchpoint::~CommandObjectMultiwordWatchpoint() +{ +} + +//------------------------------------------------------------------------- +// CommandObjectWatchpointList::Options +//------------------------------------------------------------------------- +#pragma mark List::CommandOptions + +CommandObjectWatchpointList::CommandOptions::CommandOptions(CommandInterpreter &interpreter) : + Options(interpreter), + m_level(lldb::eDescriptionLevelBrief) // Watchpoint List defaults to brief descriptions +{ +} + +CommandObjectWatchpointList::CommandOptions::~CommandOptions() +{ +} + +OptionDefinition +CommandObjectWatchpointList::CommandOptions::g_option_table[] = +{ + { LLDB_OPT_SET_1, false, "brief", 'b', no_argument, NULL, 0, eArgTypeNone, + "Give a brief description of the watchpoint (no location info)."}, + + { LLDB_OPT_SET_2, false, "full", 'f', no_argument, NULL, 0, eArgTypeNone, + "Give a full description of the watchpoint and its locations."}, + + { LLDB_OPT_SET_3, false, "verbose", 'v', no_argument, NULL, 0, eArgTypeNone, + "Explain everything we know about the watchpoint (for debugging debugger bugs)." }, + + { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL } +}; + +const OptionDefinition* +CommandObjectWatchpointList::CommandOptions::GetDefinitions() +{ + return g_option_table; +} + +Error +CommandObjectWatchpointList::CommandOptions::SetOptionValue(uint32_t option_idx, const char *option_arg) +{ + Error error; + char short_option = (char) m_getopt_table[option_idx].val; + + switch (short_option) + { + case 'b': + m_level = lldb::eDescriptionLevelBrief; + break; + case 'f': + m_level = lldb::eDescriptionLevelFull; + break; + case 'v': + m_level = lldb::eDescriptionLevelVerbose; + break; + default: + error.SetErrorStringWithFormat("Unrecognized option '%c'.\n", short_option); + break; + } + + return error; +} + +void +CommandObjectWatchpointList::CommandOptions::OptionParsingStarting() +{ + m_level = lldb::eDescriptionLevelFull; +} + +//------------------------------------------------------------------------- +// CommandObjectWatchpointList +//------------------------------------------------------------------------- +#pragma mark List + +CommandObjectWatchpointList::CommandObjectWatchpointList(CommandInterpreter &interpreter) : + CommandObject(interpreter, + "watchpoint list", + "List all watchpoints at configurable levels of detail.", + NULL), + m_options(interpreter) +{ + CommandArgumentEntry arg; + CommandObject::AddIDsArgumentData(arg); + // Add the entry for the first argument for this command to the object's arguments vector. + m_arguments.push_back(arg); +} + +CommandObjectWatchpointList::~CommandObjectWatchpointList() +{ +} + +Options * +CommandObjectWatchpointList::GetOptions() +{ + return &m_options; +} + +bool +CommandObjectWatchpointList::Execute(Args& args, CommandReturnObject &result) +{ + Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); + if (target == NULL) + { + result.AppendError ("Invalid target. No current target or watchpoints."); + result.SetStatus (eReturnStatusSuccessFinishNoResult); + return true; + } + + const WatchpointLocationList &watchpoints = target->GetWatchpointLocationList(); + Mutex::Locker locker; + target->GetWatchpointLocationList().GetListMutex(locker); + + size_t num_watchpoints = watchpoints.GetSize(); + + if (num_watchpoints == 0) + { + result.AppendMessage("No watchpoints currently set."); + result.SetStatus(eReturnStatusSuccessFinishNoResult); + return true; + } + + Stream &output_stream = result.GetOutputStream(); + + if (args.GetArgumentCount() == 0) + { + // No watchpoint selected; show info about all currently set watchpoints. + result.AppendMessage ("Current watchpoints:"); + for (size_t i = 0; i < num_watchpoints; ++i) + { + WatchpointLocation *wp_loc = watchpoints.GetByIndex(i).get(); + AddWatchpointDescription(&output_stream, wp_loc, m_options.m_level); + } + result.SetStatus(eReturnStatusSuccessFinishNoResult); + } + else + { + // Particular watchpoints selected; enable them. + std::vector<uint32_t> wp_ids; + if (!VerifyWatchpointIDs(args, wp_ids)) + { + result.AppendError("Invalid watchpoints specification."); + result.SetStatus(eReturnStatusFailed); + return false; + } + + const size_t size = wp_ids.size(); + for (size_t i = 0; i < size; ++i) + { + WatchpointLocation *wp_loc = watchpoints.FindByID(wp_ids[i]).get(); + if (wp_loc) + AddWatchpointDescription(&output_stream, wp_loc, m_options.m_level); + result.SetStatus(eReturnStatusSuccessFinishNoResult); + } + } + + return result.Succeeded(); +} + +//------------------------------------------------------------------------- +// CommandObjectWatchpointEnable +//------------------------------------------------------------------------- +#pragma mark Enable + +CommandObjectWatchpointEnable::CommandObjectWatchpointEnable(CommandInterpreter &interpreter) : + CommandObject(interpreter, + "enable", + "Enable the specified disabled watchpoint(s). If no watchpoints are specified, enable all of them.", + NULL) +{ + CommandArgumentEntry arg; + CommandObject::AddIDsArgumentData(arg); + // Add the entry for the first argument for this command to the object's arguments vector. + m_arguments.push_back(arg); +} + +CommandObjectWatchpointEnable::~CommandObjectWatchpointEnable() +{ +} + +bool +CommandObjectWatchpointEnable::Execute(Args& args, CommandReturnObject &result) +{ + Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); + if (!CheckTargetForWatchpointOperations(target, result)) + return false; + + Mutex::Locker locker; + target->GetWatchpointLocationList().GetListMutex(locker); + + const WatchpointLocationList &watchpoints = target->GetWatchpointLocationList(); + + size_t num_watchpoints = watchpoints.GetSize(); + + if (num_watchpoints == 0) + { + result.AppendError("No watchpoints exist to be enabled."); + result.SetStatus(eReturnStatusFailed); + return false; + } + + if (args.GetArgumentCount() == 0) + { + // No watchpoint selected; enable all currently set watchpoints. + target->EnableAllWatchpointLocations(); + result.AppendMessageWithFormat("All watchpoints enabled. (%lu watchpoints)\n", num_watchpoints); + result.SetStatus(eReturnStatusSuccessFinishNoResult); + } + else + { + // Particular watchpoints selected; enable them. + std::vector<uint32_t> wp_ids; + if (!VerifyWatchpointIDs(args, wp_ids)) + { + result.AppendError("Invalid watchpoints specification."); + result.SetStatus(eReturnStatusFailed); + return false; + } + + int count = 0; + const size_t size = wp_ids.size(); + for (size_t i = 0; i < size; ++i) + if (target->EnableWatchpointLocationByID(wp_ids[i])) + ++count; + result.AppendMessageWithFormat("%d watchpoints enabled.\n", count); + result.SetStatus(eReturnStatusSuccessFinishNoResult); + } + + return result.Succeeded(); +} + +//------------------------------------------------------------------------- +// CommandObjectWatchpointDisable +//------------------------------------------------------------------------- +#pragma mark Disable + +CommandObjectWatchpointDisable::CommandObjectWatchpointDisable(CommandInterpreter &interpreter) : + CommandObject(interpreter, + "watchpoint disable", + "Disable the specified watchpoint(s) without removing it/them. If no watchpoints are specified, disable them all.", + NULL) +{ + CommandArgumentEntry arg; + CommandObject::AddIDsArgumentData(arg); + // Add the entry for the first argument for this command to the object's arguments vector. + m_arguments.push_back(arg); +} + +CommandObjectWatchpointDisable::~CommandObjectWatchpointDisable() +{ +} + +bool +CommandObjectWatchpointDisable::Execute(Args& args, CommandReturnObject &result) +{ + Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); + if (!CheckTargetForWatchpointOperations(target, result)) + return false; + + Mutex::Locker locker; + target->GetWatchpointLocationList().GetListMutex(locker); + + const WatchpointLocationList &watchpoints = target->GetWatchpointLocationList(); + size_t num_watchpoints = watchpoints.GetSize(); + + if (num_watchpoints == 0) + { + result.AppendError("No watchpoints exist to be disabled."); + result.SetStatus(eReturnStatusFailed); + return false; + } + + if (args.GetArgumentCount() == 0) + { + // No watchpoint selected; disable all currently set watchpoints. + if (target->DisableAllWatchpointLocations()) + { + result.AppendMessageWithFormat("All watchpoints disabled. (%lu watchpoints)\n", num_watchpoints); + result.SetStatus(eReturnStatusSuccessFinishNoResult); + } + else + { + result.AppendError("Disable all watchpoints failed\n"); + result.SetStatus(eReturnStatusFailed); + } + } + else + { + // Particular watchpoints selected; disable them. + std::vector<uint32_t> wp_ids; + if (!VerifyWatchpointIDs(args, wp_ids)) + { + result.AppendError("Invalid watchpoints specification."); + result.SetStatus(eReturnStatusFailed); + return false; + } + + int count = 0; + const size_t size = wp_ids.size(); + for (size_t i = 0; i < size; ++i) + if (target->DisableWatchpointLocationByID(wp_ids[i])) + ++count; + result.AppendMessageWithFormat("%d watchpoints disabled.\n", count); + result.SetStatus(eReturnStatusSuccessFinishNoResult); + } + + return result.Succeeded(); +} + +//------------------------------------------------------------------------- +// CommandObjectWatchpointDelete +//------------------------------------------------------------------------- +#pragma mark Delete + +CommandObjectWatchpointDelete::CommandObjectWatchpointDelete(CommandInterpreter &interpreter) : + CommandObject(interpreter, + "watchpoint delete", + "Delete the specified watchpoint(s). If no watchpoints are specified, delete them all.", + NULL) +{ + CommandArgumentEntry arg; + CommandObject::AddIDsArgumentData(arg); + // Add the entry for the first argument for this command to the object's arguments vector. + m_arguments.push_back(arg); +} + +CommandObjectWatchpointDelete::~CommandObjectWatchpointDelete() +{ +} + +bool +CommandObjectWatchpointDelete::Execute(Args& args, CommandReturnObject &result) +{ + Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); + if (!CheckTargetForWatchpointOperations(target, result)) + return false; + + Mutex::Locker locker; + target->GetWatchpointLocationList().GetListMutex(locker); + + const WatchpointLocationList &watchpoints = target->GetWatchpointLocationList(); + + size_t num_watchpoints = watchpoints.GetSize(); + + if (num_watchpoints == 0) + { + result.AppendError("No watchpoints exist to be deleted."); + result.SetStatus(eReturnStatusFailed); + return false; + } + + if (args.GetArgumentCount() == 0) + { + if (!m_interpreter.Confirm("About to delete all watchpoints, do you want to do that?", true)) + { + result.AppendMessage("Operation cancelled..."); + } + else + { + target->RemoveAllWatchpointLocations(); + result.AppendMessageWithFormat("All watchpoints removed. (%lu watchpoints)\n", num_watchpoints); + } + result.SetStatus (eReturnStatusSuccessFinishNoResult); + } + else + { + // Particular watchpoints selected; delete them. + std::vector<uint32_t> wp_ids; + if (!VerifyWatchpointIDs(args, wp_ids)) + { + result.AppendError("Invalid watchpoints specification."); + result.SetStatus(eReturnStatusFailed); + return false; + } + + int count = 0; + const size_t size = wp_ids.size(); + for (size_t i = 0; i < size; ++i) + if (target->RemoveWatchpointLocationByID(wp_ids[i])) + ++count; + result.AppendMessageWithFormat("%d watchpoints deleted.\n",count); + result.SetStatus (eReturnStatusSuccessFinishNoResult); + } + + return result.Succeeded(); +} + diff --git a/lldb/source/Commands/CommandObjectWatchpoint.h b/lldb/source/Commands/CommandObjectWatchpoint.h new file mode 100644 index 00000000000..fd5beedd5e0 --- /dev/null +++ b/lldb/source/Commands/CommandObjectWatchpoint.h @@ -0,0 +1,145 @@ +//===-- CommandObjectWatchpoint.h -------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_CommandObjectWatchpoint_h_ +#define liblldb_CommandObjectWatchpoint_h_ + +// C Includes +// C++ Includes + +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/CommandObjectMultiword.h" +#include "lldb/Interpreter/Options.h" + +namespace lldb_private { + +//------------------------------------------------------------------------- +// CommandObjectMultiwordWatchpoint +//------------------------------------------------------------------------- + +class CommandObjectMultiwordWatchpoint : public CommandObjectMultiword +{ +public: + CommandObjectMultiwordWatchpoint (CommandInterpreter &interpreter); + + virtual + ~CommandObjectMultiwordWatchpoint (); +}; + +//------------------------------------------------------------------------- +// CommandObjectWatchpointList +//------------------------------------------------------------------------- + +class CommandObjectWatchpointList : public CommandObject +{ +public: + CommandObjectWatchpointList (CommandInterpreter &interpreter); + + virtual + ~CommandObjectWatchpointList (); + + virtual bool + Execute (Args& command, + CommandReturnObject &result); + + virtual Options * + GetOptions (); + + class CommandOptions : public Options + { + public: + + CommandOptions (CommandInterpreter &interpreter); + + virtual + ~CommandOptions (); + + virtual Error + SetOptionValue (uint32_t option_idx, const char *option_arg); + + void + OptionParsingStarting (); + + const OptionDefinition * + GetDefinitions (); + + // Options table: Required for subclasses of Options. + + static OptionDefinition g_option_table[]; + + // Instance variables to hold the values for command options. + + lldb::DescriptionLevel m_level; + }; + +private: + CommandOptions m_options; +}; + +//------------------------------------------------------------------------- +// CommandObjectWatchpointEnable +//------------------------------------------------------------------------- + +class CommandObjectWatchpointEnable : public CommandObject +{ +public: + CommandObjectWatchpointEnable (CommandInterpreter &interpreter); + + virtual + ~CommandObjectWatchpointEnable (); + + virtual bool + Execute (Args& command, + CommandReturnObject &result); + +private: +}; + +//------------------------------------------------------------------------- +// CommandObjectWatchpointDisable +//------------------------------------------------------------------------- + +class CommandObjectWatchpointDisable : public CommandObject +{ +public: + CommandObjectWatchpointDisable (CommandInterpreter &interpreter); + + virtual + ~CommandObjectWatchpointDisable (); + + virtual bool + Execute (Args& command, + CommandReturnObject &result); + +private: +}; + +//------------------------------------------------------------------------- +// CommandObjectWatchpointDelete +//------------------------------------------------------------------------- + +class CommandObjectWatchpointDelete : public CommandObject +{ +public: + CommandObjectWatchpointDelete (CommandInterpreter &interpreter); + + virtual + ~CommandObjectWatchpointDelete (); + + virtual bool + Execute (Args& command, + CommandReturnObject &result); + +private: +}; + +} // namespace lldb_private + +#endif // liblldb_CommandObjectWatchpoint_h_ diff --git a/lldb/source/Interpreter/CommandInterpreter.cpp b/lldb/source/Interpreter/CommandInterpreter.cpp index 4b4c79a5587..b3b1d3050b0 100644 --- a/lldb/source/Interpreter/CommandInterpreter.cpp +++ b/lldb/source/Interpreter/CommandInterpreter.cpp @@ -37,6 +37,7 @@ #include "../Commands/CommandObjectThread.h" #include "../Commands/CommandObjectType.h" #include "../Commands/CommandObjectVersion.h" +#include "../Commands/CommandObjectWatchpoint.h" #include "lldb/Interpreter/Args.h" #include "lldb/Interpreter/Options.h" @@ -266,6 +267,7 @@ CommandInterpreter::LoadCommandDictionary () m_command_dict["thread"] = CommandObjectSP (new CommandObjectMultiwordThread (*this)); m_command_dict["type"] = CommandObjectSP (new CommandObjectType (*this)); m_command_dict["version"] = CommandObjectSP (new CommandObjectVersion (*this)); + m_command_dict["watchpoint"]= CommandObjectSP (new CommandObjectMultiwordWatchpoint (*this)); std::auto_ptr<CommandObjectRegexCommand> break_regex_cmd_ap(new CommandObjectRegexCommand (*this, diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp index 7fc9257af92..9f9f4a7b1cd 100644 --- a/lldb/source/Target/Target.cpp +++ b/lldb/source/Target/Target.cpp @@ -586,7 +586,6 @@ Target::DisableAllWatchpointLocations () if (rc.Fail()) return false; } - m_watchpoint_location_list.SetEnabledAll (false); return true; // Success! } @@ -612,7 +611,6 @@ Target::EnableAllWatchpointLocations () if (rc.Fail()) return false; } - m_watchpoint_location_list.SetEnabledAll (true); return true; // Success! } @@ -631,11 +629,10 @@ Target::DisableWatchpointLocationByID (lldb::watch_id_t watch_id) if (wp_loc_sp) { Error rc = m_process_sp->DisableWatchpoint(wp_loc_sp.get()); - if (rc.Fail()) - return false; + if (rc.Success()) + return true; - wp_loc_sp->SetEnabled (false); - return true; + // Else, fallthrough. } return false; } @@ -655,11 +652,10 @@ Target::EnableWatchpointLocationByID (lldb::watch_id_t watch_id) if (wp_loc_sp) { Error rc = m_process_sp->EnableWatchpoint(wp_loc_sp.get()); - if (rc.Fail()) - return false; + if (rc.Success()) + return true; - wp_loc_sp->SetEnabled (true); - return true; + // Else, fallthrough. } return false; } diff --git a/lldb/test/functionalities/watchpoint/hello_watchpoint/TestMyFirstWatchpoint.py b/lldb/test/functionalities/watchpoint/hello_watchpoint/TestMyFirstWatchpoint.py index 4d4d42f5777..5cb8eeb2ca2 100644 --- a/lldb/test/functionalities/watchpoint/hello_watchpoint/TestMyFirstWatchpoint.py +++ b/lldb/test/functionalities/watchpoint/hello_watchpoint/TestMyFirstWatchpoint.py @@ -62,6 +62,11 @@ class HelloWatchpointTestCase(TestBase): substrs = ['Watchpoint created', 'size = 4', 'type = w', '%s:%d' % (self.source, self.decl)]) + # Use the '-v' option to do verbose listing of the watchpoint. + # The hit count should be 0 initially. + self.expect("watchpoint list -v", + substrs = ['hit_count = 0']) + self.runCmd("process continue") # We should be stopped again due to the watchpoint (write type), but @@ -76,6 +81,11 @@ class HelloWatchpointTestCase(TestBase): self.expect("process status", substrs = ['exited']) + # Use the '-v' option to do verbose listing of the watchpoint. + # The hit count should now be 1. + self.expect("watchpoint list -v", + substrs = ['hit_count = 1']) + if __name__ == '__main__': import atexit |