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