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