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