TestCase.cpp revision 101a2d6d590b12f9647032d656a13d3d7c432038
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
14using namespace lldb_perf;
15
16TestCase::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
31static std::string
32GetShortOptionString (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
57bool
58TestCase::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
105bool
106TestCase::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
120bool
121TestCase::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
129void
130TestCase::SetVerbose (bool b)
131{
132    m_verbose = b;
133}
134
135bool
136TestCase::GetVerbose ()
137{
138    return m_verbose;
139}
140
141void
142TestCase::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            if (m_verbose)
259                printf("RUNNING STEP %d\n",m_step);
260            ActionWanted action;
261            TestStep(m_step, action);
262            m_step++;
263            SBError err;
264            switch (action.type)
265            {
266            case ActionWanted::Type::eContinue:
267                err = m_process.Continue();
268                break;
269            case ActionWanted::Type::eStepOut:
270                if (action.thread.IsValid() == false)
271                {
272                    if (m_verbose)
273                    {
274                        Xcode::RunCommand(m_debugger,"bt all",true);
275                        printf("error: invalid thread for step out on step %d\n", m_step);
276                    }
277                    exit(501);
278                }
279                m_process.SetSelectedThread(action.thread);
280                action.thread.StepOut();
281                break;
282            case ActionWanted::Type::eStepOver:
283                if (action.thread.IsValid() == false)
284                {
285                    if (m_verbose)
286                    {
287                        Xcode::RunCommand(m_debugger,"bt all",true);
288                        printf("error: invalid thread for step over %d\n",m_step);
289                    }
290                    exit(500);
291                }
292                m_process.SetSelectedThread(action.thread);
293                action.thread.StepOver();
294                break;
295            case ActionWanted::Type::eKill:
296                if (m_verbose)
297                    printf("kill\n");
298                m_process.Kill();
299                return;
300            }
301        }
302
303	}
304
305	if (GetVerbose()) printf("I am gonna die at step %d\n",m_step);
306}
307
308int
309TestCase::Run (TestCase& test, int argc, const char** argv)
310{
311    if (test.Setup(argc, argv))
312    {
313        test.Loop();
314        Results results;
315        test.WriteResults(results);
316        return RUN_SUCCESS;
317    }
318    else
319        return RUN_SETUP_ERROR;
320}
321
322