• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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