1dda28197Spatrick //===-- CommandObjectWatchpoint.cpp ---------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick 
9061da546Spatrick #include "CommandObjectWatchpoint.h"
10061da546Spatrick #include "CommandObjectWatchpointCommand.h"
11061da546Spatrick 
12061da546Spatrick #include <vector>
13061da546Spatrick 
14061da546Spatrick #include "llvm/ADT/StringRef.h"
15061da546Spatrick 
16061da546Spatrick #include "lldb/Breakpoint/Watchpoint.h"
17061da546Spatrick #include "lldb/Breakpoint/WatchpointList.h"
18061da546Spatrick #include "lldb/Core/ValueObject.h"
19061da546Spatrick #include "lldb/Host/OptionParser.h"
20061da546Spatrick #include "lldb/Interpreter/CommandInterpreter.h"
21*f6aab3d8Srobert #include "lldb/Interpreter/CommandOptionArgumentTable.h"
22061da546Spatrick #include "lldb/Interpreter/CommandReturnObject.h"
23061da546Spatrick #include "lldb/Symbol/Variable.h"
24061da546Spatrick #include "lldb/Symbol/VariableList.h"
25061da546Spatrick #include "lldb/Target/StackFrame.h"
26061da546Spatrick #include "lldb/Target/Target.h"
27061da546Spatrick #include "lldb/Utility/StreamString.h"
28061da546Spatrick 
29061da546Spatrick using namespace lldb;
30061da546Spatrick using namespace lldb_private;
31061da546Spatrick 
AddWatchpointDescription(Stream * s,Watchpoint * wp,lldb::DescriptionLevel level)32061da546Spatrick static void AddWatchpointDescription(Stream *s, Watchpoint *wp,
33061da546Spatrick                                      lldb::DescriptionLevel level) {
34061da546Spatrick   s->IndentMore();
35061da546Spatrick   wp->GetDescription(s, level);
36061da546Spatrick   s->IndentLess();
37061da546Spatrick   s->EOL();
38061da546Spatrick }
39061da546Spatrick 
CheckTargetForWatchpointOperations(Target * target,CommandReturnObject & result)40061da546Spatrick static bool CheckTargetForWatchpointOperations(Target *target,
41061da546Spatrick                                                CommandReturnObject &result) {
42061da546Spatrick   bool process_is_valid =
43061da546Spatrick       target->GetProcessSP() && target->GetProcessSP()->IsAlive();
44061da546Spatrick   if (!process_is_valid) {
45dda28197Spatrick     result.AppendError("There's no process or it is not alive.");
46061da546Spatrick     return false;
47061da546Spatrick   }
48061da546Spatrick   // Target passes our checks, return true.
49061da546Spatrick   return true;
50061da546Spatrick }
51061da546Spatrick 
52061da546Spatrick // Equivalent class: {"-", "to", "To", "TO"} of range specifier array.
53061da546Spatrick static const char *RSA[4] = {"-", "to", "To", "TO"};
54061da546Spatrick 
55061da546Spatrick // Return the index to RSA if found; otherwise -1 is returned.
WithRSAIndex(llvm::StringRef Arg)56061da546Spatrick static int32_t WithRSAIndex(llvm::StringRef Arg) {
57061da546Spatrick 
58061da546Spatrick   uint32_t i;
59061da546Spatrick   for (i = 0; i < 4; ++i)
60*f6aab3d8Srobert     if (Arg.contains(RSA[i]))
61061da546Spatrick       return i;
62061da546Spatrick   return -1;
63061da546Spatrick }
64061da546Spatrick 
65061da546Spatrick // Return true if wp_ids is successfully populated with the watch ids. False
66061da546Spatrick // otherwise.
VerifyWatchpointIDs(Target * target,Args & args,std::vector<uint32_t> & wp_ids)67061da546Spatrick bool CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(
68061da546Spatrick     Target *target, Args &args, std::vector<uint32_t> &wp_ids) {
69061da546Spatrick   // Pre-condition: args.GetArgumentCount() > 0.
70061da546Spatrick   if (args.GetArgumentCount() == 0) {
71061da546Spatrick     if (target == nullptr)
72061da546Spatrick       return false;
73061da546Spatrick     WatchpointSP watch_sp = target->GetLastCreatedWatchpoint();
74061da546Spatrick     if (watch_sp) {
75061da546Spatrick       wp_ids.push_back(watch_sp->GetID());
76061da546Spatrick       return true;
77061da546Spatrick     } else
78061da546Spatrick       return false;
79061da546Spatrick   }
80061da546Spatrick 
81061da546Spatrick   llvm::StringRef Minus("-");
82061da546Spatrick   std::vector<llvm::StringRef> StrRefArgs;
83061da546Spatrick   llvm::StringRef first;
84061da546Spatrick   llvm::StringRef second;
85061da546Spatrick   size_t i;
86061da546Spatrick   int32_t idx;
87061da546Spatrick   // Go through the arguments and make a canonical form of arg list containing
88061da546Spatrick   // only numbers with possible "-" in between.
89061da546Spatrick   for (auto &entry : args.entries()) {
90061da546Spatrick     if ((idx = WithRSAIndex(entry.ref())) == -1) {
91061da546Spatrick       StrRefArgs.push_back(entry.ref());
92061da546Spatrick       continue;
93061da546Spatrick     }
94061da546Spatrick     // The Arg contains the range specifier, split it, then.
95061da546Spatrick     std::tie(first, second) = entry.ref().split(RSA[idx]);
96061da546Spatrick     if (!first.empty())
97061da546Spatrick       StrRefArgs.push_back(first);
98061da546Spatrick     StrRefArgs.push_back(Minus);
99061da546Spatrick     if (!second.empty())
100061da546Spatrick       StrRefArgs.push_back(second);
101061da546Spatrick   }
102061da546Spatrick   // Now process the canonical list and fill in the vector of uint32_t's. If
103061da546Spatrick   // there is any error, return false and the client should ignore wp_ids.
104061da546Spatrick   uint32_t beg, end, id;
105061da546Spatrick   size_t size = StrRefArgs.size();
106061da546Spatrick   bool in_range = false;
107061da546Spatrick   for (i = 0; i < size; ++i) {
108061da546Spatrick     llvm::StringRef Arg = StrRefArgs[i];
109061da546Spatrick     if (in_range) {
110061da546Spatrick       // Look for the 'end' of the range.  Note StringRef::getAsInteger()
111061da546Spatrick       // returns true to signify error while parsing.
112061da546Spatrick       if (Arg.getAsInteger(0, end))
113061da546Spatrick         return false;
114061da546Spatrick       // Found a range!  Now append the elements.
115061da546Spatrick       for (id = beg; id <= end; ++id)
116061da546Spatrick         wp_ids.push_back(id);
117061da546Spatrick       in_range = false;
118061da546Spatrick       continue;
119061da546Spatrick     }
120061da546Spatrick     if (i < (size - 1) && StrRefArgs[i + 1] == Minus) {
121061da546Spatrick       if (Arg.getAsInteger(0, beg))
122061da546Spatrick         return false;
123061da546Spatrick       // Turn on the in_range flag, we are looking for end of range next.
124061da546Spatrick       ++i;
125061da546Spatrick       in_range = true;
126061da546Spatrick       continue;
127061da546Spatrick     }
128061da546Spatrick     // Otherwise, we have a simple ID.  Just append it.
129061da546Spatrick     if (Arg.getAsInteger(0, beg))
130061da546Spatrick       return false;
131061da546Spatrick     wp_ids.push_back(beg);
132061da546Spatrick   }
133061da546Spatrick 
134061da546Spatrick   // It is an error if after the loop, we're still in_range.
135061da546Spatrick   return !in_range;
136061da546Spatrick }
137061da546Spatrick 
138061da546Spatrick // CommandObjectWatchpointList
139061da546Spatrick 
140061da546Spatrick // CommandObjectWatchpointList::Options
141061da546Spatrick #pragma mark List::CommandOptions
142061da546Spatrick #define LLDB_OPTIONS_watchpoint_list
143061da546Spatrick #include "CommandOptions.inc"
144061da546Spatrick 
145061da546Spatrick #pragma mark List
146061da546Spatrick 
147061da546Spatrick class CommandObjectWatchpointList : public CommandObjectParsed {
148061da546Spatrick public:
CommandObjectWatchpointList(CommandInterpreter & interpreter)149061da546Spatrick   CommandObjectWatchpointList(CommandInterpreter &interpreter)
150061da546Spatrick       : CommandObjectParsed(
151061da546Spatrick             interpreter, "watchpoint list",
152061da546Spatrick             "List all watchpoints at configurable levels of detail.", nullptr,
153*f6aab3d8Srobert             eCommandRequiresTarget) {
154061da546Spatrick     CommandArgumentEntry arg;
155061da546Spatrick     CommandObject::AddIDsArgumentData(arg, eArgTypeWatchpointID,
156061da546Spatrick                                       eArgTypeWatchpointIDRange);
157061da546Spatrick     // Add the entry for the first argument for this command to the object's
158061da546Spatrick     // arguments vector.
159061da546Spatrick     m_arguments.push_back(arg);
160061da546Spatrick   }
161061da546Spatrick 
162061da546Spatrick   ~CommandObjectWatchpointList() override = default;
163061da546Spatrick 
GetOptions()164061da546Spatrick   Options *GetOptions() override { return &m_options; }
165061da546Spatrick 
166061da546Spatrick   class CommandOptions : public Options {
167061da546Spatrick   public:
168*f6aab3d8Srobert     CommandOptions() = default;
169061da546Spatrick 
170061da546Spatrick     ~CommandOptions() override = default;
171061da546Spatrick 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)172061da546Spatrick     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
173061da546Spatrick                           ExecutionContext *execution_context) override {
174061da546Spatrick       Status error;
175061da546Spatrick       const int short_option = m_getopt_table[option_idx].val;
176061da546Spatrick 
177061da546Spatrick       switch (short_option) {
178061da546Spatrick       case 'b':
179061da546Spatrick         m_level = lldb::eDescriptionLevelBrief;
180061da546Spatrick         break;
181061da546Spatrick       case 'f':
182061da546Spatrick         m_level = lldb::eDescriptionLevelFull;
183061da546Spatrick         break;
184061da546Spatrick       case 'v':
185061da546Spatrick         m_level = lldb::eDescriptionLevelVerbose;
186061da546Spatrick         break;
187061da546Spatrick       default:
188061da546Spatrick         llvm_unreachable("Unimplemented option");
189061da546Spatrick       }
190061da546Spatrick 
191061da546Spatrick       return error;
192061da546Spatrick     }
193061da546Spatrick 
OptionParsingStarting(ExecutionContext * execution_context)194061da546Spatrick     void OptionParsingStarting(ExecutionContext *execution_context) override {
195061da546Spatrick       m_level = lldb::eDescriptionLevelFull;
196061da546Spatrick     }
197061da546Spatrick 
GetDefinitions()198061da546Spatrick     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
199*f6aab3d8Srobert       return llvm::ArrayRef(g_watchpoint_list_options);
200061da546Spatrick     }
201061da546Spatrick 
202061da546Spatrick     // Instance variables to hold the values for command options.
203061da546Spatrick 
204be691f3bSpatrick     lldb::DescriptionLevel m_level = lldb::eDescriptionLevelBrief;
205061da546Spatrick   };
206061da546Spatrick 
207061da546Spatrick protected:
DoExecute(Args & command,CommandReturnObject & result)208061da546Spatrick   bool DoExecute(Args &command, CommandReturnObject &result) override {
209061da546Spatrick     Target *target = &GetSelectedTarget();
210061da546Spatrick 
211061da546Spatrick     if (target->GetProcessSP() && target->GetProcessSP()->IsAlive()) {
212061da546Spatrick       uint32_t num_supported_hardware_watchpoints;
213061da546Spatrick       Status error = target->GetProcessSP()->GetWatchpointSupportInfo(
214061da546Spatrick           num_supported_hardware_watchpoints);
215061da546Spatrick       if (error.Success())
216061da546Spatrick         result.AppendMessageWithFormat(
217061da546Spatrick             "Number of supported hardware watchpoints: %u\n",
218061da546Spatrick             num_supported_hardware_watchpoints);
219061da546Spatrick     }
220061da546Spatrick 
221061da546Spatrick     const WatchpointList &watchpoints = target->GetWatchpointList();
222061da546Spatrick 
223061da546Spatrick     std::unique_lock<std::recursive_mutex> lock;
224061da546Spatrick     target->GetWatchpointList().GetListMutex(lock);
225061da546Spatrick 
226061da546Spatrick     size_t num_watchpoints = watchpoints.GetSize();
227061da546Spatrick 
228061da546Spatrick     if (num_watchpoints == 0) {
229061da546Spatrick       result.AppendMessage("No watchpoints currently set.");
230061da546Spatrick       result.SetStatus(eReturnStatusSuccessFinishNoResult);
231061da546Spatrick       return true;
232061da546Spatrick     }
233061da546Spatrick 
234061da546Spatrick     Stream &output_stream = result.GetOutputStream();
235061da546Spatrick 
236061da546Spatrick     if (command.GetArgumentCount() == 0) {
237061da546Spatrick       // No watchpoint selected; show info about all currently set watchpoints.
238061da546Spatrick       result.AppendMessage("Current watchpoints:");
239061da546Spatrick       for (size_t i = 0; i < num_watchpoints; ++i) {
240061da546Spatrick         Watchpoint *wp = watchpoints.GetByIndex(i).get();
241061da546Spatrick         AddWatchpointDescription(&output_stream, wp, m_options.m_level);
242061da546Spatrick       }
243061da546Spatrick       result.SetStatus(eReturnStatusSuccessFinishNoResult);
244061da546Spatrick     } else {
245061da546Spatrick       // Particular watchpoints selected; enable them.
246061da546Spatrick       std::vector<uint32_t> wp_ids;
247061da546Spatrick       if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(
248061da546Spatrick               target, command, wp_ids)) {
249061da546Spatrick         result.AppendError("Invalid watchpoints specification.");
250061da546Spatrick         return false;
251061da546Spatrick       }
252061da546Spatrick 
253061da546Spatrick       const size_t size = wp_ids.size();
254061da546Spatrick       for (size_t i = 0; i < size; ++i) {
255061da546Spatrick         Watchpoint *wp = watchpoints.FindByID(wp_ids[i]).get();
256061da546Spatrick         if (wp)
257061da546Spatrick           AddWatchpointDescription(&output_stream, wp, m_options.m_level);
258061da546Spatrick         result.SetStatus(eReturnStatusSuccessFinishNoResult);
259061da546Spatrick       }
260061da546Spatrick     }
261061da546Spatrick 
262061da546Spatrick     return result.Succeeded();
263061da546Spatrick   }
264061da546Spatrick 
265061da546Spatrick private:
266061da546Spatrick   CommandOptions m_options;
267061da546Spatrick };
268061da546Spatrick 
269061da546Spatrick // CommandObjectWatchpointEnable
270061da546Spatrick #pragma mark Enable
271061da546Spatrick 
272061da546Spatrick class CommandObjectWatchpointEnable : public CommandObjectParsed {
273061da546Spatrick public:
CommandObjectWatchpointEnable(CommandInterpreter & interpreter)274061da546Spatrick   CommandObjectWatchpointEnable(CommandInterpreter &interpreter)
275061da546Spatrick       : CommandObjectParsed(interpreter, "enable",
276061da546Spatrick                             "Enable the specified disabled watchpoint(s). If "
277061da546Spatrick                             "no watchpoints are specified, enable all of them.",
278061da546Spatrick                             nullptr, eCommandRequiresTarget) {
279061da546Spatrick     CommandArgumentEntry arg;
280061da546Spatrick     CommandObject::AddIDsArgumentData(arg, eArgTypeWatchpointID,
281061da546Spatrick                                       eArgTypeWatchpointIDRange);
282061da546Spatrick     // Add the entry for the first argument for this command to the object's
283061da546Spatrick     // arguments vector.
284061da546Spatrick     m_arguments.push_back(arg);
285061da546Spatrick   }
286061da546Spatrick 
287061da546Spatrick   ~CommandObjectWatchpointEnable() override = default;
288061da546Spatrick 
289be691f3bSpatrick   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)290be691f3bSpatrick   HandleArgumentCompletion(CompletionRequest &request,
291be691f3bSpatrick                            OptionElementVector &opt_element_vector) override {
292be691f3bSpatrick     CommandCompletions::InvokeCommonCompletionCallbacks(
293be691f3bSpatrick         GetCommandInterpreter(), CommandCompletions::eWatchPointIDCompletion,
294be691f3bSpatrick         request, nullptr);
295be691f3bSpatrick   }
296be691f3bSpatrick 
297061da546Spatrick protected:
DoExecute(Args & command,CommandReturnObject & result)298061da546Spatrick   bool DoExecute(Args &command, CommandReturnObject &result) override {
299061da546Spatrick     Target *target = &GetSelectedTarget();
300061da546Spatrick     if (!CheckTargetForWatchpointOperations(target, result))
301061da546Spatrick       return false;
302061da546Spatrick 
303061da546Spatrick     std::unique_lock<std::recursive_mutex> lock;
304061da546Spatrick     target->GetWatchpointList().GetListMutex(lock);
305061da546Spatrick 
306061da546Spatrick     const WatchpointList &watchpoints = target->GetWatchpointList();
307061da546Spatrick 
308061da546Spatrick     size_t num_watchpoints = watchpoints.GetSize();
309061da546Spatrick 
310061da546Spatrick     if (num_watchpoints == 0) {
311061da546Spatrick       result.AppendError("No watchpoints exist to be enabled.");
312061da546Spatrick       return false;
313061da546Spatrick     }
314061da546Spatrick 
315061da546Spatrick     if (command.GetArgumentCount() == 0) {
316061da546Spatrick       // No watchpoint selected; enable all currently set watchpoints.
317061da546Spatrick       target->EnableAllWatchpoints();
318061da546Spatrick       result.AppendMessageWithFormat("All watchpoints enabled. (%" PRIu64
319061da546Spatrick                                      " watchpoints)\n",
320061da546Spatrick                                      (uint64_t)num_watchpoints);
321061da546Spatrick       result.SetStatus(eReturnStatusSuccessFinishNoResult);
322061da546Spatrick     } else {
323061da546Spatrick       // Particular watchpoints selected; enable them.
324061da546Spatrick       std::vector<uint32_t> wp_ids;
325061da546Spatrick       if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(
326061da546Spatrick               target, command, wp_ids)) {
327061da546Spatrick         result.AppendError("Invalid watchpoints specification.");
328061da546Spatrick         return false;
329061da546Spatrick       }
330061da546Spatrick 
331061da546Spatrick       int count = 0;
332061da546Spatrick       const size_t size = wp_ids.size();
333061da546Spatrick       for (size_t i = 0; i < size; ++i)
334061da546Spatrick         if (target->EnableWatchpointByID(wp_ids[i]))
335061da546Spatrick           ++count;
336061da546Spatrick       result.AppendMessageWithFormat("%d watchpoints enabled.\n", count);
337061da546Spatrick       result.SetStatus(eReturnStatusSuccessFinishNoResult);
338061da546Spatrick     }
339061da546Spatrick 
340061da546Spatrick     return result.Succeeded();
341061da546Spatrick   }
342061da546Spatrick };
343061da546Spatrick 
344061da546Spatrick // CommandObjectWatchpointDisable
345061da546Spatrick #pragma mark Disable
346061da546Spatrick 
347061da546Spatrick class CommandObjectWatchpointDisable : public CommandObjectParsed {
348061da546Spatrick public:
CommandObjectWatchpointDisable(CommandInterpreter & interpreter)349061da546Spatrick   CommandObjectWatchpointDisable(CommandInterpreter &interpreter)
350061da546Spatrick       : CommandObjectParsed(interpreter, "watchpoint disable",
351061da546Spatrick                             "Disable the specified watchpoint(s) without "
352061da546Spatrick                             "removing it/them.  If no watchpoints are "
353061da546Spatrick                             "specified, disable them all.",
354061da546Spatrick                             nullptr, eCommandRequiresTarget) {
355061da546Spatrick     CommandArgumentEntry arg;
356061da546Spatrick     CommandObject::AddIDsArgumentData(arg, eArgTypeWatchpointID,
357061da546Spatrick                                       eArgTypeWatchpointIDRange);
358061da546Spatrick     // Add the entry for the first argument for this command to the object's
359061da546Spatrick     // arguments vector.
360061da546Spatrick     m_arguments.push_back(arg);
361061da546Spatrick   }
362061da546Spatrick 
363061da546Spatrick   ~CommandObjectWatchpointDisable() override = default;
364061da546Spatrick 
365be691f3bSpatrick   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)366be691f3bSpatrick   HandleArgumentCompletion(CompletionRequest &request,
367be691f3bSpatrick                            OptionElementVector &opt_element_vector) override {
368be691f3bSpatrick     CommandCompletions::InvokeCommonCompletionCallbacks(
369be691f3bSpatrick         GetCommandInterpreter(), CommandCompletions::eWatchPointIDCompletion,
370be691f3bSpatrick         request, nullptr);
371be691f3bSpatrick   }
372be691f3bSpatrick 
373061da546Spatrick protected:
DoExecute(Args & command,CommandReturnObject & result)374061da546Spatrick   bool DoExecute(Args &command, CommandReturnObject &result) override {
375061da546Spatrick     Target *target = &GetSelectedTarget();
376061da546Spatrick     if (!CheckTargetForWatchpointOperations(target, result))
377061da546Spatrick       return false;
378061da546Spatrick 
379061da546Spatrick     std::unique_lock<std::recursive_mutex> lock;
380061da546Spatrick     target->GetWatchpointList().GetListMutex(lock);
381061da546Spatrick 
382061da546Spatrick     const WatchpointList &watchpoints = target->GetWatchpointList();
383061da546Spatrick     size_t num_watchpoints = watchpoints.GetSize();
384061da546Spatrick 
385061da546Spatrick     if (num_watchpoints == 0) {
386061da546Spatrick       result.AppendError("No watchpoints exist to be disabled.");
387061da546Spatrick       return false;
388061da546Spatrick     }
389061da546Spatrick 
390061da546Spatrick     if (command.GetArgumentCount() == 0) {
391061da546Spatrick       // No watchpoint selected; disable all currently set watchpoints.
392061da546Spatrick       if (target->DisableAllWatchpoints()) {
393061da546Spatrick         result.AppendMessageWithFormat("All watchpoints disabled. (%" PRIu64
394061da546Spatrick                                        " watchpoints)\n",
395061da546Spatrick                                        (uint64_t)num_watchpoints);
396061da546Spatrick         result.SetStatus(eReturnStatusSuccessFinishNoResult);
397061da546Spatrick       } else {
398061da546Spatrick         result.AppendError("Disable all watchpoints failed\n");
399061da546Spatrick       }
400061da546Spatrick     } else {
401061da546Spatrick       // Particular watchpoints selected; disable them.
402061da546Spatrick       std::vector<uint32_t> wp_ids;
403061da546Spatrick       if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(
404061da546Spatrick               target, command, wp_ids)) {
405061da546Spatrick         result.AppendError("Invalid watchpoints specification.");
406061da546Spatrick         return false;
407061da546Spatrick       }
408061da546Spatrick 
409061da546Spatrick       int count = 0;
410061da546Spatrick       const size_t size = wp_ids.size();
411061da546Spatrick       for (size_t i = 0; i < size; ++i)
412061da546Spatrick         if (target->DisableWatchpointByID(wp_ids[i]))
413061da546Spatrick           ++count;
414061da546Spatrick       result.AppendMessageWithFormat("%d watchpoints disabled.\n", count);
415061da546Spatrick       result.SetStatus(eReturnStatusSuccessFinishNoResult);
416061da546Spatrick     }
417061da546Spatrick 
418061da546Spatrick     return result.Succeeded();
419061da546Spatrick   }
420061da546Spatrick };
421061da546Spatrick 
422061da546Spatrick // CommandObjectWatchpointDelete
423061da546Spatrick #define LLDB_OPTIONS_watchpoint_delete
424061da546Spatrick #include "CommandOptions.inc"
425061da546Spatrick 
426061da546Spatrick // CommandObjectWatchpointDelete
427061da546Spatrick #pragma mark Delete
428061da546Spatrick 
429061da546Spatrick class CommandObjectWatchpointDelete : public CommandObjectParsed {
430061da546Spatrick public:
CommandObjectWatchpointDelete(CommandInterpreter & interpreter)431061da546Spatrick   CommandObjectWatchpointDelete(CommandInterpreter &interpreter)
432061da546Spatrick       : CommandObjectParsed(interpreter, "watchpoint delete",
433061da546Spatrick                             "Delete the specified watchpoint(s).  If no "
434061da546Spatrick                             "watchpoints are specified, delete them all.",
435*f6aab3d8Srobert                             nullptr, eCommandRequiresTarget) {
436061da546Spatrick     CommandArgumentEntry arg;
437061da546Spatrick     CommandObject::AddIDsArgumentData(arg, eArgTypeWatchpointID,
438061da546Spatrick                                       eArgTypeWatchpointIDRange);
439061da546Spatrick     // Add the entry for the first argument for this command to the object's
440061da546Spatrick     // arguments vector.
441061da546Spatrick     m_arguments.push_back(arg);
442061da546Spatrick   }
443061da546Spatrick 
444061da546Spatrick   ~CommandObjectWatchpointDelete() override = default;
445061da546Spatrick 
446be691f3bSpatrick   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)447be691f3bSpatrick   HandleArgumentCompletion(CompletionRequest &request,
448be691f3bSpatrick                            OptionElementVector &opt_element_vector) override {
449be691f3bSpatrick     CommandCompletions::InvokeCommonCompletionCallbacks(
450be691f3bSpatrick         GetCommandInterpreter(), CommandCompletions::eWatchPointIDCompletion,
451be691f3bSpatrick         request, nullptr);
452be691f3bSpatrick   }
453be691f3bSpatrick 
GetOptions()454061da546Spatrick   Options *GetOptions() override { return &m_options; }
455061da546Spatrick 
456061da546Spatrick   class CommandOptions : public Options {
457061da546Spatrick   public:
458*f6aab3d8Srobert     CommandOptions() = default;
459061da546Spatrick 
460061da546Spatrick     ~CommandOptions() override = default;
461061da546Spatrick 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)462061da546Spatrick     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
463061da546Spatrick                           ExecutionContext *execution_context) override {
464061da546Spatrick       const int short_option = m_getopt_table[option_idx].val;
465061da546Spatrick 
466061da546Spatrick       switch (short_option) {
467061da546Spatrick       case 'f':
468061da546Spatrick         m_force = true;
469061da546Spatrick         break;
470061da546Spatrick       default:
471061da546Spatrick         llvm_unreachable("Unimplemented option");
472061da546Spatrick       }
473061da546Spatrick 
474061da546Spatrick       return {};
475061da546Spatrick     }
476061da546Spatrick 
OptionParsingStarting(ExecutionContext * execution_context)477061da546Spatrick     void OptionParsingStarting(ExecutionContext *execution_context) override {
478061da546Spatrick       m_force = false;
479061da546Spatrick     }
480061da546Spatrick 
GetDefinitions()481061da546Spatrick     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
482*f6aab3d8Srobert       return llvm::ArrayRef(g_watchpoint_delete_options);
483061da546Spatrick     }
484061da546Spatrick 
485061da546Spatrick     // Instance variables to hold the values for command options.
486be691f3bSpatrick     bool m_force = false;
487061da546Spatrick   };
488061da546Spatrick 
489061da546Spatrick protected:
DoExecute(Args & command,CommandReturnObject & result)490061da546Spatrick   bool DoExecute(Args &command, CommandReturnObject &result) override {
491061da546Spatrick     Target *target = &GetSelectedTarget();
492061da546Spatrick     if (!CheckTargetForWatchpointOperations(target, result))
493061da546Spatrick       return false;
494061da546Spatrick 
495061da546Spatrick     std::unique_lock<std::recursive_mutex> lock;
496061da546Spatrick     target->GetWatchpointList().GetListMutex(lock);
497061da546Spatrick 
498061da546Spatrick     const WatchpointList &watchpoints = target->GetWatchpointList();
499061da546Spatrick 
500061da546Spatrick     size_t num_watchpoints = watchpoints.GetSize();
501061da546Spatrick 
502061da546Spatrick     if (num_watchpoints == 0) {
503061da546Spatrick       result.AppendError("No watchpoints exist to be deleted.");
504061da546Spatrick       return false;
505061da546Spatrick     }
506061da546Spatrick 
507061da546Spatrick     if (command.empty()) {
508061da546Spatrick       if (!m_options.m_force &&
509061da546Spatrick           !m_interpreter.Confirm(
510061da546Spatrick               "About to delete all watchpoints, do you want to do that?",
511061da546Spatrick               true)) {
512061da546Spatrick         result.AppendMessage("Operation cancelled...");
513061da546Spatrick       } else {
514061da546Spatrick         target->RemoveAllWatchpoints();
515061da546Spatrick         result.AppendMessageWithFormat("All watchpoints removed. (%" PRIu64
516061da546Spatrick                                        " watchpoints)\n",
517061da546Spatrick                                        (uint64_t)num_watchpoints);
518061da546Spatrick       }
519061da546Spatrick       result.SetStatus(eReturnStatusSuccessFinishNoResult);
520061da546Spatrick       return result.Succeeded();
521061da546Spatrick     }
522061da546Spatrick 
523061da546Spatrick     // Particular watchpoints selected; delete them.
524061da546Spatrick     std::vector<uint32_t> wp_ids;
525061da546Spatrick     if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command,
526061da546Spatrick                                                                wp_ids)) {
527061da546Spatrick       result.AppendError("Invalid watchpoints specification.");
528061da546Spatrick       return false;
529061da546Spatrick     }
530061da546Spatrick 
531061da546Spatrick     int count = 0;
532061da546Spatrick     const size_t size = wp_ids.size();
533061da546Spatrick     for (size_t i = 0; i < size; ++i)
534061da546Spatrick       if (target->RemoveWatchpointByID(wp_ids[i]))
535061da546Spatrick         ++count;
536061da546Spatrick     result.AppendMessageWithFormat("%d watchpoints deleted.\n", count);
537061da546Spatrick     result.SetStatus(eReturnStatusSuccessFinishNoResult);
538061da546Spatrick 
539061da546Spatrick     return result.Succeeded();
540061da546Spatrick   }
541061da546Spatrick 
542061da546Spatrick private:
543061da546Spatrick   CommandOptions m_options;
544061da546Spatrick };
545061da546Spatrick 
546061da546Spatrick // CommandObjectWatchpointIgnore
547061da546Spatrick 
548061da546Spatrick #pragma mark Ignore::CommandOptions
549061da546Spatrick #define LLDB_OPTIONS_watchpoint_ignore
550061da546Spatrick #include "CommandOptions.inc"
551061da546Spatrick 
552061da546Spatrick class CommandObjectWatchpointIgnore : public CommandObjectParsed {
553061da546Spatrick public:
CommandObjectWatchpointIgnore(CommandInterpreter & interpreter)554061da546Spatrick   CommandObjectWatchpointIgnore(CommandInterpreter &interpreter)
555061da546Spatrick       : CommandObjectParsed(interpreter, "watchpoint ignore",
556061da546Spatrick                             "Set ignore count on the specified watchpoint(s).  "
557061da546Spatrick                             "If no watchpoints are specified, set them all.",
558*f6aab3d8Srobert                             nullptr, eCommandRequiresTarget) {
559061da546Spatrick     CommandArgumentEntry arg;
560061da546Spatrick     CommandObject::AddIDsArgumentData(arg, eArgTypeWatchpointID,
561061da546Spatrick                                       eArgTypeWatchpointIDRange);
562061da546Spatrick     // Add the entry for the first argument for this command to the object's
563061da546Spatrick     // arguments vector.
564061da546Spatrick     m_arguments.push_back(arg);
565061da546Spatrick   }
566061da546Spatrick 
567061da546Spatrick   ~CommandObjectWatchpointIgnore() override = default;
568061da546Spatrick 
569be691f3bSpatrick   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)570be691f3bSpatrick   HandleArgumentCompletion(CompletionRequest &request,
571be691f3bSpatrick                            OptionElementVector &opt_element_vector) override {
572be691f3bSpatrick     CommandCompletions::InvokeCommonCompletionCallbacks(
573be691f3bSpatrick         GetCommandInterpreter(), CommandCompletions::eWatchPointIDCompletion,
574be691f3bSpatrick         request, nullptr);
575be691f3bSpatrick   }
576be691f3bSpatrick 
GetOptions()577061da546Spatrick   Options *GetOptions() override { return &m_options; }
578061da546Spatrick 
579061da546Spatrick   class CommandOptions : public Options {
580061da546Spatrick   public:
581*f6aab3d8Srobert     CommandOptions() = default;
582061da546Spatrick 
583061da546Spatrick     ~CommandOptions() override = default;
584061da546Spatrick 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)585061da546Spatrick     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
586061da546Spatrick                           ExecutionContext *execution_context) override {
587061da546Spatrick       Status error;
588061da546Spatrick       const int short_option = m_getopt_table[option_idx].val;
589061da546Spatrick 
590061da546Spatrick       switch (short_option) {
591061da546Spatrick       case 'i':
592061da546Spatrick         if (option_arg.getAsInteger(0, m_ignore_count))
593061da546Spatrick           error.SetErrorStringWithFormat("invalid ignore count '%s'",
594061da546Spatrick                                          option_arg.str().c_str());
595061da546Spatrick         break;
596061da546Spatrick       default:
597061da546Spatrick         llvm_unreachable("Unimplemented option");
598061da546Spatrick       }
599061da546Spatrick 
600061da546Spatrick       return error;
601061da546Spatrick     }
602061da546Spatrick 
OptionParsingStarting(ExecutionContext * execution_context)603061da546Spatrick     void OptionParsingStarting(ExecutionContext *execution_context) override {
604061da546Spatrick       m_ignore_count = 0;
605061da546Spatrick     }
606061da546Spatrick 
GetDefinitions()607061da546Spatrick     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
608*f6aab3d8Srobert       return llvm::ArrayRef(g_watchpoint_ignore_options);
609061da546Spatrick     }
610061da546Spatrick 
611061da546Spatrick     // Instance variables to hold the values for command options.
612061da546Spatrick 
613be691f3bSpatrick     uint32_t m_ignore_count = 0;
614061da546Spatrick   };
615061da546Spatrick 
616061da546Spatrick protected:
DoExecute(Args & command,CommandReturnObject & result)617061da546Spatrick   bool DoExecute(Args &command, CommandReturnObject &result) override {
618061da546Spatrick     Target *target = &GetSelectedTarget();
619061da546Spatrick     if (!CheckTargetForWatchpointOperations(target, result))
620061da546Spatrick       return false;
621061da546Spatrick 
622061da546Spatrick     std::unique_lock<std::recursive_mutex> lock;
623061da546Spatrick     target->GetWatchpointList().GetListMutex(lock);
624061da546Spatrick 
625061da546Spatrick     const WatchpointList &watchpoints = target->GetWatchpointList();
626061da546Spatrick 
627061da546Spatrick     size_t num_watchpoints = watchpoints.GetSize();
628061da546Spatrick 
629061da546Spatrick     if (num_watchpoints == 0) {
630061da546Spatrick       result.AppendError("No watchpoints exist to be ignored.");
631061da546Spatrick       return false;
632061da546Spatrick     }
633061da546Spatrick 
634061da546Spatrick     if (command.GetArgumentCount() == 0) {
635061da546Spatrick       target->IgnoreAllWatchpoints(m_options.m_ignore_count);
636061da546Spatrick       result.AppendMessageWithFormat("All watchpoints ignored. (%" PRIu64
637061da546Spatrick                                      " watchpoints)\n",
638061da546Spatrick                                      (uint64_t)num_watchpoints);
639061da546Spatrick       result.SetStatus(eReturnStatusSuccessFinishNoResult);
640061da546Spatrick     } else {
641061da546Spatrick       // Particular watchpoints selected; ignore them.
642061da546Spatrick       std::vector<uint32_t> wp_ids;
643061da546Spatrick       if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(
644061da546Spatrick               target, command, wp_ids)) {
645061da546Spatrick         result.AppendError("Invalid watchpoints specification.");
646061da546Spatrick         return false;
647061da546Spatrick       }
648061da546Spatrick 
649061da546Spatrick       int count = 0;
650061da546Spatrick       const size_t size = wp_ids.size();
651061da546Spatrick       for (size_t i = 0; i < size; ++i)
652061da546Spatrick         if (target->IgnoreWatchpointByID(wp_ids[i], m_options.m_ignore_count))
653061da546Spatrick           ++count;
654061da546Spatrick       result.AppendMessageWithFormat("%d watchpoints ignored.\n", count);
655061da546Spatrick       result.SetStatus(eReturnStatusSuccessFinishNoResult);
656061da546Spatrick     }
657061da546Spatrick 
658061da546Spatrick     return result.Succeeded();
659061da546Spatrick   }
660061da546Spatrick 
661061da546Spatrick private:
662061da546Spatrick   CommandOptions m_options;
663061da546Spatrick };
664061da546Spatrick 
665061da546Spatrick // CommandObjectWatchpointModify
666061da546Spatrick 
667061da546Spatrick #pragma mark Modify::CommandOptions
668061da546Spatrick #define LLDB_OPTIONS_watchpoint_modify
669061da546Spatrick #include "CommandOptions.inc"
670061da546Spatrick 
671061da546Spatrick #pragma mark Modify
672061da546Spatrick 
673061da546Spatrick class CommandObjectWatchpointModify : public CommandObjectParsed {
674061da546Spatrick public:
CommandObjectWatchpointModify(CommandInterpreter & interpreter)675061da546Spatrick   CommandObjectWatchpointModify(CommandInterpreter &interpreter)
676061da546Spatrick       : CommandObjectParsed(
677061da546Spatrick             interpreter, "watchpoint modify",
678061da546Spatrick             "Modify the options on a watchpoint or set of watchpoints in the "
679061da546Spatrick             "executable.  "
680061da546Spatrick             "If no watchpoint is specified, act on the last created "
681061da546Spatrick             "watchpoint.  "
682061da546Spatrick             "Passing an empty argument clears the modification.",
683*f6aab3d8Srobert             nullptr, eCommandRequiresTarget) {
684061da546Spatrick     CommandArgumentEntry arg;
685061da546Spatrick     CommandObject::AddIDsArgumentData(arg, eArgTypeWatchpointID,
686061da546Spatrick                                       eArgTypeWatchpointIDRange);
687061da546Spatrick     // Add the entry for the first argument for this command to the object's
688061da546Spatrick     // arguments vector.
689061da546Spatrick     m_arguments.push_back(arg);
690061da546Spatrick   }
691061da546Spatrick 
692061da546Spatrick   ~CommandObjectWatchpointModify() override = default;
693061da546Spatrick 
694be691f3bSpatrick   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)695be691f3bSpatrick   HandleArgumentCompletion(CompletionRequest &request,
696be691f3bSpatrick                            OptionElementVector &opt_element_vector) override {
697be691f3bSpatrick     CommandCompletions::InvokeCommonCompletionCallbacks(
698be691f3bSpatrick         GetCommandInterpreter(), CommandCompletions::eWatchPointIDCompletion,
699be691f3bSpatrick         request, nullptr);
700be691f3bSpatrick   }
701be691f3bSpatrick 
GetOptions()702061da546Spatrick   Options *GetOptions() override { return &m_options; }
703061da546Spatrick 
704061da546Spatrick   class CommandOptions : public Options {
705061da546Spatrick   public:
706*f6aab3d8Srobert     CommandOptions() = default;
707061da546Spatrick 
708061da546Spatrick     ~CommandOptions() override = default;
709061da546Spatrick 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)710061da546Spatrick     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
711061da546Spatrick                           ExecutionContext *execution_context) override {
712061da546Spatrick       Status error;
713061da546Spatrick       const int short_option = m_getopt_table[option_idx].val;
714061da546Spatrick 
715061da546Spatrick       switch (short_option) {
716061da546Spatrick       case 'c':
717dda28197Spatrick         m_condition = std::string(option_arg);
718061da546Spatrick         m_condition_passed = true;
719061da546Spatrick         break;
720061da546Spatrick       default:
721061da546Spatrick         llvm_unreachable("Unimplemented option");
722061da546Spatrick       }
723061da546Spatrick 
724061da546Spatrick       return error;
725061da546Spatrick     }
726061da546Spatrick 
OptionParsingStarting(ExecutionContext * execution_context)727061da546Spatrick     void OptionParsingStarting(ExecutionContext *execution_context) override {
728061da546Spatrick       m_condition.clear();
729061da546Spatrick       m_condition_passed = false;
730061da546Spatrick     }
731061da546Spatrick 
GetDefinitions()732061da546Spatrick     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
733*f6aab3d8Srobert       return llvm::ArrayRef(g_watchpoint_modify_options);
734061da546Spatrick     }
735061da546Spatrick 
736061da546Spatrick     // Instance variables to hold the values for command options.
737061da546Spatrick 
738061da546Spatrick     std::string m_condition;
739be691f3bSpatrick     bool m_condition_passed = false;
740061da546Spatrick   };
741061da546Spatrick 
742061da546Spatrick protected:
DoExecute(Args & command,CommandReturnObject & result)743061da546Spatrick   bool DoExecute(Args &command, CommandReturnObject &result) override {
744061da546Spatrick     Target *target = &GetSelectedTarget();
745061da546Spatrick     if (!CheckTargetForWatchpointOperations(target, result))
746061da546Spatrick       return false;
747061da546Spatrick 
748061da546Spatrick     std::unique_lock<std::recursive_mutex> lock;
749061da546Spatrick     target->GetWatchpointList().GetListMutex(lock);
750061da546Spatrick 
751061da546Spatrick     const WatchpointList &watchpoints = target->GetWatchpointList();
752061da546Spatrick 
753061da546Spatrick     size_t num_watchpoints = watchpoints.GetSize();
754061da546Spatrick 
755061da546Spatrick     if (num_watchpoints == 0) {
756061da546Spatrick       result.AppendError("No watchpoints exist to be modified.");
757061da546Spatrick       return false;
758061da546Spatrick     }
759061da546Spatrick 
760061da546Spatrick     if (command.GetArgumentCount() == 0) {
761061da546Spatrick       WatchpointSP wp_sp = target->GetLastCreatedWatchpoint();
762061da546Spatrick       wp_sp->SetCondition(m_options.m_condition.c_str());
763061da546Spatrick       result.SetStatus(eReturnStatusSuccessFinishNoResult);
764061da546Spatrick     } else {
765061da546Spatrick       // Particular watchpoints selected; set condition on them.
766061da546Spatrick       std::vector<uint32_t> wp_ids;
767061da546Spatrick       if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(
768061da546Spatrick               target, command, wp_ids)) {
769061da546Spatrick         result.AppendError("Invalid watchpoints specification.");
770061da546Spatrick         return false;
771061da546Spatrick       }
772061da546Spatrick 
773061da546Spatrick       int count = 0;
774061da546Spatrick       const size_t size = wp_ids.size();
775061da546Spatrick       for (size_t i = 0; i < size; ++i) {
776061da546Spatrick         WatchpointSP wp_sp = watchpoints.FindByID(wp_ids[i]);
777061da546Spatrick         if (wp_sp) {
778061da546Spatrick           wp_sp->SetCondition(m_options.m_condition.c_str());
779061da546Spatrick           ++count;
780061da546Spatrick         }
781061da546Spatrick       }
782061da546Spatrick       result.AppendMessageWithFormat("%d watchpoints modified.\n", count);
783061da546Spatrick       result.SetStatus(eReturnStatusSuccessFinishNoResult);
784061da546Spatrick     }
785061da546Spatrick 
786061da546Spatrick     return result.Succeeded();
787061da546Spatrick   }
788061da546Spatrick 
789061da546Spatrick private:
790061da546Spatrick   CommandOptions m_options;
791061da546Spatrick };
792061da546Spatrick 
793061da546Spatrick // CommandObjectWatchpointSetVariable
794061da546Spatrick #pragma mark SetVariable
795061da546Spatrick 
796061da546Spatrick class CommandObjectWatchpointSetVariable : public CommandObjectParsed {
797061da546Spatrick public:
CommandObjectWatchpointSetVariable(CommandInterpreter & interpreter)798061da546Spatrick   CommandObjectWatchpointSetVariable(CommandInterpreter &interpreter)
799061da546Spatrick       : CommandObjectParsed(
800061da546Spatrick             interpreter, "watchpoint set variable",
801061da546Spatrick             "Set a watchpoint on a variable. "
802061da546Spatrick             "Use the '-w' option to specify the type of watchpoint and "
803061da546Spatrick             "the '-s' option to specify the byte size to watch for. "
804061da546Spatrick             "If no '-w' option is specified, it defaults to write. "
805061da546Spatrick             "If no '-s' option is specified, it defaults to the variable's "
806061da546Spatrick             "byte size. "
807061da546Spatrick             "Note that there are limited hardware resources for watchpoints. "
808061da546Spatrick             "If watchpoint setting fails, consider disable/delete existing "
809061da546Spatrick             "ones "
810061da546Spatrick             "to free up resources.",
811061da546Spatrick             nullptr,
812061da546Spatrick             eCommandRequiresFrame | eCommandTryTargetAPILock |
813*f6aab3d8Srobert                 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) {
814061da546Spatrick     SetHelpLong(
815061da546Spatrick         R"(
816061da546Spatrick Examples:
817061da546Spatrick 
818061da546Spatrick (lldb) watchpoint set variable -w read_write my_global_var
819061da546Spatrick 
820061da546Spatrick )"
821061da546Spatrick         "    Watches my_global_var for read/write access, with the region to watch \
822061da546Spatrick corresponding to the byte size of the data type.");
823061da546Spatrick 
824061da546Spatrick     CommandArgumentEntry arg;
825061da546Spatrick     CommandArgumentData var_name_arg;
826061da546Spatrick 
827061da546Spatrick     // Define the only variant of this arg.
828061da546Spatrick     var_name_arg.arg_type = eArgTypeVarName;
829061da546Spatrick     var_name_arg.arg_repetition = eArgRepeatPlain;
830061da546Spatrick 
831061da546Spatrick     // Push the variant into the argument entry.
832061da546Spatrick     arg.push_back(var_name_arg);
833061da546Spatrick 
834061da546Spatrick     // Push the data for the only argument into the m_arguments vector.
835061da546Spatrick     m_arguments.push_back(arg);
836061da546Spatrick 
837061da546Spatrick     // Absorb the '-w' and '-s' options into our option group.
838061da546Spatrick     m_option_group.Append(&m_option_watchpoint, LLDB_OPT_SET_ALL,
839061da546Spatrick                           LLDB_OPT_SET_1);
840061da546Spatrick     m_option_group.Finalize();
841061da546Spatrick   }
842061da546Spatrick 
843061da546Spatrick   ~CommandObjectWatchpointSetVariable() override = default;
844061da546Spatrick 
845be691f3bSpatrick   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)846be691f3bSpatrick   HandleArgumentCompletion(CompletionRequest &request,
847be691f3bSpatrick                            OptionElementVector &opt_element_vector) override {
848be691f3bSpatrick     if (request.GetCursorIndex() != 0)
849be691f3bSpatrick       return;
850be691f3bSpatrick     CommandCompletions::InvokeCommonCompletionCallbacks(
851be691f3bSpatrick         GetCommandInterpreter(), CommandCompletions::eVariablePathCompletion,
852be691f3bSpatrick         request, nullptr);
853be691f3bSpatrick   }
854be691f3bSpatrick 
GetOptions()855061da546Spatrick   Options *GetOptions() override { return &m_option_group; }
856061da546Spatrick 
857061da546Spatrick protected:
GetVariableCallback(void * baton,const char * name,VariableList & variable_list)858061da546Spatrick   static size_t GetVariableCallback(void *baton, const char *name,
859061da546Spatrick                                     VariableList &variable_list) {
860061da546Spatrick     size_t old_size = variable_list.GetSize();
861061da546Spatrick     Target *target = static_cast<Target *>(baton);
862061da546Spatrick     if (target)
863061da546Spatrick       target->GetImages().FindGlobalVariables(ConstString(name), UINT32_MAX,
864061da546Spatrick                                               variable_list);
865061da546Spatrick     return variable_list.GetSize() - old_size;
866061da546Spatrick   }
867061da546Spatrick 
DoExecute(Args & command,CommandReturnObject & result)868061da546Spatrick   bool DoExecute(Args &command, CommandReturnObject &result) override {
869061da546Spatrick     Target *target = GetDebugger().GetSelectedTarget().get();
870061da546Spatrick     StackFrame *frame = m_exe_ctx.GetFramePtr();
871061da546Spatrick 
872061da546Spatrick     // If no argument is present, issue an error message.  There's no way to
873061da546Spatrick     // set a watchpoint.
874061da546Spatrick     if (command.GetArgumentCount() <= 0) {
875be691f3bSpatrick       result.AppendError("required argument missing; "
876be691f3bSpatrick                          "specify your program variable to watch for");
877061da546Spatrick       return false;
878061da546Spatrick     }
879061da546Spatrick 
880061da546Spatrick     // If no '-w' is specified, default to '-w write'.
881061da546Spatrick     if (!m_option_watchpoint.watch_type_specified) {
882061da546Spatrick       m_option_watchpoint.watch_type = OptionGroupWatchpoint::eWatchWrite;
883061da546Spatrick     }
884061da546Spatrick 
885061da546Spatrick     // We passed the sanity check for the command. Proceed to set the
886061da546Spatrick     // watchpoint now.
887061da546Spatrick     lldb::addr_t addr = 0;
888061da546Spatrick     size_t size = 0;
889061da546Spatrick 
890061da546Spatrick     VariableSP var_sp;
891061da546Spatrick     ValueObjectSP valobj_sp;
892061da546Spatrick     Stream &output_stream = result.GetOutputStream();
893061da546Spatrick 
894061da546Spatrick     // A simple watch variable gesture allows only one argument.
895061da546Spatrick     if (command.GetArgumentCount() != 1) {
896be691f3bSpatrick       result.AppendError("specify exactly one variable to watch for");
897061da546Spatrick       return false;
898061da546Spatrick     }
899061da546Spatrick 
900061da546Spatrick     // Things have checked out ok...
901061da546Spatrick     Status error;
902061da546Spatrick     uint32_t expr_path_options =
903061da546Spatrick         StackFrame::eExpressionPathOptionCheckPtrVsMember |
904061da546Spatrick         StackFrame::eExpressionPathOptionsAllowDirectIVarAccess;
905061da546Spatrick     valobj_sp = frame->GetValueForVariableExpressionPath(
906061da546Spatrick         command.GetArgumentAtIndex(0), eNoDynamicValues, expr_path_options,
907061da546Spatrick         var_sp, error);
908061da546Spatrick 
909061da546Spatrick     if (!valobj_sp) {
910061da546Spatrick       // Not in the frame; let's check the globals.
911061da546Spatrick 
912061da546Spatrick       VariableList variable_list;
913061da546Spatrick       ValueObjectList valobj_list;
914061da546Spatrick 
915061da546Spatrick       Status error(Variable::GetValuesForVariableExpressionPath(
916061da546Spatrick           command.GetArgumentAtIndex(0),
917061da546Spatrick           m_exe_ctx.GetBestExecutionContextScope(), GetVariableCallback, target,
918061da546Spatrick           variable_list, valobj_list));
919061da546Spatrick 
920061da546Spatrick       if (valobj_list.GetSize())
921061da546Spatrick         valobj_sp = valobj_list.GetValueObjectAtIndex(0);
922061da546Spatrick     }
923061da546Spatrick 
924061da546Spatrick     CompilerType compiler_type;
925061da546Spatrick 
926061da546Spatrick     if (valobj_sp) {
927061da546Spatrick       AddressType addr_type;
928061da546Spatrick       addr = valobj_sp->GetAddressOf(false, &addr_type);
929061da546Spatrick       if (addr_type == eAddressTypeLoad) {
930061da546Spatrick         // We're in business.
931061da546Spatrick         // Find out the size of this variable.
932061da546Spatrick         size = m_option_watchpoint.watch_size == 0
933*f6aab3d8Srobert                    ? valobj_sp->GetByteSize().value_or(0)
934061da546Spatrick                    : m_option_watchpoint.watch_size;
935061da546Spatrick       }
936061da546Spatrick       compiler_type = valobj_sp->GetCompilerType();
937061da546Spatrick     } else {
938061da546Spatrick       const char *error_cstr = error.AsCString(nullptr);
939061da546Spatrick       if (error_cstr)
940be691f3bSpatrick         result.AppendError(error_cstr);
941061da546Spatrick       else
942be691f3bSpatrick         result.AppendErrorWithFormat("unable to find any variable "
943be691f3bSpatrick                                      "expression path that matches '%s'",
944061da546Spatrick                                      command.GetArgumentAtIndex(0));
945061da546Spatrick       return false;
946061da546Spatrick     }
947061da546Spatrick 
948061da546Spatrick     // Now it's time to create the watchpoint.
949061da546Spatrick     uint32_t watch_type = m_option_watchpoint.watch_type;
950061da546Spatrick 
951061da546Spatrick     error.Clear();
952061da546Spatrick     Watchpoint *wp =
953061da546Spatrick         target->CreateWatchpoint(addr, size, &compiler_type, watch_type, error)
954061da546Spatrick             .get();
955061da546Spatrick     if (wp) {
956061da546Spatrick       wp->SetWatchSpec(command.GetArgumentAtIndex(0));
957061da546Spatrick       wp->SetWatchVariable(true);
958061da546Spatrick       if (var_sp && var_sp->GetDeclaration().GetFile()) {
959061da546Spatrick         StreamString ss;
960061da546Spatrick         // True to show fullpath for declaration file.
961061da546Spatrick         var_sp->GetDeclaration().DumpStopContext(&ss, true);
962dda28197Spatrick         wp->SetDeclInfo(std::string(ss.GetString()));
963061da546Spatrick       }
964061da546Spatrick       output_stream.Printf("Watchpoint created: ");
965061da546Spatrick       wp->GetDescription(&output_stream, lldb::eDescriptionLevelFull);
966061da546Spatrick       output_stream.EOL();
967061da546Spatrick       result.SetStatus(eReturnStatusSuccessFinishResult);
968061da546Spatrick     } else {
969061da546Spatrick       result.AppendErrorWithFormat(
970061da546Spatrick           "Watchpoint creation failed (addr=0x%" PRIx64 ", size=%" PRIu64
971061da546Spatrick           ", variable expression='%s').\n",
972061da546Spatrick           addr, (uint64_t)size, command.GetArgumentAtIndex(0));
973061da546Spatrick       if (error.AsCString(nullptr))
974061da546Spatrick         result.AppendError(error.AsCString());
975061da546Spatrick     }
976061da546Spatrick 
977061da546Spatrick     return result.Succeeded();
978061da546Spatrick   }
979061da546Spatrick 
980061da546Spatrick private:
981061da546Spatrick   OptionGroupOptions m_option_group;
982061da546Spatrick   OptionGroupWatchpoint m_option_watchpoint;
983061da546Spatrick };
984061da546Spatrick 
985061da546Spatrick // CommandObjectWatchpointSetExpression
986061da546Spatrick #pragma mark Set
987061da546Spatrick 
988061da546Spatrick class CommandObjectWatchpointSetExpression : public CommandObjectRaw {
989061da546Spatrick public:
CommandObjectWatchpointSetExpression(CommandInterpreter & interpreter)990061da546Spatrick   CommandObjectWatchpointSetExpression(CommandInterpreter &interpreter)
991061da546Spatrick       : CommandObjectRaw(
992061da546Spatrick             interpreter, "watchpoint set expression",
993061da546Spatrick             "Set a watchpoint on an address by supplying an expression. "
994061da546Spatrick             "Use the '-w' option to specify the type of watchpoint and "
995061da546Spatrick             "the '-s' option to specify the byte size to watch for. "
996061da546Spatrick             "If no '-w' option is specified, it defaults to write. "
997061da546Spatrick             "If no '-s' option is specified, it defaults to the target's "
998061da546Spatrick             "pointer byte size. "
999061da546Spatrick             "Note that there are limited hardware resources for watchpoints. "
1000061da546Spatrick             "If watchpoint setting fails, consider disable/delete existing "
1001061da546Spatrick             "ones "
1002061da546Spatrick             "to free up resources.",
1003061da546Spatrick             "",
1004061da546Spatrick             eCommandRequiresFrame | eCommandTryTargetAPILock |
1005*f6aab3d8Srobert                 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) {
1006061da546Spatrick     SetHelpLong(
1007061da546Spatrick         R"(
1008061da546Spatrick Examples:
1009061da546Spatrick 
1010061da546Spatrick (lldb) watchpoint set expression -w write -s 1 -- foo + 32
1011061da546Spatrick 
1012061da546Spatrick     Watches write access for the 1-byte region pointed to by the address 'foo + 32')");
1013061da546Spatrick 
1014061da546Spatrick     CommandArgumentEntry arg;
1015061da546Spatrick     CommandArgumentData expression_arg;
1016061da546Spatrick 
1017061da546Spatrick     // Define the only variant of this arg.
1018061da546Spatrick     expression_arg.arg_type = eArgTypeExpression;
1019061da546Spatrick     expression_arg.arg_repetition = eArgRepeatPlain;
1020061da546Spatrick 
1021061da546Spatrick     // Push the only variant into the argument entry.
1022061da546Spatrick     arg.push_back(expression_arg);
1023061da546Spatrick 
1024061da546Spatrick     // Push the data for the only argument into the m_arguments vector.
1025061da546Spatrick     m_arguments.push_back(arg);
1026061da546Spatrick 
1027061da546Spatrick     // Absorb the '-w' and '-s' options into our option group.
1028061da546Spatrick     m_option_group.Append(&m_option_watchpoint, LLDB_OPT_SET_ALL,
1029061da546Spatrick                           LLDB_OPT_SET_1);
1030061da546Spatrick     m_option_group.Finalize();
1031061da546Spatrick   }
1032061da546Spatrick 
1033061da546Spatrick   ~CommandObjectWatchpointSetExpression() override = default;
1034061da546Spatrick 
1035061da546Spatrick   // Overrides base class's behavior where WantsCompletion =
1036061da546Spatrick   // !WantsRawCommandString.
WantsCompletion()1037061da546Spatrick   bool WantsCompletion() override { return true; }
1038061da546Spatrick 
GetOptions()1039061da546Spatrick   Options *GetOptions() override { return &m_option_group; }
1040061da546Spatrick 
1041061da546Spatrick protected:
DoExecute(llvm::StringRef raw_command,CommandReturnObject & result)1042061da546Spatrick   bool DoExecute(llvm::StringRef raw_command,
1043061da546Spatrick                  CommandReturnObject &result) override {
1044061da546Spatrick     auto exe_ctx = GetCommandInterpreter().GetExecutionContext();
1045061da546Spatrick     m_option_group.NotifyOptionParsingStarting(
1046061da546Spatrick         &exe_ctx); // This is a raw command, so notify the option group
1047061da546Spatrick 
1048061da546Spatrick     Target *target = GetDebugger().GetSelectedTarget().get();
1049061da546Spatrick     StackFrame *frame = m_exe_ctx.GetFramePtr();
1050061da546Spatrick 
1051061da546Spatrick     OptionsWithRaw args(raw_command);
1052061da546Spatrick 
1053061da546Spatrick     llvm::StringRef expr = args.GetRawPart();
1054061da546Spatrick 
1055061da546Spatrick     if (args.HasArgs())
1056061da546Spatrick       if (!ParseOptionsAndNotify(args.GetArgs(), result, m_option_group,
1057061da546Spatrick                                  exe_ctx))
1058061da546Spatrick         return false;
1059061da546Spatrick 
1060061da546Spatrick     // If no argument is present, issue an error message.  There's no way to
1061061da546Spatrick     // set a watchpoint.
1062061da546Spatrick     if (raw_command.trim().empty()) {
1063be691f3bSpatrick       result.AppendError("required argument missing; specify an expression "
1064be691f3bSpatrick                          "to evaluate into the address to watch for");
1065061da546Spatrick       return false;
1066061da546Spatrick     }
1067061da546Spatrick 
1068061da546Spatrick     // If no '-w' is specified, default to '-w write'.
1069061da546Spatrick     if (!m_option_watchpoint.watch_type_specified) {
1070061da546Spatrick       m_option_watchpoint.watch_type = OptionGroupWatchpoint::eWatchWrite;
1071061da546Spatrick     }
1072061da546Spatrick 
1073061da546Spatrick     // We passed the sanity check for the command. Proceed to set the
1074061da546Spatrick     // watchpoint now.
1075061da546Spatrick     lldb::addr_t addr = 0;
1076061da546Spatrick     size_t size = 0;
1077061da546Spatrick 
1078061da546Spatrick     ValueObjectSP valobj_sp;
1079061da546Spatrick 
1080061da546Spatrick     // Use expression evaluation to arrive at the address to watch.
1081061da546Spatrick     EvaluateExpressionOptions options;
1082061da546Spatrick     options.SetCoerceToId(false);
1083061da546Spatrick     options.SetUnwindOnError(true);
1084061da546Spatrick     options.SetKeepInMemory(false);
1085061da546Spatrick     options.SetTryAllThreads(true);
1086*f6aab3d8Srobert     options.SetTimeout(std::nullopt);
1087061da546Spatrick 
1088061da546Spatrick     ExpressionResults expr_result =
1089061da546Spatrick         target->EvaluateExpression(expr, frame, valobj_sp, options);
1090061da546Spatrick     if (expr_result != eExpressionCompleted) {
1091be691f3bSpatrick       result.AppendError("expression evaluation of address to watch failed");
1092be691f3bSpatrick       result.AppendErrorWithFormat("expression evaluated: \n%s", expr.data());
1093dda28197Spatrick       if (valobj_sp && !valobj_sp->GetError().Success())
1094be691f3bSpatrick         result.AppendError(valobj_sp->GetError().AsCString());
1095061da546Spatrick       return false;
1096061da546Spatrick     }
1097061da546Spatrick 
1098061da546Spatrick     // Get the address to watch.
1099061da546Spatrick     bool success = false;
1100061da546Spatrick     addr = valobj_sp->GetValueAsUnsigned(0, &success);
1101061da546Spatrick     if (!success) {
1102be691f3bSpatrick       result.AppendError("expression did not evaluate to an address");
1103061da546Spatrick       return false;
1104061da546Spatrick     }
1105061da546Spatrick 
1106061da546Spatrick     if (m_option_watchpoint.watch_size != 0)
1107061da546Spatrick       size = m_option_watchpoint.watch_size;
1108061da546Spatrick     else
1109061da546Spatrick       size = target->GetArchitecture().GetAddressByteSize();
1110061da546Spatrick 
1111061da546Spatrick     // Now it's time to create the watchpoint.
1112061da546Spatrick     uint32_t watch_type = m_option_watchpoint.watch_type;
1113061da546Spatrick 
1114061da546Spatrick     // Fetch the type from the value object, the type of the watched object is
1115061da546Spatrick     // the pointee type
1116061da546Spatrick     /// of the expression, so convert to that if we  found a valid type.
1117061da546Spatrick     CompilerType compiler_type(valobj_sp->GetCompilerType());
1118061da546Spatrick 
1119061da546Spatrick     Status error;
1120061da546Spatrick     Watchpoint *wp =
1121061da546Spatrick         target->CreateWatchpoint(addr, size, &compiler_type, watch_type, error)
1122061da546Spatrick             .get();
1123061da546Spatrick     if (wp) {
1124061da546Spatrick       Stream &output_stream = result.GetOutputStream();
1125061da546Spatrick       output_stream.Printf("Watchpoint created: ");
1126061da546Spatrick       wp->GetDescription(&output_stream, lldb::eDescriptionLevelFull);
1127061da546Spatrick       output_stream.EOL();
1128061da546Spatrick       result.SetStatus(eReturnStatusSuccessFinishResult);
1129061da546Spatrick     } else {
1130061da546Spatrick       result.AppendErrorWithFormat("Watchpoint creation failed (addr=0x%" PRIx64
1131061da546Spatrick                                    ", size=%" PRIu64 ").\n",
1132061da546Spatrick                                    addr, (uint64_t)size);
1133061da546Spatrick       if (error.AsCString(nullptr))
1134061da546Spatrick         result.AppendError(error.AsCString());
1135061da546Spatrick     }
1136061da546Spatrick 
1137061da546Spatrick     return result.Succeeded();
1138061da546Spatrick   }
1139061da546Spatrick 
1140061da546Spatrick private:
1141061da546Spatrick   OptionGroupOptions m_option_group;
1142061da546Spatrick   OptionGroupWatchpoint m_option_watchpoint;
1143061da546Spatrick };
1144061da546Spatrick 
1145061da546Spatrick // CommandObjectWatchpointSet
1146061da546Spatrick #pragma mark Set
1147061da546Spatrick 
1148061da546Spatrick class CommandObjectWatchpointSet : public CommandObjectMultiword {
1149061da546Spatrick public:
CommandObjectWatchpointSet(CommandInterpreter & interpreter)1150061da546Spatrick   CommandObjectWatchpointSet(CommandInterpreter &interpreter)
1151061da546Spatrick       : CommandObjectMultiword(
1152061da546Spatrick             interpreter, "watchpoint set", "Commands for setting a watchpoint.",
1153061da546Spatrick             "watchpoint set <subcommand> [<subcommand-options>]") {
1154061da546Spatrick 
1155061da546Spatrick     LoadSubCommand(
1156061da546Spatrick         "variable",
1157061da546Spatrick         CommandObjectSP(new CommandObjectWatchpointSetVariable(interpreter)));
1158061da546Spatrick     LoadSubCommand(
1159061da546Spatrick         "expression",
1160061da546Spatrick         CommandObjectSP(new CommandObjectWatchpointSetExpression(interpreter)));
1161061da546Spatrick   }
1162061da546Spatrick 
1163061da546Spatrick   ~CommandObjectWatchpointSet() override = default;
1164061da546Spatrick };
1165061da546Spatrick 
1166061da546Spatrick // CommandObjectMultiwordWatchpoint
1167061da546Spatrick #pragma mark MultiwordWatchpoint
1168061da546Spatrick 
CommandObjectMultiwordWatchpoint(CommandInterpreter & interpreter)1169061da546Spatrick CommandObjectMultiwordWatchpoint::CommandObjectMultiwordWatchpoint(
1170061da546Spatrick     CommandInterpreter &interpreter)
1171061da546Spatrick     : CommandObjectMultiword(interpreter, "watchpoint",
1172061da546Spatrick                              "Commands for operating on watchpoints.",
1173061da546Spatrick                              "watchpoint <subcommand> [<command-options>]") {
1174061da546Spatrick   CommandObjectSP list_command_object(
1175061da546Spatrick       new CommandObjectWatchpointList(interpreter));
1176061da546Spatrick   CommandObjectSP enable_command_object(
1177061da546Spatrick       new CommandObjectWatchpointEnable(interpreter));
1178061da546Spatrick   CommandObjectSP disable_command_object(
1179061da546Spatrick       new CommandObjectWatchpointDisable(interpreter));
1180061da546Spatrick   CommandObjectSP delete_command_object(
1181061da546Spatrick       new CommandObjectWatchpointDelete(interpreter));
1182061da546Spatrick   CommandObjectSP ignore_command_object(
1183061da546Spatrick       new CommandObjectWatchpointIgnore(interpreter));
1184061da546Spatrick   CommandObjectSP command_command_object(
1185061da546Spatrick       new CommandObjectWatchpointCommand(interpreter));
1186061da546Spatrick   CommandObjectSP modify_command_object(
1187061da546Spatrick       new CommandObjectWatchpointModify(interpreter));
1188061da546Spatrick   CommandObjectSP set_command_object(
1189061da546Spatrick       new CommandObjectWatchpointSet(interpreter));
1190061da546Spatrick 
1191061da546Spatrick   list_command_object->SetCommandName("watchpoint list");
1192061da546Spatrick   enable_command_object->SetCommandName("watchpoint enable");
1193061da546Spatrick   disable_command_object->SetCommandName("watchpoint disable");
1194061da546Spatrick   delete_command_object->SetCommandName("watchpoint delete");
1195061da546Spatrick   ignore_command_object->SetCommandName("watchpoint ignore");
1196061da546Spatrick   command_command_object->SetCommandName("watchpoint command");
1197061da546Spatrick   modify_command_object->SetCommandName("watchpoint modify");
1198061da546Spatrick   set_command_object->SetCommandName("watchpoint set");
1199061da546Spatrick 
1200061da546Spatrick   LoadSubCommand("list", list_command_object);
1201061da546Spatrick   LoadSubCommand("enable", enable_command_object);
1202061da546Spatrick   LoadSubCommand("disable", disable_command_object);
1203061da546Spatrick   LoadSubCommand("delete", delete_command_object);
1204061da546Spatrick   LoadSubCommand("ignore", ignore_command_object);
1205061da546Spatrick   LoadSubCommand("command", command_command_object);
1206061da546Spatrick   LoadSubCommand("modify", modify_command_object);
1207061da546Spatrick   LoadSubCommand("set", set_command_object);
1208061da546Spatrick }
1209061da546Spatrick 
1210061da546Spatrick CommandObjectMultiwordWatchpoint::~CommandObjectMultiwordWatchpoint() = default;
1211