130fdc8d8SChris Lattner //===-- ThreadPlanRunToAddress.cpp ------------------------------*- C++ -*-===//
230fdc8d8SChris Lattner //
330fdc8d8SChris Lattner //                     The LLVM Compiler Infrastructure
430fdc8d8SChris Lattner //
530fdc8d8SChris Lattner // This file is distributed under the University of Illinois Open Source
630fdc8d8SChris Lattner // License. See LICENSE.TXT for details.
730fdc8d8SChris Lattner //
830fdc8d8SChris Lattner //===----------------------------------------------------------------------===//
930fdc8d8SChris Lattner 
1030fdc8d8SChris Lattner // C Includes
1130fdc8d8SChris Lattner // C++ Includes
1230fdc8d8SChris Lattner // Other libraries and framework includes
1330fdc8d8SChris Lattner // Project includes
14e65b2cf2SEugene Zelenko #include "lldb/Target/ThreadPlanRunToAddress.h"
1530fdc8d8SChris Lattner #include "lldb/Core/Log.h"
1630fdc8d8SChris Lattner #include "lldb/Target/Process.h"
1730fdc8d8SChris Lattner #include "lldb/Target/RegisterContext.h"
18b9c1b51eSKate Stone #include "lldb/Target/Target.h"
19b9c1b51eSKate Stone #include "lldb/Target/Thread.h"
20*bf9a7730SZachary Turner #include "lldb/Utility/Stream.h"
2130fdc8d8SChris Lattner 
2230fdc8d8SChris Lattner using namespace lldb;
2330fdc8d8SChris Lattner using namespace lldb_private;
2430fdc8d8SChris Lattner 
2530fdc8d8SChris Lattner //----------------------------------------------------------------------
2630fdc8d8SChris Lattner // ThreadPlanRunToAddress: Continue plan
2730fdc8d8SChris Lattner //----------------------------------------------------------------------
2830fdc8d8SChris Lattner 
29b9c1b51eSKate Stone ThreadPlanRunToAddress::ThreadPlanRunToAddress(Thread &thread, Address &address,
30b9c1b51eSKate Stone                                                bool stop_others)
31b9c1b51eSKate Stone     : ThreadPlan(ThreadPlan::eKindRunToAddress, "Run to address plan", thread,
32b9c1b51eSKate Stone                  eVoteNoOpinion, eVoteNoOpinion),
33b9c1b51eSKate Stone       m_stop_others(stop_others), m_addresses(), m_break_ids() {
34b9c1b51eSKate Stone   m_addresses.push_back(
35b9c1b51eSKate Stone       address.GetOpcodeLoadAddress(m_thread.CalculateTarget().get()));
3608b87e0dSJim Ingham   SetInitialBreakpoints();
3730fdc8d8SChris Lattner }
3830fdc8d8SChris Lattner 
39b9c1b51eSKate Stone ThreadPlanRunToAddress::ThreadPlanRunToAddress(Thread &thread,
4030fdc8d8SChris Lattner                                                lldb::addr_t address,
41b9c1b51eSKate Stone                                                bool stop_others)
42b9c1b51eSKate Stone     : ThreadPlan(ThreadPlan::eKindRunToAddress, "Run to address plan", thread,
43b9c1b51eSKate Stone                  eVoteNoOpinion, eVoteNoOpinion),
44b9c1b51eSKate Stone       m_stop_others(stop_others), m_addresses(), m_break_ids() {
45b9c1b51eSKate Stone   m_addresses.push_back(
46b9c1b51eSKate Stone       m_thread.CalculateTarget()->GetOpcodeLoadAddress(address));
4708b87e0dSJim Ingham   SetInitialBreakpoints();
4808b87e0dSJim Ingham }
4908b87e0dSJim Ingham 
50b9c1b51eSKate Stone ThreadPlanRunToAddress::ThreadPlanRunToAddress(
51b9c1b51eSKate Stone     Thread &thread, const std::vector<lldb::addr_t> &addresses,
52b9c1b51eSKate Stone     bool stop_others)
53b9c1b51eSKate Stone     : ThreadPlan(ThreadPlan::eKindRunToAddress, "Run to address plan", thread,
54b9c1b51eSKate Stone                  eVoteNoOpinion, eVoteNoOpinion),
55b9c1b51eSKate Stone       m_stop_others(stop_others), m_addresses(addresses), m_break_ids() {
56d93c4a33SBruce Mitchener   // Convert all addresses into opcode addresses to make sure we set
57f3ef3d2aSGreg Clayton   // breakpoints at the correct address.
581ac04c30SGreg Clayton   Target &target = thread.GetProcess()->GetTarget();
59f3ef3d2aSGreg Clayton   std::vector<lldb::addr_t>::iterator pos, end = m_addresses.end();
60f3ef3d2aSGreg Clayton   for (pos = m_addresses.begin(); pos != end; ++pos)
61f3ef3d2aSGreg Clayton     *pos = target.GetOpcodeLoadAddress(*pos);
62f3ef3d2aSGreg Clayton 
6308b87e0dSJim Ingham   SetInitialBreakpoints();
6430fdc8d8SChris Lattner }
6530fdc8d8SChris Lattner 
66b9c1b51eSKate Stone void ThreadPlanRunToAddress::SetInitialBreakpoints() {
6708b87e0dSJim Ingham   size_t num_addresses = m_addresses.size();
6808b87e0dSJim Ingham   m_break_ids.resize(num_addresses);
6908b87e0dSJim Ingham 
70b9c1b51eSKate Stone   for (size_t i = 0; i < num_addresses; i++) {
7130fdc8d8SChris Lattner     Breakpoint *breakpoint;
72b9c1b51eSKate Stone     breakpoint = m_thread.CalculateTarget()
73b9c1b51eSKate Stone                      ->CreateBreakpoint(m_addresses[i], true, false)
74b9c1b51eSKate Stone                      .get();
75b9c1b51eSKate Stone     if (breakpoint != nullptr) {
7608b87e0dSJim Ingham       m_break_ids[i] = breakpoint->GetID();
7730fdc8d8SChris Lattner       breakpoint->SetThreadID(m_thread.GetID());
782995077dSJim Ingham       breakpoint->SetBreakpointKind("run-to-address");
7930fdc8d8SChris Lattner     }
8030fdc8d8SChris Lattner   }
8108b87e0dSJim Ingham }
8230fdc8d8SChris Lattner 
83b9c1b51eSKate Stone ThreadPlanRunToAddress::~ThreadPlanRunToAddress() {
8408b87e0dSJim Ingham   size_t num_break_ids = m_break_ids.size();
85b9c1b51eSKate Stone   for (size_t i = 0; i < num_break_ids; i++) {
861ac04c30SGreg Clayton     m_thread.CalculateTarget()->RemoveBreakpointByID(m_break_ids[i]);
8730fdc8d8SChris Lattner   }
8830fdc8d8SChris Lattner }
8930fdc8d8SChris Lattner 
90b9c1b51eSKate Stone void ThreadPlanRunToAddress::GetDescription(Stream *s,
91b9c1b51eSKate Stone                                             lldb::DescriptionLevel level) {
9208b87e0dSJim Ingham   size_t num_addresses = m_addresses.size();
9308b87e0dSJim Ingham 
94b9c1b51eSKate Stone   if (level == lldb::eDescriptionLevelBrief) {
95b9c1b51eSKate Stone     if (num_addresses == 0) {
9608b87e0dSJim Ingham       s->Printf("run to address with no addresses given.");
9708b87e0dSJim Ingham       return;
98b9c1b51eSKate Stone     } else if (num_addresses == 1)
9930fdc8d8SChris Lattner       s->Printf("run to address: ");
10008b87e0dSJim Ingham     else
10108b87e0dSJim Ingham       s->Printf("run to addresses: ");
10208b87e0dSJim Ingham 
103b9c1b51eSKate Stone     for (size_t i = 0; i < num_addresses; i++) {
10408b87e0dSJim Ingham       s->Address(m_addresses[i], sizeof(addr_t));
10508b87e0dSJim Ingham       s->Printf(" ");
10608b87e0dSJim Ingham     }
107b9c1b51eSKate Stone   } else {
108b9c1b51eSKate Stone     if (num_addresses == 0) {
10908b87e0dSJim Ingham       s->Printf("run to address with no addresses given.");
11008b87e0dSJim Ingham       return;
111b9c1b51eSKate Stone     } else if (num_addresses == 1)
11230fdc8d8SChris Lattner       s->Printf("Run to address: ");
113b9c1b51eSKate Stone     else {
11408b87e0dSJim Ingham       s->Printf("Run to addresses: ");
11508b87e0dSJim Ingham     }
11608b87e0dSJim Ingham 
117b9c1b51eSKate Stone     for (size_t i = 0; i < num_addresses; i++) {
118b9c1b51eSKate Stone       if (num_addresses > 1) {
11908b87e0dSJim Ingham         s->Printf("\n");
12008b87e0dSJim Ingham         s->Indent();
12108b87e0dSJim Ingham       }
12208b87e0dSJim Ingham 
12308b87e0dSJim Ingham       s->Address(m_addresses[i], sizeof(addr_t));
124f58a0487SJim Ingham       s->Printf(" using breakpoint: %d - ", m_break_ids[i]);
125b9c1b51eSKate Stone       Breakpoint *breakpoint =
126b9c1b51eSKate Stone           m_thread.CalculateTarget()->GetBreakpointByID(m_break_ids[i]).get();
12730fdc8d8SChris Lattner       if (breakpoint)
12830fdc8d8SChris Lattner         breakpoint->Dump(s);
12930fdc8d8SChris Lattner       else
13030fdc8d8SChris Lattner         s->Printf("but the breakpoint has been deleted.");
13130fdc8d8SChris Lattner     }
13230fdc8d8SChris Lattner   }
13308b87e0dSJim Ingham }
13430fdc8d8SChris Lattner 
135b9c1b51eSKate Stone bool ThreadPlanRunToAddress::ValidatePlan(Stream *error) {
13630fdc8d8SChris Lattner   // If we couldn't set the breakpoint for some reason, then this won't
13730fdc8d8SChris Lattner   // work.
13808b87e0dSJim Ingham   bool all_bps_good = true;
13908b87e0dSJim Ingham   size_t num_break_ids = m_break_ids.size();
14008b87e0dSJim Ingham 
141b9c1b51eSKate Stone   for (size_t i = 0; i < num_break_ids; i++) {
142b9c1b51eSKate Stone     if (m_break_ids[i] == LLDB_INVALID_BREAK_ID) {
14308b87e0dSJim Ingham       all_bps_good = false;
144b9c1b51eSKate Stone       if (error) {
14508b87e0dSJim Ingham         error->Printf("Could not set breakpoint for address: ");
14608b87e0dSJim Ingham         error->Address(m_addresses[i], sizeof(addr_t));
14708b87e0dSJim Ingham         error->Printf("\n");
14808b87e0dSJim Ingham       }
14908b87e0dSJim Ingham     }
150f48169bbSJim Ingham   }
15108b87e0dSJim Ingham   return all_bps_good;
15230fdc8d8SChris Lattner }
15330fdc8d8SChris Lattner 
154b9c1b51eSKate Stone bool ThreadPlanRunToAddress::DoPlanExplainsStop(Event *event_ptr) {
15530fdc8d8SChris Lattner   return AtOurAddress();
15630fdc8d8SChris Lattner }
15730fdc8d8SChris Lattner 
158b9c1b51eSKate Stone bool ThreadPlanRunToAddress::ShouldStop(Event *event_ptr) {
1591fd2f08eSJim Ingham   return AtOurAddress();
16030fdc8d8SChris Lattner }
16130fdc8d8SChris Lattner 
162b9c1b51eSKate Stone bool ThreadPlanRunToAddress::StopOthers() { return m_stop_others; }
16330fdc8d8SChris Lattner 
164b9c1b51eSKate Stone void ThreadPlanRunToAddress::SetStopOthers(bool new_value) {
16530fdc8d8SChris Lattner   m_stop_others = new_value;
16630fdc8d8SChris Lattner }
16730fdc8d8SChris Lattner 
168b9c1b51eSKate Stone StateType ThreadPlanRunToAddress::GetPlanRunState() { return eStateRunning; }
16930fdc8d8SChris Lattner 
170b9c1b51eSKate Stone bool ThreadPlanRunToAddress::WillStop() { return true; }
17130fdc8d8SChris Lattner 
172b9c1b51eSKate Stone bool ThreadPlanRunToAddress::MischiefManaged() {
1735160ce5cSGreg Clayton   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
17430fdc8d8SChris Lattner 
175b9c1b51eSKate Stone   if (AtOurAddress()) {
17630fdc8d8SChris Lattner     // Remove the breakpoint
17708b87e0dSJim Ingham     size_t num_break_ids = m_break_ids.size();
17830fdc8d8SChris Lattner 
179b9c1b51eSKate Stone     for (size_t i = 0; i < num_break_ids; i++) {
180b9c1b51eSKate Stone       if (m_break_ids[i] != LLDB_INVALID_BREAK_ID) {
1811ac04c30SGreg Clayton         m_thread.CalculateTarget()->RemoveBreakpointByID(m_break_ids[i]);
18208b87e0dSJim Ingham         m_break_ids[i] = LLDB_INVALID_BREAK_ID;
18308b87e0dSJim Ingham       }
18408b87e0dSJim Ingham     }
18530fdc8d8SChris Lattner     if (log)
18630fdc8d8SChris Lattner       log->Printf("Completed run to address plan.");
18730fdc8d8SChris Lattner     ThreadPlan::MischiefManaged();
18830fdc8d8SChris Lattner     return true;
189b9c1b51eSKate Stone   } else
19030fdc8d8SChris Lattner     return false;
19130fdc8d8SChris Lattner }
19230fdc8d8SChris Lattner 
193b9c1b51eSKate Stone bool ThreadPlanRunToAddress::AtOurAddress() {
19430fdc8d8SChris Lattner   lldb::addr_t current_address = m_thread.GetRegisterContext()->GetPC();
19508b87e0dSJim Ingham   bool found_it = false;
1964bf570d6SJim Ingham   size_t num_addresses = m_addresses.size();
197b9c1b51eSKate Stone   for (size_t i = 0; i < num_addresses; i++) {
198b9c1b51eSKate Stone     if (m_addresses[i] == current_address) {
19908b87e0dSJim Ingham       found_it = true;
20008b87e0dSJim Ingham       break;
20108b87e0dSJim Ingham     }
20208b87e0dSJim Ingham   }
20308b87e0dSJim Ingham   return found_it;
20430fdc8d8SChris Lattner }
205