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