static bool LocateDSYMInVincinityOfExecutable (const ModuleSpec &module_spec, FileSpec &dsym_fspec) { const FileSpec *exec_fspec = module_spec.GetFileSpecPtr(); if (exec_fspec) { char path[PATH_MAX]; if (exec_fspec->GetPath(path, sizeof(path))) { // Make sure the module isn't already just a dSYM file... if (strcasestr(path, ".dSYM/Contents/Resources/DWARF") == NULL) { size_t obj_file_path_length = strlen(path); strlcat(path, ".dSYM/Contents/Resources/DWARF/", sizeof(path)); strlcat(path, exec_fspec->GetFilename().AsCString(), sizeof(path)); dsym_fspec.SetFile(path, false); if (dsym_fspec.Exists() && FileAtPathContainsArchAndUUID (dsym_fspec, module_spec.GetArchitecturePtr(), module_spec.GetUUIDPtr())) { return true; } else { path[obj_file_path_length] = '\0'; char *last_dot = strrchr(path, '.'); while (last_dot != NULL && last_dot[0]) { char *next_slash = strchr(last_dot, '/'); if (next_slash != NULL) { *next_slash = '\0'; strlcat(path, ".dSYM/Contents/Resources/DWARF/", sizeof(path)); strlcat(path, exec_fspec->GetFilename().AsCString(), sizeof(path)); dsym_fspec.SetFile(path, false); if (dsym_fspec.Exists() && FileAtPathContainsArchAndUUID (dsym_fspec, module_spec.GetArchitecturePtr(), module_spec.GetUUIDPtr())) return true; else { *last_dot = '\0'; char *prev_slash = strrchr(path, '/'); if (prev_slash != NULL) *prev_slash = '\0'; else break; } } else { break; } } } } } } dsym_fspec.Clear(); return false; }
bool PathMappingList::FindFile (const FileSpec &orig_spec, FileSpec &new_spec) const { if (!m_pairs.empty()) { char orig_path[PATH_MAX]; char new_path[PATH_MAX]; const size_t orig_path_len = orig_spec.GetPath (orig_path, sizeof(orig_path)); if (orig_path_len > 0) { const_iterator pos, end = m_pairs.end(); for (pos = m_pairs.begin(); pos != end; ++pos) { const size_t prefix_len = pos->first.GetLength(); if (orig_path_len >= prefix_len) { if (::strncmp (pos->first.GetCString(), orig_path, prefix_len) == 0) { const size_t new_path_len = snprintf(new_path, sizeof(new_path), "%s/%s", pos->second.GetCString(), orig_path + prefix_len); if (new_path_len < sizeof(new_path)) { new_spec.SetFile (new_path, true); if (new_spec.Exists()) return true; } } } } } } new_spec.Clear(); return false; }
Error ModuleCache::Get (const FileSpec &root_dir_spec, const char *hostname, const UUID &uuid, const FileSpec &platform_module_spec, FileSpec &cached_module_spec) { cached_module_spec.Clear (); const auto module_spec_dir = GetModuleDirectory (root_dir_spec, uuid); const auto module_file_path = JoinPath (module_spec_dir, platform_module_spec.GetFilename ().AsCString ()); Error error; if (!module_file_path.Exists ()) { error.SetErrorStringWithFormat ("module %s not found", module_file_path.GetPath ().c_str ()); return error; } cached_module_spec = module_file_path; // We may have already cached module but downloaded from an another host - in this case let's create a symlink to it. const auto sysroot_module_path_spec = GetHostSysRootModulePath (root_dir_spec, hostname, platform_module_spec); if (!sysroot_module_path_spec.Exists ()) CreateHostSysRootModuleSymLink (sysroot_module_path_spec, cached_module_spec); return error; }
void Function::GetStartLineSourceInfo (FileSpec &source_file, uint32_t &line_no) { line_no = 0; source_file.Clear(); if (m_comp_unit == NULL) return; if (m_type != NULL && m_type->GetDeclaration().GetLine() != 0) { source_file = m_type->GetDeclaration().GetFile(); line_no = m_type->GetDeclaration().GetLine(); } else { LineTable *line_table = m_comp_unit->GetLineTable(); if (line_table == NULL) return; LineEntry line_entry; if (line_table->FindLineEntryByAddress (GetAddressRange().GetBaseAddress(), line_entry, NULL)) { line_no = line_entry.line; source_file = line_entry.file; } } }
bool HostInfoBase::ComputeGlobalTempFileDirectory(FileSpec &file_spec) { file_spec.Clear(); FileSpec temp_file_spec; if (!HostInfo::ComputeTempFileBaseDirectory(temp_file_spec)) return false; temp_file_spec.AppendPathComponent("lldb"); if (!FileSystem::MakeDirectory(temp_file_spec, eFilePermissionsDirectoryDefault).Success()) return false; file_spec.GetDirectory().SetCString(temp_file_spec.GetCString()); return true; }
Error File::GetFileSpec (FileSpec &file_spec) const { Error error; #ifdef LLDB_CONFIG_FCNTL_GETPATH_SUPPORTED if (IsValid ()) { char path[PATH_MAX]; if (::fcntl(GetDescriptor(), F_GETPATH, path) == -1) error.SetErrorToErrno(); else file_spec.SetFile (path, false); } else { error.SetErrorString("invalid file handle"); } #elif defined(__linux__) char proc[64]; char path[PATH_MAX]; if (::snprintf(proc, sizeof(proc), "/proc/self/fd/%d", GetDescriptor()) < 0) error.SetErrorString ("cannot resolve file descriptor"); else { ssize_t len; if ((len = ::readlink(proc, path, sizeof(path) - 1)) == -1) error.SetErrorToErrno(); else { path[len] = '\0'; file_spec.SetFile (path, false); } } #else error.SetErrorString ("File::GetFileSpec is not supported on this platform"); #endif if (error.Fail()) file_spec.Clear(); return error; }
void Function::GetEndLineSourceInfo (FileSpec &source_file, uint32_t &line_no) { line_no = 0; source_file.Clear(); // The -1 is kind of cheesy, but I want to get the last line entry for the given function, not the // first entry of the next. Address scratch_addr(GetAddressRange().GetBaseAddress()); scratch_addr.SetOffset (scratch_addr.GetOffset() + GetAddressRange().GetByteSize() - 1); LineTable *line_table = m_comp_unit->GetLineTable(); if (line_table == NULL) return; LineEntry line_entry; if (line_table->FindLineEntryByAddress (scratch_addr, line_entry, NULL)) { line_no = line_entry.line; source_file = line_entry.file; } }
bool Host::GetBundleDirectory (const FileSpec &file, FileSpec &bundle) { bundle.Clear(); return false; }
static bool LocateDSYMInVincinityOfExecutable(const ModuleSpec &module_spec, FileSpec &dsym_fspec) { Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); const FileSpec *exec_fspec = module_spec.GetFileSpecPtr(); if (exec_fspec) { char path[PATH_MAX]; if (exec_fspec->GetPath(path, sizeof(path))) { // Make sure the module isn't already just a dSYM file... if (strcasestr(path, ".dSYM/Contents/Resources/DWARF") == NULL) { if (log) { if (module_spec.GetUUIDPtr() && module_spec.GetUUIDPtr()->IsValid()) { log->Printf( "Searching for dSYM bundle next to executable %s, UUID %s", path, module_spec.GetUUIDPtr()->GetAsString().c_str()); } else { log->Printf("Searching for dSYM bundle next to executable %s", path); } } size_t obj_file_path_length = strlen(path); ::strncat(path, ".dSYM/Contents/Resources/DWARF/", sizeof(path) - strlen(path) - 1); ::strncat(path, exec_fspec->GetFilename().AsCString(), sizeof(path) - strlen(path) - 1); dsym_fspec.SetFile(path, false); ModuleSpecList module_specs; ModuleSpec matched_module_spec; if (dsym_fspec.Exists() && FileAtPathContainsArchAndUUID(dsym_fspec, module_spec.GetArchitecturePtr(), module_spec.GetUUIDPtr())) { if (log) { log->Printf("dSYM with matching UUID & arch found at %s", path); } return true; } else { path[obj_file_path_length] = '\0'; char *last_dot = strrchr(path, '.'); while (last_dot != NULL && last_dot[0]) { char *next_slash = strchr(last_dot, '/'); if (next_slash != NULL) { *next_slash = '\0'; ::strncat(path, ".dSYM/Contents/Resources/DWARF/", sizeof(path) - strlen(path) - 1); ::strncat(path, exec_fspec->GetFilename().AsCString(), sizeof(path) - strlen(path) - 1); dsym_fspec.SetFile(path, false); if (dsym_fspec.Exists() && FileAtPathContainsArchAndUUID( dsym_fspec, module_spec.GetArchitecturePtr(), module_spec.GetUUIDPtr())) { if (log) { log->Printf("dSYM with matching UUID & arch found at %s", path); } return true; } else { *last_dot = '\0'; char *prev_slash = strrchr(path, '/'); if (prev_slash != NULL) *prev_slash = '\0'; else break; } } else { break; } } } } } } dsym_fspec.Clear(); return false; }
static bool LocateDSYMInVincinityOfExecutable(const ModuleSpec &module_spec, FileSpec &dsym_fspec) { Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); const FileSpec *exec_fspec = module_spec.GetFileSpecPtr(); if (exec_fspec) { char path[PATH_MAX]; if (exec_fspec->GetPath(path, sizeof(path))) { // Make sure the module isn't already just a dSYM file... if (strcasestr(path, ".dSYM/Contents/Resources/DWARF") == NULL) { if (log) { if (module_spec.GetUUIDPtr() && module_spec.GetUUIDPtr()->IsValid()) { log->Printf( "Searching for dSYM bundle next to executable %s, UUID %s", path, module_spec.GetUUIDPtr()->GetAsString().c_str()); } else { log->Printf("Searching for dSYM bundle next to executable %s", path); } } ::strncat(path, ".dSYM/Contents/Resources/DWARF/", sizeof(path) - strlen(path) - 1); ::strncat(path, exec_fspec->GetFilename().AsCString(), sizeof(path) - strlen(path) - 1); dsym_fspec.SetFile(path, false); ModuleSpecList module_specs; ModuleSpec matched_module_spec; if (dsym_fspec.Exists() && FileAtPathContainsArchAndUUID(dsym_fspec, module_spec.GetArchitecturePtr(), module_spec.GetUUIDPtr())) { if (log) { log->Printf("dSYM with matching UUID & arch found at %s", path); } return true; } else { FileSpec parent_dirs = exec_fspec; // Remove the binary name from the FileSpec parent_dirs.RemoveLastPathComponent(); // Add a ".dSYM" name to each directory component of the path, // stripping off components. e.g. we may have a binary like // /S/L/F/Foundation.framework/Versions/A/Foundation // and // /S/L/F/Foundation.framework.dSYM // // so we'll need to start with /S/L/F/Foundation.framework/Versions/A, // add the .dSYM part to the "A", and if that doesn't exist, strip off // the "A" and try it again with "Versions", etc., until we find a // dSYM bundle or we've stripped off enough path components that // there's no need to continue. for (int i = 0; i < 4; i++) { // Does this part of the path have a "." character - could it be a // bundle's top level directory? const char *fn = parent_dirs.GetFilename().AsCString(); if (fn == nullptr) break; if (::strchr(fn, '.') != nullptr) { dsym_fspec = parent_dirs; dsym_fspec.RemoveLastPathComponent(); // If the current directory name is "Foundation.framework", see if // "Foundation.framework.dSYM/Contents/Resources/DWARF/Foundation" // exists & has the right uuid. std::string dsym_fn = fn; dsym_fn += ".dSYM"; dsym_fspec.AppendPathComponent(dsym_fn.c_str()); dsym_fspec.AppendPathComponent("Contents"); dsym_fspec.AppendPathComponent("Resources"); dsym_fspec.AppendPathComponent("DWARF"); dsym_fspec.AppendPathComponent( exec_fspec->GetFilename().AsCString()); if (dsym_fspec.Exists() && FileAtPathContainsArchAndUUID( dsym_fspec, module_spec.GetArchitecturePtr(), module_spec.GetUUIDPtr())) { if (log) { log->Printf("dSYM with matching UUID & arch found at %s", dsym_fspec.GetPath().c_str()); } return true; } } parent_dirs.RemoveLastPathComponent(); } } } } } dsym_fspec.Clear(); return false; }
Error GDBRemoteCommunication::StartDebugserverProcess (const char *hostname, uint16_t in_port, lldb_private::ProcessLaunchInfo &launch_info, uint16_t &out_port) { out_port = in_port; Error error; // If we locate debugserver, keep that located version around static FileSpec g_debugserver_file_spec; char debugserver_path[PATH_MAX]; FileSpec &debugserver_file_spec = launch_info.GetExecutableFile(); // Always check to see if we have an environment override for the path // to the debugserver to use and use it if we do. const char *env_debugserver_path = getenv("LLDB_DEBUGSERVER_PATH"); if (env_debugserver_path) debugserver_file_spec.SetFile (env_debugserver_path, false); else debugserver_file_spec = g_debugserver_file_spec; bool debugserver_exists = debugserver_file_spec.Exists(); if (!debugserver_exists) { // The debugserver binary is in the LLDB.framework/Resources // directory. if (Host::GetLLDBPath (ePathTypeSupportExecutableDir, debugserver_file_spec)) { debugserver_file_spec.GetFilename().SetCString(DEBUGSERVER_BASENAME); debugserver_exists = debugserver_file_spec.Exists(); if (debugserver_exists) { g_debugserver_file_spec = debugserver_file_spec; } else { g_debugserver_file_spec.Clear(); debugserver_file_spec.Clear(); } } } if (debugserver_exists) { debugserver_file_spec.GetPath (debugserver_path, sizeof(debugserver_path)); Args &debugserver_args = launch_info.GetArguments(); debugserver_args.Clear(); char arg_cstr[PATH_MAX]; // Start args with "debugserver /file/path -r --" debugserver_args.AppendArgument(debugserver_path); // If a host and port is supplied then use it char host_and_port[128]; if (hostname) { snprintf (host_and_port, sizeof(host_and_port), "%s:%u", hostname, in_port); debugserver_args.AppendArgument(host_and_port); } else { host_and_port[0] = '\0'; } // use native registers, not the GDB registers debugserver_args.AppendArgument("--native-regs"); // make debugserver run in its own session so signals generated by // special terminal key sequences (^C) don't affect debugserver debugserver_args.AppendArgument("--setsid"); char named_pipe_path[PATH_MAX]; named_pipe_path[0] = '\0'; bool listen = false; if (host_and_port[0]) { // Create a temporary file to get the stdout/stderr and redirect the // output of the command into this file. We will later read this file // if all goes well and fill the data into "command_output_ptr" if (in_port == 0) { // Binding to port zero, we need to figure out what port it ends up // using using a named pipe... FileSpec tmpdir_file_spec; if (Host::GetLLDBPath (ePathTypeLLDBTempSystemDir, tmpdir_file_spec)) { tmpdir_file_spec.GetFilename().SetCString("debugserver-named-pipe.XXXXXX"); strncpy(named_pipe_path, tmpdir_file_spec.GetPath().c_str(), sizeof(named_pipe_path)); } else { strncpy(named_pipe_path, "/tmp/debugserver-named-pipe.XXXXXX", sizeof(named_pipe_path)); } if (::mktemp (named_pipe_path)) { if (::mkfifo(named_pipe_path, 0600) == 0) { debugserver_args.AppendArgument("--named-pipe"); debugserver_args.AppendArgument(named_pipe_path); } } } else { listen = true; } } else { // No host and port given, so lets listen on our end and make the debugserver // connect to us.. error = StartListenThread ("localhost", 0); if (error.Fail()) return error; ConnectionFileDescriptor *connection = (ConnectionFileDescriptor *)GetConnection (); out_port = connection->GetBoundPort(3); assert (out_port != 0); char port_cstr[32]; snprintf(port_cstr, sizeof(port_cstr), "localhost:%i", out_port); // Send the host and port down that debugserver and specify an option // so that it connects back to the port we are listening to in this process debugserver_args.AppendArgument("--reverse-connect"); debugserver_args.AppendArgument(port_cstr); } const char *env_debugserver_log_file = getenv("LLDB_DEBUGSERVER_LOG_FILE"); if (env_debugserver_log_file) { ::snprintf (arg_cstr, sizeof(arg_cstr), "--log-file=%s", env_debugserver_log_file); debugserver_args.AppendArgument(arg_cstr); } const char *env_debugserver_log_flags = getenv("LLDB_DEBUGSERVER_LOG_FLAGS"); if (env_debugserver_log_flags) { ::snprintf (arg_cstr, sizeof(arg_cstr), "--log-flags=%s", env_debugserver_log_flags); debugserver_args.AppendArgument(arg_cstr); } // Close STDIN, STDOUT and STDERR. We might need to redirect them // to "/dev/null" if we run into any problems. launch_info.AppendCloseFileAction (STDIN_FILENO); launch_info.AppendCloseFileAction (STDOUT_FILENO); launch_info.AppendCloseFileAction (STDERR_FILENO); error = Host::LaunchProcess(launch_info); if (named_pipe_path[0]) { File name_pipe_file; error = name_pipe_file.Open(named_pipe_path, File::eOpenOptionRead); if (error.Success()) { char port_cstr[256]; port_cstr[0] = '\0'; size_t num_bytes = sizeof(port_cstr); error = name_pipe_file.Read(port_cstr, num_bytes); assert (error.Success()); assert (num_bytes > 0 && port_cstr[num_bytes-1] == '\0'); out_port = Args::StringToUInt32(port_cstr, 0); name_pipe_file.Close(); } Host::Unlink(named_pipe_path); } else if (listen) { } else { // Make sure we actually connect with the debugserver... JoinListenThread(); } } else { error.SetErrorStringWithFormat ("unable to locate " DEBUGSERVER_BASENAME ); } return error; }
Error GDBRemoteCommunication::StartDebugserverProcess (const char *debugserver_url, const char *unix_socket_name, // For handshaking lldb_private::ProcessLaunchInfo &launch_info) { Error error; // If we locate debugserver, keep that located version around static FileSpec g_debugserver_file_spec; // This function will fill in the launch information for the debugserver // instance that gets launched. launch_info.Clear(); char debugserver_path[PATH_MAX]; FileSpec &debugserver_file_spec = launch_info.GetExecutableFile(); // Always check to see if we have an environment override for the path // to the debugserver to use and use it if we do. const char *env_debugserver_path = getenv("LLDB_DEBUGSERVER_PATH"); if (env_debugserver_path) debugserver_file_spec.SetFile (env_debugserver_path, false); else debugserver_file_spec = g_debugserver_file_spec; bool debugserver_exists = debugserver_file_spec.Exists(); if (!debugserver_exists) { // The debugserver binary is in the LLDB.framework/Resources // directory. if (Host::GetLLDBPath (ePathTypeSupportExecutableDir, debugserver_file_spec)) { debugserver_file_spec.GetFilename().SetCString(DEBUGSERVER_BASENAME); debugserver_exists = debugserver_file_spec.Exists(); if (debugserver_exists) { g_debugserver_file_spec = debugserver_file_spec; } else { g_debugserver_file_spec.Clear(); debugserver_file_spec.Clear(); } } } if (debugserver_exists) { debugserver_file_spec.GetPath (debugserver_path, sizeof(debugserver_path)); Args &debugserver_args = launch_info.GetArguments(); debugserver_args.Clear(); char arg_cstr[PATH_MAX]; // Start args with "debugserver /file/path -r --" debugserver_args.AppendArgument(debugserver_path); debugserver_args.AppendArgument(debugserver_url); // use native registers, not the GDB registers debugserver_args.AppendArgument("--native-regs"); // make debugserver run in its own session so signals generated by // special terminal key sequences (^C) don't affect debugserver debugserver_args.AppendArgument("--setsid"); if (unix_socket_name && unix_socket_name[0]) { debugserver_args.AppendArgument("--unix-socket"); debugserver_args.AppendArgument(unix_socket_name); } const char *env_debugserver_log_file = getenv("LLDB_DEBUGSERVER_LOG_FILE"); if (env_debugserver_log_file) { ::snprintf (arg_cstr, sizeof(arg_cstr), "--log-file=%s", env_debugserver_log_file); debugserver_args.AppendArgument(arg_cstr); } const char *env_debugserver_log_flags = getenv("LLDB_DEBUGSERVER_LOG_FLAGS"); if (env_debugserver_log_flags) { ::snprintf (arg_cstr, sizeof(arg_cstr), "--log-flags=%s", env_debugserver_log_flags); debugserver_args.AppendArgument(arg_cstr); } // debugserver_args.AppendArgument("--log-file=/tmp/debugserver.txt"); // debugserver_args.AppendArgument("--log-flags=0x802e0e"); // We currently send down all arguments, attach pids, or attach // process names in dedicated GDB server packets, so we don't need // to pass them as arguments. This is currently because of all the // things we need to setup prior to launching: the environment, // current working dir, file actions, etc. #if 0 // Now append the program arguments if (inferior_argv) { // Terminate the debugserver args so we can now append the inferior args debugserver_args.AppendArgument("--"); for (int i = 0; inferior_argv[i] != NULL; ++i) debugserver_args.AppendArgument (inferior_argv[i]); } else if (attach_pid != LLDB_INVALID_PROCESS_ID) { ::snprintf (arg_cstr, sizeof(arg_cstr), "--attach=%u", attach_pid); debugserver_args.AppendArgument (arg_cstr); } else if (attach_name && attach_name[0]) { if (wait_for_launch) debugserver_args.AppendArgument ("--waitfor"); else debugserver_args.AppendArgument ("--attach"); debugserver_args.AppendArgument (attach_name); } #endif // Close STDIN, STDOUT and STDERR. We might need to redirect them // to "/dev/null" if we run into any problems. // launch_info.AppendCloseFileAction (STDIN_FILENO); // launch_info.AppendCloseFileAction (STDOUT_FILENO); // launch_info.AppendCloseFileAction (STDERR_FILENO); error = Host::LaunchProcess(launch_info); } else { error.SetErrorStringWithFormat ("unable to locate " DEBUGSERVER_BASENAME ); } return error; }
Error GDBRemoteCommunication::StartDebugserverProcess (const char *hostname, uint16_t in_port, ProcessLaunchInfo &launch_info, uint16_t &out_port) { Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); if (log) log->Printf ("GDBRemoteCommunication::%s(hostname=%s, in_port=%" PRIu16 ", out_port=%" PRIu16, __FUNCTION__, hostname ? hostname : "<empty>", in_port, out_port); out_port = in_port; Error error; // If we locate debugserver, keep that located version around static FileSpec g_debugserver_file_spec; char debugserver_path[PATH_MAX]; FileSpec &debugserver_file_spec = launch_info.GetExecutableFile(); // Always check to see if we have an environment override for the path // to the debugserver to use and use it if we do. const char *env_debugserver_path = getenv("LLDB_DEBUGSERVER_PATH"); if (env_debugserver_path) { debugserver_file_spec.SetFile (env_debugserver_path, false); if (log) log->Printf ("GDBRemoteCommunication::%s() gdb-remote stub exe path set from environment variable: %s", __FUNCTION__, env_debugserver_path); } else debugserver_file_spec = g_debugserver_file_spec; bool debugserver_exists = debugserver_file_spec.Exists(); if (!debugserver_exists) { // The debugserver binary is in the LLDB.framework/Resources // directory. if (HostInfo::GetLLDBPath(ePathTypeSupportExecutableDir, debugserver_file_spec)) { debugserver_file_spec.AppendPathComponent (DEBUGSERVER_BASENAME); debugserver_exists = debugserver_file_spec.Exists(); if (debugserver_exists) { if (log) log->Printf ("GDBRemoteCommunication::%s() found gdb-remote stub exe '%s'", __FUNCTION__, debugserver_file_spec.GetPath ().c_str ()); g_debugserver_file_spec = debugserver_file_spec; } else { if (log) log->Printf ("GDBRemoteCommunication::%s() could not find gdb-remote stub exe '%s'", __FUNCTION__, debugserver_file_spec.GetPath ().c_str ()); g_debugserver_file_spec.Clear(); debugserver_file_spec.Clear(); } } } if (debugserver_exists) { debugserver_file_spec.GetPath (debugserver_path, sizeof(debugserver_path)); Args &debugserver_args = launch_info.GetArguments(); debugserver_args.Clear(); char arg_cstr[PATH_MAX]; // Start args with "debugserver /file/path -r --" debugserver_args.AppendArgument(debugserver_path); #if !defined(__APPLE__) // First argument to lldb-server must be mode in which to run. debugserver_args.AppendArgument("gdbserver"); #endif // If a host and port is supplied then use it char host_and_port[128]; if (hostname) { snprintf (host_and_port, sizeof(host_and_port), "%s:%u", hostname, in_port); debugserver_args.AppendArgument(host_and_port); } else { host_and_port[0] = '\0'; } // use native registers, not the GDB registers debugserver_args.AppendArgument("--native-regs"); if (launch_info.GetLaunchInSeparateProcessGroup()) { debugserver_args.AppendArgument("--setsid"); } llvm::SmallString<PATH_MAX> named_pipe_path; Pipe port_pipe; bool listen = false; if (host_and_port[0]) { // Create a temporary file to get the stdout/stderr and redirect the // output of the command into this file. We will later read this file // if all goes well and fill the data into "command_output_ptr" if (in_port == 0) { // Binding to port zero, we need to figure out what port it ends up // using using a named pipe... error = port_pipe.CreateWithUniqueName("debugserver-named-pipe", false, named_pipe_path); if (error.Success()) { debugserver_args.AppendArgument("--named-pipe"); debugserver_args.AppendArgument(named_pipe_path.c_str()); } else { if (log) log->Printf("GDBRemoteCommunication::%s() " "named pipe creation failed: %s", __FUNCTION__, error.AsCString()); // let's try an unnamed pipe error = port_pipe.CreateNew(true); if (error.Fail()) { if (log) log->Printf("GDBRemoteCommunication::%s() " "unnamed pipe creation failed: %s", __FUNCTION__, error.AsCString()); return error; } int write_fd = port_pipe.GetWriteFileDescriptor(); debugserver_args.AppendArgument("--pipe"); debugserver_args.AppendArgument(std::to_string(write_fd).c_str()); launch_info.AppendCloseFileAction(port_pipe.GetReadFileDescriptor()); } } else { listen = true; } } else { // No host and port given, so lets listen on our end and make the debugserver // connect to us.. error = StartListenThread ("127.0.0.1", 0); if (error.Fail()) return error; ConnectionFileDescriptor *connection = (ConnectionFileDescriptor *)GetConnection (); // Wait for 10 seconds to resolve the bound port out_port = connection->GetListeningPort(10); if (out_port > 0) { char port_cstr[32]; snprintf(port_cstr, sizeof(port_cstr), "127.0.0.1:%i", out_port); // Send the host and port down that debugserver and specify an option // so that it connects back to the port we are listening to in this process debugserver_args.AppendArgument("--reverse-connect"); debugserver_args.AppendArgument(port_cstr); } else { error.SetErrorString ("failed to bind to port 0 on 127.0.0.1"); return error; } } const char *env_debugserver_log_file = getenv("LLDB_DEBUGSERVER_LOG_FILE"); if (env_debugserver_log_file) { ::snprintf (arg_cstr, sizeof(arg_cstr), "--log-file=%s", env_debugserver_log_file); debugserver_args.AppendArgument(arg_cstr); } const char *env_debugserver_log_flags = getenv("LLDB_DEBUGSERVER_LOG_FLAGS"); if (env_debugserver_log_flags) { ::snprintf (arg_cstr, sizeof(arg_cstr), "--log-flags=%s", env_debugserver_log_flags); debugserver_args.AppendArgument(arg_cstr); } // Add additional args, starting with LLDB_DEBUGSERVER_EXTRA_ARG_1 until an env var doesn't come back. uint32_t env_var_index = 1; bool has_env_var; do { char env_var_name[64]; snprintf (env_var_name, sizeof (env_var_name), "LLDB_DEBUGSERVER_EXTRA_ARG_%" PRIu32, env_var_index++); const char *extra_arg = getenv(env_var_name); has_env_var = extra_arg != nullptr; if (has_env_var) { debugserver_args.AppendArgument (extra_arg); if (log) log->Printf ("GDBRemoteCommunication::%s adding env var %s contents to stub command line (%s)", __FUNCTION__, env_var_name, extra_arg); } } while (has_env_var); // Close STDIN, STDOUT and STDERR. launch_info.AppendCloseFileAction (STDIN_FILENO); launch_info.AppendCloseFileAction (STDOUT_FILENO); launch_info.AppendCloseFileAction (STDERR_FILENO); // Redirect STDIN, STDOUT and STDERR to "/dev/null". launch_info.AppendSuppressFileAction (STDIN_FILENO, true, false); launch_info.AppendSuppressFileAction (STDOUT_FILENO, false, true); launch_info.AppendSuppressFileAction (STDERR_FILENO, false, true); error = Host::LaunchProcess(launch_info); if (error.Success() && launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID) { if (named_pipe_path.size() > 0) { error = port_pipe.OpenAsReader(named_pipe_path, false); if (error.Fail()) if (log) log->Printf("GDBRemoteCommunication::%s() " "failed to open named pipe %s for reading: %s", __FUNCTION__, named_pipe_path.c_str(), error.AsCString()); } if (port_pipe.CanWrite()) port_pipe.CloseWriteFileDescriptor(); if (port_pipe.CanRead()) { char port_cstr[256]; port_cstr[0] = '\0'; size_t num_bytes = sizeof(port_cstr); // Read port from pipe with 10 second timeout. error = port_pipe.ReadWithTimeout(port_cstr, num_bytes, std::chrono::seconds{10}, num_bytes); if (error.Success()) { assert(num_bytes > 0 && port_cstr[num_bytes-1] == '\0'); out_port = StringConvert::ToUInt32(port_cstr, 0); if (log) log->Printf("GDBRemoteCommunication::%s() " "debugserver listens %u port", __FUNCTION__, out_port); } else { if (log) log->Printf("GDBRemoteCommunication::%s() " "failed to read a port value from pipe %s: %s", __FUNCTION__, named_pipe_path.c_str(), error.AsCString()); } port_pipe.Close(); } if (named_pipe_path.size() > 0) { const auto err = port_pipe.Delete(named_pipe_path); if (err.Fail()) { if (log) log->Printf ("GDBRemoteCommunication::%s failed to delete pipe %s: %s", __FUNCTION__, named_pipe_path.c_str(), err.AsCString()); } } // Make sure we actually connect with the debugserver... JoinListenThread(); } } else { error.SetErrorStringWithFormat ("unable to locate " DEBUGSERVER_BASENAME ); } return error; }
bool HostInfoBase::GetLLDBPath(lldb::PathType type, FileSpec &file_spec) { file_spec.Clear(); #if defined(LLDB_DISABLE_PYTHON) if (type == lldb::ePathTypePythonDir) return false; #endif FileSpec *result = nullptr; switch (type) { case lldb::ePathTypeLLDBShlibDir: { static std::once_flag g_once_flag; static bool success = false; std::call_once(g_once_flag, []() { success = HostInfo::ComputeSharedLibraryDirectory (g_fields->m_lldb_so_dir); Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); if (log) log->Printf("HostInfoBase::GetLLDBPath(ePathTypeLLDBShlibDir) => '%s'", g_fields->m_lldb_so_dir.GetPath().c_str()); }); if (success) result = &g_fields->m_lldb_so_dir; } break; case lldb::ePathTypeSupportExecutableDir: { static std::once_flag g_once_flag; static bool success = false; std::call_once(g_once_flag, []() { success = HostInfo::ComputeSupportExeDirectory (g_fields->m_lldb_support_exe_dir); Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); if (log) log->Printf("HostInfoBase::GetLLDBPath(ePathTypeSupportExecutableDir) => '%s'", g_fields->m_lldb_support_exe_dir.GetPath().c_str()); }); if (success) result = &g_fields->m_lldb_support_exe_dir; } break; case lldb::ePathTypeHeaderDir: { static std::once_flag g_once_flag; static bool success = false; std::call_once(g_once_flag, []() { success = HostInfo::ComputeHeaderDirectory (g_fields->m_lldb_headers_dir); Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); if (log) log->Printf("HostInfoBase::GetLLDBPath(ePathTypeHeaderDir) => '%s'", g_fields->m_lldb_headers_dir.GetPath().c_str()); }); if (success) result = &g_fields->m_lldb_headers_dir; } break; case lldb::ePathTypePythonDir: { static std::once_flag g_once_flag; static bool success = false; std::call_once(g_once_flag, []() { success = HostInfo::ComputePythonDirectory (g_fields->m_lldb_python_dir); Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); if (log) log->Printf("HostInfoBase::GetLLDBPath(ePathTypePythonDir) => '%s'", g_fields->m_lldb_python_dir.GetPath().c_str()); }); if (success) result = &g_fields->m_lldb_python_dir; } break; case lldb::ePathTypeClangDir: { static std::once_flag g_once_flag; static bool success = false; std::call_once(g_once_flag, []() { success = HostInfo::ComputeClangDirectory (g_fields->m_lldb_clang_resource_dir); Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); if (log) log->Printf("HostInfoBase::GetLLDBPath(ePathTypeClangResourceDir) => '%s'", g_fields->m_lldb_clang_resource_dir.GetPath().c_str()); }); if (success) result = &g_fields->m_lldb_clang_resource_dir; } break; case lldb::ePathTypeLLDBSystemPlugins: { static std::once_flag g_once_flag; static bool success = false; std::call_once(g_once_flag, []() { success = HostInfo::ComputeSystemPluginsDirectory (g_fields->m_lldb_system_plugin_dir); Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); if (log) log->Printf("HostInfoBase::GetLLDBPath(ePathTypeLLDBSystemPlugins) => '%s'", g_fields->m_lldb_system_plugin_dir.GetPath().c_str()); }); if (success) result = &g_fields->m_lldb_system_plugin_dir; } break; case lldb::ePathTypeLLDBUserPlugins: { static std::once_flag g_once_flag; static bool success = false; std::call_once(g_once_flag, []() { success = HostInfo::ComputeUserPluginsDirectory (g_fields->m_lldb_user_plugin_dir); Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); if (log) log->Printf("HostInfoBase::GetLLDBPath(ePathTypeLLDBUserPlugins) => '%s'", g_fields->m_lldb_user_plugin_dir.GetPath().c_str()); }); if (success) result = &g_fields->m_lldb_user_plugin_dir; } break; case lldb::ePathTypeLLDBTempSystemDir: { static std::once_flag g_once_flag; static bool success = false; std::call_once(g_once_flag, []() { success = HostInfo::ComputeProcessTempFileDirectory (g_fields->m_lldb_process_tmp_dir); Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); if (log) log->Printf("HostInfoBase::GetLLDBPath(ePathTypeLLDBTempSystemDir) => '%s'", g_fields->m_lldb_process_tmp_dir.GetPath().c_str()); }); if (success) result = &g_fields->m_lldb_process_tmp_dir; } break; case lldb::ePathTypeGlobalLLDBTempSystemDir: { static std::once_flag g_once_flag; static bool success = false; std::call_once(g_once_flag, []() { success = HostInfo::ComputeGlobalTempFileDirectory (g_fields->m_lldb_global_tmp_dir); Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); if (log) log->Printf("HostInfoBase::GetLLDBPath(ePathTypeGlobalLLDBTempSystemDir) => '%s'", g_fields->m_lldb_global_tmp_dir.GetPath().c_str()); }); if (success) result = &g_fields->m_lldb_global_tmp_dir; } break; } if (!result) return false; file_spec = *result; return true; }