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