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