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