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().GetCurrentTarget().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 protected: 251 252 CommandOptions m_options; 253 }; 254 255 256 lldb::OptionDefinition 257 CommandObjectProcessLaunch::CommandOptions::g_option_table[] = 258 { 259 { 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."}, 260 { LLDB_OPT_SET_1, false, "stdin", 'i', required_argument, NULL, 0, "<path>", "Redirect stdin for the process to <path>."}, 261 { LLDB_OPT_SET_1, false, "stdout", 'o', required_argument, NULL, 0, "<path>", "Redirect stdout for the process to <path>."}, 262 { LLDB_OPT_SET_1, false, "stderr", 'e', required_argument, NULL, 0, "<path>", "Redirect stderr for the process to <path>."}, 263 { LLDB_OPT_SET_1, false, "plugin", 'p', required_argument, NULL, 0, "<plugin>", "Name of the process plugin you want to use."}, 264 { 0, false, NULL, 0, 0, NULL, 0, NULL, NULL } 265 }; 266 267 268 //------------------------------------------------------------------------- 269 // CommandObjectProcessAttach 270 //------------------------------------------------------------------------- 271 272 class CommandObjectProcessAttach : public CommandObject 273 { 274 public: 275 276 CommandObjectProcessAttach () : 277 CommandObject ("process attach", 278 "Attaches to a process.", 279 "process attach <cmd-options>") 280 { 281 SetHelpLong("Currently, you must set the executable file before you can attach " 282 "to a process.\n"); 283 } 284 285 ~CommandObjectProcessAttach () 286 { 287 } 288 289 bool 290 Execute (CommandInterpreter &interpreter, 291 Args& command, 292 CommandReturnObject &result) 293 { 294 Target *target = interpreter.GetDebugger().GetCurrentTarget().get(); 295 if (target == NULL) 296 { 297 result.AppendError ("invalid target, set executable file using 'file' command"); 298 result.SetStatus (eReturnStatusFailed); 299 return false; 300 } 301 302 // If our listener is NULL, users aren't allows to launch 303 304 Process *process = interpreter.GetDebugger().GetExecutionContext().process; 305 if (process) 306 { 307 if (process->IsAlive()) 308 { 309 result.AppendErrorWithFormat ("Process %u is currently being debugged, kill the process before attaching.\n", process->GetID()); 310 result.SetStatus (eReturnStatusFailed); 311 return false; 312 } 313 } 314 315 if (command.GetArgumentCount()) 316 { 317 result.AppendErrorWithFormat("Invalid arguments for '%s'.\nUsage: \n", m_cmd_name.c_str(), m_cmd_syntax.c_str()); 318 result.SetStatus (eReturnStatusFailed); 319 } 320 else 321 { 322 const char *plugin_name = NULL; 323 324 if (!m_options.plugin_name.empty()) 325 plugin_name = m_options.plugin_name.c_str(); 326 327 process = target->CreateProcess (interpreter.GetDebugger().GetListener(), plugin_name).get(); 328 329 if (process) 330 { 331 Error error; 332 int attach_pid = m_options.pid; 333 334 if (attach_pid != LLDB_INVALID_PROCESS_ID) 335 { 336 error = process->Attach (attach_pid); 337 if (error.Success()) 338 { 339 result.SetStatus (eReturnStatusSuccessContinuingNoResult); 340 } 341 else 342 { 343 result.AppendErrorWithFormat ("Attaching to process %i failed: %s.\n", 344 attach_pid, 345 error.AsCString()); 346 result.SetStatus (eReturnStatusFailed); 347 } 348 } 349 else if (!m_options.name.empty()) 350 { 351 error = process->Attach (m_options.name.c_str(), m_options.waitfor); 352 if (error.Success()) 353 { 354 result.SetStatus (eReturnStatusSuccessContinuingNoResult); 355 } 356 else 357 { 358 if (m_options.waitfor) 359 result.AppendErrorWithFormat ("Waiting for a process to launch named '%s': %s\n", 360 m_options.name.c_str(), 361 error.AsCString()); 362 else 363 result.AppendErrorWithFormat ("Failed to a process named '%s': %s\n", 364 m_options.name.c_str(), 365 error.AsCString()); 366 result.SetStatus (eReturnStatusFailed); 367 } 368 } 369 } 370 } 371 return result.Succeeded(); 372 } 373 374 Options * 375 GetOptions () 376 { 377 return &m_options; 378 } 379 380 class CommandOptions : public Options 381 { 382 public: 383 384 CommandOptions () : 385 Options() 386 { 387 // Keep default values of all options in one place: ResetOptionValues () 388 ResetOptionValues (); 389 } 390 391 ~CommandOptions () 392 { 393 } 394 395 Error 396 SetOptionValue (int option_idx, const char *option_arg) 397 { 398 Error error; 399 char short_option = (char) m_getopt_table[option_idx].val; 400 bool success = false; 401 switch (short_option) 402 { 403 case 'p': 404 pid = Args::StringToUInt32 (option_arg, LLDB_INVALID_PROCESS_ID, 0, &success); 405 if (!success || pid == LLDB_INVALID_PROCESS_ID) 406 { 407 error.SetErrorStringWithFormat("Invalid process ID '%s'.\n", option_arg); 408 } 409 break; 410 411 case 'P': 412 plugin_name = option_arg; 413 break; 414 415 case 'n': 416 name.assign(option_arg); 417 break; 418 419 case 'w': 420 waitfor = true; 421 break; 422 423 default: 424 error.SetErrorStringWithFormat("Invalid short option character '%c'.\n", short_option); 425 break; 426 } 427 return error; 428 } 429 430 void 431 ResetOptionValues () 432 { 433 Options::ResetOptionValues(); 434 pid = LLDB_INVALID_PROCESS_ID; 435 name.clear(); 436 waitfor = false; 437 } 438 439 const lldb::OptionDefinition* 440 GetDefinitions () 441 { 442 return g_option_table; 443 } 444 445 // Options table: Required for subclasses of Options. 446 447 static lldb::OptionDefinition g_option_table[]; 448 449 // Instance variables to hold the values for command options. 450 451 lldb::pid_t pid; 452 std::string plugin_name; 453 std::string name; 454 bool waitfor; 455 }; 456 457 protected: 458 459 CommandOptions m_options; 460 }; 461 462 463 lldb::OptionDefinition 464 CommandObjectProcessAttach::CommandOptions::g_option_table[] = 465 { 466 { LLDB_OPT_SET_ALL, false, "plugin", 'P', required_argument, NULL, 0, "<plugin>", "Name of the process plugin you want to use."}, 467 { LLDB_OPT_SET_1, false, "pid", 'p', required_argument, NULL, 0, "<pid>", "The process ID of an existing process to attach to."}, 468 { LLDB_OPT_SET_2, true, "name", 'n', required_argument, NULL, 0, "<process-name>", "The name of the process to attach to."}, 469 { LLDB_OPT_SET_2, false, "waitfor", 'w', no_argument, NULL, 0, NULL, "Wait for the the process with <process-name> to launch."}, 470 { 0, false, NULL, 0, 0, NULL, 0, NULL, NULL } 471 }; 472 473 //------------------------------------------------------------------------- 474 // CommandObjectProcessContinue 475 //------------------------------------------------------------------------- 476 477 class CommandObjectProcessContinue : public CommandObject 478 { 479 public: 480 481 CommandObjectProcessContinue () : 482 CommandObject ("process continue", 483 "Continues execution all threads in the current process.", 484 "process continue", 485 eFlagProcessMustBeLaunched | eFlagProcessMustBePaused) 486 { 487 } 488 489 490 ~CommandObjectProcessContinue () 491 { 492 } 493 494 bool 495 Execute (CommandInterpreter &interpreter, 496 Args& command, 497 CommandReturnObject &result) 498 { 499 Process *process = interpreter.GetDebugger().GetExecutionContext().process; 500 bool synchronous_execution = interpreter.GetSynchronous (); 501 502 if (process == NULL) 503 { 504 result.AppendError ("no process to continue"); 505 result.SetStatus (eReturnStatusFailed); 506 return false; 507 } 508 509 StateType state = process->GetState(); 510 if (state == eStateStopped) 511 { 512 if (command.GetArgumentCount() != 0) 513 { 514 result.AppendErrorWithFormat ("The '%s' command does not take any arguments.\n", m_cmd_name.c_str()); 515 result.SetStatus (eReturnStatusFailed); 516 return false; 517 } 518 519 const uint32_t num_threads = process->GetThreadList().GetSize(); 520 521 // Set the actions that the threads should each take when resuming 522 for (uint32_t idx=0; idx<num_threads; ++idx) 523 { 524 process->GetThreadList().GetThreadAtIndex(idx)->SetResumeState (eStateRunning); 525 } 526 527 Error error(process->Resume()); 528 if (error.Success()) 529 { 530 result.AppendMessageWithFormat ("Resuming process %i\n", process->GetID()); 531 if (synchronous_execution) 532 { 533 StateType state = process->WaitForProcessToStop (NULL); 534 535 result.SetDidChangeProcessState (true); 536 result.AppendMessageWithFormat ("Process %i %s\n", process->GetID(), StateAsCString (state)); 537 result.SetStatus (eReturnStatusSuccessFinishNoResult); 538 } 539 else 540 { 541 result.SetStatus (eReturnStatusSuccessContinuingNoResult); 542 } 543 } 544 else 545 { 546 result.AppendErrorWithFormat("Failed to resume process: %s.\n", error.AsCString()); 547 result.SetStatus (eReturnStatusFailed); 548 } 549 } 550 else 551 { 552 result.AppendErrorWithFormat ("Process cannot be continued from its current state (%s).\n", 553 StateAsCString(state)); 554 result.SetStatus (eReturnStatusFailed); 555 } 556 return result.Succeeded(); 557 } 558 }; 559 560 //------------------------------------------------------------------------- 561 // CommandObjectProcessDetach 562 //------------------------------------------------------------------------- 563 564 class CommandObjectProcessDetach : public CommandObject 565 { 566 public: 567 568 CommandObjectProcessDetach () : 569 CommandObject ("process detach", 570 "Detaches from the current process being debugged.", 571 "process detach", 572 eFlagProcessMustBeLaunched) 573 { 574 } 575 576 ~CommandObjectProcessDetach () 577 { 578 } 579 580 bool 581 Execute (CommandInterpreter &interpreter, 582 Args& command, 583 CommandReturnObject &result) 584 { 585 Process *process = interpreter.GetDebugger().GetExecutionContext().process; 586 if (process == NULL) 587 { 588 result.AppendError ("must have a valid process in order to detach"); 589 result.SetStatus (eReturnStatusFailed); 590 return false; 591 } 592 593 Error error (process->Detach()); 594 if (error.Success()) 595 { 596 result.SetStatus (eReturnStatusSuccessFinishResult); 597 } 598 else 599 { 600 result.AppendErrorWithFormat ("Detach failed: %s\n", error.AsCString()); 601 result.SetStatus (eReturnStatusFailed); 602 return false; 603 } 604 return result.Succeeded(); 605 } 606 }; 607 608 //------------------------------------------------------------------------- 609 // CommandObjectProcessSignal 610 //------------------------------------------------------------------------- 611 612 class CommandObjectProcessSignal : public CommandObject 613 { 614 public: 615 616 CommandObjectProcessSignal () : 617 CommandObject ("process signal", 618 "Sends a UNIX signal to the current process being debugged.", 619 "process signal <unix-signal-number>") 620 { 621 } 622 623 ~CommandObjectProcessSignal () 624 { 625 } 626 627 bool 628 Execute (CommandInterpreter &interpreter, 629 Args& command, 630 CommandReturnObject &result) 631 { 632 Process *process = interpreter.GetDebugger().GetExecutionContext().process; 633 if (process == NULL) 634 { 635 result.AppendError ("no process to signal"); 636 result.SetStatus (eReturnStatusFailed); 637 return false; 638 } 639 640 if (command.GetArgumentCount() == 1) 641 { 642 int signo = Args::StringToSInt32(command.GetArgumentAtIndex(0), -1, 0); 643 if (signo == -1) 644 { 645 result.AppendErrorWithFormat ("Invalid signal argument '%s'.\n", command.GetArgumentAtIndex(0)); 646 result.SetStatus (eReturnStatusFailed); 647 } 648 else 649 { 650 Error error (process->Signal (signo)); 651 if (error.Success()) 652 { 653 result.SetStatus (eReturnStatusSuccessFinishResult); 654 } 655 else 656 { 657 result.AppendErrorWithFormat ("Failed to send signal %i: %s\n", signo, error.AsCString()); 658 result.SetStatus (eReturnStatusFailed); 659 } 660 } 661 } 662 else 663 { 664 result.AppendErrorWithFormat("'%s' takes exactly one signal number argument:\nUsage: \n", m_cmd_name.c_str(), 665 m_cmd_syntax.c_str()); 666 result.SetStatus (eReturnStatusFailed); 667 } 668 return result.Succeeded(); 669 } 670 }; 671 672 673 //------------------------------------------------------------------------- 674 // CommandObjectProcessInterrupt 675 //------------------------------------------------------------------------- 676 677 class CommandObjectProcessInterrupt : public CommandObject 678 { 679 public: 680 681 682 CommandObjectProcessInterrupt () : 683 CommandObject ("process interrupt", 684 "Interrupts the current process being debugged.", 685 "process interrupt", 686 eFlagProcessMustBeLaunched) 687 { 688 } 689 690 ~CommandObjectProcessInterrupt () 691 { 692 } 693 694 bool 695 Execute (CommandInterpreter &interpreter, 696 Args& command, 697 CommandReturnObject &result) 698 { 699 Process *process = interpreter.GetDebugger().GetExecutionContext().process; 700 if (process == NULL) 701 { 702 result.AppendError ("no process to halt"); 703 result.SetStatus (eReturnStatusFailed); 704 return false; 705 } 706 707 if (command.GetArgumentCount() == 0) 708 { 709 Error error(process->Halt ()); 710 if (error.Success()) 711 { 712 result.SetStatus (eReturnStatusSuccessFinishResult); 713 714 // Maybe we should add a "SuspendThreadPlans so we 715 // can halt, and keep in place all the current thread plans. 716 process->GetThreadList().DiscardThreadPlans(); 717 } 718 else 719 { 720 result.AppendErrorWithFormat ("Failed to halt process: %s\n", error.AsCString()); 721 result.SetStatus (eReturnStatusFailed); 722 } 723 } 724 else 725 { 726 result.AppendErrorWithFormat("'%s' takes no arguments:\nUsage: \n", 727 m_cmd_name.c_str(), 728 m_cmd_syntax.c_str()); 729 result.SetStatus (eReturnStatusFailed); 730 } 731 return result.Succeeded(); 732 } 733 }; 734 735 //------------------------------------------------------------------------- 736 // CommandObjectProcessKill 737 //------------------------------------------------------------------------- 738 739 class CommandObjectProcessKill : public CommandObject 740 { 741 public: 742 743 CommandObjectProcessKill () : 744 CommandObject ("process kill", 745 "Terminates the current process being debugged.", 746 "process kill", 747 eFlagProcessMustBeLaunched) 748 { 749 } 750 751 ~CommandObjectProcessKill () 752 { 753 } 754 755 bool 756 Execute (CommandInterpreter &interpreter, 757 Args& command, 758 CommandReturnObject &result) 759 { 760 Process *process = interpreter.GetDebugger().GetExecutionContext().process; 761 if (process == NULL) 762 { 763 result.AppendError ("no process to kill"); 764 result.SetStatus (eReturnStatusFailed); 765 return false; 766 } 767 768 if (command.GetArgumentCount() == 0) 769 { 770 Error error (process->Destroy()); 771 if (error.Success()) 772 { 773 result.SetStatus (eReturnStatusSuccessFinishResult); 774 } 775 else 776 { 777 result.AppendErrorWithFormat ("Failed to kill process: %s\n", error.AsCString()); 778 result.SetStatus (eReturnStatusFailed); 779 } 780 } 781 else 782 { 783 result.AppendErrorWithFormat("'%s' takes no arguments:\nUsage: \n", 784 m_cmd_name.c_str(), 785 m_cmd_syntax.c_str()); 786 result.SetStatus (eReturnStatusFailed); 787 } 788 return result.Succeeded(); 789 } 790 }; 791 792 //------------------------------------------------------------------------- 793 // CommandObjectProcessStatus 794 //------------------------------------------------------------------------- 795 class CommandObjectProcessStatus : public CommandObject 796 { 797 public: 798 CommandObjectProcessStatus () : 799 CommandObject ("status", 800 "Shows the current status and location of executing process.", 801 "status", 802 0) 803 { 804 } 805 806 ~CommandObjectProcessStatus() 807 { 808 } 809 810 811 bool 812 Execute 813 ( 814 CommandInterpreter &interpreter, 815 Args& command, 816 CommandReturnObject &result 817 ) 818 { 819 StreamString &output_stream = result.GetOutputStream(); 820 result.SetStatus (eReturnStatusSuccessFinishNoResult); 821 ExecutionContext exe_ctx(interpreter.GetDebugger().GetExecutionContext()); 822 if (exe_ctx.process) 823 { 824 const StateType state = exe_ctx.process->GetState(); 825 if (StateIsStoppedState(state)) 826 { 827 if (state == eStateExited) 828 { 829 int exit_status = exe_ctx.process->GetExitStatus(); 830 const char *exit_description = exe_ctx.process->GetExitDescription(); 831 output_stream.Printf ("Process %d exited with status = %i (0x%8.8x) %s\n", 832 exe_ctx.process->GetID(), 833 exit_status, 834 exit_status, 835 exit_description ? exit_description : ""); 836 } 837 else 838 { 839 output_stream.Printf ("Process %d %s\n", exe_ctx.process->GetID(), StateAsCString (state)); 840 if (exe_ctx.thread == NULL) 841 exe_ctx.thread = exe_ctx.process->GetThreadList().GetThreadAtIndex(0).get(); 842 if (exe_ctx.thread != NULL) 843 { 844 DisplayThreadsInfo (interpreter, &exe_ctx, result, true, true); 845 } 846 else 847 { 848 result.AppendError ("No valid thread found in current process."); 849 result.SetStatus (eReturnStatusFailed); 850 } 851 } 852 } 853 else 854 { 855 output_stream.Printf ("Process %d is running.\n", 856 exe_ctx.process->GetID()); 857 } 858 } 859 else 860 { 861 result.AppendError ("No current location or status available."); 862 result.SetStatus (eReturnStatusFailed); 863 } 864 return result.Succeeded(); 865 } 866 }; 867 868 //------------------------------------------------------------------------- 869 // CommandObjectMultiwordProcess 870 //------------------------------------------------------------------------- 871 872 CommandObjectMultiwordProcess::CommandObjectMultiwordProcess (CommandInterpreter &interpreter) : 873 CommandObjectMultiword ("process", 874 "A set of commands for operating on a process.", 875 "process <subcommand> [<subcommand-options>]") 876 { 877 LoadSubCommand (interpreter, "attach", CommandObjectSP (new CommandObjectProcessAttach ())); 878 LoadSubCommand (interpreter, "launch", CommandObjectSP (new CommandObjectProcessLaunch ())); 879 LoadSubCommand (interpreter, "continue", CommandObjectSP (new CommandObjectProcessContinue ())); 880 LoadSubCommand (interpreter, "detach", CommandObjectSP (new CommandObjectProcessDetach ())); 881 LoadSubCommand (interpreter, "signal", CommandObjectSP (new CommandObjectProcessSignal ())); 882 LoadSubCommand (interpreter, "status", CommandObjectSP (new CommandObjectProcessStatus ())); 883 LoadSubCommand (interpreter, "interrupt", CommandObjectSP (new CommandObjectProcessInterrupt ())); 884 LoadSubCommand (interpreter, "kill", CommandObjectSP (new CommandObjectProcessKill ())); 885 } 886 887 CommandObjectMultiwordProcess::~CommandObjectMultiwordProcess () 888 { 889 } 890 891