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