1 // LLDB C++ API Test: Verify that when the Debugger stdin
2 // is set to a FILE *, lldb can still successfully run a
3 // python command in a stop hook.
15 #if !defined(PATH_MAX)
21 void test(SBDebugger &dbg, std::vector<std::string> args) {
22 // The problem we had was that when the thread that was
23 // waiting on input went into the call to 'read' it had
24 // the file handle lock. Then when the python interpreter
25 // Initialized itself to run the python command, it tried
26 // to flush the file channel, and that deadlocked.
27 // This only happens when Async is true, since otherwise
28 // the process event is handled on the I/O read thread,
29 // which sidestepped the problem.
32 SBTarget target = dbg.CreateTarget(args.at(0).c_str());
33 if (!target.IsValid())
34 throw Exception("invalid target");
36 SBBreakpoint breakpoint = target.BreakpointCreateByName("next");
37 if (!breakpoint.IsValid())
38 throw Exception("invalid breakpoint");
40 SBCommandInterpreter interp = dbg.GetCommandInterpreter();
41 SBCommandReturnObject result;
43 // Bring in the python command. We actually add two commands,
44 // one that runs in the stop hook and sets a variable when it
45 // runs, and one that reports out the variable so we can ensure
46 // that we did indeed run the stop hook.
47 const char *source_dir = "%SOURCE_DIR%";
48 SBFileSpec script_spec(source_dir);
49 script_spec.AppendPathComponent("some_cmd.py");
51 script_spec.GetPath(path, PATH_MAX);
53 std::string import_command("command script import ");
54 import_command.append(path);
55 interp.HandleCommand(import_command.c_str(), result);
56 if (!result.Succeeded())
57 throw Exception("Couldn't import %SOURCE_DIR%/some_cmd.py");
59 SBProcess process = target.LaunchSimple(nullptr, nullptr, nullptr);
60 if (!process.IsValid())
61 throw Exception("Couldn't launch process.");
62 if (process.GetState() != lldb::eStateStopped)
63 throw Exception("Process was not stopped");
65 process.SetSelectedThreadByIndexID(0);
67 // Now add the stop hook:
68 interp.HandleCommand("target stop-hook add -o some-cmd", result);
69 if (!result.Succeeded())
70 throw Exception("Couldn't add a stop hook.");
72 // Now switch the I/O over to a pipe, which will be handled by the
75 int pipe_result = pipe(to_lldb_des);
76 FILE *fh_lldb_in = fdopen(to_lldb_des[0], "r");
77 FILE *fh_to_lldb = fdopen(to_lldb_des[1], "w");
79 // We need to reset the handle before destroying the debugger
80 // or the same deadlock will stall exiting:
83 Cleanup(SBDebugger dbg, int filedes[2]) : m_dbg(dbg) {
84 m_file = m_dbg.GetInputFileHandle();
85 m_filedes[0] = filedes[0];
86 m_filedes[1] = filedes[1];
89 m_dbg.SetInputFileHandle(m_file, false);
99 Cleanup cleanup(dbg, to_lldb_des);
101 dbg.SetInputFileHandle(fh_lldb_in, false);
103 // Now run the command interpreter. You have to pass true to
104 // start thread so we will run the I/O in a separate thread.
105 dbg.RunCommandInterpreter(false, true);
107 // Now issue a stepi, and fetch the running and stopped events:
108 fprintf(fh_to_lldb, "thread step-inst\n");
114 got_event = dbg.GetListener().WaitForEventForBroadcaster(
115 100, process.GetBroadcaster(), proc_event);
117 throw Exception("Didn't get running event");
118 state = SBProcess::GetStateFromEvent(proc_event);
119 if (state != eStateRunning)
120 throw Exception("Event wasn't a running event.");
122 got_event = dbg.GetListener().WaitForEventForBroadcaster(
123 100, process.GetBroadcaster(), proc_event);
125 throw Exception("Didn't get a stopped event");
126 state = SBProcess::GetStateFromEvent(proc_event);
127 if (state != eStateStopped)
128 throw Exception("Event wasn't a stop event.");
130 // At this point the stop hook should have run. Check that:
131 interp.HandleCommand("report-cmd", result);
132 if (!result.Succeeded())
133 throw Exception("Didn't actually call stop hook.");