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.");
}
|