1 //===-- TestCase.cpp --------------------------------------------*- C++ -*-===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include "TestCase.h"
11 #include "Results.h"
12 #include "Xcode.h"
13
14 using namespace lldb_perf;
15
TestCase()16 TestCase::TestCase () :
17 m_debugger(),
18 m_target(),
19 m_process(),
20 m_thread(),
21 m_listener(),
22 m_verbose(false),
23 m_step(0)
24 {
25 SBDebugger::Initialize();
26 SBHostOS::ThreadCreated ("<lldb-tester.app.main>");
27 m_debugger = SBDebugger::Create(false);
28 m_listener = m_debugger.GetListener();
29 }
30
31 static std::string
GetShortOptionString(struct option * long_options)32 GetShortOptionString (struct option *long_options)
33 {
34 std::string option_string;
35 for (int i = 0; long_options[i].name != NULL; ++i)
36 {
37 if (long_options[i].flag == NULL)
38 {
39 option_string.push_back ((char) long_options[i].val);
40 switch (long_options[i].has_arg)
41 {
42 default:
43 case no_argument:
44 break;
45 case required_argument:
46 option_string.push_back (':');
47 break;
48 case optional_argument:
49 option_string.append (2, ':');
50 break;
51 }
52 }
53 }
54 return option_string;
55 }
56
57 bool
Setup(int & argc,const char ** & argv)58 TestCase::Setup (int& argc, const char**& argv)
59 {
60 bool done = false;
61
62 struct option* long_options = GetLongOptions();
63
64 if (long_options)
65 {
66 std::string short_option_string (GetShortOptionString(long_options));
67
68 #if __GLIBC__
69 optind = 0;
70 #else
71 optreset = 1;
72 optind = 1;
73 #endif
74 while (!done)
75 {
76 int long_options_index = -1;
77 const int short_option = ::getopt_long_only (argc,
78 const_cast<char **>(argv),
79 short_option_string.c_str(),
80 long_options,
81 &long_options_index);
82
83 switch (short_option)
84 {
85 case 0:
86 // Already handled
87 break;
88
89 case -1:
90 done = true;
91 break;
92
93 default:
94 done = !ParseOption(short_option, optarg);
95 break;
96 }
97 }
98 argc -= optind;
99 argv += optind;
100 }
101
102 return false;
103 }
104
105 bool
Launch(lldb::SBLaunchInfo & launch_info)106 TestCase::Launch (lldb::SBLaunchInfo &launch_info)
107 {
108 lldb::SBError error;
109 m_process = m_target.Launch (launch_info, error);
110 if (!error.Success())
111 fprintf (stderr, "error: %s\n", error.GetCString());
112 if (m_process.IsValid())
113 {
114 m_process.GetBroadcaster().AddListener(m_listener, SBProcess::eBroadcastBitStateChanged | SBProcess::eBroadcastBitInterrupt);
115 return true;
116 }
117 return false;
118 }
119
120 bool
Launch(std::initializer_list<const char * > args)121 TestCase::Launch (std::initializer_list<const char*> args)
122 {
123 std::vector<const char*> args_vect(args);
124 args_vect.push_back(NULL);
125 lldb::SBLaunchInfo launch_info((const char**)&args_vect[0]);
126 return Launch(launch_info);
127 }
128
129 void
SetVerbose(bool b)130 TestCase::SetVerbose (bool b)
131 {
132 m_verbose = b;
133 }
134
135 bool
GetVerbose()136 TestCase::GetVerbose ()
137 {
138 return m_verbose;
139 }
140
141 void
Loop()142 TestCase::Loop ()
143 {
144 while (true)
145 {
146 bool call_test_step = false;
147 if (m_process.IsValid())
148 {
149 SBEvent evt;
150 m_listener.WaitForEvent (UINT32_MAX, evt);
151 StateType state = SBProcess::GetStateFromEvent (evt);
152 if (m_verbose)
153 printf("event = %s\n",SBDebugger::StateAsCString(state));
154 if (SBProcess::GetRestartedFromEvent(evt))
155 continue;
156 switch (state)
157 {
158 case eStateInvalid:
159 case eStateDetached:
160 case eStateCrashed:
161 case eStateUnloaded:
162 break;
163 case eStateExited:
164 return;
165 case eStateConnected:
166 case eStateAttaching:
167 case eStateLaunching:
168 case eStateRunning:
169 case eStateStepping:
170 continue;
171 case eStateStopped:
172 case eStateSuspended:
173 {
174 call_test_step = true;
175 bool fatal = false;
176 bool selected_thread = false;
177 for (auto thread_index = 0; thread_index < m_process.GetNumThreads(); thread_index++)
178 {
179 SBThread thread(m_process.GetThreadAtIndex(thread_index));
180 SBFrame frame(thread.GetFrameAtIndex(0));
181 bool select_thread = false;
182 StopReason stop_reason = thread.GetStopReason();
183 if (m_verbose) printf("tid = 0x%llx pc = 0x%llx ",thread.GetThreadID(),frame.GetPC());
184 switch (stop_reason)
185 {
186 case eStopReasonNone:
187 if (m_verbose)
188 printf("none\n");
189 break;
190
191 case eStopReasonTrace:
192 select_thread = true;
193 if (m_verbose)
194 printf("trace\n");
195 break;
196
197 case eStopReasonPlanComplete:
198 select_thread = true;
199 if (m_verbose)
200 printf("plan complete\n");
201 break;
202 case eStopReasonThreadExiting:
203 if (m_verbose)
204 printf("thread exiting\n");
205 break;
206 case eStopReasonExec:
207 if (m_verbose)
208 printf("exec\n");
209 break;
210 case eStopReasonInvalid:
211 if (m_verbose)
212 printf("invalid\n");
213 break;
214 case eStopReasonException:
215 select_thread = true;
216 if (m_verbose)
217 printf("exception\n");
218 fatal = true;
219 break;
220 case eStopReasonBreakpoint:
221 select_thread = true;
222 if (m_verbose)
223 printf("breakpoint id = %lld.%lld\n",thread.GetStopReasonDataAtIndex(0),thread.GetStopReasonDataAtIndex(1));
224 break;
225 case eStopReasonWatchpoint:
226 select_thread = true;
227 if (m_verbose)
228 printf("watchpoint id = %lld\n",thread.GetStopReasonDataAtIndex(0));
229 break;
230 case eStopReasonSignal:
231 select_thread = true;
232 if (m_verbose)
233 printf("signal %d\n",(int)thread.GetStopReasonDataAtIndex(0));
234 break;
235 }
236 if (select_thread && !selected_thread)
237 {
238 m_thread = thread;
239 selected_thread = m_process.SetSelectedThread(thread);
240 }
241 }
242 if (fatal)
243 {
244 if (m_verbose) Xcode::RunCommand(m_debugger,"bt all",true);
245 exit(1);
246 }
247 }
248 break;
249 }
250 }
251 else
252 {
253 call_test_step = true;
254 }
255
256 if (call_test_step)
257 {
258 do_the_call:
259 if (m_verbose)
260 printf("RUNNING STEP %d\n",m_step);
261 ActionWanted action;
262 TestStep(m_step, action);
263 m_step++;
264 SBError err;
265 switch (action.type)
266 {
267 case ActionWanted::Type::eContinue:
268 err = m_process.Continue();
269 break;
270 case ActionWanted::Type::eStepOut:
271 if (action.thread.IsValid() == false)
272 {
273 if (m_verbose)
274 {
275 Xcode::RunCommand(m_debugger,"bt all",true);
276 printf("error: invalid thread for step out on step %d\n", m_step);
277 }
278 exit(501);
279 }
280 m_process.SetSelectedThread(action.thread);
281 action.thread.StepOut();
282 break;
283 case ActionWanted::Type::eStepOver:
284 if (action.thread.IsValid() == false)
285 {
286 if (m_verbose)
287 {
288 Xcode::RunCommand(m_debugger,"bt all",true);
289 printf("error: invalid thread for step over %d\n",m_step);
290 }
291 exit(500);
292 }
293 m_process.SetSelectedThread(action.thread);
294 action.thread.StepOver();
295 break;
296 case ActionWanted::Type::eRelaunch:
297 if (m_process.IsValid())
298 {
299 m_process.Kill();
300 m_process.Clear();
301 }
302 Launch(action.launch_info);
303 break;
304 case ActionWanted::Type::eKill:
305 if (m_verbose)
306 printf("kill\n");
307 m_process.Kill();
308 return;
309 case ActionWanted::Type::eCallNext:
310 goto do_the_call;
311 break;
312 }
313 }
314
315 }
316
317 if (GetVerbose()) printf("I am gonna die at step %d\n",m_step);
318 }
319
320 int
Run(TestCase & test,int argc,const char ** argv)321 TestCase::Run (TestCase& test, int argc, const char** argv)
322 {
323 if (test.Setup(argc, argv))
324 {
325 test.Loop();
326 Results results;
327 test.WriteResults(results);
328 return RUN_SUCCESS;
329 }
330 else
331 return RUN_SETUP_ERROR;
332 }
333
334