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 | |
34 | static void AddWatchpointDescription(Stream &s, Watchpoint &wp, |
35 | lldb::DescriptionLevel level) { |
36 | s.IndentMore(); |
37 | wp.GetDescription(s: &s, level); |
38 | s.IndentLess(); |
39 | s.EOL(); |
40 | } |
41 | |
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(in_string: "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. |
58 | static int32_t WithRSAIndex(llvm::StringRef Arg) { |
59 | |
60 | uint32_t i; |
61 | for (i = 0; i < 4; ++i) |
62 | if (Arg.contains(Other: 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. |
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(x: 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(Arg: entry.ref())) == -1) { |
93 | StrRefArgs.push_back(x: entry.ref()); |
94 | continue; |
95 | } |
96 | // The Arg contains the range specifier, split it, then. |
97 | std::tie(args&: first, args&: second) = entry.ref().split(Separator: RSA[idx]); |
98 | if (!first.empty()) |
99 | StrRefArgs.push_back(x: first); |
100 | StrRefArgs.push_back(x: Minus); |
101 | if (!second.empty()) |
102 | StrRefArgs.push_back(x: 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(Radix: 0, Result&: end)) |
115 | return false; |
116 | // Found a range! Now append the elements. |
117 | for (id = beg; id <= end; ++id) |
118 | wp_ids.push_back(x: id); |
119 | in_range = false; |
120 | continue; |
121 | } |
122 | if (i < (size - 1) && StrRefArgs[i + 1] == Minus) { |
123 | if (Arg.getAsInteger(Radix: 0, Result&: 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(Radix: 0, Result&: beg)) |
132 | return false; |
133 | wp_ids.push_back(x: 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: |
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(type: eWatchpointArgs); |
157 | } |
158 | |
159 | ~CommandObjectWatchpointList() override = default; |
160 | |
161 | Options *GetOptions() override { return &m_options; } |
162 | |
163 | class CommandOptions : public Options { |
164 | public: |
165 | CommandOptions() = default; |
166 | |
167 | ~CommandOptions() override = default; |
168 | |
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 | |
191 | void OptionParsingStarting(ExecutionContext *execution_context) override { |
192 | m_level = lldb::eDescriptionLevelFull; |
193 | } |
194 | |
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: |
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 | format: "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(in_string: "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(in_string: "Current watchpoints:" ); |
236 | for (size_t i = 0; i < num_watchpoints; ++i) { |
237 | WatchpointSP watch_sp = watchpoints.GetByIndex(i); |
238 | AddWatchpointDescription(s&: output_stream, wp&: *watch_sp, level: 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, args&: command, wp_ids&: wp_ids)) { |
246 | result.AppendError(in_string: "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(watchID: wp_ids[i]); |
253 | if (watch_sp) |
254 | AddWatchpointDescription(s&: output_stream, wp&: *watch_sp, level: 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: |
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(type: eWatchpointArgs); |
275 | } |
276 | |
277 | ~CommandObjectWatchpointEnable() override = default; |
278 | |
279 | void |
280 | HandleArgumentCompletion(CompletionRequest &request, |
281 | OptionElementVector &opt_element_vector) override { |
282 | lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks( |
283 | interpreter&: GetCommandInterpreter(), completion_mask: lldb::eWatchpointIDCompletion, request, |
284 | searcher: nullptr); |
285 | } |
286 | |
287 | protected: |
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(in_string: "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(format: "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, args&: command, wp_ids)) { |
317 | result.AppendError(in_string: "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(watch_id: wp_ids[i])) |
325 | ++count; |
326 | result.AppendMessageWithFormat(format: "%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: |
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(type: eWatchpointArgs); |
344 | } |
345 | |
346 | ~CommandObjectWatchpointDisable() override = default; |
347 | |
348 | void |
349 | HandleArgumentCompletion(CompletionRequest &request, |
350 | OptionElementVector &opt_element_vector) override { |
351 | lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks( |
352 | interpreter&: GetCommandInterpreter(), completion_mask: lldb::eWatchpointIDCompletion, request, |
353 | searcher: nullptr); |
354 | } |
355 | |
356 | protected: |
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(in_string: "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(format: "All watchpoints disabled. (%" PRIu64 |
377 | " watchpoints)\n" , |
378 | (uint64_t)num_watchpoints); |
379 | result.SetStatus(eReturnStatusSuccessFinishNoResult); |
380 | } else { |
381 | result.AppendError(in_string: "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, args&: command, wp_ids)) { |
388 | result.AppendError(in_string: "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(watch_id: wp_ids[i])) |
396 | ++count; |
397 | result.AppendMessageWithFormat(format: "%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: |
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(type: eWatchpointArgs); |
418 | } |
419 | |
420 | ~CommandObjectWatchpointDelete() override = default; |
421 | |
422 | void |
423 | HandleArgumentCompletion(CompletionRequest &request, |
424 | OptionElementVector &opt_element_vector) override { |
425 | lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks( |
426 | interpreter&: GetCommandInterpreter(), completion_mask: lldb::eWatchpointIDCompletion, request, |
427 | searcher: nullptr); |
428 | } |
429 | |
430 | Options *GetOptions() override { return &m_options; } |
431 | |
432 | class CommandOptions : public Options { |
433 | public: |
434 | CommandOptions() = default; |
435 | |
436 | ~CommandOptions() override = default; |
437 | |
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 | |
453 | void OptionParsingStarting(ExecutionContext *execution_context) override { |
454 | m_force = false; |
455 | } |
456 | |
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: |
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(in_string: "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 | message: "About to delete all watchpoints, do you want to do that?" , |
487 | default_answer: true)) { |
488 | result.AppendMessage(in_string: "Operation cancelled..." ); |
489 | } else { |
490 | target->RemoveAllWatchpoints(); |
491 | result.AppendMessageWithFormat(format: "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, args&: command, |
502 | wp_ids&: wp_ids)) { |
503 | result.AppendError(in_string: "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(watch_id: wp_ids[i])) |
511 | ++count; |
512 | result.AppendMessageWithFormat(format: "%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: |
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(type: eWatchpointArgs); |
534 | } |
535 | |
536 | ~CommandObjectWatchpointIgnore() override = default; |
537 | |
538 | void |
539 | HandleArgumentCompletion(CompletionRequest &request, |
540 | OptionElementVector &opt_element_vector) override { |
541 | lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks( |
542 | interpreter&: GetCommandInterpreter(), completion_mask: lldb::eWatchpointIDCompletion, request, |
543 | searcher: nullptr); |
544 | } |
545 | |
546 | Options *GetOptions() override { return &m_options; } |
547 | |
548 | class CommandOptions : public Options { |
549 | public: |
550 | CommandOptions() = default; |
551 | |
552 | ~CommandOptions() override = default; |
553 | |
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(Radix: 0, Result&: 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 | |
572 | void OptionParsingStarting(ExecutionContext *execution_context) override { |
573 | m_ignore_count = 0; |
574 | } |
575 | |
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: |
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(in_string: "No watchpoints exist to be ignored." ); |
600 | return; |
601 | } |
602 | |
603 | if (command.GetArgumentCount() == 0) { |
604 | target->IgnoreAllWatchpoints(ignore_count: m_options.m_ignore_count); |
605 | result.AppendMessageWithFormat(format: "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, args&: command, wp_ids)) { |
614 | result.AppendError(in_string: "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(watch_id: wp_ids[i], ignore_count: m_options.m_ignore_count)) |
622 | ++count; |
623 | result.AppendMessageWithFormat(format: "%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: |
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(type: eWatchpointArgs); |
652 | } |
653 | |
654 | ~CommandObjectWatchpointModify() override = default; |
655 | |
656 | void |
657 | HandleArgumentCompletion(CompletionRequest &request, |
658 | OptionElementVector &opt_element_vector) override { |
659 | lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks( |
660 | interpreter&: GetCommandInterpreter(), completion_mask: lldb::eWatchpointIDCompletion, request, |
661 | searcher: nullptr); |
662 | } |
663 | |
664 | Options *GetOptions() override { return &m_options; } |
665 | |
666 | class CommandOptions : public Options { |
667 | public: |
668 | CommandOptions() = default; |
669 | |
670 | ~CommandOptions() override = default; |
671 | |
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 | |
689 | void OptionParsingStarting(ExecutionContext *execution_context) override { |
690 | m_condition.clear(); |
691 | m_condition_passed = false; |
692 | } |
693 | |
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: |
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(in_string: "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, args&: command, wp_ids&: wp_ids)) { |
731 | result.AppendError(in_string: "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(watchID: wp_ids[i]); |
739 | if (watch_sp) { |
740 | watch_sp->SetCondition(m_options.m_condition.c_str()); |
741 | ++count; |
742 | } |
743 | } |
744 | result.AppendMessageWithFormat(format: "%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: |
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(arg_type: eArgTypeVarName); |
785 | |
786 | // Absorb the '-w' and '-s' options into our option group. |
787 | m_option_group.Append(group: &m_option_watchpoint, LLDB_OPT_SET_1, LLDB_OPT_SET_1); |
788 | m_option_group.Finalize(); |
789 | } |
790 | |
791 | ~CommandObjectWatchpointSetVariable() override = default; |
792 | |
793 | Options *GetOptions() override { return &m_option_group; } |
794 | |
795 | protected: |
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(name: ConstString(name), UINT32_MAX, |
802 | variable_list); |
803 | return variable_list.GetSize() - old_size; |
804 | } |
805 | |
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(in_string: "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(in_string: "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 | var_expr: command.GetArgumentAtIndex(idx: 0), use_dynamic: eNoDynamicValues, options: 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 | variable_expr_path: command.GetArgumentAtIndex(idx: 0), |
855 | scope: m_exe_ctx.GetBestExecutionContextScope(), callback: GetVariableCallback, baton: target, |
856 | variable_list, valobj_list)); |
857 | |
858 | if (valobj_list.GetSize()) |
859 | valobj_sp = valobj_list.GetValueObjectAtIndex(idx: 0); |
860 | } |
861 | |
862 | CompilerType compiler_type; |
863 | |
864 | if (valobj_sp) { |
865 | AddressType addr_type; |
866 | addr = valobj_sp->GetAddressOf(scalar_is_load_address: false, address_type: &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(u: 0) |
872 | : m_option_watchpoint.watch_size.GetCurrentValue(); |
873 | } |
874 | compiler_type = valobj_sp->GetCompilerType(); |
875 | } else { |
876 | const char *error_cstr = error.AsCString(default_error_str: nullptr); |
877 | if (error_cstr) |
878 | result.AppendError(in_string: error_cstr); |
879 | else |
880 | result.AppendErrorWithFormat(format: "unable to find any variable " |
881 | "expression path that matches '%s'" , |
882 | command.GetArgumentAtIndex(idx: 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, type: &compiler_type, kind: watch_type, error); |
908 | if (!watch_sp) { |
909 | result.AppendErrorWithFormat( |
910 | format: "Watchpoint creation failed (addr=0x%" PRIx64 ", size=%" PRIu64 |
911 | ", variable expression='%s').\n" , |
912 | addr, static_cast<uint64_t>(size), command.GetArgumentAtIndex(idx: 0)); |
913 | if (const char *error_message = error.AsCString(default_error_str: nullptr)) |
914 | result.AppendError(in_string: error_message); |
915 | return; |
916 | } |
917 | |
918 | watch_sp->SetWatchSpec(command.GetArgumentAtIndex(idx: 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(s: &ss, show_fullpaths: 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(format: "Watchpoint created: " ); |
931 | watch_sp->GetDescription(s: &output_stream, level: 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: |
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(arg_type: eArgTypeExpression); |
972 | |
973 | // Absorb the '-w' and '-s' options into our option group. |
974 | m_option_group.Append(group: &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. |
983 | bool WantsCompletion() override { return true; } |
984 | |
985 | Options *GetOptions() override { return &m_option_group; } |
986 | |
987 | protected: |
988 | void DoExecute(llvm::StringRef raw_command, |
989 | CommandReturnObject &result) override { |
990 | auto exe_ctx = GetCommandInterpreter().GetExecutionContext(); |
991 | m_option_group.NotifyOptionParsingStarting( |
992 | execution_context: &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&: args.GetArgs(), result, group_options&: 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(in_string: "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(expression: expr, exe_scope: frame, result_valobj_sp&: valobj_sp, options); |
1038 | if (expr_result != eExpressionCompleted) { |
1039 | result.AppendError(in_string: "expression evaluation of address to watch failed" ); |
1040 | result.AppendErrorWithFormat(format: "expression evaluated: \n%s" , expr.data()); |
1041 | if (valobj_sp && !valobj_sp->GetError().Success()) |
1042 | result.AppendError(in_string: valobj_sp->GetError().AsCString()); |
1043 | return; |
1044 | } |
1045 | |
1046 | // Get the address to watch. |
1047 | bool success = false; |
1048 | addr = valobj_sp->GetValueAsUnsigned(fail_value: 0, success: &success); |
1049 | if (!success) { |
1050 | result.AppendError(in_string: "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(encoding: eEncodingUint, bit_size: 8); |
1092 | compiler_type = clang_uint8_type.GetArrayType(size); |
1093 | } |
1094 | } |
1095 | |
1096 | Status error; |
1097 | WatchpointSP watch_sp = |
1098 | target->CreateWatchpoint(addr, size, type: &compiler_type, kind: watch_type, error); |
1099 | if (watch_sp) { |
1100 | watch_sp->SetWatchSpec(std::string(expr)); |
1101 | Stream &output_stream = result.GetOutputStream(); |
1102 | output_stream.Printf(format: "Watchpoint created: " ); |
1103 | watch_sp->GetDescription(s: &output_stream, level: lldb::eDescriptionLevelFull); |
1104 | output_stream.EOL(); |
1105 | result.SetStatus(eReturnStatusSuccessFinishResult); |
1106 | } else { |
1107 | result.AppendErrorWithFormat(format: "Watchpoint creation failed (addr=0x%" PRIx64 |
1108 | ", size=%" PRIu64 ").\n" , |
1109 | addr, (uint64_t)size); |
1110 | if (error.AsCString(default_error_str: nullptr)) |
1111 | result.AppendError(in_string: 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: |
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 | cmd_name: "variable" , |
1132 | command_obj: CommandObjectSP(new CommandObjectWatchpointSetVariable(interpreter))); |
1133 | LoadSubCommand( |
1134 | cmd_name: "expression" , |
1135 | command_obj: CommandObjectSP(new CommandObjectWatchpointSetExpression(interpreter))); |
1136 | } |
1137 | |
1138 | ~CommandObjectWatchpointSet() override = default; |
1139 | }; |
1140 | |
1141 | // CommandObjectMultiwordWatchpoint |
1142 | #pragma mark MultiwordWatchpoint |
1143 | |
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(cmd_name: "list" , command_obj: list_command_object); |
1176 | LoadSubCommand(cmd_name: "enable" , command_obj: enable_command_object); |
1177 | LoadSubCommand(cmd_name: "disable" , command_obj: disable_command_object); |
1178 | LoadSubCommand(cmd_name: "delete" , command_obj: delete_command_object); |
1179 | LoadSubCommand(cmd_name: "ignore" , command_obj: ignore_command_object); |
1180 | LoadSubCommand(cmd_name: "command" , command_obj: command_command_object); |
1181 | LoadSubCommand(cmd_name: "modify" , command_obj: modify_command_object); |
1182 | LoadSubCommand(cmd_name: "set" , command_obj: set_command_object); |
1183 | } |
1184 | |
1185 | CommandObjectMultiwordWatchpoint::~CommandObjectMultiwordWatchpoint() = default; |
1186 | |