Chandler Carruth 2946cd7010 Update the file headers across all of the LLVM projects in the monorepo
to reflect the new license.

We understand that people may be surprised that we're moving the header
entirely to discuss the new license. We checked this carefully with the
Foundation's lawyer and we believe this is the correct approach.

Essentially, all code in the project is now made available by the LLVM
project under our new license, so you will see that the license headers
include that license only. Some of our contributors have contributed
code under our old license, and accordingly, we have retained a copy of
our old license notice in the top-level files in each project and
repository.

llvm-svn: 351636
2019-01-19 08:50:56 +00:00

308 lines
9.0 KiB
C++

//===-- TestCase.cpp --------------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "TestCase.h"
#include "Results.h"
#include "Xcode.h"
using namespace lldb_perf;
TestCase::TestCase()
: m_debugger(), m_target(), m_process(), m_thread(), m_listener(),
m_verbose(false), m_step(0) {
SBDebugger::Initialize();
SBHostOS::ThreadCreated("<lldb-tester.app.main>");
m_debugger = SBDebugger::Create(false);
m_listener = m_debugger.GetListener();
m_listener.StartListeningForEventClass(
m_debugger, SBProcess::GetBroadcasterClass(),
SBProcess::eBroadcastBitStateChanged | SBProcess::eBroadcastBitInterrupt);
}
static std::string GetShortOptionString(struct option *long_options) {
std::string option_string;
for (int i = 0; long_options[i].name != NULL; ++i) {
if (long_options[i].flag == NULL) {
option_string.push_back((char)long_options[i].val);
switch (long_options[i].has_arg) {
default:
case no_argument:
break;
case required_argument:
option_string.push_back(':');
break;
case optional_argument:
option_string.append(2, ':');
break;
}
}
}
return option_string;
}
bool TestCase::Setup(int &argc, const char **&argv) {
bool done = false;
struct option *long_options = GetLongOptions();
if (long_options) {
std::string short_option_string(GetShortOptionString(long_options));
#if __GLIBC__
optind = 0;
#else
optreset = 1;
optind = 1;
#endif
while (!done) {
int long_options_index = -1;
const int short_option = ::getopt_long_only(
argc, const_cast<char **>(argv), short_option_string.c_str(),
long_options, &long_options_index);
switch (short_option) {
case 0:
// Already handled
break;
case -1:
done = true;
break;
default:
done = !ParseOption(short_option, optarg);
break;
}
}
argc -= optind;
argv += optind;
}
return false;
}
bool TestCase::Launch(lldb::SBLaunchInfo &launch_info) {
lldb::SBError error;
m_process = m_target.Launch(launch_info, error);
if (!error.Success())
fprintf(stderr, "error: %s\n", error.GetCString());
if (m_process.IsValid())
return true;
return false;
}
bool TestCase::Launch(std::initializer_list<const char *> args) {
std::vector<const char *> args_vect(args);
args_vect.push_back(NULL);
lldb::SBLaunchInfo launch_info((const char **)&args_vect[0]);
return Launch(launch_info);
}
void TestCase::SetVerbose(bool b) { m_verbose = b; }
bool TestCase::GetVerbose() { return m_verbose; }
void TestCase::Loop() {
while (true) {
bool call_test_step = false;
if (m_process.IsValid()) {
SBEvent evt;
m_listener.WaitForEvent(UINT32_MAX, evt);
StateType state = SBProcess::GetStateFromEvent(evt);
if (m_verbose)
printf("event = %s\n", SBDebugger::StateAsCString(state));
if (SBProcess::GetRestartedFromEvent(evt)) {
if (m_verbose) {
const uint32_t num_threads = m_process.GetNumThreads();
for (auto thread_index = 0; thread_index < num_threads;
thread_index++) {
SBThread thread(m_process.GetThreadAtIndex(thread_index));
SBFrame frame(thread.GetFrameAtIndex(0));
SBStream strm;
strm.RedirectToFileHandle(stdout, false);
frame.GetDescription(strm);
}
puts("restarted");
}
call_test_step = false;
} else {
switch (state) {
case eStateInvalid:
case eStateDetached:
case eStateCrashed:
case eStateUnloaded:
break;
case eStateExited:
return;
case eStateConnected:
case eStateAttaching:
case eStateLaunching:
case eStateRunning:
case eStateStepping:
call_test_step = false;
break;
case eStateStopped:
case eStateSuspended: {
call_test_step = true;
bool fatal = false;
bool selected_thread = false;
const uint32_t num_threads = m_process.GetNumThreads();
for (auto thread_index = 0; thread_index < num_threads;
thread_index++) {
SBThread thread(m_process.GetThreadAtIndex(thread_index));
SBFrame frame(thread.GetFrameAtIndex(0));
SBStream strm;
strm.RedirectToFileHandle(stdout, false);
frame.GetDescription(strm);
bool select_thread = false;
StopReason stop_reason = thread.GetStopReason();
if (m_verbose)
printf("tid = 0x%llx pc = 0x%llx ", thread.GetThreadID(),
frame.GetPC());
switch (stop_reason) {
case eStopReasonNone:
if (m_verbose)
printf("none\n");
break;
case eStopReasonTrace:
select_thread = true;
if (m_verbose)
printf("trace\n");
break;
case eStopReasonPlanComplete:
select_thread = true;
if (m_verbose)
printf("plan complete\n");
break;
case eStopReasonThreadExiting:
if (m_verbose)
printf("thread exiting\n");
break;
case eStopReasonExec:
if (m_verbose)
printf("exec\n");
break;
case eStopReasonInvalid:
if (m_verbose)
printf("invalid\n");
break;
case eStopReasonException:
select_thread = true;
if (m_verbose)
printf("exception\n");
fatal = true;
break;
case eStopReasonBreakpoint:
select_thread = true;
if (m_verbose)
printf("breakpoint id = %lld.%lld\n",
thread.GetStopReasonDataAtIndex(0),
thread.GetStopReasonDataAtIndex(1));
break;
case eStopReasonWatchpoint:
select_thread = true;
if (m_verbose)
printf("watchpoint id = %lld\n",
thread.GetStopReasonDataAtIndex(0));
break;
case eStopReasonSignal:
select_thread = true;
if (m_verbose)
printf("signal %d\n", (int)thread.GetStopReasonDataAtIndex(0));
break;
}
if (select_thread && !selected_thread) {
m_thread = thread;
selected_thread = m_process.SetSelectedThread(thread);
}
}
if (fatal) {
if (m_verbose)
Xcode::RunCommand(m_debugger, "bt all", true);
exit(1);
}
} break;
}
}
} else {
call_test_step = true;
}
if (call_test_step) {
do_the_call:
if (m_verbose)
printf("RUNNING STEP %d\n", m_step);
ActionWanted action;
TestStep(m_step, action);
m_step++;
SBError err;
switch (action.type) {
case ActionWanted::Type::eNone:
// Just exit and wait for the next event
break;
case ActionWanted::Type::eContinue:
err = m_process.Continue();
break;
case ActionWanted::Type::eStepOut:
if (action.thread.IsValid() == false) {
if (m_verbose) {
Xcode::RunCommand(m_debugger, "bt all", true);
printf("error: invalid thread for step out on step %d\n", m_step);
}
exit(501);
}
m_process.SetSelectedThread(action.thread);
action.thread.StepOut();
break;
case ActionWanted::Type::eStepOver:
if (action.thread.IsValid() == false) {
if (m_verbose) {
Xcode::RunCommand(m_debugger, "bt all", true);
printf("error: invalid thread for step over %d\n", m_step);
}
exit(500);
}
m_process.SetSelectedThread(action.thread);
action.thread.StepOver();
break;
case ActionWanted::Type::eRelaunch:
if (m_process.IsValid()) {
m_process.Kill();
m_process.Clear();
}
Launch(action.launch_info);
break;
case ActionWanted::Type::eKill:
if (m_verbose)
printf("kill\n");
m_process.Kill();
return;
case ActionWanted::Type::eCallNext:
goto do_the_call;
break;
}
}
}
if (GetVerbose())
printf("I am gonna die at step %d\n", m_step);
}
int TestCase::Run(TestCase &test, int argc, const char **argv) {
if (test.Setup(argc, argv)) {
test.Loop();
Results results;
test.WriteResults(results);
return RUN_SUCCESS;
} else
return RUN_SETUP_ERROR;
}