1 //===-- CommandObjectWatchpoint.cpp -----------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "CommandObjectWatchpoint.h"
10 #include "CommandObjectWatchpointCommand.h"
11 
12 #include <vector>
13 
14 #include "llvm/ADT/StringRef.h"
15 
16 #include "lldb/Breakpoint/Watchpoint.h"
17 #include "lldb/Breakpoint/WatchpointList.h"
18 #include "lldb/Core/ValueObject.h"
19 #include "lldb/Core/ValueObjectVariable.h"
20 #include "lldb/Host/OptionParser.h"
21 #include "lldb/Interpreter/CommandCompletions.h"
22 #include "lldb/Interpreter/CommandInterpreter.h"
23 #include "lldb/Interpreter/CommandReturnObject.h"
24 #include "lldb/Symbol/Variable.h"
25 #include "lldb/Symbol/VariableList.h"
26 #include "lldb/Target/StackFrame.h"
27 #include "lldb/Target/Target.h"
28 #include "lldb/Utility/StreamString.h"
29 
30 using namespace lldb;
31 using namespace lldb_private;
32 
33 static void AddWatchpointDescription(Stream *s, Watchpoint *wp,
34                                      lldb::DescriptionLevel level) {
35   s->IndentMore();
36   wp->GetDescription(s, level);
37   s->IndentLess();
38   s->EOL();
39 }
40 
41 static bool CheckTargetForWatchpointOperations(Target *target,
42                                                CommandReturnObject &result) {
43   if (target == nullptr) {
44     result.AppendError("Invalid target.  No existing target or watchpoints.");
45     result.SetStatus(eReturnStatusFailed);
46     return false;
47   }
48   bool process_is_valid =
49       target->GetProcessSP() && target->GetProcessSP()->IsAlive();
50   if (!process_is_valid) {
51     result.AppendError("Thre's no process or it is not alive.");
52     result.SetStatus(eReturnStatusFailed);
53     return false;
54   }
55   // Target passes our checks, return true.
56   return true;
57 }
58 
59 // Equivalent class: {"-", "to", "To", "TO"} of range specifier array.
60 static const char *RSA[4] = {"-", "to", "To", "TO"};
61 
62 // Return the index to RSA if found; otherwise -1 is returned.
63 static int32_t WithRSAIndex(llvm::StringRef Arg) {
64 
65   uint32_t i;
66   for (i = 0; i < 4; ++i)
67     if (Arg.find(RSA[i]) != llvm::StringRef::npos)
68       return i;
69   return -1;
70 }
71 
72 // Return true if wp_ids is successfully populated with the watch ids. False
73 // otherwise.
74 bool CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(
75     Target *target, Args &args, std::vector<uint32_t> &wp_ids) {
76   // Pre-condition: args.GetArgumentCount() > 0.
77   if (args.GetArgumentCount() == 0) {
78     if (target == nullptr)
79       return false;
80     WatchpointSP watch_sp = target->GetLastCreatedWatchpoint();
81     if (watch_sp) {
82       wp_ids.push_back(watch_sp->GetID());
83       return true;
84     } else
85       return false;
86   }
87 
88   llvm::StringRef Minus("-");
89   std::vector<llvm::StringRef> StrRefArgs;
90   llvm::StringRef first;
91   llvm::StringRef second;
92   size_t i;
93   int32_t idx;
94   // Go through the arguments and make a canonical form of arg list containing
95   // only numbers with possible "-" in between.
96   for (auto &entry : args.entries()) {
97     if ((idx = WithRSAIndex(entry.ref)) == -1) {
98       StrRefArgs.push_back(entry.ref);
99       continue;
100     }
101     // The Arg contains the range specifier, split it, then.
102     std::tie(first, second) = entry.ref.split(RSA[idx]);
103     if (!first.empty())
104       StrRefArgs.push_back(first);
105     StrRefArgs.push_back(Minus);
106     if (!second.empty())
107       StrRefArgs.push_back(second);
108   }
109   // Now process the canonical list and fill in the vector of uint32_t's. If
110   // there is any error, return false and the client should ignore wp_ids.
111   uint32_t beg, end, id;
112   size_t size = StrRefArgs.size();
113   bool in_range = false;
114   for (i = 0; i < size; ++i) {
115     llvm::StringRef Arg = StrRefArgs[i];
116     if (in_range) {
117       // Look for the 'end' of the range.  Note StringRef::getAsInteger()
118       // returns true to signify error while parsing.
119       if (Arg.getAsInteger(0, end))
120         return false;
121       // Found a range!  Now append the elements.
122       for (id = beg; id <= end; ++id)
123         wp_ids.push_back(id);
124       in_range = false;
125       continue;
126     }
127     if (i < (size - 1) && StrRefArgs[i + 1] == Minus) {
128       if (Arg.getAsInteger(0, beg))
129         return false;
130       // Turn on the in_range flag, we are looking for end of range next.
131       ++i;
132       in_range = true;
133       continue;
134     }
135     // Otherwise, we have a simple ID.  Just append it.
136     if (Arg.getAsInteger(0, beg))
137       return false;
138     wp_ids.push_back(beg);
139   }
140 
141   // It is an error if after the loop, we're still in_range.
142   return !in_range;
143 }
144 
145 //-------------------------------------------------------------------------
146 // CommandObjectWatchpointList
147 //-------------------------------------------------------------------------
148 
149 //-------------------------------------------------------------------------
150 // CommandObjectWatchpointList::Options
151 //-------------------------------------------------------------------------
152 #pragma mark List::CommandOptions
153 
154 static constexpr OptionDefinition g_watchpoint_list_options[] = {
155     // clang-format off
156   { LLDB_OPT_SET_1, false, "brief",   'b', OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone, "Give a brief description of the watchpoint (no location info)." },
157   { LLDB_OPT_SET_2, false, "full",    'f', OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone, "Give a full description of the watchpoint and its locations." },
158   { LLDB_OPT_SET_3, false, "verbose", 'v', OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone, "Explain everything we know about the watchpoint (for debugging debugger bugs)." }
159     // clang-format on
160 };
161 
162 #pragma mark List
163 
164 class CommandObjectWatchpointList : public CommandObjectParsed {
165 public:
166   CommandObjectWatchpointList(CommandInterpreter &interpreter)
167       : CommandObjectParsed(
168             interpreter, "watchpoint list",
169             "List all watchpoints at configurable levels of detail.", nullptr),
170         m_options() {
171     CommandArgumentEntry arg;
172     CommandObject::AddIDsArgumentData(arg, eArgTypeWatchpointID,
173                                       eArgTypeWatchpointIDRange);
174     // Add the entry for the first argument for this command to the object's
175     // arguments vector.
176     m_arguments.push_back(arg);
177   }
178 
179   ~CommandObjectWatchpointList() override = default;
180 
181   Options *GetOptions() override { return &m_options; }
182 
183   class CommandOptions : public Options {
184   public:
185     CommandOptions()
186         : Options(),
187           m_level(lldb::eDescriptionLevelBrief) // Watchpoint List defaults to
188                                                 // brief descriptions
189     {}
190 
191     ~CommandOptions() override = default;
192 
193     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
194                           ExecutionContext *execution_context) override {
195       Status error;
196       const int short_option = m_getopt_table[option_idx].val;
197 
198       switch (short_option) {
199       case 'b':
200         m_level = lldb::eDescriptionLevelBrief;
201         break;
202       case 'f':
203         m_level = lldb::eDescriptionLevelFull;
204         break;
205       case 'v':
206         m_level = lldb::eDescriptionLevelVerbose;
207         break;
208       default:
209         error.SetErrorStringWithFormat("unrecognized option '%c'",
210                                        short_option);
211         break;
212       }
213 
214       return error;
215     }
216 
217     void OptionParsingStarting(ExecutionContext *execution_context) override {
218       m_level = lldb::eDescriptionLevelFull;
219     }
220 
221     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
222       return llvm::makeArrayRef(g_watchpoint_list_options);
223     }
224 
225     // Instance variables to hold the values for command options.
226 
227     lldb::DescriptionLevel m_level;
228   };
229 
230 protected:
231   bool DoExecute(Args &command, CommandReturnObject &result) override {
232     Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
233     if (target == nullptr) {
234       result.AppendError("Invalid target. No current target or watchpoints.");
235       result.SetStatus(eReturnStatusSuccessFinishNoResult);
236       return true;
237     }
238 
239     if (target->GetProcessSP() && target->GetProcessSP()->IsAlive()) {
240       uint32_t num_supported_hardware_watchpoints;
241       Status error = target->GetProcessSP()->GetWatchpointSupportInfo(
242           num_supported_hardware_watchpoints);
243       if (error.Success())
244         result.AppendMessageWithFormat(
245             "Number of supported hardware watchpoints: %u\n",
246             num_supported_hardware_watchpoints);
247     }
248 
249     const WatchpointList &watchpoints = target->GetWatchpointList();
250 
251     std::unique_lock<std::recursive_mutex> lock;
252     target->GetWatchpointList().GetListMutex(lock);
253 
254     size_t num_watchpoints = watchpoints.GetSize();
255 
256     if (num_watchpoints == 0) {
257       result.AppendMessage("No watchpoints currently set.");
258       result.SetStatus(eReturnStatusSuccessFinishNoResult);
259       return true;
260     }
261 
262     Stream &output_stream = result.GetOutputStream();
263 
264     if (command.GetArgumentCount() == 0) {
265       // No watchpoint selected; show info about all currently set watchpoints.
266       result.AppendMessage("Current watchpoints:");
267       for (size_t i = 0; i < num_watchpoints; ++i) {
268         Watchpoint *wp = watchpoints.GetByIndex(i).get();
269         AddWatchpointDescription(&output_stream, wp, m_options.m_level);
270       }
271       result.SetStatus(eReturnStatusSuccessFinishNoResult);
272     } else {
273       // Particular watchpoints selected; enable them.
274       std::vector<uint32_t> wp_ids;
275       if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(
276               target, command, wp_ids)) {
277         result.AppendError("Invalid watchpoints specification.");
278         result.SetStatus(eReturnStatusFailed);
279         return false;
280       }
281 
282       const size_t size = wp_ids.size();
283       for (size_t i = 0; i < size; ++i) {
284         Watchpoint *wp = watchpoints.FindByID(wp_ids[i]).get();
285         if (wp)
286           AddWatchpointDescription(&output_stream, wp, m_options.m_level);
287         result.SetStatus(eReturnStatusSuccessFinishNoResult);
288       }
289     }
290 
291     return result.Succeeded();
292   }
293 
294 private:
295   CommandOptions m_options;
296 };
297 
298 //-------------------------------------------------------------------------
299 // CommandObjectWatchpointEnable
300 //-------------------------------------------------------------------------
301 #pragma mark Enable
302 
303 class CommandObjectWatchpointEnable : public CommandObjectParsed {
304 public:
305   CommandObjectWatchpointEnable(CommandInterpreter &interpreter)
306       : CommandObjectParsed(interpreter, "enable",
307                             "Enable the specified disabled watchpoint(s). If "
308                             "no watchpoints are specified, enable all of them.",
309                             nullptr) {
310     CommandArgumentEntry arg;
311     CommandObject::AddIDsArgumentData(arg, eArgTypeWatchpointID,
312                                       eArgTypeWatchpointIDRange);
313     // Add the entry for the first argument for this command to the object's
314     // arguments vector.
315     m_arguments.push_back(arg);
316   }
317 
318   ~CommandObjectWatchpointEnable() override = default;
319 
320 protected:
321   bool DoExecute(Args &command, CommandReturnObject &result) override {
322     Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
323     if (!CheckTargetForWatchpointOperations(target, result))
324       return false;
325 
326     std::unique_lock<std::recursive_mutex> lock;
327     target->GetWatchpointList().GetListMutex(lock);
328 
329     const WatchpointList &watchpoints = target->GetWatchpointList();
330 
331     size_t num_watchpoints = watchpoints.GetSize();
332 
333     if (num_watchpoints == 0) {
334       result.AppendError("No watchpoints exist to be enabled.");
335       result.SetStatus(eReturnStatusFailed);
336       return false;
337     }
338 
339     if (command.GetArgumentCount() == 0) {
340       // No watchpoint selected; enable all currently set watchpoints.
341       target->EnableAllWatchpoints();
342       result.AppendMessageWithFormat("All watchpoints enabled. (%" PRIu64
343                                      " watchpoints)\n",
344                                      (uint64_t)num_watchpoints);
345       result.SetStatus(eReturnStatusSuccessFinishNoResult);
346     } else {
347       // Particular watchpoints selected; enable them.
348       std::vector<uint32_t> wp_ids;
349       if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(
350               target, command, wp_ids)) {
351         result.AppendError("Invalid watchpoints specification.");
352         result.SetStatus(eReturnStatusFailed);
353         return false;
354       }
355 
356       int count = 0;
357       const size_t size = wp_ids.size();
358       for (size_t i = 0; i < size; ++i)
359         if (target->EnableWatchpointByID(wp_ids[i]))
360           ++count;
361       result.AppendMessageWithFormat("%d watchpoints enabled.\n", count);
362       result.SetStatus(eReturnStatusSuccessFinishNoResult);
363     }
364 
365     return result.Succeeded();
366   }
367 };
368 
369 //-------------------------------------------------------------------------
370 // CommandObjectWatchpointDisable
371 //-------------------------------------------------------------------------
372 #pragma mark Disable
373 
374 class CommandObjectWatchpointDisable : public CommandObjectParsed {
375 public:
376   CommandObjectWatchpointDisable(CommandInterpreter &interpreter)
377       : CommandObjectParsed(interpreter, "watchpoint disable",
378                             "Disable the specified watchpoint(s) without "
379                             "removing it/them.  If no watchpoints are "
380                             "specified, disable them all.",
381                             nullptr) {
382     CommandArgumentEntry arg;
383     CommandObject::AddIDsArgumentData(arg, eArgTypeWatchpointID,
384                                       eArgTypeWatchpointIDRange);
385     // Add the entry for the first argument for this command to the object's
386     // arguments vector.
387     m_arguments.push_back(arg);
388   }
389 
390   ~CommandObjectWatchpointDisable() override = default;
391 
392 protected:
393   bool DoExecute(Args &command, CommandReturnObject &result) override {
394     Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
395     if (!CheckTargetForWatchpointOperations(target, result))
396       return false;
397 
398     std::unique_lock<std::recursive_mutex> lock;
399     target->GetWatchpointList().GetListMutex(lock);
400 
401     const WatchpointList &watchpoints = target->GetWatchpointList();
402     size_t num_watchpoints = watchpoints.GetSize();
403 
404     if (num_watchpoints == 0) {
405       result.AppendError("No watchpoints exist to be disabled.");
406       result.SetStatus(eReturnStatusFailed);
407       return false;
408     }
409 
410     if (command.GetArgumentCount() == 0) {
411       // No watchpoint selected; disable all currently set watchpoints.
412       if (target->DisableAllWatchpoints()) {
413         result.AppendMessageWithFormat("All watchpoints disabled. (%" PRIu64
414                                        " watchpoints)\n",
415                                        (uint64_t)num_watchpoints);
416         result.SetStatus(eReturnStatusSuccessFinishNoResult);
417       } else {
418         result.AppendError("Disable all watchpoints failed\n");
419         result.SetStatus(eReturnStatusFailed);
420       }
421     } else {
422       // Particular watchpoints selected; disable them.
423       std::vector<uint32_t> wp_ids;
424       if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(
425               target, command, wp_ids)) {
426         result.AppendError("Invalid watchpoints specification.");
427         result.SetStatus(eReturnStatusFailed);
428         return false;
429       }
430 
431       int count = 0;
432       const size_t size = wp_ids.size();
433       for (size_t i = 0; i < size; ++i)
434         if (target->DisableWatchpointByID(wp_ids[i]))
435           ++count;
436       result.AppendMessageWithFormat("%d watchpoints disabled.\n", count);
437       result.SetStatus(eReturnStatusSuccessFinishNoResult);
438     }
439 
440     return result.Succeeded();
441   }
442 };
443 
444 //-------------------------------------------------------------------------
445 // CommandObjectWatchpointDelete
446 //-------------------------------------------------------------------------
447 #pragma mark Delete
448 
449 class CommandObjectWatchpointDelete : public CommandObjectParsed {
450 public:
451   CommandObjectWatchpointDelete(CommandInterpreter &interpreter)
452       : CommandObjectParsed(interpreter, "watchpoint delete",
453                             "Delete the specified watchpoint(s).  If no "
454                             "watchpoints are specified, delete them all.",
455                             nullptr) {
456     CommandArgumentEntry arg;
457     CommandObject::AddIDsArgumentData(arg, eArgTypeWatchpointID,
458                                       eArgTypeWatchpointIDRange);
459     // Add the entry for the first argument for this command to the object's
460     // arguments vector.
461     m_arguments.push_back(arg);
462   }
463 
464   ~CommandObjectWatchpointDelete() override = default;
465 
466 protected:
467   bool DoExecute(Args &command, CommandReturnObject &result) override {
468     Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
469     if (!CheckTargetForWatchpointOperations(target, result))
470       return false;
471 
472     std::unique_lock<std::recursive_mutex> lock;
473     target->GetWatchpointList().GetListMutex(lock);
474 
475     const WatchpointList &watchpoints = target->GetWatchpointList();
476 
477     size_t num_watchpoints = watchpoints.GetSize();
478 
479     if (num_watchpoints == 0) {
480       result.AppendError("No watchpoints exist to be deleted.");
481       result.SetStatus(eReturnStatusFailed);
482       return false;
483     }
484 
485     if (command.GetArgumentCount() == 0) {
486       if (!m_interpreter.Confirm(
487               "About to delete all watchpoints, do you want to do that?",
488               true)) {
489         result.AppendMessage("Operation cancelled...");
490       } else {
491         target->RemoveAllWatchpoints();
492         result.AppendMessageWithFormat("All watchpoints removed. (%" PRIu64
493                                        " watchpoints)\n",
494                                        (uint64_t)num_watchpoints);
495       }
496       result.SetStatus(eReturnStatusSuccessFinishNoResult);
497     } else {
498       // Particular watchpoints selected; delete them.
499       std::vector<uint32_t> wp_ids;
500       if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(
501               target, command, wp_ids)) {
502         result.AppendError("Invalid watchpoints specification.");
503         result.SetStatus(eReturnStatusFailed);
504         return false;
505       }
506 
507       int count = 0;
508       const size_t size = wp_ids.size();
509       for (size_t i = 0; i < size; ++i)
510         if (target->RemoveWatchpointByID(wp_ids[i]))
511           ++count;
512       result.AppendMessageWithFormat("%d watchpoints deleted.\n", count);
513       result.SetStatus(eReturnStatusSuccessFinishNoResult);
514     }
515 
516     return result.Succeeded();
517   }
518 };
519 
520 //-------------------------------------------------------------------------
521 // CommandObjectWatchpointIgnore
522 //-------------------------------------------------------------------------
523 
524 #pragma mark Ignore::CommandOptions
525 static constexpr OptionDefinition g_watchpoint_ignore_options[] = {
526     // clang-format off
527   { LLDB_OPT_SET_ALL, true, "ignore-count", 'i', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeCount, "Set the number of times this watchpoint is skipped before stopping." }
528     // clang-format on
529 };
530 
531 class CommandObjectWatchpointIgnore : public CommandObjectParsed {
532 public:
533   CommandObjectWatchpointIgnore(CommandInterpreter &interpreter)
534       : CommandObjectParsed(interpreter, "watchpoint ignore",
535                             "Set ignore count on the specified watchpoint(s).  "
536                             "If no watchpoints are specified, set them all.",
537                             nullptr),
538         m_options() {
539     CommandArgumentEntry arg;
540     CommandObject::AddIDsArgumentData(arg, eArgTypeWatchpointID,
541                                       eArgTypeWatchpointIDRange);
542     // Add the entry for the first argument for this command to the object's
543     // arguments vector.
544     m_arguments.push_back(arg);
545   }
546 
547   ~CommandObjectWatchpointIgnore() override = default;
548 
549   Options *GetOptions() override { return &m_options; }
550 
551   class CommandOptions : public Options {
552   public:
553     CommandOptions() : Options(), m_ignore_count(0) {}
554 
555     ~CommandOptions() override = default;
556 
557     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
558                           ExecutionContext *execution_context) override {
559       Status error;
560       const int short_option = m_getopt_table[option_idx].val;
561 
562       switch (short_option) {
563       case 'i':
564         if (option_arg.getAsInteger(0, m_ignore_count))
565           error.SetErrorStringWithFormat("invalid ignore count '%s'",
566                                          option_arg.str().c_str());
567         break;
568       default:
569         error.SetErrorStringWithFormat("unrecognized option '%c'",
570                                        short_option);
571         break;
572       }
573 
574       return error;
575     }
576 
577     void OptionParsingStarting(ExecutionContext *execution_context) override {
578       m_ignore_count = 0;
579     }
580 
581     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
582       return llvm::makeArrayRef(g_watchpoint_ignore_options);
583     }
584 
585     // Instance variables to hold the values for command options.
586 
587     uint32_t m_ignore_count;
588   };
589 
590 protected:
591   bool DoExecute(Args &command, CommandReturnObject &result) override {
592     Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
593     if (!CheckTargetForWatchpointOperations(target, result))
594       return false;
595 
596     std::unique_lock<std::recursive_mutex> lock;
597     target->GetWatchpointList().GetListMutex(lock);
598 
599     const WatchpointList &watchpoints = target->GetWatchpointList();
600 
601     size_t num_watchpoints = watchpoints.GetSize();
602 
603     if (num_watchpoints == 0) {
604       result.AppendError("No watchpoints exist to be ignored.");
605       result.SetStatus(eReturnStatusFailed);
606       return false;
607     }
608 
609     if (command.GetArgumentCount() == 0) {
610       target->IgnoreAllWatchpoints(m_options.m_ignore_count);
611       result.AppendMessageWithFormat("All watchpoints ignored. (%" PRIu64
612                                      " watchpoints)\n",
613                                      (uint64_t)num_watchpoints);
614       result.SetStatus(eReturnStatusSuccessFinishNoResult);
615     } else {
616       // Particular watchpoints selected; ignore them.
617       std::vector<uint32_t> wp_ids;
618       if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(
619               target, command, wp_ids)) {
620         result.AppendError("Invalid watchpoints specification.");
621         result.SetStatus(eReturnStatusFailed);
622         return false;
623       }
624 
625       int count = 0;
626       const size_t size = wp_ids.size();
627       for (size_t i = 0; i < size; ++i)
628         if (target->IgnoreWatchpointByID(wp_ids[i], m_options.m_ignore_count))
629           ++count;
630       result.AppendMessageWithFormat("%d watchpoints ignored.\n", count);
631       result.SetStatus(eReturnStatusSuccessFinishNoResult);
632     }
633 
634     return result.Succeeded();
635   }
636 
637 private:
638   CommandOptions m_options;
639 };
640 
641 //-------------------------------------------------------------------------
642 // CommandObjectWatchpointModify
643 //-------------------------------------------------------------------------
644 
645 #pragma mark Modify::CommandOptions
646 
647 static constexpr OptionDefinition g_watchpoint_modify_options[] = {
648     // clang-format off
649   { LLDB_OPT_SET_ALL, false, "condition", 'c', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeExpression, "The watchpoint stops only if this condition expression evaluates to true." }
650     // clang-format on
651 };
652 
653 #pragma mark Modify
654 
655 class CommandObjectWatchpointModify : public CommandObjectParsed {
656 public:
657   CommandObjectWatchpointModify(CommandInterpreter &interpreter)
658       : CommandObjectParsed(
659             interpreter, "watchpoint modify",
660             "Modify the options on a watchpoint or set of watchpoints in the "
661             "executable.  "
662             "If no watchpoint is specified, act on the last created "
663             "watchpoint.  "
664             "Passing an empty argument clears the modification.",
665             nullptr),
666         m_options() {
667     CommandArgumentEntry arg;
668     CommandObject::AddIDsArgumentData(arg, eArgTypeWatchpointID,
669                                       eArgTypeWatchpointIDRange);
670     // Add the entry for the first argument for this command to the object's
671     // arguments vector.
672     m_arguments.push_back(arg);
673   }
674 
675   ~CommandObjectWatchpointModify() override = default;
676 
677   Options *GetOptions() override { return &m_options; }
678 
679   class CommandOptions : public Options {
680   public:
681     CommandOptions() : Options(), m_condition(), m_condition_passed(false) {}
682 
683     ~CommandOptions() override = default;
684 
685     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
686                           ExecutionContext *execution_context) override {
687       Status error;
688       const int short_option = m_getopt_table[option_idx].val;
689 
690       switch (short_option) {
691       case 'c':
692         m_condition = option_arg;
693         m_condition_passed = true;
694         break;
695       default:
696         error.SetErrorStringWithFormat("unrecognized option '%c'",
697                                        short_option);
698         break;
699       }
700 
701       return error;
702     }
703 
704     void OptionParsingStarting(ExecutionContext *execution_context) override {
705       m_condition.clear();
706       m_condition_passed = false;
707     }
708 
709     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
710       return llvm::makeArrayRef(g_watchpoint_modify_options);
711     }
712 
713     // Instance variables to hold the values for command options.
714 
715     std::string m_condition;
716     bool m_condition_passed;
717   };
718 
719 protected:
720   bool DoExecute(Args &command, CommandReturnObject &result) override {
721     Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
722     if (!CheckTargetForWatchpointOperations(target, result))
723       return false;
724 
725     std::unique_lock<std::recursive_mutex> lock;
726     target->GetWatchpointList().GetListMutex(lock);
727 
728     const WatchpointList &watchpoints = target->GetWatchpointList();
729 
730     size_t num_watchpoints = watchpoints.GetSize();
731 
732     if (num_watchpoints == 0) {
733       result.AppendError("No watchpoints exist to be modified.");
734       result.SetStatus(eReturnStatusFailed);
735       return false;
736     }
737 
738     if (command.GetArgumentCount() == 0) {
739       WatchpointSP wp_sp = target->GetLastCreatedWatchpoint();
740       wp_sp->SetCondition(m_options.m_condition.c_str());
741       result.SetStatus(eReturnStatusSuccessFinishNoResult);
742     } else {
743       // Particular watchpoints selected; set condition on them.
744       std::vector<uint32_t> wp_ids;
745       if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(
746               target, command, wp_ids)) {
747         result.AppendError("Invalid watchpoints specification.");
748         result.SetStatus(eReturnStatusFailed);
749         return false;
750       }
751 
752       int count = 0;
753       const size_t size = wp_ids.size();
754       for (size_t i = 0; i < size; ++i) {
755         WatchpointSP wp_sp = watchpoints.FindByID(wp_ids[i]);
756         if (wp_sp) {
757           wp_sp->SetCondition(m_options.m_condition.c_str());
758           ++count;
759         }
760       }
761       result.AppendMessageWithFormat("%d watchpoints modified.\n", count);
762       result.SetStatus(eReturnStatusSuccessFinishNoResult);
763     }
764 
765     return result.Succeeded();
766   }
767 
768 private:
769   CommandOptions m_options;
770 };
771 
772 //-------------------------------------------------------------------------
773 // CommandObjectWatchpointSetVariable
774 //-------------------------------------------------------------------------
775 #pragma mark SetVariable
776 
777 class CommandObjectWatchpointSetVariable : public CommandObjectParsed {
778 public:
779   CommandObjectWatchpointSetVariable(CommandInterpreter &interpreter)
780       : CommandObjectParsed(
781             interpreter, "watchpoint set variable",
782             "Set a watchpoint on a variable. "
783             "Use the '-w' option to specify the type of watchpoint and "
784             "the '-s' option to specify the byte size to watch for. "
785             "If no '-w' option is specified, it defaults to write. "
786             "If no '-s' option is specified, it defaults to the variable's "
787             "byte size. "
788             "Note that there are limited hardware resources for watchpoints. "
789             "If watchpoint setting fails, consider disable/delete existing "
790             "ones "
791             "to free up resources.",
792             nullptr,
793             eCommandRequiresFrame | eCommandTryTargetAPILock |
794                 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused),
795         m_option_group(), m_option_watchpoint() {
796     SetHelpLong(
797         R"(
798 Examples:
799 
800 (lldb) watchpoint set variable -w read_write my_global_var
801 
802 )"
803         "    Watches my_global_var for read/write access, with the region to watch \
804 corresponding to the byte size of the data type.");
805 
806     CommandArgumentEntry arg;
807     CommandArgumentData var_name_arg;
808 
809     // Define the only variant of this arg.
810     var_name_arg.arg_type = eArgTypeVarName;
811     var_name_arg.arg_repetition = eArgRepeatPlain;
812 
813     // Push the variant into the argument entry.
814     arg.push_back(var_name_arg);
815 
816     // Push the data for the only argument into the m_arguments vector.
817     m_arguments.push_back(arg);
818 
819     // Absorb the '-w' and '-s' options into our option group.
820     m_option_group.Append(&m_option_watchpoint, LLDB_OPT_SET_ALL,
821                           LLDB_OPT_SET_1);
822     m_option_group.Finalize();
823   }
824 
825   ~CommandObjectWatchpointSetVariable() override = default;
826 
827   Options *GetOptions() override { return &m_option_group; }
828 
829 protected:
830   static size_t GetVariableCallback(void *baton, const char *name,
831                                     VariableList &variable_list) {
832     Target *target = static_cast<Target *>(baton);
833     if (target) {
834       return target->GetImages().FindGlobalVariables(ConstString(name),
835                                                      UINT32_MAX, variable_list);
836     }
837     return 0;
838   }
839 
840   bool DoExecute(Args &command, CommandReturnObject &result) override {
841     Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
842     StackFrame *frame = m_exe_ctx.GetFramePtr();
843 
844     // If no argument is present, issue an error message.  There's no way to
845     // set a watchpoint.
846     if (command.GetArgumentCount() <= 0) {
847       result.GetErrorStream().Printf("error: required argument missing; "
848                                      "specify your program variable to watch "
849                                      "for\n");
850       result.SetStatus(eReturnStatusFailed);
851       return false;
852     }
853 
854     // If no '-w' is specified, default to '-w write'.
855     if (!m_option_watchpoint.watch_type_specified) {
856       m_option_watchpoint.watch_type = OptionGroupWatchpoint::eWatchWrite;
857     }
858 
859     // We passed the sanity check for the command. Proceed to set the
860     // watchpoint now.
861     lldb::addr_t addr = 0;
862     size_t size = 0;
863 
864     VariableSP var_sp;
865     ValueObjectSP valobj_sp;
866     Stream &output_stream = result.GetOutputStream();
867 
868     // A simple watch variable gesture allows only one argument.
869     if (command.GetArgumentCount() != 1) {
870       result.GetErrorStream().Printf(
871           "error: specify exactly one variable to watch for\n");
872       result.SetStatus(eReturnStatusFailed);
873       return false;
874     }
875 
876     // Things have checked out ok...
877     Status error;
878     uint32_t expr_path_options =
879         StackFrame::eExpressionPathOptionCheckPtrVsMember |
880         StackFrame::eExpressionPathOptionsAllowDirectIVarAccess;
881     valobj_sp = frame->GetValueForVariableExpressionPath(
882         command.GetArgumentAtIndex(0), eNoDynamicValues, expr_path_options,
883         var_sp, error);
884 
885     if (!valobj_sp) {
886       // Not in the frame; let's check the globals.
887 
888       VariableList variable_list;
889       ValueObjectList valobj_list;
890 
891       Status error(Variable::GetValuesForVariableExpressionPath(
892           command.GetArgumentAtIndex(0),
893           m_exe_ctx.GetBestExecutionContextScope(), GetVariableCallback, target,
894           variable_list, valobj_list));
895 
896       if (valobj_list.GetSize())
897         valobj_sp = valobj_list.GetValueObjectAtIndex(0);
898     }
899 
900     CompilerType compiler_type;
901 
902     if (valobj_sp) {
903       AddressType addr_type;
904       addr = valobj_sp->GetAddressOf(false, &addr_type);
905       if (addr_type == eAddressTypeLoad) {
906         // We're in business.
907         // Find out the size of this variable.
908         size = m_option_watchpoint.watch_size == 0
909                    ? valobj_sp->GetByteSize()
910                    : m_option_watchpoint.watch_size;
911       }
912       compiler_type = valobj_sp->GetCompilerType();
913     } else {
914       const char *error_cstr = error.AsCString(nullptr);
915       if (error_cstr)
916         result.GetErrorStream().Printf("error: %s\n", error_cstr);
917       else
918         result.GetErrorStream().Printf("error: unable to find any variable "
919                                        "expression path that matches '%s'\n",
920                                        command.GetArgumentAtIndex(0));
921       return false;
922     }
923 
924     // Now it's time to create the watchpoint.
925     uint32_t watch_type = m_option_watchpoint.watch_type;
926 
927     error.Clear();
928     Watchpoint *wp =
929         target->CreateWatchpoint(addr, size, &compiler_type, watch_type, error)
930             .get();
931     if (wp) {
932       wp->SetWatchSpec(command.GetArgumentAtIndex(0));
933       wp->SetWatchVariable(true);
934       if (var_sp && var_sp->GetDeclaration().GetFile()) {
935         StreamString ss;
936         // True to show fullpath for declaration file.
937         var_sp->GetDeclaration().DumpStopContext(&ss, true);
938         wp->SetDeclInfo(ss.GetString());
939       }
940       output_stream.Printf("Watchpoint created: ");
941       wp->GetDescription(&output_stream, lldb::eDescriptionLevelFull);
942       output_stream.EOL();
943       result.SetStatus(eReturnStatusSuccessFinishResult);
944     } else {
945       result.AppendErrorWithFormat(
946           "Watchpoint creation failed (addr=0x%" PRIx64 ", size=%" PRIu64
947           ", variable expression='%s').\n",
948           addr, (uint64_t)size, command.GetArgumentAtIndex(0));
949       if (error.AsCString(nullptr))
950         result.AppendError(error.AsCString());
951       result.SetStatus(eReturnStatusFailed);
952     }
953 
954     return result.Succeeded();
955   }
956 
957 private:
958   OptionGroupOptions m_option_group;
959   OptionGroupWatchpoint m_option_watchpoint;
960 };
961 
962 //-------------------------------------------------------------------------
963 // CommandObjectWatchpointSetExpression
964 //-------------------------------------------------------------------------
965 #pragma mark Set
966 
967 class CommandObjectWatchpointSetExpression : public CommandObjectRaw {
968 public:
969   CommandObjectWatchpointSetExpression(CommandInterpreter &interpreter)
970       : CommandObjectRaw(
971             interpreter, "watchpoint set expression",
972             "Set a watchpoint on an address by supplying an expression. "
973             "Use the '-w' option to specify the type of watchpoint and "
974             "the '-s' option to specify the byte size to watch for. "
975             "If no '-w' option is specified, it defaults to write. "
976             "If no '-s' option is specified, it defaults to the target's "
977             "pointer byte size. "
978             "Note that there are limited hardware resources for watchpoints. "
979             "If watchpoint setting fails, consider disable/delete existing "
980             "ones "
981             "to free up resources.",
982             "",
983             eCommandRequiresFrame | eCommandTryTargetAPILock |
984                 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused),
985         m_option_group(), m_option_watchpoint() {
986     SetHelpLong(
987         R"(
988 Examples:
989 
990 (lldb) watchpoint set expression -w write -s 1 -- foo + 32
991 
992     Watches write access for the 1-byte region pointed to by the address 'foo + 32')");
993 
994     CommandArgumentEntry arg;
995     CommandArgumentData expression_arg;
996 
997     // Define the only variant of this arg.
998     expression_arg.arg_type = eArgTypeExpression;
999     expression_arg.arg_repetition = eArgRepeatPlain;
1000 
1001     // Push the only variant into the argument entry.
1002     arg.push_back(expression_arg);
1003 
1004     // Push the data for the only argument into the m_arguments vector.
1005     m_arguments.push_back(arg);
1006 
1007     // Absorb the '-w' and '-s' options into our option group.
1008     m_option_group.Append(&m_option_watchpoint, LLDB_OPT_SET_ALL,
1009                           LLDB_OPT_SET_1);
1010     m_option_group.Finalize();
1011   }
1012 
1013   ~CommandObjectWatchpointSetExpression() override = default;
1014 
1015   // Overrides base class's behavior where WantsCompletion =
1016   // !WantsRawCommandString.
1017   bool WantsCompletion() override { return true; }
1018 
1019   Options *GetOptions() override { return &m_option_group; }
1020 
1021 protected:
1022   bool DoExecute(llvm::StringRef raw_command,
1023                  CommandReturnObject &result) override {
1024     auto exe_ctx = GetCommandInterpreter().GetExecutionContext();
1025     m_option_group.NotifyOptionParsingStarting(
1026         &exe_ctx); // This is a raw command, so notify the option group
1027 
1028     Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
1029     StackFrame *frame = m_exe_ctx.GetFramePtr();
1030 
1031     OptionsWithRaw args(raw_command);
1032 
1033     llvm::StringRef expr = args.GetRawPart();
1034 
1035     if (args.HasArgs())
1036       if (!ParseOptionsAndNotify(args.GetArgs(), result, m_option_group,
1037                                  exe_ctx))
1038         return false;
1039 
1040     // If no argument is present, issue an error message.  There's no way to
1041     // set a watchpoint.
1042     if (raw_command.trim().empty()) {
1043       result.GetErrorStream().Printf("error: required argument missing; "
1044                                      "specify an expression to evaulate into "
1045                                      "the address to watch for\n");
1046       result.SetStatus(eReturnStatusFailed);
1047       return false;
1048     }
1049 
1050     // If no '-w' is specified, default to '-w write'.
1051     if (!m_option_watchpoint.watch_type_specified) {
1052       m_option_watchpoint.watch_type = OptionGroupWatchpoint::eWatchWrite;
1053     }
1054 
1055     // We passed the sanity check for the command. Proceed to set the
1056     // watchpoint now.
1057     lldb::addr_t addr = 0;
1058     size_t size = 0;
1059 
1060     ValueObjectSP valobj_sp;
1061 
1062     // Use expression evaluation to arrive at the address to watch.
1063     EvaluateExpressionOptions options;
1064     options.SetCoerceToId(false);
1065     options.SetUnwindOnError(true);
1066     options.SetKeepInMemory(false);
1067     options.SetTryAllThreads(true);
1068     options.SetTimeout(llvm::None);
1069 
1070     ExpressionResults expr_result =
1071         target->EvaluateExpression(expr, frame, valobj_sp, options);
1072     if (expr_result != eExpressionCompleted) {
1073       result.GetErrorStream().Printf(
1074           "error: expression evaluation of address to watch failed\n");
1075       result.GetErrorStream() << "expression evaluated: \n" << expr << "\n";
1076       result.SetStatus(eReturnStatusFailed);
1077       return false;
1078     }
1079 
1080     // Get the address to watch.
1081     bool success = false;
1082     addr = valobj_sp->GetValueAsUnsigned(0, &success);
1083     if (!success) {
1084       result.GetErrorStream().Printf(
1085           "error: expression did not evaluate to an address\n");
1086       result.SetStatus(eReturnStatusFailed);
1087       return false;
1088     }
1089 
1090     if (m_option_watchpoint.watch_size != 0)
1091       size = m_option_watchpoint.watch_size;
1092     else
1093       size = target->GetArchitecture().GetAddressByteSize();
1094 
1095     // Now it's time to create the watchpoint.
1096     uint32_t watch_type = m_option_watchpoint.watch_type;
1097 
1098     // Fetch the type from the value object, the type of the watched object is
1099     // the pointee type
1100     /// of the expression, so convert to that if we  found a valid type.
1101     CompilerType compiler_type(valobj_sp->GetCompilerType());
1102 
1103     Status error;
1104     Watchpoint *wp =
1105         target->CreateWatchpoint(addr, size, &compiler_type, watch_type, error)
1106             .get();
1107     if (wp) {
1108       Stream &output_stream = result.GetOutputStream();
1109       output_stream.Printf("Watchpoint created: ");
1110       wp->GetDescription(&output_stream, lldb::eDescriptionLevelFull);
1111       output_stream.EOL();
1112       result.SetStatus(eReturnStatusSuccessFinishResult);
1113     } else {
1114       result.AppendErrorWithFormat("Watchpoint creation failed (addr=0x%" PRIx64
1115                                    ", size=%" PRIu64 ").\n",
1116                                    addr, (uint64_t)size);
1117       if (error.AsCString(nullptr))
1118         result.AppendError(error.AsCString());
1119       result.SetStatus(eReturnStatusFailed);
1120     }
1121 
1122     return result.Succeeded();
1123   }
1124 
1125 private:
1126   OptionGroupOptions m_option_group;
1127   OptionGroupWatchpoint m_option_watchpoint;
1128 };
1129 
1130 //-------------------------------------------------------------------------
1131 // CommandObjectWatchpointSet
1132 //-------------------------------------------------------------------------
1133 #pragma mark Set
1134 
1135 class CommandObjectWatchpointSet : public CommandObjectMultiword {
1136 public:
1137   CommandObjectWatchpointSet(CommandInterpreter &interpreter)
1138       : CommandObjectMultiword(
1139             interpreter, "watchpoint set", "Commands for setting a watchpoint.",
1140             "watchpoint set <subcommand> [<subcommand-options>]") {
1141 
1142     LoadSubCommand(
1143         "variable",
1144         CommandObjectSP(new CommandObjectWatchpointSetVariable(interpreter)));
1145     LoadSubCommand(
1146         "expression",
1147         CommandObjectSP(new CommandObjectWatchpointSetExpression(interpreter)));
1148   }
1149 
1150   ~CommandObjectWatchpointSet() override = default;
1151 };
1152 
1153 //-------------------------------------------------------------------------
1154 // CommandObjectMultiwordWatchpoint
1155 //-------------------------------------------------------------------------
1156 #pragma mark MultiwordWatchpoint
1157 
1158 CommandObjectMultiwordWatchpoint::CommandObjectMultiwordWatchpoint(
1159     CommandInterpreter &interpreter)
1160     : CommandObjectMultiword(interpreter, "watchpoint",
1161                              "Commands for operating on watchpoints.",
1162                              "watchpoint <subcommand> [<command-options>]") {
1163   CommandObjectSP list_command_object(
1164       new CommandObjectWatchpointList(interpreter));
1165   CommandObjectSP enable_command_object(
1166       new CommandObjectWatchpointEnable(interpreter));
1167   CommandObjectSP disable_command_object(
1168       new CommandObjectWatchpointDisable(interpreter));
1169   CommandObjectSP delete_command_object(
1170       new CommandObjectWatchpointDelete(interpreter));
1171   CommandObjectSP ignore_command_object(
1172       new CommandObjectWatchpointIgnore(interpreter));
1173   CommandObjectSP command_command_object(
1174       new CommandObjectWatchpointCommand(interpreter));
1175   CommandObjectSP modify_command_object(
1176       new CommandObjectWatchpointModify(interpreter));
1177   CommandObjectSP set_command_object(
1178       new CommandObjectWatchpointSet(interpreter));
1179 
1180   list_command_object->SetCommandName("watchpoint list");
1181   enable_command_object->SetCommandName("watchpoint enable");
1182   disable_command_object->SetCommandName("watchpoint disable");
1183   delete_command_object->SetCommandName("watchpoint delete");
1184   ignore_command_object->SetCommandName("watchpoint ignore");
1185   command_command_object->SetCommandName("watchpoint command");
1186   modify_command_object->SetCommandName("watchpoint modify");
1187   set_command_object->SetCommandName("watchpoint set");
1188 
1189   LoadSubCommand("list", list_command_object);
1190   LoadSubCommand("enable", enable_command_object);
1191   LoadSubCommand("disable", disable_command_object);
1192   LoadSubCommand("delete", delete_command_object);
1193   LoadSubCommand("ignore", ignore_command_object);
1194   LoadSubCommand("command", command_command_object);
1195   LoadSubCommand("modify", modify_command_object);
1196   LoadSubCommand("set", set_command_object);
1197 }
1198 
1199 CommandObjectMultiwordWatchpoint::~CommandObjectMultiwordWatchpoint() = default;
1200