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