1 #include "debug_lldb.hpp"
2 #include <atomic>
3 #include <boost/filesystem.hpp>
4 #include <glib.h>
5 #include <thread>
6 
main()7 int main() {
8   auto build_path = boost::filesystem::canonical(JUCI_BUILD_PATH);
9   auto exec_path = build_path / "tests" / "lldb_test_files" / "lldb_test_executable";
10   g_assert(boost::filesystem::exists(exec_path));
11 
12   auto tests_path = boost::filesystem::canonical(JUCI_TESTS_PATH);
13   auto source_path = tests_path / "lldb_test_files" / "main.cpp";
14   g_assert(boost::filesystem::exists(source_path));
15 
16   {
17     auto parsed_run_arguments = Debug::LLDB::get().parse_run_arguments("\"~/test/te st\"");
18     assert(std::get<0>(parsed_run_arguments).size() == 0);
19 
20     assert(std::get<1>(parsed_run_arguments) == "~/test/te st");
21 
22     assert(std::get<2>(parsed_run_arguments).size() == 0);
23   }
24   {
25     auto parsed_run_arguments = Debug::LLDB::get().parse_run_arguments("~/test/te\\ st");
26     assert(std::get<0>(parsed_run_arguments).size() == 0);
27 
28     assert(std::get<1>(parsed_run_arguments) == "~/test/te st");
29 
30     assert(std::get<2>(parsed_run_arguments).size() == 0);
31   }
32   {
33     auto parsed_run_arguments = Debug::LLDB::get().parse_run_arguments("~/test/te\\ st Arg1\\\\ arg2");
34     assert(std::get<0>(parsed_run_arguments).size() == 0);
35 
36     assert(std::get<1>(parsed_run_arguments) == "~/test/te st");
37 
38     assert(std::get<2>(parsed_run_arguments).size() == 2);
39     assert(std::get<2>(parsed_run_arguments)[0] == "Arg1\\");
40     assert(std::get<2>(parsed_run_arguments)[1] == "arg2");
41   }
42   {
43     auto parsed_run_arguments = Debug::LLDB::get().parse_run_arguments("~/test/te\\ st Arg1\\\\\\ arg1");
44     assert(std::get<0>(parsed_run_arguments).size() == 0);
45 
46     assert(std::get<1>(parsed_run_arguments) == "~/test/te st");
47 
48     assert(std::get<2>(parsed_run_arguments).size() == 1);
49     assert(std::get<2>(parsed_run_arguments)[0] == "Arg1\\ arg1");
50   }
51   {
52     auto parsed_run_arguments = Debug::LLDB::get().parse_run_arguments("\"~/test/te st\" Arg1 \"Ar g2\" Ar\\ g3");
53     assert(std::get<0>(parsed_run_arguments).size() == 0);
54 
55     assert(std::get<1>(parsed_run_arguments) == "~/test/te st");
56 
57     assert(std::get<2>(parsed_run_arguments).size() == 3);
58     assert(std::get<2>(parsed_run_arguments)[0] == "Arg1");
59     assert(std::get<2>(parsed_run_arguments)[1] == "Ar g2");
60     assert(std::get<2>(parsed_run_arguments)[2] == "Ar g3");
61   }
62   {
63     auto parsed_run_arguments = Debug::LLDB::get().parse_run_arguments("ENV1=Test ENV2=Te\\ st ENV3=\"te ts\" ~/test/te\\ st Arg1 \"Ar g2\" Ar\\ g3");
64     assert(std::get<0>(parsed_run_arguments).size() == 3);
65     assert(std::get<0>(parsed_run_arguments)[0] == "ENV1=Test");
66     assert(std::get<0>(parsed_run_arguments)[1] == "ENV2=Te st");
67     assert(std::get<0>(parsed_run_arguments)[2] == "ENV3=te ts");
68 
69     assert(std::get<1>(parsed_run_arguments) == "~/test/te st");
70 
71     assert(std::get<2>(parsed_run_arguments).size() == 3);
72     assert(std::get<2>(parsed_run_arguments)[0] == "Arg1");
73     assert(std::get<2>(parsed_run_arguments)[1] == "Ar g2");
74     assert(std::get<2>(parsed_run_arguments)[2] == "Ar g3");
75   }
76 
77   std::vector<std::pair<boost::filesystem::path, int>> breakpoints;
78   breakpoints.emplace_back(source_path, 2);
79 
80   std::atomic<bool> exited(false);
81   int exit_status;
82   std::atomic<int> line_nr(0);
83   Debug::LLDB::get().on_exit.emplace_back([&](int exit_status_) {
84     exit_status = exit_status_;
85     exited = true;
86   });
87   Debug::LLDB::get().on_event.emplace_back([&](const lldb::SBEvent &event) {
88     LockGuard lock(Debug::LLDB::get().mutex);
89     auto process = lldb::SBProcess::GetProcessFromEvent(event);
90     auto state = lldb::SBProcess::GetStateFromEvent(event);
91     if(state == lldb::StateType::eStateStopped) {
92       auto line_entry = process.GetSelectedThread().GetSelectedFrame().GetLineEntry();
93       if(line_entry.IsValid()) {
94         lldb::SBStream stream;
95         line_entry.GetFileSpec().GetDescription(stream);
96         line_nr = line_entry.GetLine();
97       }
98     }
99   });
100 
101   Debug::LLDB::get().start(exec_path.string(), "", breakpoints);
102 
103   for(;;) {
104     if(exited) {
105       g_assert_cmpint(exit_status, ==, 0);
106       break;
107     }
108     else if(line_nr > 0) {
109       for(;;) {
110         if(Debug::LLDB::get().is_stopped())
111           break;
112         std::this_thread::sleep_for(std::chrono::milliseconds(100));
113       }
114       g_assert_cmpint(line_nr, ==, 2);
115       g_assert(Debug::LLDB::get().get_backtrace().size() > 0);
116       auto variables = Debug::LLDB::get().get_variables();
117       g_assert_cmpstr(variables.at(0).name.c_str(), ==, "an_int");
118       line_nr = 0;
119       Debug::LLDB::get().step_over();
120       for(;;) {
121         if(line_nr > 0 && Debug::LLDB::get().is_stopped())
122           break;
123         std::this_thread::sleep_for(std::chrono::milliseconds(100));
124       }
125       g_assert_cmpint(line_nr, ==, 3);
126       g_assert(Debug::LLDB::get().get_backtrace().size() > 0);
127       variables = Debug::LLDB::get().get_variables();
128       g_assert_cmpstr(variables.at(0).name.c_str(), ==, "an_int");
129       auto value = Debug::LLDB::get().get_value("an_int", source_path, 2, 7);
130       g_assert_cmpuint(value.size(), >, 16);
131       auto value_substr = value.substr(0, 16);
132       g_assert_cmpstr(value_substr.c_str(), ==, "(int) an_int = 1");
133       line_nr = 0;
134       Debug::LLDB::get().continue_debug();
135     }
136     std::this_thread::sleep_for(std::chrono::milliseconds(10));
137   }
138 
139   Debug::LLDB::destroy();
140 }
141