1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
|
// 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.");
}
|