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