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