1 //===-- ProcessLaunchInfo.cpp -----------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "lldb/Host/Config.h" 11 12 #include "lldb/Core/Debugger.h" 13 #include "lldb/Core/Log.h" 14 #include "lldb/Host/FileSystem.h" 15 #include "lldb/Target/ProcessLaunchInfo.h" 16 #include "lldb/Target/FileAction.h" 17 #include "lldb/Target/Target.h" 18 19 #if !defined(_WIN32) 20 #include <limits.h> 21 #endif 22 23 using namespace lldb; 24 using namespace lldb_private; 25 26 //---------------------------------------------------------------------------- 27 // ProcessLaunchInfo member functions 28 //---------------------------------------------------------------------------- 29 30 ProcessLaunchInfo::ProcessLaunchInfo () : 31 ProcessInfo(), 32 m_working_dir (), 33 m_plugin_name (), 34 m_flags (0), 35 m_file_actions (), 36 m_pty (new lldb_utility::PseudoTerminal), 37 m_resume_count (0), 38 m_monitor_callback (NULL), 39 m_monitor_callback_baton (NULL), 40 m_monitor_signals (false), 41 m_listener_sp (), 42 m_hijack_listener_sp () 43 { 44 } 45 46 ProcessLaunchInfo::ProcessLaunchInfo(const FileSpec &stdin_file_spec, 47 const FileSpec &stdout_file_spec, 48 const FileSpec &stderr_file_spec, 49 const FileSpec &working_directory, 50 uint32_t launch_flags) : 51 ProcessInfo(), 52 m_working_dir(), 53 m_plugin_name(), 54 m_flags(launch_flags), 55 m_file_actions(), 56 m_pty(new lldb_utility::PseudoTerminal), 57 m_resume_count(0), 58 m_monitor_callback(NULL), 59 m_monitor_callback_baton(NULL), 60 m_monitor_signals(false), 61 m_listener_sp (), 62 m_hijack_listener_sp() 63 { 64 if (stdin_file_spec) 65 { 66 FileAction file_action; 67 const bool read = true; 68 const bool write = false; 69 if (file_action.Open(STDIN_FILENO, stdin_file_spec, read, write)) 70 AppendFileAction (file_action); 71 } 72 if (stdout_file_spec) 73 { 74 FileAction file_action; 75 const bool read = false; 76 const bool write = true; 77 if (file_action.Open(STDOUT_FILENO, stdout_file_spec, read, write)) 78 AppendFileAction (file_action); 79 } 80 if (stderr_file_spec) 81 { 82 FileAction file_action; 83 const bool read = false; 84 const bool write = true; 85 if (file_action.Open(STDERR_FILENO, stderr_file_spec, read, write)) 86 AppendFileAction (file_action); 87 } 88 if (working_directory) 89 SetWorkingDirectory(working_directory); 90 } 91 92 bool 93 ProcessLaunchInfo::AppendCloseFileAction (int fd) 94 { 95 FileAction file_action; 96 if (file_action.Close (fd)) 97 { 98 AppendFileAction (file_action); 99 return true; 100 } 101 return false; 102 } 103 104 bool 105 ProcessLaunchInfo::AppendDuplicateFileAction (int fd, int dup_fd) 106 { 107 FileAction file_action; 108 if (file_action.Duplicate (fd, dup_fd)) 109 { 110 AppendFileAction (file_action); 111 return true; 112 } 113 return false; 114 } 115 116 bool 117 ProcessLaunchInfo::AppendOpenFileAction(int fd, const FileSpec &file_spec, 118 bool read, bool write) 119 { 120 FileAction file_action; 121 if (file_action.Open(fd, file_spec, read, write)) 122 { 123 AppendFileAction (file_action); 124 return true; 125 } 126 return false; 127 } 128 129 bool 130 ProcessLaunchInfo::AppendSuppressFileAction (int fd, bool read, bool write) 131 { 132 FileAction file_action; 133 if (file_action.Open(fd, FileSpec{FileSystem::DEV_NULL, false}, read, write)) 134 { 135 AppendFileAction (file_action); 136 return true; 137 } 138 return false; 139 } 140 141 const FileAction * 142 ProcessLaunchInfo::GetFileActionAtIndex(size_t idx) const 143 { 144 if (idx < m_file_actions.size()) 145 return &m_file_actions[idx]; 146 return NULL; 147 } 148 149 const FileAction * 150 ProcessLaunchInfo::GetFileActionForFD(int fd) const 151 { 152 for (size_t idx=0, count=m_file_actions.size(); idx < count; ++idx) 153 { 154 if (m_file_actions[idx].GetFD () == fd) 155 return &m_file_actions[idx]; 156 } 157 return NULL; 158 } 159 160 const FileSpec & 161 ProcessLaunchInfo::GetWorkingDirectory() const 162 { 163 return m_working_dir; 164 } 165 166 void 167 ProcessLaunchInfo::SetWorkingDirectory(const FileSpec &working_dir) 168 { 169 m_working_dir = working_dir; 170 } 171 172 const char * 173 ProcessLaunchInfo::GetProcessPluginName () const 174 { 175 if (m_plugin_name.empty()) 176 return NULL; 177 return m_plugin_name.c_str(); 178 } 179 180 void 181 ProcessLaunchInfo::SetProcessPluginName (const char *plugin) 182 { 183 if (plugin && plugin[0]) 184 m_plugin_name.assign (plugin); 185 else 186 m_plugin_name.clear(); 187 } 188 189 const FileSpec & 190 ProcessLaunchInfo::GetShell () const 191 { 192 return m_shell; 193 } 194 195 void 196 ProcessLaunchInfo::SetShell (const FileSpec &shell) 197 { 198 m_shell = shell; 199 if (m_shell) 200 { 201 m_shell.ResolveExecutableLocation(); 202 m_flags.Set (lldb::eLaunchFlagLaunchInShell); 203 } 204 else 205 m_flags.Clear (lldb::eLaunchFlagLaunchInShell); 206 } 207 208 void 209 ProcessLaunchInfo::SetLaunchInSeparateProcessGroup (bool separate) 210 { 211 if (separate) 212 m_flags.Set(lldb::eLaunchFlagLaunchInSeparateProcessGroup); 213 else 214 m_flags.Clear (lldb::eLaunchFlagLaunchInSeparateProcessGroup); 215 } 216 217 void 218 ProcessLaunchInfo::SetShellExpandArguments (bool expand) 219 { 220 if (expand) 221 m_flags.Set(lldb::eLaunchFlagShellExpandArguments); 222 else 223 m_flags.Clear(lldb::eLaunchFlagShellExpandArguments); 224 } 225 226 void 227 ProcessLaunchInfo::Clear () 228 { 229 ProcessInfo::Clear(); 230 m_working_dir.Clear(); 231 m_plugin_name.clear(); 232 m_shell.Clear(); 233 m_flags.Clear(); 234 m_file_actions.clear(); 235 m_resume_count = 0; 236 m_listener_sp.reset(); 237 m_hijack_listener_sp.reset(); 238 } 239 240 void 241 ProcessLaunchInfo::SetMonitorProcessCallback (Host::MonitorChildProcessCallback callback, 242 void *baton, 243 bool monitor_signals) 244 { 245 m_monitor_callback = callback; 246 m_monitor_callback_baton = baton; 247 m_monitor_signals = monitor_signals; 248 } 249 250 bool 251 ProcessLaunchInfo::MonitorProcess () const 252 { 253 if (m_monitor_callback && ProcessIDIsValid()) 254 { 255 Host::StartMonitoringChildProcess (m_monitor_callback, 256 m_monitor_callback_baton, 257 GetProcessID(), 258 m_monitor_signals); 259 return true; 260 } 261 return false; 262 } 263 264 void 265 ProcessLaunchInfo::SetDetachOnError (bool enable) 266 { 267 if (enable) 268 m_flags.Set(lldb::eLaunchFlagDetachOnError); 269 else 270 m_flags.Clear(lldb::eLaunchFlagDetachOnError); 271 } 272 273 void 274 ProcessLaunchInfo::FinalizeFileActions (Target *target, bool default_to_use_pty) 275 { 276 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); 277 278 // If nothing for stdin or stdout or stderr was specified, then check the process for any default 279 // settings that were set with "settings set" 280 if (GetFileActionForFD(STDIN_FILENO) == NULL || 281 GetFileActionForFD(STDOUT_FILENO) == NULL || 282 GetFileActionForFD(STDERR_FILENO) == NULL) 283 { 284 if (log) 285 log->Printf ("ProcessLaunchInfo::%s at least one of stdin/stdout/stderr was not set, evaluating default handling", 286 __FUNCTION__); 287 288 if (m_flags.Test(eLaunchFlagLaunchInTTY)) 289 { 290 // Do nothing, if we are launching in a remote terminal 291 // no file actions should be done at all. 292 return; 293 } 294 295 if (m_flags.Test(eLaunchFlagDisableSTDIO)) 296 { 297 if (log) 298 log->Printf ("ProcessLaunchInfo::%s eLaunchFlagDisableSTDIO set, adding suppression action for stdin, stdout and stderr", 299 __FUNCTION__); 300 AppendSuppressFileAction (STDIN_FILENO , true, false); 301 AppendSuppressFileAction (STDOUT_FILENO, false, true); 302 AppendSuppressFileAction (STDERR_FILENO, false, true); 303 } 304 else 305 { 306 // Check for any values that might have gotten set with any of: 307 // (lldb) settings set target.input-path 308 // (lldb) settings set target.output-path 309 // (lldb) settings set target.error-path 310 FileSpec in_file_spec; 311 FileSpec out_file_spec; 312 FileSpec err_file_spec; 313 if (target) 314 { 315 // Only override with the target settings if we don't already have 316 // an action for in, out or error 317 if (GetFileActionForFD(STDIN_FILENO) == NULL) 318 in_file_spec = target->GetStandardInputPath(); 319 if (GetFileActionForFD(STDOUT_FILENO) == NULL) 320 out_file_spec = target->GetStandardOutputPath(); 321 if (GetFileActionForFD(STDERR_FILENO) == NULL) 322 err_file_spec = target->GetStandardErrorPath(); 323 } 324 325 if (log) 326 log->Printf ("ProcessLaunchInfo::%s target stdin='%s', target stdout='%s', stderr='%s'", 327 __FUNCTION__, 328 in_file_spec ? in_file_spec.GetCString() : "<null>", 329 out_file_spec ? out_file_spec.GetCString() : "<null>", 330 err_file_spec ? err_file_spec.GetCString() : "<null>"); 331 332 if (in_file_spec) 333 { 334 AppendOpenFileAction(STDIN_FILENO, in_file_spec, true, false); 335 if (log) 336 log->Printf ("ProcessLaunchInfo::%s appended stdin open file action for %s", 337 __FUNCTION__, in_file_spec.GetCString()); 338 } 339 340 if (out_file_spec) 341 { 342 AppendOpenFileAction(STDOUT_FILENO, out_file_spec, false, true); 343 if (log) 344 log->Printf ("ProcessLaunchInfo::%s appended stdout open file action for %s", 345 __FUNCTION__, out_file_spec.GetCString()); 346 } 347 348 if (err_file_spec) 349 { 350 AppendOpenFileAction(STDERR_FILENO, err_file_spec, false, true); 351 if (log) 352 log->Printf ("ProcessLaunchInfo::%s appended stderr open file action for %s", 353 __FUNCTION__, err_file_spec.GetCString()); 354 } 355 356 if (default_to_use_pty && (!in_file_spec || !out_file_spec || !err_file_spec)) 357 { 358 if (log) 359 log->Printf ("ProcessLaunchInfo::%s default_to_use_pty is set, and at least one stdin/stderr/stdout is unset, so generating a pty to use for it", 360 __FUNCTION__); 361 362 int open_flags = O_RDWR | O_NOCTTY; 363 #if !defined(_MSC_VER) 364 // We really shouldn't be specifying platform specific flags 365 // that are intended for a system call in generic code. But 366 // this will have to do for now. 367 open_flags |= O_CLOEXEC; 368 #endif 369 if (m_pty->OpenFirstAvailableMaster(open_flags, NULL, 0)) 370 { 371 const FileSpec slave_file_spec{m_pty->GetSlaveName(NULL, 0), false}; 372 373 // Only use the slave tty if we don't have anything specified for 374 // input and don't have an action for stdin 375 if (!in_file_spec && GetFileActionForFD(STDIN_FILENO) == NULL) 376 { 377 AppendOpenFileAction(STDIN_FILENO, slave_file_spec, true, false); 378 } 379 380 // Only use the slave tty if we don't have anything specified for 381 // output and don't have an action for stdout 382 if (!out_file_spec && GetFileActionForFD(STDOUT_FILENO) == NULL) 383 { 384 AppendOpenFileAction(STDOUT_FILENO, slave_file_spec, false, true); 385 } 386 387 // Only use the slave tty if we don't have anything specified for 388 // error and don't have an action for stderr 389 if (!err_file_spec && GetFileActionForFD(STDERR_FILENO) == NULL) 390 { 391 AppendOpenFileAction(STDERR_FILENO, slave_file_spec, false, true); 392 } 393 } 394 } 395 } 396 } 397 } 398 399 400 bool 401 ProcessLaunchInfo::ConvertArgumentsForLaunchingInShell (Error &error, 402 bool localhost, 403 bool will_debug, 404 bool first_arg_is_full_shell_command, 405 int32_t num_resumes) 406 { 407 error.Clear(); 408 409 if (GetFlags().Test (eLaunchFlagLaunchInShell)) 410 { 411 if (m_shell) 412 { 413 std::string shell_executable = m_shell.GetPath(); 414 415 const char **argv = GetArguments().GetConstArgumentVector (); 416 if (argv == NULL || argv[0] == NULL) 417 return false; 418 Args shell_arguments; 419 std::string safe_arg; 420 shell_arguments.AppendArgument (shell_executable.c_str()); 421 const llvm::Triple &triple = GetArchitecture().GetTriple(); 422 if (triple.getOS() == llvm::Triple::Win32 && !triple.isWindowsCygwinEnvironment()) 423 shell_arguments.AppendArgument("/C"); 424 else 425 shell_arguments.AppendArgument("-c"); 426 427 StreamString shell_command; 428 if (will_debug) 429 { 430 // Add a modified PATH environment variable in case argv[0] 431 // is a relative path. 432 const char *argv0 = argv[0]; 433 FileSpec arg_spec(argv0, false); 434 if (arg_spec.IsRelative()) 435 { 436 // We have a relative path to our executable which may not work if 437 // we just try to run "a.out" (without it being converted to "./a.out") 438 FileSpec working_dir = GetWorkingDirectory(); 439 // Be sure to put quotes around PATH's value in case any paths have spaces... 440 std::string new_path("PATH=\""); 441 const size_t empty_path_len = new_path.size(); 442 443 if (working_dir) 444 { 445 new_path += working_dir.GetPath(); 446 } 447 else 448 { 449 char current_working_dir[PATH_MAX]; 450 const char *cwd = getcwd(current_working_dir, sizeof(current_working_dir)); 451 if (cwd && cwd[0]) 452 new_path += cwd; 453 } 454 const char *curr_path = getenv("PATH"); 455 if (curr_path) 456 { 457 if (new_path.size() > empty_path_len) 458 new_path += ':'; 459 new_path += curr_path; 460 } 461 new_path += "\" "; 462 shell_command.PutCString(new_path.c_str()); 463 } 464 465 if (triple.getOS() != llvm::Triple::Win32 || triple.isWindowsCygwinEnvironment()) 466 shell_command.PutCString("exec"); 467 468 // Only Apple supports /usr/bin/arch being able to specify the architecture 469 if (GetArchitecture().IsValid() && // Valid architecture 470 GetArchitecture().GetTriple().getVendor() == llvm::Triple::Apple && // Apple only 471 GetArchitecture().GetCore() != ArchSpec::eCore_x86_64_x86_64h) // Don't do this for x86_64h 472 { 473 shell_command.Printf(" /usr/bin/arch -arch %s", GetArchitecture().GetArchitectureName()); 474 // Set the resume count to 2: 475 // 1 - stop in shell 476 // 2 - stop in /usr/bin/arch 477 // 3 - then we will stop in our program 478 SetResumeCount(num_resumes + 1); 479 } 480 else 481 { 482 // Set the resume count to 1: 483 // 1 - stop in shell 484 // 2 - then we will stop in our program 485 SetResumeCount(num_resumes); 486 } 487 } 488 489 if (first_arg_is_full_shell_command) 490 { 491 // There should only be one argument that is the shell command itself to be used as is 492 if (argv[0] && !argv[1]) 493 shell_command.Printf("%s", argv[0]); 494 else 495 return false; 496 } 497 else 498 { 499 for (size_t i=0; argv[i] != NULL; ++i) 500 { 501 const char *arg = Args::GetShellSafeArgument (argv[i], safe_arg); 502 shell_command.Printf(" %s", arg); 503 } 504 } 505 shell_arguments.AppendArgument (shell_command.GetString().c_str()); 506 m_executable = m_shell; 507 m_arguments = shell_arguments; 508 return true; 509 } 510 else 511 { 512 error.SetErrorString ("invalid shell path"); 513 } 514 } 515 else 516 { 517 error.SetErrorString ("not launching in shell"); 518 } 519 return false; 520 } 521 522 Listener & 523 ProcessLaunchInfo::GetListenerForProcess (Debugger &debugger) 524 { 525 if (m_listener_sp) 526 return *m_listener_sp; 527 else 528 return debugger.GetListener(); 529 } 530