blob: 151d3d7105c794a4196ce905502e8c177f257a67 [file] [log] [blame]
Johnny Chen01acfa72011-09-22 18:04:58 +00001//===-- 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
12// C Includes
13// C++ Includes
14// Other libraries and framework includes
15// Project includes
16#include "lldb/Breakpoint/WatchpointLocation.h"
17#include "lldb/Breakpoint/WatchpointLocationList.h"
18#include "lldb/Core/StreamString.h"
19#include "lldb/Interpreter/CommandInterpreter.h"
20#include "lldb/Interpreter/CommandReturnObject.h"
21#include "lldb/Target/Target.h"
22#include "lldb/Interpreter/CommandCompletions.h"
23
24#include <vector>
25
26using namespace lldb;
27using namespace lldb_private;
28
29static void
30AddWatchpointDescription(Stream *s, WatchpointLocation *wp_loc, lldb::DescriptionLevel level)
31{
32 s->IndentMore();
33 wp_loc->GetDescription(s, level);
34 s->IndentLess();
35 s->EOL();
36}
37
38static bool
39CheckTargetForWatchpointOperations(Target *target, CommandReturnObject &result)
40{
41 if (target == NULL)
42 {
43 result.AppendError ("Invalid target. No existing target or watchpoints.");
44 result.SetStatus (eReturnStatusFailed);
45 return false;
46 }
47 bool process_is_valid = target->GetProcessSP() && target->GetProcessSP()->IsAlive();
48 if (!process_is_valid)
49 {
50 result.AppendError ("Thre's no process or it is not alive.");
51 result.SetStatus (eReturnStatusFailed);
52 return false;
53 }
54 // Target passes our checks, return true.
55 return true;
56}
57
58#include "llvm/ADT/StringRef.h"
59
60// Equivalent class: {"-", "to", "To", "TO"} of range specifier array.
61static const char* RSA[4] = { "-", "to", "To", "TO" };
62
63// Return the index to RSA if found; otherwise -1 is returned.
64static int32_t
65WithRSAIndex(llvm::StringRef &Arg)
66{
67
68 uint32_t i;
69 for (i = 0; i < 4; ++i)
70 if (Arg.find(RSA[i]) != llvm::StringRef::npos)
71 return i;
72 return -1;
73}
74
75// Return true if wp_ids is successfully populated with the watch ids.
76// False otherwise.
77static bool
78VerifyWatchpointIDs(Args &args, std::vector<uint32_t> &wp_ids)
79{
80 // Pre-condition: args.GetArgumentCount() > 0.
81 assert(args.GetArgumentCount() > 0);
82
83 llvm::StringRef Minus("-");
84 std::vector<llvm::StringRef> StrRefArgs;
85 std::pair<llvm::StringRef, llvm::StringRef> Pair;
86 size_t i;
87 int32_t idx;
88 // Go through the argments and make a canonical form of arg list containing
89 // only numbers with possible "-" in between.
90 for (i = 0; i < args.GetArgumentCount(); ++i) {
91 llvm::StringRef Arg(args.GetArgumentAtIndex(i));
92 if ((idx = WithRSAIndex(Arg)) == -1) {
93 StrRefArgs.push_back(Arg);
94 continue;
95 }
96 // The Arg contains the range specifier, split it, then.
97 Pair = Arg.split(RSA[idx]);
98 if (!Pair.first.empty())
99 StrRefArgs.push_back(Pair.first);
100 StrRefArgs.push_back(Minus);
101 if (!Pair.second.empty())
102 StrRefArgs.push_back(Pair.second);
103 }
104 // Now process the canonical list and fill in the vector of uint32_t's.
105 // If 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; in_range = true;
127 continue;
128 }
129 // Otherwise, we have a simple ID. Just append it.
130 if (Arg.getAsInteger(0, beg))
131 return false;
132 wp_ids.push_back(beg);
133 }
134 // It is an error if after the loop, we're still in_range.
135 if (in_range)
136 return false;
137
138 return true; // Success!
139}
140
141//-------------------------------------------------------------------------
142// CommandObjectMultiwordWatchpoint
143//-------------------------------------------------------------------------
144#pragma mark MultiwordWatchpoint
145
146CommandObjectMultiwordWatchpoint::CommandObjectMultiwordWatchpoint(CommandInterpreter &interpreter) :
147 CommandObjectMultiword (interpreter,
148 "watchpoint",
149 "A set of commands for operating on watchpoints.",
150 "watchpoint <command> [<command-options>]")
151{
152 bool status;
153
154 CommandObjectSP list_command_object (new CommandObjectWatchpointList (interpreter));
155 CommandObjectSP enable_command_object (new CommandObjectWatchpointEnable (interpreter));
156 CommandObjectSP disable_command_object (new CommandObjectWatchpointDisable (interpreter));
157 CommandObjectSP delete_command_object (new CommandObjectWatchpointDelete (interpreter));
158
159 list_command_object->SetCommandName ("watchpoint list");
160 enable_command_object->SetCommandName("watchpoint enable");
161 disable_command_object->SetCommandName("watchpoint disable");
162 delete_command_object->SetCommandName("watchpoint delete");
163
164 status = LoadSubCommand ("list", list_command_object);
165 status = LoadSubCommand ("enable", enable_command_object);
166 status = LoadSubCommand ("disable", disable_command_object);
167 status = LoadSubCommand ("delete", delete_command_object);
168}
169
170CommandObjectMultiwordWatchpoint::~CommandObjectMultiwordWatchpoint()
171{
172}
173
174//-------------------------------------------------------------------------
175// CommandObjectWatchpointList::Options
176//-------------------------------------------------------------------------
177#pragma mark List::CommandOptions
178
179CommandObjectWatchpointList::CommandOptions::CommandOptions(CommandInterpreter &interpreter) :
180 Options(interpreter),
181 m_level(lldb::eDescriptionLevelBrief) // Watchpoint List defaults to brief descriptions
182{
183}
184
185CommandObjectWatchpointList::CommandOptions::~CommandOptions()
186{
187}
188
189OptionDefinition
190CommandObjectWatchpointList::CommandOptions::g_option_table[] =
191{
192 { LLDB_OPT_SET_1, false, "brief", 'b', no_argument, NULL, 0, eArgTypeNone,
193 "Give a brief description of the watchpoint (no location info)."},
194
195 { LLDB_OPT_SET_2, false, "full", 'f', no_argument, NULL, 0, eArgTypeNone,
196 "Give a full description of the watchpoint and its locations."},
197
198 { LLDB_OPT_SET_3, false, "verbose", 'v', no_argument, NULL, 0, eArgTypeNone,
199 "Explain everything we know about the watchpoint (for debugging debugger bugs)." },
200
201 { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
202};
203
204const OptionDefinition*
205CommandObjectWatchpointList::CommandOptions::GetDefinitions()
206{
207 return g_option_table;
208}
209
210Error
211CommandObjectWatchpointList::CommandOptions::SetOptionValue(uint32_t option_idx, const char *option_arg)
212{
213 Error error;
214 char short_option = (char) m_getopt_table[option_idx].val;
215
216 switch (short_option)
217 {
218 case 'b':
219 m_level = lldb::eDescriptionLevelBrief;
220 break;
221 case 'f':
222 m_level = lldb::eDescriptionLevelFull;
223 break;
224 case 'v':
225 m_level = lldb::eDescriptionLevelVerbose;
226 break;
227 default:
228 error.SetErrorStringWithFormat("Unrecognized option '%c'.\n", short_option);
229 break;
230 }
231
232 return error;
233}
234
235void
236CommandObjectWatchpointList::CommandOptions::OptionParsingStarting()
237{
238 m_level = lldb::eDescriptionLevelFull;
239}
240
241//-------------------------------------------------------------------------
242// CommandObjectWatchpointList
243//-------------------------------------------------------------------------
244#pragma mark List
245
246CommandObjectWatchpointList::CommandObjectWatchpointList(CommandInterpreter &interpreter) :
247 CommandObject(interpreter,
248 "watchpoint list",
249 "List all watchpoints at configurable levels of detail.",
250 NULL),
251 m_options(interpreter)
252{
253 CommandArgumentEntry arg;
Johnny Chencacedfb2011-09-22 22:34:09 +0000254 CommandObject::AddIDsArgumentData(arg, eArgTypeWatchpointID, eArgTypeWatchpointIDRange);
Johnny Chen01acfa72011-09-22 18:04:58 +0000255 // Add the entry for the first argument for this command to the object's arguments vector.
256 m_arguments.push_back(arg);
257}
258
259CommandObjectWatchpointList::~CommandObjectWatchpointList()
260{
261}
262
263Options *
264CommandObjectWatchpointList::GetOptions()
265{
266 return &m_options;
267}
268
269bool
270CommandObjectWatchpointList::Execute(Args& args, CommandReturnObject &result)
271{
272 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
273 if (target == NULL)
274 {
275 result.AppendError ("Invalid target. No current target or watchpoints.");
276 result.SetStatus (eReturnStatusSuccessFinishNoResult);
277 return true;
278 }
279
280 const WatchpointLocationList &watchpoints = target->GetWatchpointLocationList();
281 Mutex::Locker locker;
282 target->GetWatchpointLocationList().GetListMutex(locker);
283
284 size_t num_watchpoints = watchpoints.GetSize();
285
286 if (num_watchpoints == 0)
287 {
288 result.AppendMessage("No watchpoints currently set.");
289 result.SetStatus(eReturnStatusSuccessFinishNoResult);
290 return true;
291 }
292
293 Stream &output_stream = result.GetOutputStream();
294
295 if (args.GetArgumentCount() == 0)
296 {
297 // No watchpoint selected; show info about all currently set watchpoints.
298 result.AppendMessage ("Current watchpoints:");
299 for (size_t i = 0; i < num_watchpoints; ++i)
300 {
301 WatchpointLocation *wp_loc = watchpoints.GetByIndex(i).get();
302 AddWatchpointDescription(&output_stream, wp_loc, m_options.m_level);
303 }
304 result.SetStatus(eReturnStatusSuccessFinishNoResult);
305 }
306 else
307 {
308 // Particular watchpoints selected; enable them.
309 std::vector<uint32_t> wp_ids;
310 if (!VerifyWatchpointIDs(args, wp_ids))
311 {
312 result.AppendError("Invalid watchpoints specification.");
313 result.SetStatus(eReturnStatusFailed);
314 return false;
315 }
316
317 const size_t size = wp_ids.size();
318 for (size_t i = 0; i < size; ++i)
319 {
320 WatchpointLocation *wp_loc = watchpoints.FindByID(wp_ids[i]).get();
321 if (wp_loc)
322 AddWatchpointDescription(&output_stream, wp_loc, m_options.m_level);
323 result.SetStatus(eReturnStatusSuccessFinishNoResult);
324 }
325 }
326
327 return result.Succeeded();
328}
329
330//-------------------------------------------------------------------------
331// CommandObjectWatchpointEnable
332//-------------------------------------------------------------------------
333#pragma mark Enable
334
335CommandObjectWatchpointEnable::CommandObjectWatchpointEnable(CommandInterpreter &interpreter) :
336 CommandObject(interpreter,
337 "enable",
338 "Enable the specified disabled watchpoint(s). If no watchpoints are specified, enable all of them.",
339 NULL)
340{
341 CommandArgumentEntry arg;
Johnny Chencacedfb2011-09-22 22:34:09 +0000342 CommandObject::AddIDsArgumentData(arg, eArgTypeWatchpointID, eArgTypeWatchpointIDRange);
Johnny Chen01acfa72011-09-22 18:04:58 +0000343 // Add the entry for the first argument for this command to the object's arguments vector.
344 m_arguments.push_back(arg);
345}
346
347CommandObjectWatchpointEnable::~CommandObjectWatchpointEnable()
348{
349}
350
351bool
352CommandObjectWatchpointEnable::Execute(Args& args, CommandReturnObject &result)
353{
354 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
355 if (!CheckTargetForWatchpointOperations(target, result))
356 return false;
357
358 Mutex::Locker locker;
359 target->GetWatchpointLocationList().GetListMutex(locker);
360
361 const WatchpointLocationList &watchpoints = target->GetWatchpointLocationList();
362
363 size_t num_watchpoints = watchpoints.GetSize();
364
365 if (num_watchpoints == 0)
366 {
367 result.AppendError("No watchpoints exist to be enabled.");
368 result.SetStatus(eReturnStatusFailed);
369 return false;
370 }
371
372 if (args.GetArgumentCount() == 0)
373 {
374 // No watchpoint selected; enable all currently set watchpoints.
375 target->EnableAllWatchpointLocations();
376 result.AppendMessageWithFormat("All watchpoints enabled. (%lu watchpoints)\n", num_watchpoints);
377 result.SetStatus(eReturnStatusSuccessFinishNoResult);
378 }
379 else
380 {
381 // Particular watchpoints selected; enable them.
382 std::vector<uint32_t> wp_ids;
383 if (!VerifyWatchpointIDs(args, wp_ids))
384 {
385 result.AppendError("Invalid watchpoints specification.");
386 result.SetStatus(eReturnStatusFailed);
387 return false;
388 }
389
390 int count = 0;
391 const size_t size = wp_ids.size();
392 for (size_t i = 0; i < size; ++i)
393 if (target->EnableWatchpointLocationByID(wp_ids[i]))
394 ++count;
395 result.AppendMessageWithFormat("%d watchpoints enabled.\n", count);
396 result.SetStatus(eReturnStatusSuccessFinishNoResult);
397 }
398
399 return result.Succeeded();
400}
401
402//-------------------------------------------------------------------------
403// CommandObjectWatchpointDisable
404//-------------------------------------------------------------------------
405#pragma mark Disable
406
407CommandObjectWatchpointDisable::CommandObjectWatchpointDisable(CommandInterpreter &interpreter) :
408 CommandObject(interpreter,
409 "watchpoint disable",
410 "Disable the specified watchpoint(s) without removing it/them. If no watchpoints are specified, disable them all.",
411 NULL)
412{
413 CommandArgumentEntry arg;
Johnny Chencacedfb2011-09-22 22:34:09 +0000414 CommandObject::AddIDsArgumentData(arg, eArgTypeWatchpointID, eArgTypeWatchpointIDRange);
Johnny Chen01acfa72011-09-22 18:04:58 +0000415 // Add the entry for the first argument for this command to the object's arguments vector.
416 m_arguments.push_back(arg);
417}
418
419CommandObjectWatchpointDisable::~CommandObjectWatchpointDisable()
420{
421}
422
423bool
424CommandObjectWatchpointDisable::Execute(Args& args, CommandReturnObject &result)
425{
426 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
427 if (!CheckTargetForWatchpointOperations(target, result))
428 return false;
429
430 Mutex::Locker locker;
431 target->GetWatchpointLocationList().GetListMutex(locker);
432
433 const WatchpointLocationList &watchpoints = target->GetWatchpointLocationList();
434 size_t num_watchpoints = watchpoints.GetSize();
435
436 if (num_watchpoints == 0)
437 {
438 result.AppendError("No watchpoints exist to be disabled.");
439 result.SetStatus(eReturnStatusFailed);
440 return false;
441 }
442
443 if (args.GetArgumentCount() == 0)
444 {
445 // No watchpoint selected; disable all currently set watchpoints.
446 if (target->DisableAllWatchpointLocations())
447 {
448 result.AppendMessageWithFormat("All watchpoints disabled. (%lu watchpoints)\n", num_watchpoints);
449 result.SetStatus(eReturnStatusSuccessFinishNoResult);
450 }
451 else
452 {
453 result.AppendError("Disable all watchpoints failed\n");
454 result.SetStatus(eReturnStatusFailed);
455 }
456 }
457 else
458 {
459 // Particular watchpoints selected; disable them.
460 std::vector<uint32_t> wp_ids;
461 if (!VerifyWatchpointIDs(args, wp_ids))
462 {
463 result.AppendError("Invalid watchpoints specification.");
464 result.SetStatus(eReturnStatusFailed);
465 return false;
466 }
467
468 int count = 0;
469 const size_t size = wp_ids.size();
470 for (size_t i = 0; i < size; ++i)
471 if (target->DisableWatchpointLocationByID(wp_ids[i]))
472 ++count;
473 result.AppendMessageWithFormat("%d watchpoints disabled.\n", count);
474 result.SetStatus(eReturnStatusSuccessFinishNoResult);
475 }
476
477 return result.Succeeded();
478}
479
480//-------------------------------------------------------------------------
481// CommandObjectWatchpointDelete
482//-------------------------------------------------------------------------
483#pragma mark Delete
484
485CommandObjectWatchpointDelete::CommandObjectWatchpointDelete(CommandInterpreter &interpreter) :
486 CommandObject(interpreter,
487 "watchpoint delete",
488 "Delete the specified watchpoint(s). If no watchpoints are specified, delete them all.",
489 NULL)
490{
491 CommandArgumentEntry arg;
Johnny Chencacedfb2011-09-22 22:34:09 +0000492 CommandObject::AddIDsArgumentData(arg, eArgTypeWatchpointID, eArgTypeWatchpointIDRange);
Johnny Chen01acfa72011-09-22 18:04:58 +0000493 // Add the entry for the first argument for this command to the object's arguments vector.
494 m_arguments.push_back(arg);
495}
496
497CommandObjectWatchpointDelete::~CommandObjectWatchpointDelete()
498{
499}
500
501bool
502CommandObjectWatchpointDelete::Execute(Args& args, CommandReturnObject &result)
503{
504 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
505 if (!CheckTargetForWatchpointOperations(target, result))
506 return false;
507
508 Mutex::Locker locker;
509 target->GetWatchpointLocationList().GetListMutex(locker);
510
511 const WatchpointLocationList &watchpoints = target->GetWatchpointLocationList();
512
513 size_t num_watchpoints = watchpoints.GetSize();
514
515 if (num_watchpoints == 0)
516 {
517 result.AppendError("No watchpoints exist to be deleted.");
518 result.SetStatus(eReturnStatusFailed);
519 return false;
520 }
521
522 if (args.GetArgumentCount() == 0)
523 {
524 if (!m_interpreter.Confirm("About to delete all watchpoints, do you want to do that?", true))
525 {
526 result.AppendMessage("Operation cancelled...");
527 }
528 else
529 {
530 target->RemoveAllWatchpointLocations();
531 result.AppendMessageWithFormat("All watchpoints removed. (%lu watchpoints)\n", num_watchpoints);
532 }
533 result.SetStatus (eReturnStatusSuccessFinishNoResult);
534 }
535 else
536 {
537 // Particular watchpoints selected; delete them.
538 std::vector<uint32_t> wp_ids;
539 if (!VerifyWatchpointIDs(args, wp_ids))
540 {
541 result.AppendError("Invalid watchpoints specification.");
542 result.SetStatus(eReturnStatusFailed);
543 return false;
544 }
545
546 int count = 0;
547 const size_t size = wp_ids.size();
548 for (size_t i = 0; i < size; ++i)
549 if (target->RemoveWatchpointLocationByID(wp_ids[i]))
550 ++count;
551 result.AppendMessageWithFormat("%d watchpoints deleted.\n",count);
552 result.SetStatus (eReturnStatusSuccessFinishNoResult);
553 }
554
555 return result.Succeeded();
556}
557