2 // This program creates NUMBER_OF_SIMULTANEOUS_DEBUG_SESSIONS of pthreads,
3 // creates an lldb Debugger on each thread, creates targets, inserts two
4 // breakpoints, runs to the first breakpoint, backtraces, runs to the second
5 // breakpoint, backtraces, kills the inferior process, closes down the
8 // The main thread keeps track of which pthreads have completed and which
9 // pthreads have completed successfully, and exits when all pthreads have
10 // completed successfully, or our time limit has been exceeded.
12 // This test file helps to uncover race conditions and locking mistakes
13 // that are hit when lldb is being used to debug multiple processes
21 #include "lldb/API/LLDB.h"
22 #include "lldb/API/SBCommandInterpreter.h"
23 #include "lldb/API/SBCommandReturnObject.h"
24 #include "lldb/API/SBDebugger.h"
30 #define NUMBER_OF_SIMULTANEOUS_DEBUG_SESSIONS 10
35 #define STR(x) STR1(x)
39 bool *completed_threads_array
= 0;
40 bool *successful_threads_array
= 0;
42 const char *inferior_process_name
= "testprog";
45 wait_for_stop_event (SBProcess process
, SBListener listener
)
51 bool waitfor_ret
= listener
.WaitForEvent (2, event
);
52 if (event
.GetType() == SBProcess::eBroadcastBitStateChanged
)
54 if (process
.GetState() == StateType::eStateStopped
55 || process
.GetState() == StateType::eStateCrashed
56 || process
.GetState() == StateType::eStateDetached
57 || process
.GetState() == StateType::eStateExited
)
67 walk_stack_to_main (SBThread thread
)
69 if (thread
.IsValid() == 0)
74 bool found_main
= false;
75 uint32_t curr_frame
= 0;
76 const uint32_t framecount
= thread
.GetNumFrames();
77 while (!found_main
&& curr_frame
< framecount
)
79 SBFrame frame
= thread
.GetFrameAtIndex (curr_frame
);
80 if (strcmp (frame
.GetFunctionName(), "main") == 0)
90 void *do_one_debugger (void *in
)
92 uint64_t threadnum
= (uint64_t) in
;
94 #if defined (__APPLE__)
96 asprintf (&threadname
, "thread #%lld", threadnum
);
97 pthread_setname_np (threadname
);
102 printf ("#%lld: Starting debug session\n", threadnum
);
105 SBDebugger debugger
= lldb::SBDebugger::Create (false);
106 if (debugger
.IsValid ())
108 debugger
.SetAsync (true);
109 SBTarget target
= debugger
.CreateTargetWithFileAndArch(inferior_process_name
,
110 STR(LLDB_HOST_ARCH
));
111 SBCommandInterpreter command_interp
= debugger
.GetCommandInterpreter();
112 if (target
.IsValid())
114 SBBreakpoint bar_br
= target
.BreakpointCreateByName ("bar", "testprog");
115 if (!bar_br
.IsValid())
117 printf ("#%" PRIu64
": failed to set breakpoint on bar, exiting.\n", threadnum
);
120 SBBreakpoint foo_br
= target
.BreakpointCreateByName ("foo", "testprog");
121 if (!foo_br
.IsValid())
123 printf ("#%" PRIu64
": Failed to set breakpoint on foo()\n", threadnum
);
126 SBLaunchInfo
launch_info (NULL
);
128 SBProcess process
= target
.Launch (launch_info
, error
);
129 if (process
.IsValid())
131 SBListener listener
= debugger
.GetListener();
132 SBBroadcaster broadcaster
= process
.GetBroadcaster();
133 uint32_t rc
= broadcaster
.AddListener (listener
, SBProcess::eBroadcastBitStateChanged
);
136 printf ("adding listener failed\n");
140 wait_for_stop_event (process
, listener
);
142 if (!walk_stack_to_main (process
.GetThreadAtIndex(0)))
144 printf ("#%" PRIu64
": backtrace while @ foo() failed\n", threadnum
);
145 completed_threads_array
[threadnum
] = true;
149 // On Linux the () are included.
150 const char* hit_fn
= process
.GetThreadAtIndex(0).GetFrameAtIndex(0).GetFunctionName();
151 if (strcmp (hit_fn
, "foo") != 0 && strcmp (hit_fn
, "foo()") != 0)
154 printf ("#%" PRIu64
": First breakpoint did not stop at foo(), instead stopped at '%s'\n", threadnum
, process
.GetThreadAtIndex(0).GetFrameAtIndex(0).GetFunctionName());
156 completed_threads_array
[threadnum
] = true;
162 wait_for_stop_event (process
, listener
);
164 if (process
.GetState() == StateType::eStateExited
)
166 printf ("#%" PRIu64
": Process exited\n", threadnum
);
167 completed_threads_array
[threadnum
] = true;
172 if (!walk_stack_to_main (process
.GetThreadAtIndex(0)))
174 printf ("#%" PRIu64
": backtrace while @ bar() failed\n", threadnum
);
175 completed_threads_array
[threadnum
] = true;
179 hit_fn
= process
.GetThreadAtIndex(0).GetFrameAtIndex(0).GetFunctionName();
180 if (strcmp (hit_fn
, "bar") != 0 && strcmp (hit_fn
, "bar()") != 0)
182 printf ("#%" PRIu64
": First breakpoint did not stop at bar()\n", threadnum
);
183 completed_threads_array
[threadnum
] = true;
189 wait_for_stop_event (process
, listener
);
191 SBDebugger::Destroy(debugger
);
194 printf ("#%" PRIu64
": All good!\n", threadnum
);
196 successful_threads_array
[threadnum
] = true;
197 completed_threads_array
[threadnum
] = true;
202 printf("#%" PRIu64
": process failed to launch\n", threadnum
);
203 successful_threads_array
[threadnum
] = false;
204 completed_threads_array
[threadnum
] = true;
210 printf ("#%" PRIu64
": did not get valid target\n", threadnum
);
211 successful_threads_array
[threadnum
] = false;
212 completed_threads_array
[threadnum
] = true;
218 printf ("#%" PRIu64
": did not get debugger\n", threadnum
);
219 successful_threads_array
[threadnum
] = false;
220 completed_threads_array
[threadnum
] = true;
223 completed_threads_array
[threadnum
] = true;
227 int count_completed_threads(int num_threads
) {
228 int num_completed_threads
= 0;
229 for (int i
= 0; i
< num_threads
; i
++)
230 if (completed_threads_array
[i
])
231 num_completed_threads
++;
232 return num_completed_threads
;
235 int count_successful_threads(int num_threads
) {
236 int num_successful_threads
= 0;
237 for (int i
= 0; i
< num_threads
; i
++)
238 if (successful_threads_array
[i
])
239 num_successful_threads
++;
240 return num_successful_threads
;
243 int main (int argc
, char **argv
)
245 #if !defined(_MSC_VER)
246 signal(SIGPIPE
, SIG_IGN
);
249 SBDebugger::Initialize();
251 completed_threads_array
= (bool *) malloc (sizeof (bool) * NUMBER_OF_SIMULTANEOUS_DEBUG_SESSIONS
);
252 memset (completed_threads_array
, 0, sizeof (bool) * NUMBER_OF_SIMULTANEOUS_DEBUG_SESSIONS
);
253 successful_threads_array
= (bool *) malloc (sizeof (bool) * NUMBER_OF_SIMULTANEOUS_DEBUG_SESSIONS
);
254 memset (successful_threads_array
, 0, sizeof (bool) * NUMBER_OF_SIMULTANEOUS_DEBUG_SESSIONS
);
256 if (argc
> 1 && argv
[1] != NULL
)
258 inferior_process_name
= argv
[1];
261 std::thread threads
[NUMBER_OF_SIMULTANEOUS_DEBUG_SESSIONS
];
262 for (uint64_t i
= 0; i
< NUMBER_OF_SIMULTANEOUS_DEBUG_SESSIONS
; i
++)
264 threads
[i
] = std::move(std::thread(do_one_debugger
, (void*)i
));
268 int max_time_to_wait
= 40; // 40 iterations, or 120 seconds
269 if (getenv("ASAN_OPTIONS"))
270 max_time_to_wait
*= 4;
271 for (int iter
= 0; iter
< max_time_to_wait
; iter
++) {
272 std::this_thread::sleep_for(std::chrono::seconds(3));
273 int successful_threads
= count_successful_threads(NUMBER_OF_SIMULTANEOUS_DEBUG_SESSIONS
);
274 int total_completed_threads
= count_completed_threads(NUMBER_OF_SIMULTANEOUS_DEBUG_SESSIONS
);
276 if (total_completed_threads
== NUMBER_OF_SIMULTANEOUS_DEBUG_SESSIONS
)
279 printf ("All threads completed.\n");
280 printf ("%d threads completed successfully out of %d\n", successful_threads
, NUMBER_OF_SIMULTANEOUS_DEBUG_SESSIONS
);
282 SBDebugger::Terminate();
288 printf ("%d threads completed so far (%d successfully), out of %d\n", total_completed_threads
, successful_threads
, NUMBER_OF_SIMULTANEOUS_DEBUG_SESSIONS
);
291 if (iter
== max_time_to_wait
)
292 printf("reached maximum timeout but only %d threads have completed "
294 "(%d successfully), out of %d. Exiting.\n",
295 total_completed_threads
, successful_threads
,
296 NUMBER_OF_SIMULTANEOUS_DEBUG_SESSIONS
);
299 SBDebugger::Terminate();