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