1 //===-- CommandObjectProcess.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 "CommandObjectProcess.h" 11 12 // C Includes 13 // C++ Includes 14 // Other libraries and framework includes 15 // Project includes 16 #include "lldb/Interpreter/Args.h" 17 #include "lldb/Interpreter/Options.h" 18 #include "lldb/Core/State.h" 19 #include "lldb/Interpreter/CommandInterpreter.h" 20 #include "lldb/Interpreter/CommandReturnObject.h" 21 #include "./CommandObjectThread.h" 22 #include "lldb/Target/Process.h" 23 #include "lldb/Target/Target.h" 24 #include "lldb/Target/Thread.h" 25 26 using namespace lldb; 27 using namespace lldb_private; 28 29 //------------------------------------------------------------------------- 30 // CommandObjectProcessLaunch 31 //------------------------------------------------------------------------- 32 33 class CommandObjectProcessLaunch : public CommandObject 34 { 35 public: 36 37 class CommandOptions : public Options 38 { 39 public: 40 41 CommandOptions () : 42 Options() 43 { 44 // Keep default values of all options in one place: ResetOptionValues () 45 ResetOptionValues (); 46 } 47 48 ~CommandOptions () 49 { 50 } 51 52 Error 53 SetOptionValue (int option_idx, const char *option_arg) 54 { 55 Error error; 56 char short_option = (char) m_getopt_table[option_idx].val; 57 58 switch (short_option) 59 { 60 case 's': stop_at_entry = true; break; 61 case 'e': stderr_path = option_arg; break; 62 case 'i': stdin_path = option_arg; break; 63 case 'o': stdout_path = option_arg; break; 64 case 'p': plugin_name = option_arg; break; 65 default: 66 error.SetErrorStringWithFormat("Invalid short option character '%c'.\n", short_option); 67 break; 68 69 } 70 return error; 71 } 72 73 void 74 ResetOptionValues () 75 { 76 Options::ResetOptionValues(); 77 stop_at_entry = false; 78 stdin_path.clear(); 79 stdout_path.clear(); 80 stderr_path.clear(); 81 plugin_name.clear(); 82 } 83 84 const lldb::OptionDefinition* 85 GetDefinitions () 86 { 87 return g_option_table; 88 } 89 90 // Options table: Required for subclasses of Options. 91 92 static lldb::OptionDefinition g_option_table[]; 93 94 // Instance variables to hold the values for command options. 95 96 bool stop_at_entry; 97 std::string stderr_path; 98 std::string stdin_path; 99 std::string stdout_path; 100 std::string plugin_name; 101 102 }; 103 104 CommandObjectProcessLaunch () : 105 CommandObject ("process launch", 106 "Launches the executable in the debugger.", 107 "process launch [<cmd-options>] [<arguments-for-running-the-program>]") 108 { 109 } 110 111 112 ~CommandObjectProcessLaunch () 113 { 114 } 115 116 Options * 117 GetOptions () 118 { 119 return &m_options; 120 } 121 122 bool 123 Execute (CommandInterpreter &interpreter, 124 Args& launch_args, 125 CommandReturnObject &result) 126 { 127 Target *target = interpreter.GetDebugger().GetSelectedTarget().get(); 128 bool synchronous_execution = interpreter.GetSynchronous (); 129 // bool launched = false; 130 // bool stopped_after_launch = false; 131 132 if (target == NULL) 133 { 134 result.AppendError ("invalid target, set executable file using 'file' command"); 135 result.SetStatus (eReturnStatusFailed); 136 return false; 137 } 138 139 // If our listener is NULL, users aren't allows to launch 140 char filename[PATH_MAX]; 141 Module *exe_module = target->GetExecutableModule().get(); 142 exe_module->GetFileSpec().GetPath(filename, sizeof(filename)); 143 144 Process *process = interpreter.GetDebugger().GetExecutionContext().process; 145 if (process) 146 { 147 if (process->IsAlive()) 148 { 149 result.AppendErrorWithFormat ("Process %u is currently being debugged, kill the process before running again.\n", 150 process->GetID()); 151 result.SetStatus (eReturnStatusFailed); 152 return false; 153 } 154 } 155 156 const char *plugin_name; 157 if (!m_options.plugin_name.empty()) 158 plugin_name = m_options.plugin_name.c_str(); 159 else 160 plugin_name = NULL; 161 162 process = target->CreateProcess (interpreter.GetDebugger().GetListener(), plugin_name).get(); 163 164 const Args *environment = interpreter.GetEnvironmentVariables(); 165 const Args *run_args = interpreter.GetProgramArguments(); 166 uint32_t launch_flags = eLaunchFlagNone; 167 if (interpreter.GetDisableASLR()) 168 launch_flags |= eLaunchFlagDisableASLR; 169 170 // There are two possible sources of args to be passed to the process upon launching: Those the user 171 // typed at the run command (launch_args); or those the user pre-set in the run-args variable (run_args). 172 173 // If launch_args is empty, use run_args. 174 if (launch_args.GetArgumentCount() == 0) 175 { 176 if (run_args != NULL) 177 launch_args.AppendArguments (*run_args); 178 } 179 else 180 { 181 // launch-args was not empty; use that, AND re-set run-args to contains launch-args values. 182 StateVariable *run_args_var = interpreter.GetStateVariable ("run-args"); 183 if (run_args_var != NULL) 184 { 185 run_args_var->ArrayClearValues(); 186 run_args_var->GetArgs().AppendArguments (launch_args); 187 } 188 } 189 190 191 if (process) 192 { 193 const char *archname = exe_module->GetArchitecture().AsCString(); 194 195 const char * stdin_path = NULL; 196 const char * stdout_path = NULL; 197 const char * stderr_path = NULL; 198 199 if (!(m_options.stdin_path.empty() && 200 m_options.stdout_path.empty() && 201 m_options.stderr_path.empty())) 202 { 203 stdin_path = m_options.stdin_path.empty() ? "/dev/null" : m_options.stdin_path.c_str(); 204 stdout_path = m_options.stdout_path.empty() ? "/dev/null" : m_options.stdout_path.c_str(); 205 stderr_path = m_options.stderr_path.empty() ? "/dev/null" : m_options.stderr_path.c_str(); 206 } 207 208 Error error (process->Launch (launch_args.GetConstArgumentVector(), 209 environment ? environment->GetConstArgumentVector() : NULL, 210 launch_flags, 211 stdin_path, 212 stdout_path, 213 stderr_path)); 214 215 if (error.Success()) 216 { 217 result.AppendMessageWithFormat ("Launching '%s' (%s)\n", filename, archname); 218 result.SetStatus (eReturnStatusSuccessContinuingNoResult); 219 if (m_options.stop_at_entry == false) 220 { 221 StateType state = process->WaitForProcessToStop (NULL); 222 223 if (state == eStateStopped) 224 { 225 // Call continue_command. 226 CommandReturnObject continue_result; 227 interpreter.HandleCommand("process continue", false, continue_result); 228 } 229 230 if (synchronous_execution) 231 { 232 result.SetDidChangeProcessState (true); 233 result.SetStatus (eReturnStatusSuccessFinishNoResult); 234 } 235 } 236 } 237 else 238 { 239 result.AppendErrorWithFormat ("Process launch failed: %s", 240 error.AsCString()); 241 result.SetStatus (eReturnStatusFailed); 242 } 243 } 244 else 245 { 246 result.AppendErrorWithFormat ("Process launch failed: unable to create a process object.\n"); 247 result.SetStatus (eReturnStatusFailed); 248 return false; 249 } 250 251 return result.Succeeded(); 252 } 253 254 virtual const char *GetRepeatCommand (Args ¤t_command_args, uint32_t index) 255 { 256 // No repeat for "process launch"... 257 return ""; 258 } 259 260 protected: 261 262 CommandOptions m_options; 263 }; 264 265 266 lldb::OptionDefinition 267 CommandObjectProcessLaunch::CommandOptions::g_option_table[] = 268 { 269 { LLDB_OPT_SET_1, false, "stop-at-entry", 's', no_argument, NULL, 0, NULL, "Stop at the entry point of the program when launching a process."}, 270 { LLDB_OPT_SET_1, false, "stdin", 'i', required_argument, NULL, 0, "<path>", "Redirect stdin for the process to <path>."}, 271 { LLDB_OPT_SET_1, false, "stdout", 'o', required_argument, NULL, 0, "<path>", "Redirect stdout for the process to <path>."}, 272 { LLDB_OPT_SET_1, false, "stderr", 'e', required_argument, NULL, 0, "<path>", "Redirect stderr for the process to <path>."}, 273 { LLDB_OPT_SET_1, false, "plugin", 'p', required_argument, NULL, 0, "<plugin>", "Name of the process plugin you want to use."}, 274 { 0, false, NULL, 0, 0, NULL, 0, NULL, NULL } 275 }; 276 277 278 //------------------------------------------------------------------------- 279 // CommandObjectProcessAttach 280 //------------------------------------------------------------------------- 281 282 class CommandObjectProcessAttach : public CommandObject 283 { 284 public: 285 286 class CommandOptions : public Options 287 { 288 public: 289 290 CommandOptions () : 291 Options() 292 { 293 // Keep default values of all options in one place: ResetOptionValues () 294 ResetOptionValues (); 295 } 296 297 ~CommandOptions () 298 { 299 } 300 301 Error 302 SetOptionValue (int option_idx, const char *option_arg) 303 { 304 Error error; 305 char short_option = (char) m_getopt_table[option_idx].val; 306 bool success = false; 307 switch (short_option) 308 { 309 case 'p': 310 pid = Args::StringToUInt32 (option_arg, LLDB_INVALID_PROCESS_ID, 0, &success); 311 if (!success || pid == LLDB_INVALID_PROCESS_ID) 312 { 313 error.SetErrorStringWithFormat("Invalid process ID '%s'.\n", option_arg); 314 } 315 break; 316 317 case 'P': 318 plugin_name = option_arg; 319 break; 320 321 case 'n': 322 name.assign(option_arg); 323 break; 324 325 case 'w': 326 waitfor = true; 327 break; 328 329 default: 330 error.SetErrorStringWithFormat("Invalid short option character '%c'.\n", short_option); 331 break; 332 } 333 return error; 334 } 335 336 void 337 ResetOptionValues () 338 { 339 Options::ResetOptionValues(); 340 pid = LLDB_INVALID_PROCESS_ID; 341 name.clear(); 342 waitfor = false; 343 } 344 345 const lldb::OptionDefinition* 346 GetDefinitions () 347 { 348 return g_option_table; 349 } 350 351 virtual bool 352 HandleOptionArgumentCompletion (CommandInterpreter &interpreter, 353 Args &input, 354 int cursor_index, 355 int char_pos, 356 OptionElementVector &opt_element_vector, 357 int opt_element_index, 358 int match_start_point, 359 int max_return_elements, 360 bool &word_complete, 361 StringList &matches) 362 { 363 int opt_arg_pos = opt_element_vector[opt_element_index].opt_arg_pos; 364 int opt_defs_index = opt_element_vector[opt_element_index].opt_defs_index; 365 366 // We are only completing the name option for now... 367 368 const lldb::OptionDefinition *opt_defs = GetDefinitions(); 369 if (opt_defs[opt_defs_index].short_option == 'n') 370 { 371 // Are we in the name? 372 373 // Look to see if there is a -P argument provided, and if so use that plugin, otherwise 374 // use the default plugin. 375 Process *process = interpreter.GetDebugger().GetExecutionContext().process; 376 bool need_to_delete_process = false; 377 378 const char *partial_name = NULL; 379 partial_name = input.GetArgumentAtIndex(opt_arg_pos); 380 381 if (process && process->IsAlive()) 382 return true; 383 384 Target *target = interpreter.GetDebugger().GetSelectedTarget().get(); 385 if (target == NULL) 386 { 387 // No target has been set yet, for now do host completion. Otherwise I don't know how we would 388 // figure out what the right target to use is... 389 std::vector<lldb::pid_t> pids; 390 Host::ListProcessesMatchingName (partial_name, matches, pids); 391 return true; 392 } 393 if (!process) 394 { 395 process = target->CreateProcess (interpreter.GetDebugger().GetListener(), partial_name).get(); 396 need_to_delete_process = true; 397 } 398 399 if (process) 400 { 401 matches.Clear(); 402 std::vector<lldb::pid_t> pids; 403 process->ListProcessesMatchingName (NULL, matches, pids); 404 if (need_to_delete_process) 405 target->DeleteCurrentProcess(); 406 return true; 407 } 408 } 409 410 return false; 411 } 412 413 // Options table: Required for subclasses of Options. 414 415 static lldb::OptionDefinition g_option_table[]; 416 417 // Instance variables to hold the values for command options. 418 419 lldb::pid_t pid; 420 std::string plugin_name; 421 std::string name; 422 bool waitfor; 423 }; 424 425 CommandObjectProcessAttach () : 426 CommandObject ("process attach", 427 "Attaches to a process.", 428 "process attach <cmd-options>") 429 { 430 SetHelpLong("Currently, you must set the executable file before you can attach " 431 "to a process.\n"); 432 } 433 434 ~CommandObjectProcessAttach () 435 { 436 } 437 438 bool 439 Execute (CommandInterpreter &interpreter, 440 Args& command, 441 CommandReturnObject &result) 442 { 443 Target *target = interpreter.GetDebugger().GetSelectedTarget().get(); 444 445 Process *process = interpreter.GetDebugger().GetExecutionContext().process; 446 if (process) 447 { 448 if (process->IsAlive()) 449 { 450 result.AppendErrorWithFormat ("Process %u is currently being debugged, kill the process before attaching.\n", 451 process->GetID()); 452 result.SetStatus (eReturnStatusFailed); 453 return false; 454 } 455 } 456 457 if (target == NULL) 458 { 459 // If there isn't a current target create one. 460 TargetSP new_target_sp; 461 FileSpec emptyFileSpec; 462 ArchSpec emptyArchSpec; 463 Error error; 464 465 error = interpreter.GetDebugger().GetTargetList().CreateTarget(interpreter.GetDebugger(), 466 emptyFileSpec, 467 emptyArchSpec, 468 NULL, 469 false, 470 new_target_sp); 471 target = new_target_sp.get(); 472 if (target == NULL || error.Fail()) 473 { 474 result.AppendError(error.AsCString("Error creating empty target")); 475 return false; 476 } 477 interpreter.GetDebugger().GetTargetList().SetSelectedTarget(target); 478 } 479 480 // Record the old executable module, we want to issue a warning if the process of attaching changed the 481 // current executable (like somebody said "file foo" then attached to a PID whose executable was bar.) 482 483 ModuleSP old_exec_module_sp = target->GetExecutableModule(); 484 ArchSpec old_arch_spec = target->GetArchitecture(); 485 486 if (command.GetArgumentCount()) 487 { 488 result.AppendErrorWithFormat("Invalid arguments for '%s'.\nUsage: \n", m_cmd_name.c_str(), m_cmd_syntax.c_str()); 489 result.SetStatus (eReturnStatusFailed); 490 } 491 else 492 { 493 const char *plugin_name = NULL; 494 495 if (!m_options.plugin_name.empty()) 496 plugin_name = m_options.plugin_name.c_str(); 497 498 process = target->CreateProcess (interpreter.GetDebugger().GetListener(), plugin_name).get(); 499 500 if (process) 501 { 502 Error error; 503 int attach_pid = m_options.pid; 504 505 // If we are waiting for a process with this name to show up, do that first. 506 if (m_options.waitfor) 507 { 508 if (m_options.name.empty()) 509 { 510 result.AppendError("Invalid arguments: must supply a process name with the waitfor option.\n"); 511 result.SetStatus (eReturnStatusFailed); 512 return false; 513 } 514 else 515 { 516 error = process->Attach (m_options.name.c_str(), m_options.waitfor); 517 if (error.Success()) 518 { 519 result.SetStatus (eReturnStatusSuccessContinuingNoResult); 520 } 521 else 522 { 523 result.AppendErrorWithFormat ("Waiting for a process to launch named '%s': %s\n", 524 m_options.name.c_str(), 525 error.AsCString()); 526 result.SetStatus (eReturnStatusFailed); 527 return false; 528 } 529 } 530 } 531 else 532 { 533 // If the process was specified by name look it up, so we can warn if there are multiple 534 // processes with this pid. 535 536 if (attach_pid == LLDB_INVALID_PROCESS_ID && !m_options.name.empty()) 537 { 538 std::vector<lldb::pid_t> pids; 539 StringList matches; 540 541 process->ListProcessesMatchingName(m_options.name.c_str(), matches, pids); 542 if (matches.GetSize() > 1) 543 { 544 result.AppendErrorWithFormat("More than one process named %s\n", m_options.name.c_str()); 545 result.SetStatus (eReturnStatusFailed); 546 return false; 547 } 548 else if (matches.GetSize() == 0) 549 { 550 result.AppendErrorWithFormat("Could not find a process named %s\n", m_options.name.c_str()); 551 result.SetStatus (eReturnStatusFailed); 552 return false; 553 } 554 else 555 { 556 attach_pid = pids[0]; 557 } 558 559 } 560 561 if (attach_pid != LLDB_INVALID_PROCESS_ID) 562 { 563 error = process->Attach (attach_pid); 564 if (error.Success()) 565 { 566 result.SetStatus (eReturnStatusSuccessContinuingNoResult); 567 } 568 else 569 { 570 result.AppendErrorWithFormat ("Attaching to process %i failed: %s.\n", 571 attach_pid, 572 error.AsCString()); 573 result.SetStatus (eReturnStatusFailed); 574 } 575 } 576 else 577 { 578 result.AppendErrorWithFormat ("No PID specified for attach\n", 579 attach_pid, 580 error.AsCString()); 581 result.SetStatus (eReturnStatusFailed); 582 583 } 584 } 585 } 586 } 587 588 if (result.Succeeded()) 589 { 590 // Okay, we're done. Last step is to warn if the executable module has changed: 591 if (!old_exec_module_sp) 592 { 593 char new_path[PATH_MAX + 1]; 594 target->GetExecutableModule()->GetFileSpec().GetPath(new_path, PATH_MAX); 595 596 result.AppendMessageWithFormat("Executable module set to \"%s\".\n", 597 new_path); 598 } 599 else if (old_exec_module_sp->GetFileSpec() != target->GetExecutableModule()->GetFileSpec()) 600 { 601 char old_path[PATH_MAX + 1]; 602 char new_path[PATH_MAX + 1]; 603 604 old_exec_module_sp->GetFileSpec().GetPath(old_path, PATH_MAX); 605 target->GetExecutableModule()->GetFileSpec().GetPath (new_path, PATH_MAX); 606 607 result.AppendWarningWithFormat("Executable module changed from \"%s\" to \"%s\".\n", 608 old_path, new_path); 609 } 610 611 if (!old_arch_spec.IsValid()) 612 { 613 result.AppendMessageWithFormat ("Architecture set to: %s.\n", target->GetArchitecture().AsCString()); 614 } 615 else if (old_arch_spec != target->GetArchitecture()) 616 { 617 result.AppendWarningWithFormat("Architecture changed from %s to %s.\n", 618 old_arch_spec.AsCString(), target->GetArchitecture().AsCString()); 619 } 620 } 621 return result.Succeeded(); 622 } 623 624 Options * 625 GetOptions () 626 { 627 return &m_options; 628 } 629 630 protected: 631 632 CommandOptions m_options; 633 }; 634 635 636 lldb::OptionDefinition 637 CommandObjectProcessAttach::CommandOptions::g_option_table[] = 638 { 639 { LLDB_OPT_SET_ALL, false, "plugin", 'P', required_argument, NULL, 0, "<plugin>", "Name of the process plugin you want to use."}, 640 { LLDB_OPT_SET_1, false, "pid", 'p', required_argument, NULL, 0, "<pid>", "The process ID of an existing process to attach to."}, 641 { LLDB_OPT_SET_2, true, "name", 'n', required_argument, NULL, 0, "<process-name>", "The name of the process to attach to."}, 642 { LLDB_OPT_SET_2, false, "waitfor", 'w', no_argument, NULL, 0, NULL, "Wait for the the process with <process-name> to launch."}, 643 { 0, false, NULL, 0, 0, NULL, 0, NULL, NULL } 644 }; 645 646 //------------------------------------------------------------------------- 647 // CommandObjectProcessContinue 648 //------------------------------------------------------------------------- 649 650 class CommandObjectProcessContinue : public CommandObject 651 { 652 public: 653 654 CommandObjectProcessContinue () : 655 CommandObject ("process continue", 656 "Continues execution all threads in the current process.", 657 "process continue", 658 eFlagProcessMustBeLaunched | eFlagProcessMustBePaused) 659 { 660 } 661 662 663 ~CommandObjectProcessContinue () 664 { 665 } 666 667 bool 668 Execute (CommandInterpreter &interpreter, 669 Args& command, 670 CommandReturnObject &result) 671 { 672 Process *process = interpreter.GetDebugger().GetExecutionContext().process; 673 bool synchronous_execution = interpreter.GetSynchronous (); 674 675 if (process == NULL) 676 { 677 result.AppendError ("no process to continue"); 678 result.SetStatus (eReturnStatusFailed); 679 return false; 680 } 681 682 StateType state = process->GetState(); 683 if (state == eStateStopped) 684 { 685 if (command.GetArgumentCount() != 0) 686 { 687 result.AppendErrorWithFormat ("The '%s' command does not take any arguments.\n", m_cmd_name.c_str()); 688 result.SetStatus (eReturnStatusFailed); 689 return false; 690 } 691 692 const uint32_t num_threads = process->GetThreadList().GetSize(); 693 694 // Set the actions that the threads should each take when resuming 695 for (uint32_t idx=0; idx<num_threads; ++idx) 696 { 697 process->GetThreadList().GetThreadAtIndex(idx)->SetResumeState (eStateRunning); 698 } 699 700 Error error(process->Resume()); 701 if (error.Success()) 702 { 703 result.AppendMessageWithFormat ("Resuming process %i\n", process->GetID()); 704 if (synchronous_execution) 705 { 706 state = process->WaitForProcessToStop (NULL); 707 708 result.SetDidChangeProcessState (true); 709 result.AppendMessageWithFormat ("Process %i %s\n", process->GetID(), StateAsCString (state)); 710 result.SetStatus (eReturnStatusSuccessFinishNoResult); 711 } 712 else 713 { 714 result.SetStatus (eReturnStatusSuccessContinuingNoResult); 715 } 716 } 717 else 718 { 719 result.AppendErrorWithFormat("Failed to resume process: %s.\n", error.AsCString()); 720 result.SetStatus (eReturnStatusFailed); 721 } 722 } 723 else 724 { 725 result.AppendErrorWithFormat ("Process cannot be continued from its current state (%s).\n", 726 StateAsCString(state)); 727 result.SetStatus (eReturnStatusFailed); 728 } 729 return result.Succeeded(); 730 } 731 }; 732 733 //------------------------------------------------------------------------- 734 // CommandObjectProcessDetach 735 //------------------------------------------------------------------------- 736 737 class CommandObjectProcessDetach : public CommandObject 738 { 739 public: 740 741 CommandObjectProcessDetach () : 742 CommandObject ("process detach", 743 "Detaches from the current process being debugged.", 744 "process detach", 745 eFlagProcessMustBeLaunched) 746 { 747 } 748 749 ~CommandObjectProcessDetach () 750 { 751 } 752 753 bool 754 Execute (CommandInterpreter &interpreter, 755 Args& command, 756 CommandReturnObject &result) 757 { 758 Process *process = interpreter.GetDebugger().GetExecutionContext().process; 759 if (process == NULL) 760 { 761 result.AppendError ("must have a valid process in order to detach"); 762 result.SetStatus (eReturnStatusFailed); 763 return false; 764 } 765 766 Error error (process->Detach()); 767 if (error.Success()) 768 { 769 result.SetStatus (eReturnStatusSuccessFinishResult); 770 } 771 else 772 { 773 result.AppendErrorWithFormat ("Detach failed: %s\n", error.AsCString()); 774 result.SetStatus (eReturnStatusFailed); 775 return false; 776 } 777 return result.Succeeded(); 778 } 779 }; 780 781 //------------------------------------------------------------------------- 782 // CommandObjectProcessSignal 783 //------------------------------------------------------------------------- 784 785 class CommandObjectProcessSignal : public CommandObject 786 { 787 public: 788 789 CommandObjectProcessSignal () : 790 CommandObject ("process signal", 791 "Sends a UNIX signal to the current process being debugged.", 792 "process signal <unix-signal-number>") 793 { 794 } 795 796 ~CommandObjectProcessSignal () 797 { 798 } 799 800 bool 801 Execute (CommandInterpreter &interpreter, 802 Args& command, 803 CommandReturnObject &result) 804 { 805 Process *process = interpreter.GetDebugger().GetExecutionContext().process; 806 if (process == NULL) 807 { 808 result.AppendError ("no process to signal"); 809 result.SetStatus (eReturnStatusFailed); 810 return false; 811 } 812 813 if (command.GetArgumentCount() == 1) 814 { 815 int signo = Args::StringToSInt32(command.GetArgumentAtIndex(0), -1, 0); 816 if (signo == -1) 817 { 818 result.AppendErrorWithFormat ("Invalid signal argument '%s'.\n", command.GetArgumentAtIndex(0)); 819 result.SetStatus (eReturnStatusFailed); 820 } 821 else 822 { 823 Error error (process->Signal (signo)); 824 if (error.Success()) 825 { 826 result.SetStatus (eReturnStatusSuccessFinishResult); 827 } 828 else 829 { 830 result.AppendErrorWithFormat ("Failed to send signal %i: %s\n", signo, error.AsCString()); 831 result.SetStatus (eReturnStatusFailed); 832 } 833 } 834 } 835 else 836 { 837 result.AppendErrorWithFormat("'%s' takes exactly one signal number argument:\nUsage: \n", m_cmd_name.c_str(), 838 m_cmd_syntax.c_str()); 839 result.SetStatus (eReturnStatusFailed); 840 } 841 return result.Succeeded(); 842 } 843 }; 844 845 846 //------------------------------------------------------------------------- 847 // CommandObjectProcessInterrupt 848 //------------------------------------------------------------------------- 849 850 class CommandObjectProcessInterrupt : public CommandObject 851 { 852 public: 853 854 855 CommandObjectProcessInterrupt () : 856 CommandObject ("process interrupt", 857 "Interrupts the current process being debugged.", 858 "process interrupt", 859 eFlagProcessMustBeLaunched) 860 { 861 } 862 863 ~CommandObjectProcessInterrupt () 864 { 865 } 866 867 bool 868 Execute (CommandInterpreter &interpreter, 869 Args& command, 870 CommandReturnObject &result) 871 { 872 Process *process = interpreter.GetDebugger().GetExecutionContext().process; 873 if (process == NULL) 874 { 875 result.AppendError ("no process to halt"); 876 result.SetStatus (eReturnStatusFailed); 877 return false; 878 } 879 880 if (command.GetArgumentCount() == 0) 881 { 882 Error error(process->Halt ()); 883 if (error.Success()) 884 { 885 result.SetStatus (eReturnStatusSuccessFinishResult); 886 887 // Maybe we should add a "SuspendThreadPlans so we 888 // can halt, and keep in place all the current thread plans. 889 process->GetThreadList().DiscardThreadPlans(); 890 } 891 else 892 { 893 result.AppendErrorWithFormat ("Failed to halt process: %s\n", error.AsCString()); 894 result.SetStatus (eReturnStatusFailed); 895 } 896 } 897 else 898 { 899 result.AppendErrorWithFormat("'%s' takes no arguments:\nUsage: \n", 900 m_cmd_name.c_str(), 901 m_cmd_syntax.c_str()); 902 result.SetStatus (eReturnStatusFailed); 903 } 904 return result.Succeeded(); 905 } 906 }; 907 908 //------------------------------------------------------------------------- 909 // CommandObjectProcessKill 910 //------------------------------------------------------------------------- 911 912 class CommandObjectProcessKill : public CommandObject 913 { 914 public: 915 916 CommandObjectProcessKill () : 917 CommandObject ("process kill", 918 "Terminates the current process being debugged.", 919 "process kill", 920 eFlagProcessMustBeLaunched) 921 { 922 } 923 924 ~CommandObjectProcessKill () 925 { 926 } 927 928 bool 929 Execute (CommandInterpreter &interpreter, 930 Args& command, 931 CommandReturnObject &result) 932 { 933 Process *process = interpreter.GetDebugger().GetExecutionContext().process; 934 if (process == NULL) 935 { 936 result.AppendError ("no process to kill"); 937 result.SetStatus (eReturnStatusFailed); 938 return false; 939 } 940 941 if (command.GetArgumentCount() == 0) 942 { 943 Error error (process->Destroy()); 944 if (error.Success()) 945 { 946 result.SetStatus (eReturnStatusSuccessFinishResult); 947 } 948 else 949 { 950 result.AppendErrorWithFormat ("Failed to kill process: %s\n", error.AsCString()); 951 result.SetStatus (eReturnStatusFailed); 952 } 953 } 954 else 955 { 956 result.AppendErrorWithFormat("'%s' takes no arguments:\nUsage: \n", 957 m_cmd_name.c_str(), 958 m_cmd_syntax.c_str()); 959 result.SetStatus (eReturnStatusFailed); 960 } 961 return result.Succeeded(); 962 } 963 }; 964 965 //------------------------------------------------------------------------- 966 // CommandObjectProcessStatus 967 //------------------------------------------------------------------------- 968 class CommandObjectProcessStatus : public CommandObject 969 { 970 public: 971 CommandObjectProcessStatus () : 972 CommandObject ("status", 973 "Shows the current status and location of executing process.", 974 "status", 975 0) 976 { 977 } 978 979 ~CommandObjectProcessStatus() 980 { 981 } 982 983 984 bool 985 Execute 986 ( 987 CommandInterpreter &interpreter, 988 Args& command, 989 CommandReturnObject &result 990 ) 991 { 992 StreamString &output_stream = result.GetOutputStream(); 993 result.SetStatus (eReturnStatusSuccessFinishNoResult); 994 ExecutionContext exe_ctx(interpreter.GetDebugger().GetExecutionContext()); 995 if (exe_ctx.process) 996 { 997 const StateType state = exe_ctx.process->GetState(); 998 if (StateIsStoppedState(state)) 999 { 1000 if (state == eStateExited) 1001 { 1002 int exit_status = exe_ctx.process->GetExitStatus(); 1003 const char *exit_description = exe_ctx.process->GetExitDescription(); 1004 output_stream.Printf ("Process %d exited with status = %i (0x%8.8x) %s\n", 1005 exe_ctx.process->GetID(), 1006 exit_status, 1007 exit_status, 1008 exit_description ? exit_description : ""); 1009 } 1010 else 1011 { 1012 output_stream.Printf ("Process %d %s\n", exe_ctx.process->GetID(), StateAsCString (state)); 1013 if (exe_ctx.thread == NULL) 1014 exe_ctx.thread = exe_ctx.process->GetThreadList().GetThreadAtIndex(0).get(); 1015 if (exe_ctx.thread != NULL) 1016 { 1017 DisplayThreadsInfo (interpreter, &exe_ctx, result, true, true); 1018 } 1019 else 1020 { 1021 result.AppendError ("No valid thread found in current process."); 1022 result.SetStatus (eReturnStatusFailed); 1023 } 1024 } 1025 } 1026 else 1027 { 1028 output_stream.Printf ("Process %d is running.\n", 1029 exe_ctx.process->GetID()); 1030 } 1031 } 1032 else 1033 { 1034 result.AppendError ("No current location or status available."); 1035 result.SetStatus (eReturnStatusFailed); 1036 } 1037 return result.Succeeded(); 1038 } 1039 }; 1040 1041 //------------------------------------------------------------------------- 1042 // CommandObjectMultiwordProcess 1043 //------------------------------------------------------------------------- 1044 1045 CommandObjectMultiwordProcess::CommandObjectMultiwordProcess (CommandInterpreter &interpreter) : 1046 CommandObjectMultiword ("process", 1047 "A set of commands for operating on a process.", 1048 "process <subcommand> [<subcommand-options>]") 1049 { 1050 LoadSubCommand (interpreter, "attach", CommandObjectSP (new CommandObjectProcessAttach ())); 1051 LoadSubCommand (interpreter, "launch", CommandObjectSP (new CommandObjectProcessLaunch ())); 1052 LoadSubCommand (interpreter, "continue", CommandObjectSP (new CommandObjectProcessContinue ())); 1053 LoadSubCommand (interpreter, "detach", CommandObjectSP (new CommandObjectProcessDetach ())); 1054 LoadSubCommand (interpreter, "signal", CommandObjectSP (new CommandObjectProcessSignal ())); 1055 LoadSubCommand (interpreter, "status", CommandObjectSP (new CommandObjectProcessStatus ())); 1056 LoadSubCommand (interpreter, "interrupt", CommandObjectSP (new CommandObjectProcessInterrupt ())); 1057 LoadSubCommand (interpreter, "kill", CommandObjectSP (new CommandObjectProcessKill ())); 1058 } 1059 1060 CommandObjectMultiwordProcess::~CommandObjectMultiwordProcess () 1061 { 1062 } 1063 1064