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/Core/ValueObject.h"
20 #include "lldb/Host/OptionParser.h"
21 #include "lldb/Interpreter/CommandInterpreter.h"
22 #include "lldb/Interpreter/CommandOptionArgumentTable.h"
23 #include "lldb/Interpreter/CommandReturnObject.h"
24 #include "lldb/Symbol/Function.h"
25 #include "lldb/Symbol/Variable.h"
26 #include "lldb/Symbol/VariableList.h"
27 #include "lldb/Target/StackFrame.h"
28 #include "lldb/Target/Target.h"
29 #include "lldb/Utility/StreamString.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 if (target == nullptr)
74 return false;
75 WatchpointSP watch_sp = target->GetLastCreatedWatchpoint();
76 if (watch_sp) {
77 wp_ids.push_back(watch_sp->GetID());
78 return true;
79 } else
80 return false;
81 }
82
83 llvm::StringRef Minus("-");
84 std::vector<llvm::StringRef> StrRefArgs;
85 llvm::StringRef first;
86 llvm::StringRef second;
87 size_t i;
88 int32_t idx;
89 // Go through the arguments and make a canonical form of arg list containing
90 // only numbers with possible "-" in between.
91 for (auto &entry : args.entries()) {
92 if ((idx = WithRSAIndex(entry.ref())) == -1) {
93 StrRefArgs.push_back(entry.ref());
94 continue;
95 }
96 // The Arg contains the range specifier, split it, then.
97 std::tie(first, second) = entry.ref().split(RSA[idx]);
98 if (!first.empty())
99 StrRefArgs.push_back(first);
100 StrRefArgs.push_back(Minus);
101 if (!second.empty())
102 StrRefArgs.push_back(second);
103 }
104 // Now process the canonical list and fill in the vector of uint32_t's. If
105 // there is any error, return false and the client should ignore wp_ids.
106 uint32_t beg, end, id;
107 size_t size = StrRefArgs.size();
108 bool in_range = false;
109 for (i = 0; i < size; ++i) {
110 llvm::StringRef Arg = StrRefArgs[i];
111 if (in_range) {
112 // Look for the 'end' of the range. Note StringRef::getAsInteger()
113 // returns true to signify error while parsing.
114 if (Arg.getAsInteger(0, end))
115 return false;
116 // Found a range! Now append the elements.
117 for (id = beg; id <= end; ++id)
118 wp_ids.push_back(id);
119 in_range = false;
120 continue;
121 }
122 if (i < (size - 1) && StrRefArgs[i + 1] == Minus) {
123 if (Arg.getAsInteger(0, beg))
124 return false;
125 // Turn on the in_range flag, we are looking for end of range next.
126 ++i;
127 in_range = true;
128 continue;
129 }
130 // Otherwise, we have a simple ID. Just append it.
131 if (Arg.getAsInteger(0, beg))
132 return false;
133 wp_ids.push_back(beg);
134 }
135
136 // It is an error if after the loop, we're still in_range.
137 return !in_range;
138 }
139
140 // CommandObjectWatchpointList
141
142 // CommandObjectWatchpointList::Options
143 #pragma mark List::CommandOptions
144 #define LLDB_OPTIONS_watchpoint_list
145 #include "CommandOptions.inc"
146
147 #pragma mark List
148
149 class CommandObjectWatchpointList : public CommandObjectParsed {
150 public:
CommandObjectWatchpointList(CommandInterpreter & interpreter)151 CommandObjectWatchpointList(CommandInterpreter &interpreter)
152 : CommandObjectParsed(
153 interpreter, "watchpoint list",
154 "List all watchpoints at configurable levels of detail.", nullptr,
155 eCommandRequiresTarget) {
156 CommandObject::AddIDsArgumentData(eWatchpointArgs);
157 }
158
159 ~CommandObjectWatchpointList() override = default;
160
GetOptions()161 Options *GetOptions() override { return &m_options; }
162
163 class CommandOptions : public Options {
164 public:
165 CommandOptions() = default;
166
167 ~CommandOptions() override = default;
168
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)169 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
170 ExecutionContext *execution_context) override {
171 Status error;
172 const int short_option = m_getopt_table[option_idx].val;
173
174 switch (short_option) {
175 case 'b':
176 m_level = lldb::eDescriptionLevelBrief;
177 break;
178 case 'f':
179 m_level = lldb::eDescriptionLevelFull;
180 break;
181 case 'v':
182 m_level = lldb::eDescriptionLevelVerbose;
183 break;
184 default:
185 llvm_unreachable("Unimplemented option");
186 }
187
188 return error;
189 }
190
OptionParsingStarting(ExecutionContext * execution_context)191 void OptionParsingStarting(ExecutionContext *execution_context) override {
192 m_level = lldb::eDescriptionLevelFull;
193 }
194
GetDefinitions()195 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
196 return llvm::ArrayRef(g_watchpoint_list_options);
197 }
198
199 // Instance variables to hold the values for command options.
200
201 lldb::DescriptionLevel m_level = lldb::eDescriptionLevelBrief;
202 };
203
204 protected:
DoExecute(Args & command,CommandReturnObject & result)205 void DoExecute(Args &command, CommandReturnObject &result) override {
206 Target *target = &GetSelectedTarget();
207
208 if (target->GetProcessSP() && target->GetProcessSP()->IsAlive()) {
209 std::optional<uint32_t> num_supported_hardware_watchpoints =
210 target->GetProcessSP()->GetWatchpointSlotCount();
211
212 if (num_supported_hardware_watchpoints)
213 result.AppendMessageWithFormat(
214 "Number of supported hardware watchpoints: %u\n",
215 *num_supported_hardware_watchpoints);
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 = &GetSelectedTarget();
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 = &GetSelectedTarget();
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 = &GetSelectedTarget();
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.SetErrorStringWithFormat("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 = &GetSelectedTarget();
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 = &GetSelectedTarget();
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 = GetDebugger().GetSelectedTarget().get();
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 lldb::addr_t addr = 0;
826 size_t size = 0;
827
828 VariableSP var_sp;
829 ValueObjectSP valobj_sp;
830 Stream &output_stream = result.GetOutputStream();
831
832 // A simple watch variable gesture allows only one argument.
833 if (command.GetArgumentCount() != 1) {
834 result.AppendError("specify exactly one variable to watch for");
835 return;
836 }
837
838 // Things have checked out ok...
839 Status error;
840 uint32_t expr_path_options =
841 StackFrame::eExpressionPathOptionCheckPtrVsMember |
842 StackFrame::eExpressionPathOptionsAllowDirectIVarAccess;
843 valobj_sp = frame->GetValueForVariableExpressionPath(
844 command.GetArgumentAtIndex(0), eNoDynamicValues, expr_path_options,
845 var_sp, error);
846
847 if (!valobj_sp) {
848 // Not in the frame; let's check the globals.
849
850 VariableList variable_list;
851 ValueObjectList valobj_list;
852
853 Status error(Variable::GetValuesForVariableExpressionPath(
854 command.GetArgumentAtIndex(0),
855 m_exe_ctx.GetBestExecutionContextScope(), GetVariableCallback, target,
856 variable_list, valobj_list));
857
858 if (valobj_list.GetSize())
859 valobj_sp = valobj_list.GetValueObjectAtIndex(0);
860 }
861
862 CompilerType compiler_type;
863
864 if (valobj_sp) {
865 AddressType addr_type;
866 addr = valobj_sp->GetAddressOf(false, &addr_type);
867 if (addr_type == eAddressTypeLoad) {
868 // We're in business.
869 // Find out the size of this variable.
870 size = m_option_watchpoint.watch_size.GetCurrentValue() == 0
871 ? valobj_sp->GetByteSize().value_or(0)
872 : m_option_watchpoint.watch_size.GetCurrentValue();
873 }
874 compiler_type = valobj_sp->GetCompilerType();
875 } else {
876 const char *error_cstr = error.AsCString(nullptr);
877 if (error_cstr)
878 result.AppendError(error_cstr);
879 else
880 result.AppendErrorWithFormat("unable to find any variable "
881 "expression path that matches '%s'",
882 command.GetArgumentAtIndex(0));
883 return;
884 }
885
886 // Now it's time to create the watchpoint.
887 uint32_t watch_type = 0;
888 switch (m_option_watchpoint.watch_type) {
889 case OptionGroupWatchpoint::eWatchModify:
890 watch_type |= LLDB_WATCH_TYPE_MODIFY;
891 break;
892 case OptionGroupWatchpoint::eWatchRead:
893 watch_type |= LLDB_WATCH_TYPE_READ;
894 break;
895 case OptionGroupWatchpoint::eWatchReadWrite:
896 watch_type |= LLDB_WATCH_TYPE_READ | LLDB_WATCH_TYPE_WRITE;
897 break;
898 case OptionGroupWatchpoint::eWatchWrite:
899 watch_type |= LLDB_WATCH_TYPE_WRITE;
900 break;
901 case OptionGroupWatchpoint::eWatchInvalid:
902 break;
903 };
904
905 error.Clear();
906 WatchpointSP watch_sp =
907 target->CreateWatchpoint(addr, size, &compiler_type, watch_type, error);
908 if (!watch_sp) {
909 result.AppendErrorWithFormat(
910 "Watchpoint creation failed (addr=0x%" PRIx64 ", size=%" PRIu64
911 ", variable expression='%s').\n",
912 addr, static_cast<uint64_t>(size), command.GetArgumentAtIndex(0));
913 if (const char *error_message = error.AsCString(nullptr))
914 result.AppendError(error_message);
915 return;
916 }
917
918 watch_sp->SetWatchSpec(command.GetArgumentAtIndex(0));
919 watch_sp->SetWatchVariable(true);
920 if (var_sp) {
921 if (var_sp->GetDeclaration().GetFile()) {
922 StreamString ss;
923 // True to show fullpath for declaration file.
924 var_sp->GetDeclaration().DumpStopContext(&ss, true);
925 watch_sp->SetDeclInfo(std::string(ss.GetString()));
926 }
927 if (var_sp->GetScope() == eValueTypeVariableLocal)
928 watch_sp->SetupVariableWatchpointDisabler(m_exe_ctx.GetFrameSP());
929 }
930 output_stream.Printf("Watchpoint created: ");
931 watch_sp->GetDescription(&output_stream, lldb::eDescriptionLevelFull);
932 output_stream.EOL();
933 result.SetStatus(eReturnStatusSuccessFinishResult);
934 }
935
936 private:
937 OptionGroupOptions m_option_group;
938 OptionGroupWatchpoint m_option_watchpoint;
939 };
940
941 // CommandObjectWatchpointSetExpression
942 #pragma mark Set
943
944 class CommandObjectWatchpointSetExpression : public CommandObjectRaw {
945 public:
CommandObjectWatchpointSetExpression(CommandInterpreter & interpreter)946 CommandObjectWatchpointSetExpression(CommandInterpreter &interpreter)
947 : CommandObjectRaw(
948 interpreter, "watchpoint set expression",
949 "Set a watchpoint on an address by supplying an expression. "
950 "Use the '-l' option to specify the language of the expression. "
951 "Use the '-w' option to specify the type of watchpoint and "
952 "the '-s' option to specify the byte size to watch for. "
953 "If no '-w' option is specified, it defaults to modify. "
954 "If no '-s' option is specified, it defaults to the target's "
955 "pointer byte size. "
956 "Note that there are limited hardware resources for watchpoints. "
957 "If watchpoint setting fails, consider disable/delete existing "
958 "ones "
959 "to free up resources.",
960 "",
961 eCommandRequiresFrame | eCommandTryTargetAPILock |
962 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) {
963 SetHelpLong(
964 R"(
965 Examples:
966
967 (lldb) watchpoint set expression -w modify -s 1 -- foo + 32
968
969 Watches write access for the 1-byte region pointed to by the address 'foo + 32')");
970
971 AddSimpleArgumentList(eArgTypeExpression);
972
973 // Absorb the '-w' and '-s' options into our option group.
974 m_option_group.Append(&m_option_watchpoint, LLDB_OPT_SET_ALL,
975 LLDB_OPT_SET_1);
976 m_option_group.Finalize();
977 }
978
979 ~CommandObjectWatchpointSetExpression() override = default;
980
981 // Overrides base class's behavior where WantsCompletion =
982 // !WantsRawCommandString.
WantsCompletion()983 bool WantsCompletion() override { return true; }
984
GetOptions()985 Options *GetOptions() override { return &m_option_group; }
986
987 protected:
DoExecute(llvm::StringRef raw_command,CommandReturnObject & result)988 void DoExecute(llvm::StringRef raw_command,
989 CommandReturnObject &result) override {
990 auto exe_ctx = GetCommandInterpreter().GetExecutionContext();
991 m_option_group.NotifyOptionParsingStarting(
992 &exe_ctx); // This is a raw command, so notify the option group
993
994 Target *target = GetDebugger().GetSelectedTarget().get();
995 StackFrame *frame = m_exe_ctx.GetFramePtr();
996
997 OptionsWithRaw args(raw_command);
998
999 llvm::StringRef expr = args.GetRawPart();
1000
1001 if (args.HasArgs())
1002 if (!ParseOptionsAndNotify(args.GetArgs(), result, m_option_group,
1003 exe_ctx))
1004 return;
1005
1006 // If no argument is present, issue an error message. There's no way to
1007 // set a watchpoint.
1008 if (raw_command.trim().empty()) {
1009 result.AppendError("required argument missing; specify an expression "
1010 "to evaluate into the address to watch for");
1011 return;
1012 }
1013
1014 // If no '-w' is specified, default to '-w write'.
1015 if (!m_option_watchpoint.watch_type_specified) {
1016 m_option_watchpoint.watch_type = OptionGroupWatchpoint::eWatchModify;
1017 }
1018
1019 // We passed the sanity check for the command. Proceed to set the
1020 // watchpoint now.
1021 lldb::addr_t addr = 0;
1022 size_t size = 0;
1023
1024 ValueObjectSP valobj_sp;
1025
1026 // Use expression evaluation to arrive at the address to watch.
1027 EvaluateExpressionOptions options;
1028 options.SetCoerceToId(false);
1029 options.SetUnwindOnError(true);
1030 options.SetKeepInMemory(false);
1031 options.SetTryAllThreads(true);
1032 options.SetTimeout(std::nullopt);
1033 if (m_option_watchpoint.language_type != eLanguageTypeUnknown)
1034 options.SetLanguage(m_option_watchpoint.language_type);
1035
1036 ExpressionResults expr_result =
1037 target->EvaluateExpression(expr, frame, valobj_sp, options);
1038 if (expr_result != eExpressionCompleted) {
1039 result.AppendError("expression evaluation of address to watch failed");
1040 result.AppendErrorWithFormat("expression evaluated: \n%s", expr.data());
1041 if (valobj_sp && !valobj_sp->GetError().Success())
1042 result.AppendError(valobj_sp->GetError().AsCString());
1043 return;
1044 }
1045
1046 // Get the address to watch.
1047 bool success = false;
1048 addr = valobj_sp->GetValueAsUnsigned(0, &success);
1049 if (!success) {
1050 result.AppendError("expression did not evaluate to an address");
1051 return;
1052 }
1053
1054 if (m_option_watchpoint.watch_size.GetCurrentValue() != 0)
1055 size = m_option_watchpoint.watch_size.GetCurrentValue();
1056 else
1057 size = target->GetArchitecture().GetAddressByteSize();
1058
1059 // Now it's time to create the watchpoint.
1060 uint32_t watch_type;
1061 switch (m_option_watchpoint.watch_type) {
1062 case OptionGroupWatchpoint::eWatchRead:
1063 watch_type = LLDB_WATCH_TYPE_READ;
1064 break;
1065 case OptionGroupWatchpoint::eWatchWrite:
1066 watch_type = LLDB_WATCH_TYPE_WRITE;
1067 break;
1068 case OptionGroupWatchpoint::eWatchModify:
1069 watch_type = LLDB_WATCH_TYPE_MODIFY;
1070 break;
1071 case OptionGroupWatchpoint::eWatchReadWrite:
1072 watch_type = LLDB_WATCH_TYPE_READ | LLDB_WATCH_TYPE_WRITE;
1073 break;
1074 default:
1075 watch_type = LLDB_WATCH_TYPE_MODIFY;
1076 }
1077
1078 // Fetch the type from the value object, the type of the watched object is
1079 // the pointee type
1080 /// of the expression, so convert to that if we found a valid type.
1081 CompilerType compiler_type(valobj_sp->GetCompilerType());
1082
1083 std::optional<uint64_t> valobj_size = valobj_sp->GetByteSize();
1084 // Set the type as a uint8_t array if the size being watched is
1085 // larger than the ValueObject's size (which is probably the size
1086 // of a pointer).
1087 if (valobj_size && size > *valobj_size) {
1088 auto type_system = compiler_type.GetTypeSystem();
1089 if (type_system) {
1090 CompilerType clang_uint8_type =
1091 type_system->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 8);
1092 compiler_type = clang_uint8_type.GetArrayType(size);
1093 }
1094 }
1095
1096 Status error;
1097 WatchpointSP watch_sp =
1098 target->CreateWatchpoint(addr, size, &compiler_type, watch_type, error);
1099 if (watch_sp) {
1100 watch_sp->SetWatchSpec(std::string(expr));
1101 Stream &output_stream = result.GetOutputStream();
1102 output_stream.Printf("Watchpoint created: ");
1103 watch_sp->GetDescription(&output_stream, lldb::eDescriptionLevelFull);
1104 output_stream.EOL();
1105 result.SetStatus(eReturnStatusSuccessFinishResult);
1106 } else {
1107 result.AppendErrorWithFormat("Watchpoint creation failed (addr=0x%" PRIx64
1108 ", size=%" PRIu64 ").\n",
1109 addr, (uint64_t)size);
1110 if (error.AsCString(nullptr))
1111 result.AppendError(error.AsCString());
1112 }
1113 }
1114
1115 private:
1116 OptionGroupOptions m_option_group;
1117 OptionGroupWatchpoint m_option_watchpoint;
1118 };
1119
1120 // CommandObjectWatchpointSet
1121 #pragma mark Set
1122
1123 class CommandObjectWatchpointSet : public CommandObjectMultiword {
1124 public:
CommandObjectWatchpointSet(CommandInterpreter & interpreter)1125 CommandObjectWatchpointSet(CommandInterpreter &interpreter)
1126 : CommandObjectMultiword(
1127 interpreter, "watchpoint set", "Commands for setting a watchpoint.",
1128 "watchpoint set <subcommand> [<subcommand-options>]") {
1129
1130 LoadSubCommand(
1131 "variable",
1132 CommandObjectSP(new CommandObjectWatchpointSetVariable(interpreter)));
1133 LoadSubCommand(
1134 "expression",
1135 CommandObjectSP(new CommandObjectWatchpointSetExpression(interpreter)));
1136 }
1137
1138 ~CommandObjectWatchpointSet() override = default;
1139 };
1140
1141 // CommandObjectMultiwordWatchpoint
1142 #pragma mark MultiwordWatchpoint
1143
CommandObjectMultiwordWatchpoint(CommandInterpreter & interpreter)1144 CommandObjectMultiwordWatchpoint::CommandObjectMultiwordWatchpoint(
1145 CommandInterpreter &interpreter)
1146 : CommandObjectMultiword(interpreter, "watchpoint",
1147 "Commands for operating on watchpoints.",
1148 "watchpoint <subcommand> [<command-options>]") {
1149 CommandObjectSP list_command_object(
1150 new CommandObjectWatchpointList(interpreter));
1151 CommandObjectSP enable_command_object(
1152 new CommandObjectWatchpointEnable(interpreter));
1153 CommandObjectSP disable_command_object(
1154 new CommandObjectWatchpointDisable(interpreter));
1155 CommandObjectSP delete_command_object(
1156 new CommandObjectWatchpointDelete(interpreter));
1157 CommandObjectSP ignore_command_object(
1158 new CommandObjectWatchpointIgnore(interpreter));
1159 CommandObjectSP command_command_object(
1160 new CommandObjectWatchpointCommand(interpreter));
1161 CommandObjectSP modify_command_object(
1162 new CommandObjectWatchpointModify(interpreter));
1163 CommandObjectSP set_command_object(
1164 new CommandObjectWatchpointSet(interpreter));
1165
1166 list_command_object->SetCommandName("watchpoint list");
1167 enable_command_object->SetCommandName("watchpoint enable");
1168 disable_command_object->SetCommandName("watchpoint disable");
1169 delete_command_object->SetCommandName("watchpoint delete");
1170 ignore_command_object->SetCommandName("watchpoint ignore");
1171 command_command_object->SetCommandName("watchpoint command");
1172 modify_command_object->SetCommandName("watchpoint modify");
1173 set_command_object->SetCommandName("watchpoint set");
1174
1175 LoadSubCommand("list", list_command_object);
1176 LoadSubCommand("enable", enable_command_object);
1177 LoadSubCommand("disable", disable_command_object);
1178 LoadSubCommand("delete", delete_command_object);
1179 LoadSubCommand("ignore", ignore_command_object);
1180 LoadSubCommand("command", command_command_object);
1181 LoadSubCommand("modify", modify_command_object);
1182 LoadSubCommand("set", set_command_object);
1183 }
1184
1185 CommandObjectMultiwordWatchpoint::~CommandObjectMultiwordWatchpoint() = default;
1186