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 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 26 using namespace lldb; 27 using namespace lldb_private; 28 29 static void 30 AddWatchpointDescription(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 38 static bool 39 CheckTargetForWatchpointOperations(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. 61 static const char* RSA[4] = { "-", "to", "To", "TO" }; 62 63 // Return the index to RSA if found; otherwise -1 is returned. 64 static int32_t 65 WithRSAIndex(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. 77 static bool 78 VerifyWatchpointIDs(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 146 CommandObjectMultiwordWatchpoint::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 170 CommandObjectMultiwordWatchpoint::~CommandObjectMultiwordWatchpoint() 171 { 172 } 173 174 //------------------------------------------------------------------------- 175 // CommandObjectWatchpointList::Options 176 //------------------------------------------------------------------------- 177 #pragma mark List::CommandOptions 178 179 CommandObjectWatchpointList::CommandOptions::CommandOptions(CommandInterpreter &interpreter) : 180 Options(interpreter), 181 m_level(lldb::eDescriptionLevelBrief) // Watchpoint List defaults to brief descriptions 182 { 183 } 184 185 CommandObjectWatchpointList::CommandOptions::~CommandOptions() 186 { 187 } 188 189 OptionDefinition 190 CommandObjectWatchpointList::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 204 const OptionDefinition* 205 CommandObjectWatchpointList::CommandOptions::GetDefinitions() 206 { 207 return g_option_table; 208 } 209 210 Error 211 CommandObjectWatchpointList::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 235 void 236 CommandObjectWatchpointList::CommandOptions::OptionParsingStarting() 237 { 238 m_level = lldb::eDescriptionLevelFull; 239 } 240 241 //------------------------------------------------------------------------- 242 // CommandObjectWatchpointList 243 //------------------------------------------------------------------------- 244 #pragma mark List 245 246 CommandObjectWatchpointList::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; 254 CommandObject::AddIDsArgumentData(arg, eArgTypeWatchpointID, eArgTypeWatchpointIDRange); 255 // Add the entry for the first argument for this command to the object's arguments vector. 256 m_arguments.push_back(arg); 257 } 258 259 CommandObjectWatchpointList::~CommandObjectWatchpointList() 260 { 261 } 262 263 Options * 264 CommandObjectWatchpointList::GetOptions() 265 { 266 return &m_options; 267 } 268 269 bool 270 CommandObjectWatchpointList::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 335 CommandObjectWatchpointEnable::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; 342 CommandObject::AddIDsArgumentData(arg, eArgTypeWatchpointID, eArgTypeWatchpointIDRange); 343 // Add the entry for the first argument for this command to the object's arguments vector. 344 m_arguments.push_back(arg); 345 } 346 347 CommandObjectWatchpointEnable::~CommandObjectWatchpointEnable() 348 { 349 } 350 351 bool 352 CommandObjectWatchpointEnable::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 407 CommandObjectWatchpointDisable::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; 414 CommandObject::AddIDsArgumentData(arg, eArgTypeWatchpointID, eArgTypeWatchpointIDRange); 415 // Add the entry for the first argument for this command to the object's arguments vector. 416 m_arguments.push_back(arg); 417 } 418 419 CommandObjectWatchpointDisable::~CommandObjectWatchpointDisable() 420 { 421 } 422 423 bool 424 CommandObjectWatchpointDisable::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 485 CommandObjectWatchpointDelete::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; 492 CommandObject::AddIDsArgumentData(arg, eArgTypeWatchpointID, eArgTypeWatchpointIDRange); 493 // Add the entry for the first argument for this command to the object's arguments vector. 494 m_arguments.push_back(arg); 495 } 496 497 CommandObjectWatchpointDelete::~CommandObjectWatchpointDelete() 498 { 499 } 500 501 bool 502 CommandObjectWatchpointDelete::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 558