1 //===-- CommandObjectBreakpoint.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 "lldb/lldb-python.h" 11 12 #include "CommandObjectBreakpoint.h" 13 #include "CommandObjectBreakpointCommand.h" 14 15 // C Includes 16 // C++ Includes 17 // Other libraries and framework includes 18 // Project includes 19 #include "lldb/Breakpoint/Breakpoint.h" 20 #include "lldb/Breakpoint/BreakpointIDList.h" 21 #include "lldb/Breakpoint/BreakpointLocation.h" 22 #include "lldb/Interpreter/Options.h" 23 #include "lldb/Core/RegularExpression.h" 24 #include "lldb/Core/StreamString.h" 25 #include "lldb/Interpreter/CommandInterpreter.h" 26 #include "lldb/Interpreter/CommandReturnObject.h" 27 #include "lldb/Target/Target.h" 28 #include "lldb/Interpreter/CommandCompletions.h" 29 #include "lldb/Target/StackFrame.h" 30 #include "lldb/Target/Thread.h" 31 #include "lldb/Target/ThreadSpec.h" 32 33 #include <vector> 34 35 using namespace lldb; 36 using namespace lldb_private; 37 38 static void 39 AddBreakpointDescription (Stream *s, Breakpoint *bp, lldb::DescriptionLevel level) 40 { 41 s->IndentMore(); 42 bp->GetDescription (s, level, true); 43 s->IndentLess(); 44 s->EOL(); 45 } 46 47 //------------------------------------------------------------------------- 48 // CommandObjectBreakpointSet 49 //------------------------------------------------------------------------- 50 51 52 class CommandObjectBreakpointSet : public CommandObjectParsed 53 { 54 public: 55 56 typedef enum BreakpointSetType 57 { 58 eSetTypeInvalid, 59 eSetTypeFileAndLine, 60 eSetTypeAddress, 61 eSetTypeFunctionName, 62 eSetTypeFunctionRegexp, 63 eSetTypeSourceRegexp, 64 eSetTypeException 65 } BreakpointSetType; 66 67 CommandObjectBreakpointSet (CommandInterpreter &interpreter) : 68 CommandObjectParsed (interpreter, 69 "breakpoint set", 70 "Sets a breakpoint or set of breakpoints in the executable.", 71 "breakpoint set <cmd-options>"), 72 m_options (interpreter) 73 { 74 } 75 76 77 virtual 78 ~CommandObjectBreakpointSet () {} 79 80 virtual Options * 81 GetOptions () 82 { 83 return &m_options; 84 } 85 86 class CommandOptions : public Options 87 { 88 public: 89 90 CommandOptions (CommandInterpreter &interpreter) : 91 Options (interpreter), 92 m_condition (), 93 m_filenames (), 94 m_line_num (0), 95 m_column (0), 96 m_func_names (), 97 m_func_name_type_mask (eFunctionNameTypeNone), 98 m_func_regexp (), 99 m_source_text_regexp(), 100 m_modules (), 101 m_load_addr(), 102 m_ignore_count (0), 103 m_thread_id(LLDB_INVALID_THREAD_ID), 104 m_thread_index (UINT32_MAX), 105 m_thread_name(), 106 m_queue_name(), 107 m_catch_bp (false), 108 m_throw_bp (true), 109 m_hardware (false), 110 m_language (eLanguageTypeUnknown), 111 m_skip_prologue (eLazyBoolCalculate), 112 m_one_shot (false) 113 { 114 } 115 116 117 virtual 118 ~CommandOptions () {} 119 120 virtual Error 121 SetOptionValue (uint32_t option_idx, const char *option_arg) 122 { 123 Error error; 124 const int short_option = m_getopt_table[option_idx].val; 125 126 switch (short_option) 127 { 128 case 'a': 129 { 130 ExecutionContext exe_ctx (m_interpreter.GetExecutionContext()); 131 m_load_addr = Args::StringToAddress(&exe_ctx, option_arg, LLDB_INVALID_ADDRESS, &error); 132 } 133 break; 134 135 case 'b': 136 m_func_names.push_back (option_arg); 137 m_func_name_type_mask |= eFunctionNameTypeBase; 138 break; 139 140 case 'C': 141 m_column = Args::StringToUInt32 (option_arg, 0); 142 break; 143 144 case 'c': 145 m_condition.assign(option_arg); 146 break; 147 148 case 'D': 149 m_use_dummy = true; 150 break; 151 152 case 'E': 153 { 154 LanguageType language = LanguageRuntime::GetLanguageTypeFromString (option_arg); 155 156 switch (language) 157 { 158 case eLanguageTypeC89: 159 case eLanguageTypeC: 160 case eLanguageTypeC99: 161 case eLanguageTypeC11: 162 m_language = eLanguageTypeC; 163 break; 164 case eLanguageTypeC_plus_plus: 165 case eLanguageTypeC_plus_plus_03: 166 case eLanguageTypeC_plus_plus_11: 167 m_language = eLanguageTypeC_plus_plus; 168 break; 169 case eLanguageTypeObjC: 170 m_language = eLanguageTypeObjC; 171 break; 172 case eLanguageTypeObjC_plus_plus: 173 error.SetErrorStringWithFormat ("Set exception breakpoints separately for c++ and objective-c"); 174 break; 175 case eLanguageTypeUnknown: 176 error.SetErrorStringWithFormat ("Unknown language type: '%s' for exception breakpoint", option_arg); 177 break; 178 default: 179 error.SetErrorStringWithFormat ("Unsupported language type: '%s' for exception breakpoint", option_arg); 180 } 181 } 182 break; 183 184 case 'f': 185 m_filenames.AppendIfUnique (FileSpec(option_arg, false)); 186 break; 187 188 case 'F': 189 m_func_names.push_back (option_arg); 190 m_func_name_type_mask |= eFunctionNameTypeFull; 191 break; 192 193 case 'h': 194 { 195 bool success; 196 m_catch_bp = Args::StringToBoolean (option_arg, true, &success); 197 if (!success) 198 error.SetErrorStringWithFormat ("Invalid boolean value for on-catch option: '%s'", option_arg); 199 } 200 break; 201 202 case 'H': 203 m_hardware = true; 204 break; 205 206 case 'i': 207 { 208 m_ignore_count = Args::StringToUInt32(option_arg, UINT32_MAX, 0); 209 if (m_ignore_count == UINT32_MAX) 210 error.SetErrorStringWithFormat ("invalid ignore count '%s'", option_arg); 211 break; 212 } 213 214 case 'K': 215 { 216 bool success; 217 bool value; 218 value = Args::StringToBoolean (option_arg, true, &success); 219 if (value) 220 m_skip_prologue = eLazyBoolYes; 221 else 222 m_skip_prologue = eLazyBoolNo; 223 224 if (!success) 225 error.SetErrorStringWithFormat ("Invalid boolean value for skip prologue option: '%s'", option_arg); 226 } 227 break; 228 229 case 'l': 230 m_line_num = Args::StringToUInt32 (option_arg, 0); 231 break; 232 233 case 'M': 234 m_func_names.push_back (option_arg); 235 m_func_name_type_mask |= eFunctionNameTypeMethod; 236 break; 237 238 case 'n': 239 m_func_names.push_back (option_arg); 240 m_func_name_type_mask |= eFunctionNameTypeAuto; 241 break; 242 243 case 'o': 244 m_one_shot = true; 245 break; 246 247 case 'p': 248 m_source_text_regexp.assign (option_arg); 249 break; 250 251 case 'q': 252 m_queue_name.assign (option_arg); 253 break; 254 255 case 'r': 256 m_func_regexp.assign (option_arg); 257 break; 258 259 case 's': 260 { 261 m_modules.AppendIfUnique (FileSpec (option_arg, false)); 262 break; 263 } 264 265 case 'S': 266 m_func_names.push_back (option_arg); 267 m_func_name_type_mask |= eFunctionNameTypeSelector; 268 break; 269 270 case 't' : 271 { 272 m_thread_id = Args::StringToUInt64(option_arg, LLDB_INVALID_THREAD_ID, 0); 273 if (m_thread_id == LLDB_INVALID_THREAD_ID) 274 error.SetErrorStringWithFormat ("invalid thread id string '%s'", option_arg); 275 } 276 break; 277 278 case 'T': 279 m_thread_name.assign (option_arg); 280 break; 281 282 case 'w': 283 { 284 bool success; 285 m_throw_bp = Args::StringToBoolean (option_arg, true, &success); 286 if (!success) 287 error.SetErrorStringWithFormat ("Invalid boolean value for on-throw option: '%s'", option_arg); 288 } 289 break; 290 291 case 'x': 292 { 293 m_thread_index = Args::StringToUInt32(option_arg, UINT32_MAX, 0); 294 if (m_thread_id == UINT32_MAX) 295 error.SetErrorStringWithFormat ("invalid thread index string '%s'", option_arg); 296 297 } 298 break; 299 300 default: 301 error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option); 302 break; 303 } 304 305 return error; 306 } 307 void 308 OptionParsingStarting () 309 { 310 m_condition.clear(); 311 m_filenames.Clear(); 312 m_line_num = 0; 313 m_column = 0; 314 m_func_names.clear(); 315 m_func_name_type_mask = eFunctionNameTypeNone; 316 m_func_regexp.clear(); 317 m_source_text_regexp.clear(); 318 m_modules.Clear(); 319 m_load_addr = LLDB_INVALID_ADDRESS; 320 m_ignore_count = 0; 321 m_thread_id = LLDB_INVALID_THREAD_ID; 322 m_thread_index = UINT32_MAX; 323 m_thread_name.clear(); 324 m_queue_name.clear(); 325 m_catch_bp = false; 326 m_throw_bp = true; 327 m_hardware = false; 328 m_language = eLanguageTypeUnknown; 329 m_skip_prologue = eLazyBoolCalculate; 330 m_one_shot = false; 331 m_use_dummy = false; 332 } 333 334 const OptionDefinition* 335 GetDefinitions () 336 { 337 return g_option_table; 338 } 339 340 // Options table: Required for subclasses of Options. 341 342 static OptionDefinition g_option_table[]; 343 344 // Instance variables to hold the values for command options. 345 346 std::string m_condition; 347 FileSpecList m_filenames; 348 uint32_t m_line_num; 349 uint32_t m_column; 350 std::vector<std::string> m_func_names; 351 uint32_t m_func_name_type_mask; 352 std::string m_func_regexp; 353 std::string m_source_text_regexp; 354 FileSpecList m_modules; 355 lldb::addr_t m_load_addr; 356 uint32_t m_ignore_count; 357 lldb::tid_t m_thread_id; 358 uint32_t m_thread_index; 359 std::string m_thread_name; 360 std::string m_queue_name; 361 bool m_catch_bp; 362 bool m_throw_bp; 363 bool m_hardware; // Request to use hardware breakpoints 364 lldb::LanguageType m_language; 365 LazyBool m_skip_prologue; 366 bool m_one_shot; 367 bool m_use_dummy; 368 369 }; 370 371 protected: 372 virtual bool 373 DoExecute (Args& command, 374 CommandReturnObject &result) 375 { 376 Target *target = GetSelectedOrDummyTarget(m_options.m_use_dummy); 377 378 if (target == nullptr) 379 { 380 result.AppendError ("Invalid target. Must set target before setting breakpoints (see 'target create' command)."); 381 result.SetStatus (eReturnStatusFailed); 382 return false; 383 } 384 385 // The following are the various types of breakpoints that could be set: 386 // 1). -f -l -p [-s -g] (setting breakpoint by source location) 387 // 2). -a [-s -g] (setting breakpoint by address) 388 // 3). -n [-s -g] (setting breakpoint by function name) 389 // 4). -r [-s -g] (setting breakpoint by function name regular expression) 390 // 5). -p -f (setting a breakpoint by comparing a reg-exp to source text) 391 // 6). -E [-w -h] (setting a breakpoint for exceptions for a given language.) 392 393 BreakpointSetType break_type = eSetTypeInvalid; 394 395 if (m_options.m_line_num != 0) 396 break_type = eSetTypeFileAndLine; 397 else if (m_options.m_load_addr != LLDB_INVALID_ADDRESS) 398 break_type = eSetTypeAddress; 399 else if (!m_options.m_func_names.empty()) 400 break_type = eSetTypeFunctionName; 401 else if (!m_options.m_func_regexp.empty()) 402 break_type = eSetTypeFunctionRegexp; 403 else if (!m_options.m_source_text_regexp.empty()) 404 break_type = eSetTypeSourceRegexp; 405 else if (m_options.m_language != eLanguageTypeUnknown) 406 break_type = eSetTypeException; 407 408 Breakpoint *bp = NULL; 409 FileSpec module_spec; 410 const bool internal = false; 411 412 switch (break_type) 413 { 414 case eSetTypeFileAndLine: // Breakpoint by source position 415 { 416 FileSpec file; 417 const size_t num_files = m_options.m_filenames.GetSize(); 418 if (num_files == 0) 419 { 420 if (!GetDefaultFile (target, file, result)) 421 { 422 result.AppendError("No file supplied and no default file available."); 423 result.SetStatus (eReturnStatusFailed); 424 return false; 425 } 426 } 427 else if (num_files > 1) 428 { 429 result.AppendError("Only one file at a time is allowed for file and line breakpoints."); 430 result.SetStatus (eReturnStatusFailed); 431 return false; 432 } 433 else 434 file = m_options.m_filenames.GetFileSpecAtIndex(0); 435 436 // Only check for inline functions if 437 LazyBool check_inlines = eLazyBoolCalculate; 438 439 bp = target->CreateBreakpoint (&(m_options.m_modules), 440 file, 441 m_options.m_line_num, 442 check_inlines, 443 m_options.m_skip_prologue, 444 internal, 445 m_options.m_hardware).get(); 446 } 447 break; 448 449 case eSetTypeAddress: // Breakpoint by address 450 bp = target->CreateBreakpoint (m_options.m_load_addr, 451 internal, 452 m_options.m_hardware).get(); 453 break; 454 455 case eSetTypeFunctionName: // Breakpoint by function name 456 { 457 uint32_t name_type_mask = m_options.m_func_name_type_mask; 458 459 if (name_type_mask == 0) 460 name_type_mask = eFunctionNameTypeAuto; 461 462 bp = target->CreateBreakpoint (&(m_options.m_modules), 463 &(m_options.m_filenames), 464 m_options.m_func_names, 465 name_type_mask, 466 m_options.m_skip_prologue, 467 internal, 468 m_options.m_hardware).get(); 469 } 470 break; 471 472 case eSetTypeFunctionRegexp: // Breakpoint by regular expression function name 473 { 474 RegularExpression regexp(m_options.m_func_regexp.c_str()); 475 if (!regexp.IsValid()) 476 { 477 char err_str[1024]; 478 regexp.GetErrorAsCString(err_str, sizeof(err_str)); 479 result.AppendErrorWithFormat("Function name regular expression could not be compiled: \"%s\"", 480 err_str); 481 result.SetStatus (eReturnStatusFailed); 482 return false; 483 } 484 485 bp = target->CreateFuncRegexBreakpoint (&(m_options.m_modules), 486 &(m_options.m_filenames), 487 regexp, 488 m_options.m_skip_prologue, 489 internal, 490 m_options.m_hardware).get(); 491 } 492 break; 493 case eSetTypeSourceRegexp: // Breakpoint by regexp on source text. 494 { 495 const size_t num_files = m_options.m_filenames.GetSize(); 496 497 if (num_files == 0) 498 { 499 FileSpec file; 500 if (!GetDefaultFile (target, file, result)) 501 { 502 result.AppendError ("No files provided and could not find default file."); 503 result.SetStatus (eReturnStatusFailed); 504 return false; 505 } 506 else 507 { 508 m_options.m_filenames.Append (file); 509 } 510 } 511 512 RegularExpression regexp(m_options.m_source_text_regexp.c_str()); 513 if (!regexp.IsValid()) 514 { 515 char err_str[1024]; 516 regexp.GetErrorAsCString(err_str, sizeof(err_str)); 517 result.AppendErrorWithFormat("Source text regular expression could not be compiled: \"%s\"", 518 err_str); 519 result.SetStatus (eReturnStatusFailed); 520 return false; 521 } 522 bp = target->CreateSourceRegexBreakpoint (&(m_options.m_modules), 523 &(m_options.m_filenames), 524 regexp, 525 internal, 526 m_options.m_hardware).get(); 527 } 528 break; 529 case eSetTypeException: 530 { 531 bp = target->CreateExceptionBreakpoint (m_options.m_language, 532 m_options.m_catch_bp, 533 m_options.m_throw_bp, 534 m_options.m_hardware).get(); 535 } 536 break; 537 default: 538 break; 539 } 540 541 // Now set the various options that were passed in: 542 if (bp) 543 { 544 if (m_options.m_thread_id != LLDB_INVALID_THREAD_ID) 545 bp->SetThreadID (m_options.m_thread_id); 546 547 if (m_options.m_thread_index != UINT32_MAX) 548 bp->GetOptions()->GetThreadSpec()->SetIndex(m_options.m_thread_index); 549 550 if (!m_options.m_thread_name.empty()) 551 bp->GetOptions()->GetThreadSpec()->SetName(m_options.m_thread_name.c_str()); 552 553 if (!m_options.m_queue_name.empty()) 554 bp->GetOptions()->GetThreadSpec()->SetQueueName(m_options.m_queue_name.c_str()); 555 556 if (m_options.m_ignore_count != 0) 557 bp->GetOptions()->SetIgnoreCount(m_options.m_ignore_count); 558 559 if (!m_options.m_condition.empty()) 560 bp->GetOptions()->SetCondition(m_options.m_condition.c_str()); 561 562 bp->SetOneShot (m_options.m_one_shot); 563 } 564 565 if (bp) 566 { 567 Stream &output_stream = result.GetOutputStream(); 568 const bool show_locations = false; 569 bp->GetDescription(&output_stream, lldb::eDescriptionLevelInitial, show_locations); 570 // Don't print out this warning for exception breakpoints. They can get set before the target 571 // is set, but we won't know how to actually set the breakpoint till we run. 572 if (bp->GetNumLocations() == 0 && break_type != eSetTypeException) 573 output_stream.Printf ("WARNING: Unable to resolve breakpoint to any actual locations.\n"); 574 result.SetStatus (eReturnStatusSuccessFinishResult); 575 } 576 else if (!bp) 577 { 578 result.AppendError ("Breakpoint creation failed: No breakpoint created."); 579 result.SetStatus (eReturnStatusFailed); 580 } 581 582 return result.Succeeded(); 583 } 584 585 private: 586 bool 587 GetDefaultFile (Target *target, FileSpec &file, CommandReturnObject &result) 588 { 589 uint32_t default_line; 590 // First use the Source Manager's default file. 591 // Then use the current stack frame's file. 592 if (!target->GetSourceManager().GetDefaultFileAndLine(file, default_line)) 593 { 594 StackFrame *cur_frame = m_exe_ctx.GetFramePtr(); 595 if (cur_frame == NULL) 596 { 597 result.AppendError ("No selected frame to use to find the default file."); 598 result.SetStatus (eReturnStatusFailed); 599 return false; 600 } 601 else if (!cur_frame->HasDebugInformation()) 602 { 603 result.AppendError ("Cannot use the selected frame to find the default file, it has no debug info."); 604 result.SetStatus (eReturnStatusFailed); 605 return false; 606 } 607 else 608 { 609 const SymbolContext &sc = cur_frame->GetSymbolContext (eSymbolContextLineEntry); 610 if (sc.line_entry.file) 611 { 612 file = sc.line_entry.file; 613 } 614 else 615 { 616 result.AppendError ("Can't find the file for the selected frame to use as the default file."); 617 result.SetStatus (eReturnStatusFailed); 618 return false; 619 } 620 } 621 } 622 return true; 623 } 624 625 CommandOptions m_options; 626 }; 627 // If an additional option set beyond LLDB_OPTION_SET_10 is added, make sure to 628 // update the numbers passed to LLDB_OPT_SET_FROM_TO(...) appropriately. 629 #define LLDB_OPT_FILE ( LLDB_OPT_SET_FROM_TO(1, 9) & ~LLDB_OPT_SET_2 ) 630 #define LLDB_OPT_NOT_10 ( LLDB_OPT_SET_FROM_TO(1, 10) & ~LLDB_OPT_SET_10 ) 631 #define LLDB_OPT_SKIP_PROLOGUE ( LLDB_OPT_SET_1 | LLDB_OPT_SET_FROM_TO(3,8) ) 632 633 OptionDefinition 634 CommandObjectBreakpointSet::CommandOptions::g_option_table[] = 635 { 636 { LLDB_OPT_NOT_10, false, "shlib", 's', OptionParser::eRequiredArgument, NULL, NULL, CommandCompletions::eModuleCompletion, eArgTypeShlibName, 637 "Set the breakpoint only in this shared library. " 638 "Can repeat this option multiple times to specify multiple shared libraries."}, 639 640 { LLDB_OPT_SET_ALL, false, "ignore-count", 'i', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeCount, 641 "Set the number of times this breakpoint is skipped before stopping." }, 642 643 { LLDB_OPT_SET_ALL, false, "one-shot", 'o', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, 644 "The breakpoint is deleted the first time it causes a stop." }, 645 646 { LLDB_OPT_SET_ALL, false, "condition", 'c', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeExpression, 647 "The breakpoint stops only if this condition expression evaluates to true."}, 648 649 { LLDB_OPT_SET_ALL, false, "thread-index", 'x', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeThreadIndex, 650 "The breakpoint stops only for the thread whose indeX matches this argument."}, 651 652 { LLDB_OPT_SET_ALL, false, "thread-id", 't', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeThreadID, 653 "The breakpoint stops only for the thread whose TID matches this argument."}, 654 655 { LLDB_OPT_SET_ALL, false, "thread-name", 'T', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeThreadName, 656 "The breakpoint stops only for the thread whose thread name matches this argument."}, 657 658 { LLDB_OPT_SET_ALL, false, "hardware", 'H', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, 659 "Require the breakpoint to use hardware breakpoints."}, 660 661 { LLDB_OPT_SET_ALL, false, "queue-name", 'q', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeQueueName, 662 "The breakpoint stops only for threads in the queue whose name is given by this argument."}, 663 664 { LLDB_OPT_FILE, false, "file", 'f', OptionParser::eRequiredArgument, NULL, NULL, CommandCompletions::eSourceFileCompletion, eArgTypeFilename, 665 "Specifies the source file in which to set this breakpoint. " 666 "Note, by default lldb only looks for files that are #included if they use the standard include file extensions. " 667 "To set breakpoints on .c/.cpp/.m/.mm files that are #included, set target.inline-breakpoint-strategy" 668 " to \"always\"."}, 669 670 { LLDB_OPT_SET_1, true, "line", 'l', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeLineNum, 671 "Specifies the line number on which to set this breakpoint."}, 672 673 // Comment out this option for the moment, as we don't actually use it, but will in the future. 674 // This way users won't see it, but the infrastructure is left in place. 675 // { 0, false, "column", 'C', OptionParser::eRequiredArgument, NULL, "<column>", 676 // "Set the breakpoint by source location at this particular column."}, 677 678 { LLDB_OPT_SET_2, true, "address", 'a', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeAddressOrExpression, 679 "Set the breakpoint by address, at the specified address."}, 680 681 { LLDB_OPT_SET_3, true, "name", 'n', OptionParser::eRequiredArgument, NULL, NULL, CommandCompletions::eSymbolCompletion, eArgTypeFunctionName, 682 "Set the breakpoint by function name. Can be repeated multiple times to make one breakpoint for multiple names" }, 683 684 { LLDB_OPT_SET_4, true, "fullname", 'F', OptionParser::eRequiredArgument, NULL, NULL, CommandCompletions::eSymbolCompletion, eArgTypeFullName, 685 "Set the breakpoint by fully qualified function names. For C++ this means namespaces and all arguments, and " 686 "for Objective C this means a full function prototype with class and selector. " 687 "Can be repeated multiple times to make one breakpoint for multiple names." }, 688 689 { LLDB_OPT_SET_5, true, "selector", 'S', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeSelector, 690 "Set the breakpoint by ObjC selector name. Can be repeated multiple times to make one breakpoint for multiple Selectors." }, 691 692 { LLDB_OPT_SET_6, true, "method", 'M', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeMethod, 693 "Set the breakpoint by C++ method names. Can be repeated multiple times to make one breakpoint for multiple methods." }, 694 695 { LLDB_OPT_SET_7, true, "func-regex", 'r', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeRegularExpression, 696 "Set the breakpoint by function name, evaluating a regular-expression to find the function name(s)." }, 697 698 { LLDB_OPT_SET_8, true, "basename", 'b', OptionParser::eRequiredArgument, NULL, NULL, CommandCompletions::eSymbolCompletion, eArgTypeFunctionName, 699 "Set the breakpoint by function basename (C++ namespaces and arguments will be ignored). " 700 "Can be repeated multiple times to make one breakpoint for multiple symbols." }, 701 702 { LLDB_OPT_SET_9, true, "source-pattern-regexp", 'p', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeRegularExpression, 703 "Set the breakpoint by specifying a regular expression which is matched against the source text in a source file or files " 704 "specified with the -f option. The -f option can be specified more than once. " 705 "If no source files are specified, uses the current \"default source file\"" }, 706 707 { LLDB_OPT_SET_10, true, "language-exception", 'E', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeLanguage, 708 "Set the breakpoint on exceptions thrown by the specified language (without options, on throw but not catch.)" }, 709 710 { LLDB_OPT_SET_10, false, "on-throw", 'w', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBoolean, 711 "Set the breakpoint on exception throW." }, 712 713 { LLDB_OPT_SET_10, false, "on-catch", 'h', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBoolean, 714 "Set the breakpoint on exception catcH." }, 715 716 { LLDB_OPT_SKIP_PROLOGUE, false, "skip-prologue", 'K', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBoolean, 717 "sKip the prologue if the breakpoint is at the beginning of a function. If not set the target.skip-prologue setting is used." }, 718 719 { LLDB_OPT_SET_ALL, false, "dummy-breakpoints", 'D', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, 720 "Sets Dummy breakpoints - i.e. breakpoints set before a file is provided, which prime new targets."}, 721 722 { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL } 723 }; 724 725 //------------------------------------------------------------------------- 726 // CommandObjectBreakpointModify 727 //------------------------------------------------------------------------- 728 #pragma mark Modify 729 730 class CommandObjectBreakpointModify : public CommandObjectParsed 731 { 732 public: 733 734 CommandObjectBreakpointModify (CommandInterpreter &interpreter) : 735 CommandObjectParsed (interpreter, 736 "breakpoint modify", 737 "Modify the options on a breakpoint or set of breakpoints in the executable. " 738 "If no breakpoint is specified, acts on the last created breakpoint. " 739 "With the exception of -e, -d and -i, passing an empty argument clears the modification.", 740 NULL), 741 m_options (interpreter) 742 { 743 CommandArgumentEntry arg; 744 CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID, eArgTypeBreakpointIDRange); 745 // Add the entry for the first argument for this command to the object's arguments vector. 746 m_arguments.push_back (arg); 747 } 748 749 750 virtual 751 ~CommandObjectBreakpointModify () {} 752 753 virtual Options * 754 GetOptions () 755 { 756 return &m_options; 757 } 758 759 class CommandOptions : public Options 760 { 761 public: 762 763 CommandOptions (CommandInterpreter &interpreter) : 764 Options (interpreter), 765 m_ignore_count (0), 766 m_thread_id(LLDB_INVALID_THREAD_ID), 767 m_thread_id_passed(false), 768 m_thread_index (UINT32_MAX), 769 m_thread_index_passed(false), 770 m_thread_name(), 771 m_queue_name(), 772 m_condition (), 773 m_one_shot (false), 774 m_enable_passed (false), 775 m_enable_value (false), 776 m_name_passed (false), 777 m_queue_passed (false), 778 m_condition_passed (false), 779 m_one_shot_passed (false), 780 m_use_dummy (false) 781 { 782 } 783 784 virtual 785 ~CommandOptions () {} 786 787 virtual Error 788 SetOptionValue (uint32_t option_idx, const char *option_arg) 789 { 790 Error error; 791 const int short_option = m_getopt_table[option_idx].val; 792 793 switch (short_option) 794 { 795 case 'c': 796 if (option_arg != NULL) 797 m_condition.assign (option_arg); 798 else 799 m_condition.clear(); 800 m_condition_passed = true; 801 break; 802 case 'd': 803 m_enable_passed = true; 804 m_enable_value = false; 805 break; 806 case 'D': 807 m_use_dummy = true; 808 break; 809 case 'e': 810 m_enable_passed = true; 811 m_enable_value = true; 812 break; 813 case 'i': 814 { 815 m_ignore_count = Args::StringToUInt32(option_arg, UINT32_MAX, 0); 816 if (m_ignore_count == UINT32_MAX) 817 error.SetErrorStringWithFormat ("invalid ignore count '%s'", option_arg); 818 } 819 break; 820 case 'o': 821 { 822 bool value, success; 823 value = Args::StringToBoolean(option_arg, false, &success); 824 if (success) 825 { 826 m_one_shot_passed = true; 827 m_one_shot = value; 828 } 829 else 830 error.SetErrorStringWithFormat("invalid boolean value '%s' passed for -o option", option_arg); 831 } 832 break; 833 case 't' : 834 { 835 if (option_arg[0] == '\0') 836 { 837 m_thread_id = LLDB_INVALID_THREAD_ID; 838 m_thread_id_passed = true; 839 } 840 else 841 { 842 m_thread_id = Args::StringToUInt64(option_arg, LLDB_INVALID_THREAD_ID, 0); 843 if (m_thread_id == LLDB_INVALID_THREAD_ID) 844 error.SetErrorStringWithFormat ("invalid thread id string '%s'", option_arg); 845 else 846 m_thread_id_passed = true; 847 } 848 } 849 break; 850 case 'T': 851 if (option_arg != NULL) 852 m_thread_name.assign (option_arg); 853 else 854 m_thread_name.clear(); 855 m_name_passed = true; 856 break; 857 case 'q': 858 if (option_arg != NULL) 859 m_queue_name.assign (option_arg); 860 else 861 m_queue_name.clear(); 862 m_queue_passed = true; 863 break; 864 case 'x': 865 { 866 if (option_arg[0] == '\n') 867 { 868 m_thread_index = UINT32_MAX; 869 m_thread_index_passed = true; 870 } 871 else 872 { 873 m_thread_index = Args::StringToUInt32 (option_arg, UINT32_MAX, 0); 874 if (m_thread_id == UINT32_MAX) 875 error.SetErrorStringWithFormat ("invalid thread index string '%s'", option_arg); 876 else 877 m_thread_index_passed = true; 878 } 879 } 880 break; 881 default: 882 error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option); 883 break; 884 } 885 886 return error; 887 } 888 void 889 OptionParsingStarting () 890 { 891 m_ignore_count = 0; 892 m_thread_id = LLDB_INVALID_THREAD_ID; 893 m_thread_id_passed = false; 894 m_thread_index = UINT32_MAX; 895 m_thread_index_passed = false; 896 m_thread_name.clear(); 897 m_queue_name.clear(); 898 m_condition.clear(); 899 m_one_shot = false; 900 m_enable_passed = false; 901 m_queue_passed = false; 902 m_name_passed = false; 903 m_condition_passed = false; 904 m_one_shot_passed = false; 905 m_use_dummy = false; 906 } 907 908 const OptionDefinition* 909 GetDefinitions () 910 { 911 return g_option_table; 912 } 913 914 915 // Options table: Required for subclasses of Options. 916 917 static OptionDefinition g_option_table[]; 918 919 // Instance variables to hold the values for command options. 920 921 uint32_t m_ignore_count; 922 lldb::tid_t m_thread_id; 923 bool m_thread_id_passed; 924 uint32_t m_thread_index; 925 bool m_thread_index_passed; 926 std::string m_thread_name; 927 std::string m_queue_name; 928 std::string m_condition; 929 bool m_one_shot; 930 bool m_enable_passed; 931 bool m_enable_value; 932 bool m_name_passed; 933 bool m_queue_passed; 934 bool m_condition_passed; 935 bool m_one_shot_passed; 936 bool m_use_dummy; 937 938 }; 939 940 protected: 941 virtual bool 942 DoExecute (Args& command, CommandReturnObject &result) 943 { 944 Target *target = GetSelectedOrDummyTarget(m_options.m_use_dummy); 945 if (target == NULL) 946 { 947 result.AppendError ("Invalid target. No existing target or breakpoints."); 948 result.SetStatus (eReturnStatusFailed); 949 return false; 950 } 951 952 Mutex::Locker locker; 953 target->GetBreakpointList().GetListMutex(locker); 954 955 BreakpointIDList valid_bp_ids; 956 957 CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids); 958 959 if (result.Succeeded()) 960 { 961 const size_t count = valid_bp_ids.GetSize(); 962 for (size_t i = 0; i < count; ++i) 963 { 964 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i); 965 966 if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) 967 { 968 Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get(); 969 if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) 970 { 971 BreakpointLocation *location = bp->FindLocationByID (cur_bp_id.GetLocationID()).get(); 972 if (location) 973 { 974 if (m_options.m_thread_id_passed) 975 location->SetThreadID (m_options.m_thread_id); 976 977 if (m_options.m_thread_index_passed) 978 location->SetThreadIndex(m_options.m_thread_index); 979 980 if (m_options.m_name_passed) 981 location->SetThreadName(m_options.m_thread_name.c_str()); 982 983 if (m_options.m_queue_passed) 984 location->SetQueueName(m_options.m_queue_name.c_str()); 985 986 if (m_options.m_ignore_count != 0) 987 location->SetIgnoreCount(m_options.m_ignore_count); 988 989 if (m_options.m_enable_passed) 990 location->SetEnabled (m_options.m_enable_value); 991 992 if (m_options.m_condition_passed) 993 location->SetCondition (m_options.m_condition.c_str()); 994 } 995 } 996 else 997 { 998 if (m_options.m_thread_id_passed) 999 bp->SetThreadID (m_options.m_thread_id); 1000 1001 if (m_options.m_thread_index_passed) 1002 bp->SetThreadIndex(m_options.m_thread_index); 1003 1004 if (m_options.m_name_passed) 1005 bp->SetThreadName(m_options.m_thread_name.c_str()); 1006 1007 if (m_options.m_queue_passed) 1008 bp->SetQueueName(m_options.m_queue_name.c_str()); 1009 1010 if (m_options.m_ignore_count != 0) 1011 bp->SetIgnoreCount(m_options.m_ignore_count); 1012 1013 if (m_options.m_enable_passed) 1014 bp->SetEnabled (m_options.m_enable_value); 1015 1016 if (m_options.m_condition_passed) 1017 bp->SetCondition (m_options.m_condition.c_str()); 1018 } 1019 } 1020 } 1021 } 1022 1023 return result.Succeeded(); 1024 } 1025 1026 private: 1027 CommandOptions m_options; 1028 }; 1029 1030 #pragma mark Modify::CommandOptions 1031 OptionDefinition 1032 CommandObjectBreakpointModify::CommandOptions::g_option_table[] = 1033 { 1034 { LLDB_OPT_SET_ALL, false, "ignore-count", 'i', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeCount, "Set the number of times this breakpoint is skipped before stopping." }, 1035 { LLDB_OPT_SET_ALL, false, "one-shot", 'o', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBoolean, "The breakpoint is deleted the first time it stop causes a stop." }, 1036 { LLDB_OPT_SET_ALL, false, "thread-index", 'x', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeThreadIndex, "The breakpoint stops only for the thread whose index matches this argument."}, 1037 { LLDB_OPT_SET_ALL, false, "thread-id", 't', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeThreadID, "The breakpoint stops only for the thread whose TID matches this argument."}, 1038 { LLDB_OPT_SET_ALL, false, "thread-name", 'T', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeThreadName, "The breakpoint stops only for the thread whose thread name matches this argument."}, 1039 { LLDB_OPT_SET_ALL, false, "queue-name", 'q', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeQueueName, "The breakpoint stops only for threads in the queue whose name is given by this argument."}, 1040 { LLDB_OPT_SET_ALL, false, "condition", 'c', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeExpression, "The breakpoint stops only if this condition expression evaluates to true."}, 1041 { LLDB_OPT_SET_1, false, "enable", 'e', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Enable the breakpoint."}, 1042 { LLDB_OPT_SET_2, false, "disable", 'd', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Disable the breakpoint."}, 1043 { LLDB_OPT_SET_ALL, false, "dummy-breakpoints", 'D', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Sets Dummy breakpoints - i.e. breakpoints set before a file is provided, which prime new targets."}, 1044 1045 { 0, false, NULL, 0 , 0, NULL, NULL, 0, eArgTypeNone, NULL } 1046 }; 1047 1048 //------------------------------------------------------------------------- 1049 // CommandObjectBreakpointEnable 1050 //------------------------------------------------------------------------- 1051 #pragma mark Enable 1052 1053 class CommandObjectBreakpointEnable : public CommandObjectParsed 1054 { 1055 public: 1056 CommandObjectBreakpointEnable (CommandInterpreter &interpreter) : 1057 CommandObjectParsed (interpreter, 1058 "enable", 1059 "Enable the specified disabled breakpoint(s). If no breakpoints are specified, enable all of them.", 1060 NULL) 1061 { 1062 CommandArgumentEntry arg; 1063 CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID, eArgTypeBreakpointIDRange); 1064 // Add the entry for the first argument for this command to the object's arguments vector. 1065 m_arguments.push_back (arg); 1066 } 1067 1068 1069 virtual 1070 ~CommandObjectBreakpointEnable () {} 1071 1072 protected: 1073 virtual bool 1074 DoExecute (Args& command, CommandReturnObject &result) 1075 { 1076 Target *target = GetSelectedOrDummyTarget(); 1077 if (target == NULL) 1078 { 1079 result.AppendError ("Invalid target. No existing target or breakpoints."); 1080 result.SetStatus (eReturnStatusFailed); 1081 return false; 1082 } 1083 1084 Mutex::Locker locker; 1085 target->GetBreakpointList().GetListMutex(locker); 1086 1087 const BreakpointList &breakpoints = target->GetBreakpointList(); 1088 1089 size_t num_breakpoints = breakpoints.GetSize(); 1090 1091 if (num_breakpoints == 0) 1092 { 1093 result.AppendError ("No breakpoints exist to be enabled."); 1094 result.SetStatus (eReturnStatusFailed); 1095 return false; 1096 } 1097 1098 if (command.GetArgumentCount() == 0) 1099 { 1100 // No breakpoint selected; enable all currently set breakpoints. 1101 target->EnableAllBreakpoints (); 1102 result.AppendMessageWithFormat ("All breakpoints enabled. (%" PRIu64 " breakpoints)\n", (uint64_t)num_breakpoints); 1103 result.SetStatus (eReturnStatusSuccessFinishNoResult); 1104 } 1105 else 1106 { 1107 // Particular breakpoint selected; enable that breakpoint. 1108 BreakpointIDList valid_bp_ids; 1109 CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids); 1110 1111 if (result.Succeeded()) 1112 { 1113 int enable_count = 0; 1114 int loc_count = 0; 1115 const size_t count = valid_bp_ids.GetSize(); 1116 for (size_t i = 0; i < count; ++i) 1117 { 1118 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i); 1119 1120 if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) 1121 { 1122 Breakpoint *breakpoint = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get(); 1123 if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) 1124 { 1125 BreakpointLocation *location = breakpoint->FindLocationByID (cur_bp_id.GetLocationID()).get(); 1126 if (location) 1127 { 1128 location->SetEnabled (true); 1129 ++loc_count; 1130 } 1131 } 1132 else 1133 { 1134 breakpoint->SetEnabled (true); 1135 ++enable_count; 1136 } 1137 } 1138 } 1139 result.AppendMessageWithFormat ("%d breakpoints enabled.\n", enable_count + loc_count); 1140 result.SetStatus (eReturnStatusSuccessFinishNoResult); 1141 } 1142 } 1143 1144 return result.Succeeded(); 1145 } 1146 }; 1147 1148 //------------------------------------------------------------------------- 1149 // CommandObjectBreakpointDisable 1150 //------------------------------------------------------------------------- 1151 #pragma mark Disable 1152 1153 class CommandObjectBreakpointDisable : public CommandObjectParsed 1154 { 1155 public: 1156 CommandObjectBreakpointDisable (CommandInterpreter &interpreter) : 1157 CommandObjectParsed (interpreter, 1158 "breakpoint disable", 1159 "Disable the specified breakpoint(s) without removing it/them. If no breakpoints are specified, disable them all.", 1160 NULL) 1161 { 1162 SetHelpLong( 1163 "Disable the specified breakpoint(s) without removing it/them. \n\ 1164 If no breakpoints are specified, disable them all.\n\ 1165 \n\ 1166 Note: disabling a breakpoint will cause none of its locations to be hit\n\ 1167 regardless of whether they are enabled or disabled. So the sequence: \n\ 1168 \n\ 1169 (lldb) break disable 1\n\ 1170 (lldb) break enable 1.1\n\ 1171 \n\ 1172 will NOT cause location 1.1 to get hit. To achieve that, do:\n\ 1173 \n\ 1174 (lldb) break disable 1.*\n\ 1175 (lldb) break enable 1.1\n\ 1176 \n\ 1177 The first command disables all the locations of breakpoint 1, \n\ 1178 the second re-enables the first location." 1179 ); 1180 1181 CommandArgumentEntry arg; 1182 CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID, eArgTypeBreakpointIDRange); 1183 // Add the entry for the first argument for this command to the object's arguments vector. 1184 m_arguments.push_back (arg); 1185 1186 } 1187 1188 1189 virtual 1190 ~CommandObjectBreakpointDisable () {} 1191 1192 protected: 1193 virtual bool 1194 DoExecute (Args& command, CommandReturnObject &result) 1195 { 1196 Target *target = GetSelectedOrDummyTarget(); 1197 if (target == NULL) 1198 { 1199 result.AppendError ("Invalid target. No existing target or breakpoints."); 1200 result.SetStatus (eReturnStatusFailed); 1201 return false; 1202 } 1203 1204 Mutex::Locker locker; 1205 target->GetBreakpointList().GetListMutex(locker); 1206 1207 const BreakpointList &breakpoints = target->GetBreakpointList(); 1208 size_t num_breakpoints = breakpoints.GetSize(); 1209 1210 if (num_breakpoints == 0) 1211 { 1212 result.AppendError ("No breakpoints exist to be disabled."); 1213 result.SetStatus (eReturnStatusFailed); 1214 return false; 1215 } 1216 1217 if (command.GetArgumentCount() == 0) 1218 { 1219 // No breakpoint selected; disable all currently set breakpoints. 1220 target->DisableAllBreakpoints (); 1221 result.AppendMessageWithFormat ("All breakpoints disabled. (%" PRIu64 " breakpoints)\n", (uint64_t)num_breakpoints); 1222 result.SetStatus (eReturnStatusSuccessFinishNoResult); 1223 } 1224 else 1225 { 1226 // Particular breakpoint selected; disable that breakpoint. 1227 BreakpointIDList valid_bp_ids; 1228 1229 CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids); 1230 1231 if (result.Succeeded()) 1232 { 1233 int disable_count = 0; 1234 int loc_count = 0; 1235 const size_t count = valid_bp_ids.GetSize(); 1236 for (size_t i = 0; i < count; ++i) 1237 { 1238 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i); 1239 1240 if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) 1241 { 1242 Breakpoint *breakpoint = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get(); 1243 if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) 1244 { 1245 BreakpointLocation *location = breakpoint->FindLocationByID (cur_bp_id.GetLocationID()).get(); 1246 if (location) 1247 { 1248 location->SetEnabled (false); 1249 ++loc_count; 1250 } 1251 } 1252 else 1253 { 1254 breakpoint->SetEnabled (false); 1255 ++disable_count; 1256 } 1257 } 1258 } 1259 result.AppendMessageWithFormat ("%d breakpoints disabled.\n", disable_count + loc_count); 1260 result.SetStatus (eReturnStatusSuccessFinishNoResult); 1261 } 1262 } 1263 1264 return result.Succeeded(); 1265 } 1266 1267 }; 1268 1269 //------------------------------------------------------------------------- 1270 // CommandObjectBreakpointList 1271 //------------------------------------------------------------------------- 1272 #pragma mark List 1273 1274 class CommandObjectBreakpointList : public CommandObjectParsed 1275 { 1276 public: 1277 CommandObjectBreakpointList (CommandInterpreter &interpreter) : 1278 CommandObjectParsed (interpreter, 1279 "breakpoint list", 1280 "List some or all breakpoints at configurable levels of detail.", 1281 NULL), 1282 m_options (interpreter) 1283 { 1284 CommandArgumentEntry arg; 1285 CommandArgumentData bp_id_arg; 1286 1287 // Define the first (and only) variant of this arg. 1288 bp_id_arg.arg_type = eArgTypeBreakpointID; 1289 bp_id_arg.arg_repetition = eArgRepeatOptional; 1290 1291 // There is only one variant this argument could be; put it into the argument entry. 1292 arg.push_back (bp_id_arg); 1293 1294 // Push the data for the first argument into the m_arguments vector. 1295 m_arguments.push_back (arg); 1296 } 1297 1298 1299 virtual 1300 ~CommandObjectBreakpointList () {} 1301 1302 virtual Options * 1303 GetOptions () 1304 { 1305 return &m_options; 1306 } 1307 1308 class CommandOptions : public Options 1309 { 1310 public: 1311 1312 CommandOptions (CommandInterpreter &interpreter) : 1313 Options (interpreter), 1314 m_level (lldb::eDescriptionLevelBrief), 1315 m_use_dummy(false) 1316 { 1317 } 1318 1319 virtual 1320 ~CommandOptions () {} 1321 1322 virtual Error 1323 SetOptionValue (uint32_t option_idx, const char *option_arg) 1324 { 1325 Error error; 1326 const int short_option = m_getopt_table[option_idx].val; 1327 1328 switch (short_option) 1329 { 1330 case 'b': 1331 m_level = lldb::eDescriptionLevelBrief; 1332 break; 1333 case 'D': 1334 m_use_dummy = true; 1335 break; 1336 case 'f': 1337 m_level = lldb::eDescriptionLevelFull; 1338 break; 1339 case 'v': 1340 m_level = lldb::eDescriptionLevelVerbose; 1341 break; 1342 case 'i': 1343 m_internal = true; 1344 break; 1345 default: 1346 error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option); 1347 break; 1348 } 1349 1350 return error; 1351 } 1352 1353 void 1354 OptionParsingStarting () 1355 { 1356 m_level = lldb::eDescriptionLevelFull; 1357 m_internal = false; 1358 m_use_dummy = false; 1359 } 1360 1361 const OptionDefinition * 1362 GetDefinitions () 1363 { 1364 return g_option_table; 1365 } 1366 1367 // Options table: Required for subclasses of Options. 1368 1369 static OptionDefinition g_option_table[]; 1370 1371 // Instance variables to hold the values for command options. 1372 1373 lldb::DescriptionLevel m_level; 1374 1375 bool m_internal; 1376 bool m_use_dummy; 1377 }; 1378 1379 protected: 1380 virtual bool 1381 DoExecute (Args& command, CommandReturnObject &result) 1382 { 1383 Target *target = GetSelectedOrDummyTarget(m_options.m_use_dummy); 1384 1385 if (target == NULL) 1386 { 1387 result.AppendError ("Invalid target. No current target or breakpoints."); 1388 result.SetStatus (eReturnStatusSuccessFinishNoResult); 1389 return true; 1390 } 1391 1392 const BreakpointList &breakpoints = target->GetBreakpointList(m_options.m_internal); 1393 Mutex::Locker locker; 1394 target->GetBreakpointList(m_options.m_internal).GetListMutex(locker); 1395 1396 size_t num_breakpoints = breakpoints.GetSize(); 1397 1398 if (num_breakpoints == 0) 1399 { 1400 result.AppendMessage ("No breakpoints currently set."); 1401 result.SetStatus (eReturnStatusSuccessFinishNoResult); 1402 return true; 1403 } 1404 1405 Stream &output_stream = result.GetOutputStream(); 1406 1407 if (command.GetArgumentCount() == 0) 1408 { 1409 // No breakpoint selected; show info about all currently set breakpoints. 1410 result.AppendMessage ("Current breakpoints:"); 1411 for (size_t i = 0; i < num_breakpoints; ++i) 1412 { 1413 Breakpoint *breakpoint = breakpoints.GetBreakpointAtIndex (i).get(); 1414 AddBreakpointDescription (&output_stream, breakpoint, m_options.m_level); 1415 } 1416 result.SetStatus (eReturnStatusSuccessFinishNoResult); 1417 } 1418 else 1419 { 1420 // Particular breakpoints selected; show info about that breakpoint. 1421 BreakpointIDList valid_bp_ids; 1422 CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids); 1423 1424 if (result.Succeeded()) 1425 { 1426 for (size_t i = 0; i < valid_bp_ids.GetSize(); ++i) 1427 { 1428 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i); 1429 Breakpoint *breakpoint = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get(); 1430 AddBreakpointDescription (&output_stream, breakpoint, m_options.m_level); 1431 } 1432 result.SetStatus (eReturnStatusSuccessFinishNoResult); 1433 } 1434 else 1435 { 1436 result.AppendError ("Invalid breakpoint id."); 1437 result.SetStatus (eReturnStatusFailed); 1438 } 1439 } 1440 1441 return result.Succeeded(); 1442 } 1443 1444 private: 1445 CommandOptions m_options; 1446 }; 1447 1448 #pragma mark List::CommandOptions 1449 OptionDefinition 1450 CommandObjectBreakpointList::CommandOptions::g_option_table[] = 1451 { 1452 { LLDB_OPT_SET_ALL, false, "internal", 'i', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, 1453 "Show debugger internal breakpoints" }, 1454 1455 { LLDB_OPT_SET_1, false, "brief", 'b', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, 1456 "Give a brief description of the breakpoint (no location info)."}, 1457 1458 // FIXME: We need to add an "internal" command, and then add this sort of thing to it. 1459 // But I need to see it for now, and don't want to wait. 1460 { LLDB_OPT_SET_2, false, "full", 'f', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, 1461 "Give a full description of the breakpoint and its locations."}, 1462 1463 { LLDB_OPT_SET_3, false, "verbose", 'v', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, 1464 "Explain everything we know about the breakpoint (for debugging debugger bugs)." }, 1465 1466 { LLDB_OPT_SET_ALL, false, "dummy-breakpoints", 'D', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, 1467 "List Dummy breakpoints - i.e. breakpoints set before a file is provided, which prime new targets."}, 1468 1469 { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL } 1470 }; 1471 1472 //------------------------------------------------------------------------- 1473 // CommandObjectBreakpointClear 1474 //------------------------------------------------------------------------- 1475 #pragma mark Clear 1476 1477 class CommandObjectBreakpointClear : public CommandObjectParsed 1478 { 1479 public: 1480 1481 typedef enum BreakpointClearType 1482 { 1483 eClearTypeInvalid, 1484 eClearTypeFileAndLine 1485 } BreakpointClearType; 1486 1487 CommandObjectBreakpointClear (CommandInterpreter &interpreter) : 1488 CommandObjectParsed (interpreter, 1489 "breakpoint clear", 1490 "Clears a breakpoint or set of breakpoints in the executable.", 1491 "breakpoint clear <cmd-options>"), 1492 m_options (interpreter) 1493 { 1494 } 1495 1496 virtual 1497 ~CommandObjectBreakpointClear () {} 1498 1499 virtual Options * 1500 GetOptions () 1501 { 1502 return &m_options; 1503 } 1504 1505 class CommandOptions : public Options 1506 { 1507 public: 1508 1509 CommandOptions (CommandInterpreter &interpreter) : 1510 Options (interpreter), 1511 m_filename (), 1512 m_line_num (0) 1513 { 1514 } 1515 1516 virtual 1517 ~CommandOptions () {} 1518 1519 virtual Error 1520 SetOptionValue (uint32_t option_idx, const char *option_arg) 1521 { 1522 Error error; 1523 const int short_option = m_getopt_table[option_idx].val; 1524 1525 switch (short_option) 1526 { 1527 case 'f': 1528 m_filename.assign (option_arg); 1529 break; 1530 1531 case 'l': 1532 m_line_num = Args::StringToUInt32 (option_arg, 0); 1533 break; 1534 1535 default: 1536 error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option); 1537 break; 1538 } 1539 1540 return error; 1541 } 1542 1543 void 1544 OptionParsingStarting () 1545 { 1546 m_filename.clear(); 1547 m_line_num = 0; 1548 } 1549 1550 const OptionDefinition* 1551 GetDefinitions () 1552 { 1553 return g_option_table; 1554 } 1555 1556 // Options table: Required for subclasses of Options. 1557 1558 static OptionDefinition g_option_table[]; 1559 1560 // Instance variables to hold the values for command options. 1561 1562 std::string m_filename; 1563 uint32_t m_line_num; 1564 1565 }; 1566 1567 protected: 1568 virtual bool 1569 DoExecute (Args& command, CommandReturnObject &result) 1570 { 1571 Target *target = GetSelectedOrDummyTarget(); 1572 if (target == NULL) 1573 { 1574 result.AppendError ("Invalid target. No existing target or breakpoints."); 1575 result.SetStatus (eReturnStatusFailed); 1576 return false; 1577 } 1578 1579 // The following are the various types of breakpoints that could be cleared: 1580 // 1). -f -l (clearing breakpoint by source location) 1581 1582 BreakpointClearType break_type = eClearTypeInvalid; 1583 1584 if (m_options.m_line_num != 0) 1585 break_type = eClearTypeFileAndLine; 1586 1587 Mutex::Locker locker; 1588 target->GetBreakpointList().GetListMutex(locker); 1589 1590 BreakpointList &breakpoints = target->GetBreakpointList(); 1591 size_t num_breakpoints = breakpoints.GetSize(); 1592 1593 // Early return if there's no breakpoint at all. 1594 if (num_breakpoints == 0) 1595 { 1596 result.AppendError ("Breakpoint clear: No breakpoint cleared."); 1597 result.SetStatus (eReturnStatusFailed); 1598 return result.Succeeded(); 1599 } 1600 1601 // Find matching breakpoints and delete them. 1602 1603 // First create a copy of all the IDs. 1604 std::vector<break_id_t> BreakIDs; 1605 for (size_t i = 0; i < num_breakpoints; ++i) 1606 BreakIDs.push_back(breakpoints.GetBreakpointAtIndex(i).get()->GetID()); 1607 1608 int num_cleared = 0; 1609 StreamString ss; 1610 switch (break_type) 1611 { 1612 case eClearTypeFileAndLine: // Breakpoint by source position 1613 { 1614 const ConstString filename(m_options.m_filename.c_str()); 1615 BreakpointLocationCollection loc_coll; 1616 1617 for (size_t i = 0; i < num_breakpoints; ++i) 1618 { 1619 Breakpoint *bp = breakpoints.FindBreakpointByID(BreakIDs[i]).get(); 1620 1621 if (bp->GetMatchingFileLine(filename, m_options.m_line_num, loc_coll)) 1622 { 1623 // If the collection size is 0, it's a full match and we can just remove the breakpoint. 1624 if (loc_coll.GetSize() == 0) 1625 { 1626 bp->GetDescription(&ss, lldb::eDescriptionLevelBrief); 1627 ss.EOL(); 1628 target->RemoveBreakpointByID (bp->GetID()); 1629 ++num_cleared; 1630 } 1631 } 1632 } 1633 } 1634 break; 1635 1636 default: 1637 break; 1638 } 1639 1640 if (num_cleared > 0) 1641 { 1642 Stream &output_stream = result.GetOutputStream(); 1643 output_stream.Printf ("%d breakpoints cleared:\n", num_cleared); 1644 output_stream << ss.GetData(); 1645 output_stream.EOL(); 1646 result.SetStatus (eReturnStatusSuccessFinishNoResult); 1647 } 1648 else 1649 { 1650 result.AppendError ("Breakpoint clear: No breakpoint cleared."); 1651 result.SetStatus (eReturnStatusFailed); 1652 } 1653 1654 return result.Succeeded(); 1655 } 1656 1657 private: 1658 CommandOptions m_options; 1659 }; 1660 1661 #pragma mark Clear::CommandOptions 1662 1663 OptionDefinition 1664 CommandObjectBreakpointClear::CommandOptions::g_option_table[] = 1665 { 1666 { LLDB_OPT_SET_1, false, "file", 'f', OptionParser::eRequiredArgument, NULL, NULL, CommandCompletions::eSourceFileCompletion, eArgTypeFilename, 1667 "Specify the breakpoint by source location in this particular file."}, 1668 1669 { LLDB_OPT_SET_1, true, "line", 'l', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeLineNum, 1670 "Specify the breakpoint by source location at this particular line."}, 1671 1672 { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL } 1673 }; 1674 1675 //------------------------------------------------------------------------- 1676 // CommandObjectBreakpointDelete 1677 //------------------------------------------------------------------------- 1678 #pragma mark Delete 1679 1680 class CommandObjectBreakpointDelete : public CommandObjectParsed 1681 { 1682 public: 1683 CommandObjectBreakpointDelete (CommandInterpreter &interpreter) : 1684 CommandObjectParsed (interpreter, 1685 "breakpoint delete", 1686 "Delete the specified breakpoint(s). If no breakpoints are specified, delete them all.", 1687 NULL), 1688 m_options (interpreter) 1689 { 1690 CommandArgumentEntry arg; 1691 CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID, eArgTypeBreakpointIDRange); 1692 // Add the entry for the first argument for this command to the object's arguments vector. 1693 m_arguments.push_back (arg); 1694 } 1695 1696 virtual 1697 ~CommandObjectBreakpointDelete () {} 1698 1699 virtual Options * 1700 GetOptions () 1701 { 1702 return &m_options; 1703 } 1704 1705 class CommandOptions : public Options 1706 { 1707 public: 1708 1709 CommandOptions (CommandInterpreter &interpreter) : 1710 Options (interpreter), 1711 m_use_dummy (false), 1712 m_force (false) 1713 { 1714 } 1715 1716 virtual 1717 ~CommandOptions () {} 1718 1719 virtual Error 1720 SetOptionValue (uint32_t option_idx, const char *option_arg) 1721 { 1722 Error error; 1723 const int short_option = m_getopt_table[option_idx].val; 1724 1725 switch (short_option) 1726 { 1727 case 'f': 1728 m_force = true; 1729 break; 1730 1731 case 'D': 1732 m_use_dummy = true; 1733 break; 1734 1735 default: 1736 error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option); 1737 break; 1738 } 1739 1740 return error; 1741 } 1742 1743 void 1744 OptionParsingStarting () 1745 { 1746 m_use_dummy = false; 1747 m_force = false; 1748 } 1749 1750 const OptionDefinition* 1751 GetDefinitions () 1752 { 1753 return g_option_table; 1754 } 1755 1756 // Options table: Required for subclasses of Options. 1757 1758 static OptionDefinition g_option_table[]; 1759 1760 // Instance variables to hold the values for command options. 1761 bool m_use_dummy; 1762 bool m_force; 1763 }; 1764 1765 protected: 1766 virtual bool 1767 DoExecute (Args& command, CommandReturnObject &result) 1768 { 1769 Target *target = GetSelectedOrDummyTarget(m_options.m_use_dummy); 1770 1771 if (target == NULL) 1772 { 1773 result.AppendError ("Invalid target. No existing target or breakpoints."); 1774 result.SetStatus (eReturnStatusFailed); 1775 return false; 1776 } 1777 1778 Mutex::Locker locker; 1779 target->GetBreakpointList().GetListMutex(locker); 1780 1781 const BreakpointList &breakpoints = target->GetBreakpointList(); 1782 1783 size_t num_breakpoints = breakpoints.GetSize(); 1784 1785 if (num_breakpoints == 0) 1786 { 1787 result.AppendError ("No breakpoints exist to be deleted."); 1788 result.SetStatus (eReturnStatusFailed); 1789 return false; 1790 } 1791 1792 if (command.GetArgumentCount() == 0) 1793 { 1794 if (!m_options.m_force && !m_interpreter.Confirm ("About to delete all breakpoints, do you want to do that?", true)) 1795 { 1796 result.AppendMessage("Operation cancelled..."); 1797 } 1798 else 1799 { 1800 target->RemoveAllBreakpoints (); 1801 result.AppendMessageWithFormat ("All breakpoints removed. (%" PRIu64 " breakpoint%s)\n", (uint64_t)num_breakpoints, num_breakpoints > 1 ? "s" : ""); 1802 } 1803 result.SetStatus (eReturnStatusSuccessFinishNoResult); 1804 } 1805 else 1806 { 1807 // Particular breakpoint selected; disable that breakpoint. 1808 BreakpointIDList valid_bp_ids; 1809 CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids); 1810 1811 if (result.Succeeded()) 1812 { 1813 int delete_count = 0; 1814 int disable_count = 0; 1815 const size_t count = valid_bp_ids.GetSize(); 1816 for (size_t i = 0; i < count; ++i) 1817 { 1818 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i); 1819 1820 if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) 1821 { 1822 if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) 1823 { 1824 Breakpoint *breakpoint = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get(); 1825 BreakpointLocation *location = breakpoint->FindLocationByID (cur_bp_id.GetLocationID()).get(); 1826 // It makes no sense to try to delete individual locations, so we disable them instead. 1827 if (location) 1828 { 1829 location->SetEnabled (false); 1830 ++disable_count; 1831 } 1832 } 1833 else 1834 { 1835 target->RemoveBreakpointByID (cur_bp_id.GetBreakpointID()); 1836 ++delete_count; 1837 } 1838 } 1839 } 1840 result.AppendMessageWithFormat ("%d breakpoints deleted; %d breakpoint locations disabled.\n", 1841 delete_count, disable_count); 1842 result.SetStatus (eReturnStatusSuccessFinishNoResult); 1843 } 1844 } 1845 return result.Succeeded(); 1846 } 1847 private: 1848 CommandOptions m_options; 1849 }; 1850 1851 OptionDefinition 1852 CommandObjectBreakpointDelete::CommandOptions::g_option_table[] = 1853 { 1854 { LLDB_OPT_SET_1, false, "force", 'f', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, 1855 "Delete all breakpoints without querying for confirmation."}, 1856 1857 { LLDB_OPT_SET_1, false, "dummy-breakpoints", 'D', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, 1858 "Delete Dummy breakpoints - i.e. breakpoints set before a file is provided, which prime new targets."}, 1859 1860 { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL } 1861 }; 1862 1863 //------------------------------------------------------------------------- 1864 // CommandObjectMultiwordBreakpoint 1865 //------------------------------------------------------------------------- 1866 #pragma mark MultiwordBreakpoint 1867 1868 CommandObjectMultiwordBreakpoint::CommandObjectMultiwordBreakpoint (CommandInterpreter &interpreter) : 1869 CommandObjectMultiword (interpreter, 1870 "breakpoint", 1871 "A set of commands for operating on breakpoints. Also see _regexp-break.", 1872 "breakpoint <command> [<command-options>]") 1873 { 1874 CommandObjectSP list_command_object (new CommandObjectBreakpointList (interpreter)); 1875 CommandObjectSP enable_command_object (new CommandObjectBreakpointEnable (interpreter)); 1876 CommandObjectSP disable_command_object (new CommandObjectBreakpointDisable (interpreter)); 1877 CommandObjectSP clear_command_object (new CommandObjectBreakpointClear (interpreter)); 1878 CommandObjectSP delete_command_object (new CommandObjectBreakpointDelete (interpreter)); 1879 CommandObjectSP set_command_object (new CommandObjectBreakpointSet (interpreter)); 1880 CommandObjectSP command_command_object (new CommandObjectBreakpointCommand (interpreter)); 1881 CommandObjectSP modify_command_object (new CommandObjectBreakpointModify(interpreter)); 1882 1883 list_command_object->SetCommandName ("breakpoint list"); 1884 enable_command_object->SetCommandName("breakpoint enable"); 1885 disable_command_object->SetCommandName("breakpoint disable"); 1886 clear_command_object->SetCommandName("breakpoint clear"); 1887 delete_command_object->SetCommandName("breakpoint delete"); 1888 set_command_object->SetCommandName("breakpoint set"); 1889 command_command_object->SetCommandName ("breakpoint command"); 1890 modify_command_object->SetCommandName ("breakpoint modify"); 1891 1892 LoadSubCommand ("list", list_command_object); 1893 LoadSubCommand ("enable", enable_command_object); 1894 LoadSubCommand ("disable", disable_command_object); 1895 LoadSubCommand ("clear", clear_command_object); 1896 LoadSubCommand ("delete", delete_command_object); 1897 LoadSubCommand ("set", set_command_object); 1898 LoadSubCommand ("command", command_command_object); 1899 LoadSubCommand ("modify", modify_command_object); 1900 } 1901 1902 CommandObjectMultiwordBreakpoint::~CommandObjectMultiwordBreakpoint () 1903 { 1904 } 1905 1906 void 1907 CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (Args &args, Target *target, CommandReturnObject &result, 1908 BreakpointIDList *valid_ids) 1909 { 1910 // args can be strings representing 1). integers (for breakpoint ids) 1911 // 2). the full breakpoint & location canonical representation 1912 // 3). the word "to" or a hyphen, representing a range (in which case there 1913 // had *better* be an entry both before & after of one of the first two types. 1914 // If args is empty, we will use the last created breakpoint (if there is one.) 1915 1916 Args temp_args; 1917 1918 if (args.GetArgumentCount() == 0) 1919 { 1920 if (target->GetLastCreatedBreakpoint()) 1921 { 1922 valid_ids->AddBreakpointID (BreakpointID(target->GetLastCreatedBreakpoint()->GetID(), LLDB_INVALID_BREAK_ID)); 1923 result.SetStatus (eReturnStatusSuccessFinishNoResult); 1924 } 1925 else 1926 { 1927 result.AppendError("No breakpoint specified and no last created breakpoint."); 1928 result.SetStatus (eReturnStatusFailed); 1929 } 1930 return; 1931 } 1932 1933 // Create a new Args variable to use; copy any non-breakpoint-id-ranges stuff directly from the old ARGS to 1934 // the new TEMP_ARGS. Do not copy breakpoint id range strings over; instead generate a list of strings for 1935 // all the breakpoint ids in the range, and shove all of those breakpoint id strings into TEMP_ARGS. 1936 1937 BreakpointIDList::FindAndReplaceIDRanges (args, target, result, temp_args); 1938 1939 // NOW, convert the list of breakpoint id strings in TEMP_ARGS into an actual BreakpointIDList: 1940 1941 valid_ids->InsertStringArray (temp_args.GetConstArgumentVector(), temp_args.GetArgumentCount(), result); 1942 1943 // At this point, all of the breakpoint ids that the user passed in have been converted to breakpoint IDs 1944 // and put into valid_ids. 1945 1946 if (result.Succeeded()) 1947 { 1948 // Now that we've converted everything from args into a list of breakpoint ids, go through our tentative list 1949 // of breakpoint id's and verify that they correspond to valid/currently set breakpoints. 1950 1951 const size_t count = valid_ids->GetSize(); 1952 for (size_t i = 0; i < count; ++i) 1953 { 1954 BreakpointID cur_bp_id = valid_ids->GetBreakpointIDAtIndex (i); 1955 Breakpoint *breakpoint = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get(); 1956 if (breakpoint != NULL) 1957 { 1958 const size_t num_locations = breakpoint->GetNumLocations(); 1959 if (static_cast<size_t>(cur_bp_id.GetLocationID()) > num_locations) 1960 { 1961 StreamString id_str; 1962 BreakpointID::GetCanonicalReference (&id_str, 1963 cur_bp_id.GetBreakpointID(), 1964 cur_bp_id.GetLocationID()); 1965 i = valid_ids->GetSize() + 1; 1966 result.AppendErrorWithFormat ("'%s' is not a currently valid breakpoint/location id.\n", 1967 id_str.GetData()); 1968 result.SetStatus (eReturnStatusFailed); 1969 } 1970 } 1971 else 1972 { 1973 i = valid_ids->GetSize() + 1; 1974 result.AppendErrorWithFormat ("'%d' is not a currently valid breakpoint id.\n", cur_bp_id.GetBreakpointID()); 1975 result.SetStatus (eReturnStatusFailed); 1976 } 1977 } 1978 } 1979 } 1980