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