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