135 lines
4.3 KiB
Plaintext
135 lines
4.3 KiB
Plaintext
// LLDB C++ API Test: Verify that when the Debugger stdin
|
|
// is set to a FILE *, lldb can still successfully run a
|
|
// python command in a stop hook.
|
|
|
|
#include <errno.h>
|
|
#include <mutex>
|
|
#include <stdio.h>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
%include_SB_APIs%
|
|
|
|
#include "common.h"
|
|
|
|
#if !defined(PATH_MAX)
|
|
#define PATH_MAX 4096
|
|
#endif
|
|
|
|
using namespace lldb;
|
|
|
|
void test(SBDebugger &dbg, std::vector<std::string> args) {
|
|
// The problem we had was that when the thread that was
|
|
// waiting on input went into the call to 'read' it had
|
|
// the file handle lock. Then when the python interpreter
|
|
// Initialized itself to run the python command, it tried
|
|
// to flush the file channel, and that deadlocked.
|
|
// This only happens when Async is true, since otherwise
|
|
// the process event is handled on the I/O read thread,
|
|
// which sidestepped the problem.
|
|
dbg.SetAsync(true);
|
|
|
|
SBTarget target = dbg.CreateTarget(args.at(0).c_str());
|
|
if (!target.IsValid())
|
|
throw Exception("invalid target");
|
|
|
|
SBBreakpoint breakpoint = target.BreakpointCreateByName("next");
|
|
if (!breakpoint.IsValid())
|
|
throw Exception("invalid breakpoint");
|
|
|
|
SBCommandInterpreter interp = dbg.GetCommandInterpreter();
|
|
SBCommandReturnObject result;
|
|
|
|
// Bring in the python command. We actually add two commands,
|
|
// one that runs in the stop hook and sets a variable when it
|
|
// runs, and one that reports out the variable so we can ensure
|
|
// that we did indeed run the stop hook.
|
|
const char *source_dir = "%SOURCE_DIR%";
|
|
SBFileSpec script_spec(source_dir);
|
|
script_spec.AppendPathComponent("some_cmd.py");
|
|
char path[PATH_MAX];
|
|
script_spec.GetPath(path, PATH_MAX);
|
|
|
|
std::string import_command("command script import ");
|
|
import_command.append(path);
|
|
interp.HandleCommand(import_command.c_str(), result);
|
|
if (!result.Succeeded())
|
|
throw Exception("Couldn't import %SOURCE_DIR%/some_cmd.py");
|
|
|
|
SBProcess process = target.LaunchSimple(nullptr, nullptr, nullptr);
|
|
if (!process.IsValid())
|
|
throw Exception("Couldn't launch process.");
|
|
if (process.GetState() != lldb::eStateStopped)
|
|
throw Exception("Process was not stopped");
|
|
|
|
process.SetSelectedThreadByIndexID(0);
|
|
|
|
// Now add the stop hook:
|
|
interp.HandleCommand("target stop-hook add -o some-cmd", result);
|
|
if (!result.Succeeded())
|
|
throw Exception("Couldn't add a stop hook.");
|
|
|
|
// Now switch the I/O over to a pipe, which will be handled by the
|
|
// NativeFile class:
|
|
int to_lldb_des[2];
|
|
int pipe_result = pipe(to_lldb_des);
|
|
FILE *fh_lldb_in = fdopen(to_lldb_des[0], "r");
|
|
FILE *fh_to_lldb = fdopen(to_lldb_des[1], "w");
|
|
|
|
// We need to reset the handle before destroying the debugger
|
|
// or the same deadlock will stall exiting:
|
|
class Cleanup {
|
|
public:
|
|
Cleanup(SBDebugger dbg, int filedes[2]) : m_dbg(dbg) {
|
|
m_file = m_dbg.GetInputFileHandle();
|
|
m_filedes[0] = filedes[0];
|
|
m_filedes[1] = filedes[1];
|
|
}
|
|
~Cleanup() {
|
|
m_dbg.SetInputFileHandle(m_file, false);
|
|
close(m_filedes[0]);
|
|
close(m_filedes[1]);
|
|
}
|
|
|
|
private:
|
|
FILE *m_file;
|
|
SBDebugger m_dbg;
|
|
int m_filedes[2];
|
|
};
|
|
Cleanup cleanup(dbg, to_lldb_des);
|
|
|
|
dbg.SetInputFileHandle(fh_lldb_in, false);
|
|
|
|
// Now run the command interpreter. You have to pass true to
|
|
// start thread so we will run the I/O in a separate thread.
|
|
dbg.RunCommandInterpreter(false, true);
|
|
|
|
// Now issue a stepi, and fetch the running and stopped events:
|
|
fprintf(fh_to_lldb, "thread step-inst\n");
|
|
|
|
SBEvent proc_event;
|
|
StateType state;
|
|
bool got_event;
|
|
|
|
got_event = dbg.GetListener().WaitForEventForBroadcaster(
|
|
100, process.GetBroadcaster(), proc_event);
|
|
if (!got_event)
|
|
throw Exception("Didn't get running event");
|
|
state = SBProcess::GetStateFromEvent(proc_event);
|
|
if (state != eStateRunning)
|
|
throw Exception("Event wasn't a running event.");
|
|
|
|
got_event = dbg.GetListener().WaitForEventForBroadcaster(
|
|
100, process.GetBroadcaster(), proc_event);
|
|
if (!got_event)
|
|
throw Exception("Didn't get a stopped event");
|
|
state = SBProcess::GetStateFromEvent(proc_event);
|
|
if (state != eStateStopped)
|
|
throw Exception("Event wasn't a stop event.");
|
|
|
|
// At this point the stop hook should have run. Check that:
|
|
interp.HandleCommand("report-cmd", result);
|
|
if (!result.Succeeded())
|
|
throw Exception("Didn't actually call stop hook.");
|
|
}
|