TestCase.cpp revision b8158c8227c34b0fde91cf8602003f250bead007
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::eRelaunch: 296 if (m_process.IsValid()) 297 { 298 m_process.Kill(); 299 m_process.Clear(); 300 } 301 Launch(action.launch_info); 302 break; 303 case ActionWanted::Type::eKill: 304 if (m_verbose) 305 printf("kill\n"); 306 m_process.Kill(); 307 return; 308 } 309 } 310 311 } 312 313 if (GetVerbose()) printf("I am gonna die at step %d\n",m_step); 314} 315 316int 317TestCase::Run (TestCase& test, int argc, const char** argv) 318{ 319 if (test.Setup(argc, argv)) 320 { 321 test.Loop(); 322 Results results; 323 test.WriteResults(results); 324 return RUN_SUCCESS; 325 } 326 else 327 return RUN_SETUP_ERROR; 328} 329 330