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