Ejemplo n.º 1
0
        public async Task <int> WaitForExitAsync()
        {
            try
            {
                await Task.Run(() =>
                {
                    if (!_process.WaitForExit(_timeoutMs))
                    {
                        Trace.WriteLine($"Timeout waiting for {ProcessName} [{Id}]");
                        throw new ProcessException(
                            ErrorStrings.TimeoutWaitingForProcess(ProcessName));
                    }

                    // WaitForExit(int) does not guarantee that data received handlers
                    // completed. Instead, the documentation tells us to call WaitForExit().
                    _process.WaitForExit();
                });

                return(_process.ExitCode);
            }
            catch (Exception e) when(e is InvalidOperationException || e is Win32Exception)
            {
                Trace.WriteLine($"Error waiting for {ProcessName} [{Id}]: {e}");
                throw new ProcessException(
                          ErrorStrings.ErrorWaitingForProcess(ProcessName, e.Message), e);
            }
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Attempts to start the process and returns a task that is completed when the process
        /// exits with an exit code of zero (success). Standard output and error output are
        /// captured.
        /// </summary>
        /// <returns>A task evaluates to the output of the process.</returns>
        /// <exception cref="ProcessException">
        /// Thrown if the process cannot be started, or if it does not exit within the timeout
        /// period that was specified when the process was created.
        /// </exception>
        /// <exception cref="ProcessExecutionException">
        /// Thrown if the process exits with a non-zero exit code. Use the OutputLines and
        /// ErrorLines properties to get the process output and error text, respectively.
        /// </exception>
        public static async Task <List <string> > RunToExitWithSuccessCapturingOutputAsync(
            this IProcess process)
        {
            List <string> outputLines = new List <string>();
            List <string> errorLines  = new List <string>();

            process.OutputDataReceived += (obj, args) =>
            {
                if (args.Text != null)
                {
                    outputLines.Add(args.Text);
                }
            };
            process.ErrorDataReceived += (obj, args) =>
            {
                if (args.Text != null)
                {
                    errorLines.Add(args.Text);
                }
            };

            var code = await process.RunToExitAsync();

            if (code != 0)
            {
                throw new ProcessExecutionException(
                          ErrorStrings.ProcessExitedWithErrorCode(process.ProcessName, code),
                          code, outputLines, errorLines);
            }
            return(outputLines);
        }
Ejemplo n.º 3
0
        // Attempts to start the process and returns as soon as it has started.
        // Throws ProcessException if the process cannot be started.
        public void Start(bool standardOutputReadLine = true)
        {
            try
            {
                _process.Start();
                Id          = _process.Id;
                ProcessName = Path.GetFileName(_process.StartInfo.FileName);
                AssignProcessToJobObject(_handle, _process.Handle);
                Trace.WriteLine($"Started {_process.StartInfo.FileName} " +
                                $"{_process.StartInfo.Arguments} with id {Id}");
                if (_process.StartInfo.RedirectStandardError)
                {
                    _process.BeginErrorReadLine();
                }

                if (_process.StartInfo.RedirectStandardOutput && standardOutputReadLine)
                {
                    _process.BeginOutputReadLine();
                }
            }
            catch (Exception e) when(e is InvalidOperationException || e is Win32Exception)
            {
                string name = Path.GetFileName(_process.StartInfo.FileName);

                Trace.WriteLine($"Error launching {name}: {e}");
                throw new ProcessException(
                          ErrorStrings.FailedToLaunchProcess(_process.StartInfo.FileName, e.Message), e);
            }
        }
Ejemplo n.º 4
0
 /// <summary>
 /// Checks exit code of the process. If it is non-zero it throws
 /// the ProcessExecutionException.
 /// </summary>
 /// <exception cref="ProcessExecutionException">
 /// Thrown if the process exits with a non-zero exit code.
 /// </exception>
 /// <param name="code">Exit code of the process.</param>
 public static void CheckExitCode(this IProcess process, int code)
 {
     if (code != 0)
     {
         throw new ProcessExecutionException(
                   ErrorStrings.ProcessExitedWithErrorCode(process.ProcessName, code), code);
     }
 }
Ejemplo n.º 5
0
        /// <summary>
        /// Parses an elf binary or symbol file and returns the build ID encoded
        /// in the .note.gnu.build-id section of the file.
        /// </summary>
        /// <param name="filepath">The local or remote absolute file path.</param>
        /// <param name="target">Optional parameter specifying the remote gamelet.</param>
        /// <returns>A non-empty build id.</returns>
        /// <exception cref="BinaryFileUtilException">
        /// Thrown when an error is encountered reading or parsing the build id.
        /// InnerException contains more details.
        /// </exception>
        public async Task <BuildId> ReadBuildIdAsync(string filepath, SshTarget target = null)
        {
            try
            {
                var outputLines = await ReadSectionFromFileAsync(".note.gnu.build-id", filepath,
                                                                 target);

                var hexString = ParseHexDump(outputLines);
                var result    = ParseBuildIdOutput(hexString);
                if (result == BuildId.Empty)
                {
                    throw new InvalidBuildIdException(
                              ErrorStrings.FailedToReadBuildId(filepath,
                                                               ErrorStrings.EmptyBuildId));
                }
                return(result);
            }
            catch (ProcessExecutionException e)
            {
                LogObjdumpOutput(e);

                // objdump returned an error code, possibly because the file being parsed is not
                // actually an elf file. With an SSH target, exit code 255 means SSH failed before
                // it had a chance to execute the remote command.
                if (target != null && e.ExitCode < 255)
                {
                    // The remote command failed, so we need to fix the exception message.
                    // TODO: ManagedProcess should report the remote filename.
                    throw new BinaryFileUtilException(
                              ErrorStrings.FailedToReadBuildId(
                                  filepath, ErrorStrings.ProcessExitedWithErrorCode(
                                      YetiConstants.ObjDumpLinuxExecutable, e.ExitCode)),
                              e);
                }
                else
                {
                    throw new BinaryFileUtilException(
                              ErrorStrings.FailedToReadBuildId(filepath, e.Message), e);
                }
            }
            catch (ProcessException e)
            {
                // objdump failed to launch, possibly because the SDK was not found. With an SSH
                // target, this indicates that SSH failed to launch. In either case, the specific
                // filepath was never accessed, so it is not part of the error.
                throw new BinaryFileUtilException(
                          ErrorStrings.FailedToReadBuildId(e.Message), e);
            }
            catch (FormatException e)
            {
                // Indicates the build ID section is malformed.
                throw new InvalidBuildIdException(
                          ErrorStrings.FailedToReadBuildId(
                              filepath, ErrorStrings.MalformedBuildID),
                          e);
            }
        }
Ejemplo n.º 6
0
        ManagedProcess(ProcessStartInfo startInfo, int timeoutMs, bool showWindow = false)
        {
            _process = new Process {
                StartInfo = startInfo
            };
            _timeoutMs = timeoutMs;

            if (showWindow)
            {
                // When launching the process, show the window. Don't redirect standard output so
                // it can appear in the console window if applicable, but still redirect standard
                // error so errors are logged.
                _process.StartInfo.RedirectStandardInput  = false;
                _process.StartInfo.RedirectStandardOutput = false;
                _process.StartInfo.RedirectStandardError  = true;
                _process.StartInfo.UseShellExecute        = false;
                _process.StartInfo.CreateNoWindow         = false;
            }
            else
            {
                _process.StartInfo.RedirectStandardInput  = true;
                _process.StartInfo.RedirectStandardOutput = true;
                _process.StartInfo.RedirectStandardError  = true;
                _process.StartInfo.UseShellExecute        = false;
                _process.StartInfo.CreateNoWindow         = true;
            }

            _process.OutputDataReceived += OutputHandler;
            _process.ErrorDataReceived  += ErrorHandler;

            _process.EnableRaisingEvents = true;
            _process.Exited += ExitHandler;

            _handle = CreateJobObject(IntPtr.Zero, null);
            var info = new JobObjectBasicLimitInformation
            {
                LimitFlags = 0x2000
            };

            var extendedInfo = new JobobjectExtendedLimitInformation
            {
                BasicLimitInformation = info
            };

            int    length          = Marshal.SizeOf(typeof(JobobjectExtendedLimitInformation));
            IntPtr extendedInfoPtr = Marshal.AllocHGlobal(length);

            Marshal.StructureToPtr(extendedInfo, extendedInfoPtr, false);

            if (!SetInformationJobObject(_handle, JobObjectInfoType.ExtendedLimitInformation,
                                         extendedInfoPtr, (uint)length))
            {
                throw new Exception(
                          ErrorStrings.FailedToSetJobLimitInfo(Marshal.GetLastWin32Error()));
            }
        }
Ejemplo n.º 7
0
        /// <summary>
        /// Parses an elf binary or symbol file and returns the debug symbol file name encoded
        /// in the .gnu_debuglink section of the file.
        /// </summary>
        /// <param name="filepath">The local file path.</param>
        /// <returns>A non-empty string.</returns>
        /// <exception cref="BinaryFileUtilException">
        /// Thrown when an error is encountered reading or parsing the debug symbol file name.
        /// InnerException contains more details.
        /// </exception>
        public async Task <string> ReadSymbolFileNameAsync(string filepath)
        {
            List <string> outputLines;

            try
            {
                outputLines = await ReadSectionFromFileAsync(".gnu_debuglink", filepath, null);

                var hexString      = ParseHexDump(outputLines);
                var symbolFileName = ParseObjdumpHexString(hexString);
                if (string.IsNullOrEmpty(symbolFileName))
                {
                    throw new BinaryFileUtilException(
                              ErrorStrings.FailedToReadSymbolFileName(
                                  filepath, ErrorStrings.NoDebugLink));
                }
                return(symbolFileName);
            }
            catch (ProcessExecutionException e)
            {
                LogObjdumpOutput(e);

                // objdump returned a non-zero exit code
                throw new BinaryFileUtilException(
                          ErrorStrings.FailedToReadSymbolFileName(filepath, e.Message), e);
            }
            catch (ProcessException e)
            {
                // objdump failed to launch. The specific filepath was never accessed,
                // so it is not part of the error.
                throw new BinaryFileUtilException(
                          ErrorStrings.FailedToReadSymbolFileName(e.Message), e);
            }
            catch (FormatException e)
            {
                // Indicates the debug link section is malformed.
                throw new BinaryFileUtilException(
                          ErrorStrings.FailedToReadSymbolFileName(
                              filepath, ErrorStrings.MalformedDebugLink),
                          e);
            }
        }
Ejemplo n.º 8
0
        public async Task VerifySymbolFileAsync(string filepath, bool isDebugInfoFile)
        {
            try
            {
                var outputLines = await ReadSectionHeaderListFromFileAsync(filepath);

                if (!isDebugInfoFile)
                {
                    // If we are not to check the presence of .debug_info, it is sufficient that
                    // reading the sections succeeded.
                    return;
                }

                // Verify that the file has a .debug_info section in the section table.
                bool foundSectionTableStart = false;
                foreach (string line in outputLines)
                {
                    if (foundSectionTableStart)
                    {
                        if (_debugInfoSectionRegex.IsMatch(line))
                        {
                            // We found the .debug_info section, let us declare success.
                            return;
                        }
                    }
                    else if (_sectionTableStartRegex.IsMatch(line))
                    {
                        foundSectionTableStart = true;
                    }
                }

                // If we found the section table but did not find .debug_info, report an error.
                if (foundSectionTableStart)
                {
                    throw new BinaryFileUtilException(
                              ErrorStrings.MissingDebugInfoInSymbolFile(filepath));
                }

                // If we did not find the section table, let us log this.
                Trace.WriteLine($"Internal error: Could not find a section table in llvm-objdump " +
                                " output for '{filepath}'. Output of objdump:");
                Trace.WriteLine(Environment.NewLine +
                                string.Join(Environment.NewLine, outputLines));
            }
            catch (ProcessExecutionException e)
            {
                LogObjdumpOutput(e);

                // objdump returned an error code, possibly because the file being parsed is not
                // actually an elf file.
                // Let us handle some common errors specially to produce better error messages.
                if (e.ErrorLines.Count > 0)
                {
                    if (_fileTruncatedRegex.IsMatch(e.ErrorLines[0]))
                    {
                        throw new BinaryFileUtilException(
                                  ErrorStrings.SymbolFileTruncated(filepath), e);
                    }
                    else if (_fileNotRecognizedRegex.IsMatch(e.ErrorLines[0]))
                    {
                        throw new BinaryFileUtilException(
                                  ErrorStrings.InvalidSymbolFileFormat(filepath), e);
                    }
                }
                throw new BinaryFileUtilException(
                          ErrorStrings.FailedToReadSymbolFile(filepath, e.Message), e);
            }
            catch (ProcessException e)
            {
                // objdump failed to launch, possibly because the SDK was not found.
                throw new BinaryFileUtilException(
                          ErrorStrings.FailedToReadSymbolFile(filepath, e.Message), e);
            }
        }