Index: lldb/packages/Python/lldbsuite/test/lldbutil.py
===================================================================
--- lldb/packages/Python/lldbsuite/test/lldbutil.py
+++ lldb/packages/Python/lldbsuite/test/lldbutil.py
@@ -235,7 +235,7 @@
     elif enum == lldb.eStateSuspended:
         return "suspended"
     else:
-        raise Exception("Unknown StateType enum")
+        raise Exception("Unknown StateType enum: " + str(enum))
 
 
 def stop_reason_to_str(enum):
@@ -860,11 +860,28 @@
 def run_to_breakpoint_do_run(test, target, bkpt, launch_info = None,
                              only_one_thread = True, extra_images = None):
 
+    # The (local) file path that the process will dump its stderr output in.
+    recorded_stderr_path = None
+
     # Launch the process, and do not stop at the entry point.
     if not launch_info:
         launch_info = target.GetLaunchInfo()
         launch_info.SetWorkingDirectory(test.get_process_working_directory())
 
+        # If we're not in remote mode, record the stderr of the process.
+        # Getting this to work in remote requires also transferring the file
+        # back afterwards. Windows also doesn't support redirecting stderr.
+        #
+        # Don't do this if the test specified its own launch_info as we don't
+        # know if this unintentionally overwrite an action of the test.
+        if not lldb.remote_platform and test.getPlatform() != "windows":
+           stderr_fd = 2
+           recorded_stderr_path = test.getBuildArtifact("recorded_stderr.txt")
+           readMode = False
+           writeMode = True
+           launch_info.AddOpenFileAction(stderr_fd, recorded_stderr_path,
+                                         readMode, writeMode)
+
     if extra_images:
         environ = test.registerSharedLibrariesWithTarget(target, extra_images)
         launch_info.SetEnvironmentEntries(environ, True)
@@ -889,7 +906,25 @@
     test.assertFalse(error.Fail(),
                      "Process launch failed: %s" % (error.GetCString()))
 
-    test.assertEqual(process.GetState(), lldb.eStateStopped)
+    # If we asked the process to dump its stderr output, then read it now so
+    # the output can be appended to the errors below.
+    recorded_stderr = None
+    if recorded_stderr_path:
+        with open(recorded_stderr_path, 'r') as f:
+            recorded_stderr = f.read()
+
+    def processStateInfo(process):
+        # If 'exited', print exit code and extracted description.
+        if process.state == lldb.eStateExited:
+            return ("Exit code/status: " + str(process.GetExitStatus()) + ". " +
+                "Exit description: " + str(process.exit_description))
+        return ""
+
+    if process.state != lldb.eStateStopped:
+        test.fail("Test process is not stopped at breakpoint, but instead in" +
+                  " state '" + state_type_to_str(process.state) + "'. " +
+                  processStateInfo(process) + ".\nstderr of inferior:\n" +
+                  str(recorded_stderr))
 
     # Frame #0 should be at our breakpoint.
     threads = get_threads_stopped_at_breakpoint(
Index: lldb/test/API/lldbutil-tests/failed-to-hit-breakpoint/Makefile
===================================================================
--- /dev/null
+++ lldb/test/API/lldbutil-tests/failed-to-hit-breakpoint/Makefile
@@ -0,0 +1,3 @@
+C_SOURCES := main.c
+
+include Makefile.rules
Index: lldb/test/API/lldbutil-tests/failed-to-hit-breakpoint/TestLLDBUtilFailedToHitBreakpoint.py
===================================================================
--- /dev/null
+++ lldb/test/API/lldbutil-tests/failed-to-hit-breakpoint/TestLLDBUtilFailedToHitBreakpoint.py
@@ -0,0 +1,30 @@
+"""
+Tests lldbutil's behaviour when running to a source breakpoint fails.
+"""
+
+import lldb
+import lldbsuite.test.lldbutil as lldbutil
+from lldbsuite.test.lldbtest import *
+from textwrap import dedent
+
+
+class TestCase(TestBase):
+
+    mydir = TestBase.compute_mydir(__file__)
+    NO_DEBUG_INFO_TESTCASE = True
+
+    def test_error_message(self):
+        """
+        Tests that run_to_source_breakpoint prints the right error message
+        when failing to hit the wanted breakpoint.
+        """
+        self.build()
+        try:
+            lldbutil.run_to_source_breakpoint(self, "// break here", lldb.SBFileSpec("main.c"))
+        except AssertionError as e:
+            self.assertIn("Test process is not stopped at breakpoint, but " +
+                          "instead in state 'exited'. Exit code/status: 0. " +
+                          "Exit description: None.\nstderr of inferior:\n" +
+                          "stderr_needle\n", str(e))
+        else:
+            self.fail("Hit breakpoint in unreachable code path.")
Index: lldb/test/API/lldbutil-tests/failed-to-hit-breakpoint/main.c
===================================================================
--- /dev/null
+++ lldb/test/API/lldbutil-tests/failed-to-hit-breakpoint/main.c
@@ -0,0 +1,13 @@
+#include <stdio.h>
+
+int main(int argc, char **argv) {
+  // Prin the string that the test looks for to make sure stderr got recorded.
+  fprintf(stderr, "stderr_needle\n");
+  // This is unreachable during normal test execution as we don't pass any
+  // (or +100) arguments. This still needs to be theoretically reachable code
+  // so that the compiler will generate code for this (that we can set a
+  // breakpoint on).
+  if (argc > 100)
+    return 1; // break here
+  return 0;
+}