1//===-- ThreadPlanRunToAddress.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 "lldb/Target/ThreadPlanRunToAddress.h"
11
12// C Includes
13// C++ Includes
14// Other libraries and framework includes
15// Project includes
16#include "lldb/lldb-private-log.h"
17#include "lldb/Core/Log.h"
18#include "lldb/Core/Stream.h"
19#include "lldb/Target/Target.h"
20#include "lldb/Target/Process.h"
21#include "lldb/Target/Thread.h"
22#include "lldb/Target/RegisterContext.h"
23
24using namespace lldb;
25using namespace lldb_private;
26
27//----------------------------------------------------------------------
28// ThreadPlanRunToAddress: Continue plan
29//----------------------------------------------------------------------
30
31ThreadPlanRunToAddress::ThreadPlanRunToAddress
32(
33    Thread &thread,
34    Address &address,
35    bool stop_others
36) :
37    ThreadPlan (ThreadPlan::eKindRunToAddress, "Run to address plan", thread, eVoteNoOpinion, eVoteNoOpinion),
38    m_stop_others (stop_others),
39    m_addresses (),
40    m_break_ids ()
41{
42    m_addresses.push_back (address.GetOpcodeLoadAddress (m_thread.CalculateTarget().get()));
43    SetInitialBreakpoints();
44}
45
46ThreadPlanRunToAddress::ThreadPlanRunToAddress
47(
48    Thread &thread,
49    lldb::addr_t address,
50    bool stop_others
51) :
52    ThreadPlan (ThreadPlan::eKindRunToAddress, "Run to address plan", thread, eVoteNoOpinion, eVoteNoOpinion),
53    m_stop_others (stop_others),
54    m_addresses (),
55    m_break_ids ()
56{
57    m_addresses.push_back(m_thread.CalculateTarget()->GetOpcodeLoadAddress(address));
58    SetInitialBreakpoints();
59}
60
61ThreadPlanRunToAddress::ThreadPlanRunToAddress
62(
63    Thread &thread,
64    const std::vector<lldb::addr_t> &addresses,
65    bool stop_others
66) :
67    ThreadPlan (ThreadPlan::eKindRunToAddress, "Run to address plan", thread, eVoteNoOpinion, eVoteNoOpinion),
68    m_stop_others (stop_others),
69    m_addresses (addresses),
70    m_break_ids ()
71{
72    // Convert all addressses into opcode addresses to make sure we set
73    // breakpoints at the correct address.
74    Target &target = thread.GetProcess()->GetTarget();
75    std::vector<lldb::addr_t>::iterator pos, end = m_addresses.end();
76    for (pos = m_addresses.begin(); pos != end; ++pos)
77        *pos = target.GetOpcodeLoadAddress (*pos);
78
79    SetInitialBreakpoints();
80}
81
82void
83ThreadPlanRunToAddress::SetInitialBreakpoints ()
84{
85    size_t num_addresses = m_addresses.size();
86    m_break_ids.resize(num_addresses);
87
88    for (size_t i = 0; i < num_addresses; i++)
89    {
90        Breakpoint *breakpoint;
91        breakpoint = m_thread.CalculateTarget()->CreateBreakpoint (m_addresses[i], true).get();
92        if (breakpoint != NULL)
93        {
94            m_break_ids[i] = breakpoint->GetID();
95            breakpoint->SetThreadID(m_thread.GetID());
96            breakpoint->SetBreakpointKind("run-to-address");
97        }
98    }
99}
100
101ThreadPlanRunToAddress::~ThreadPlanRunToAddress ()
102{
103    size_t num_break_ids = m_break_ids.size();
104    for (size_t i = 0; i <  num_break_ids; i++)
105    {
106        m_thread.CalculateTarget()->RemoveBreakpointByID (m_break_ids[i]);
107    }
108}
109
110void
111ThreadPlanRunToAddress::GetDescription (Stream *s, lldb::DescriptionLevel level)
112{
113    size_t num_addresses = m_addresses.size();
114
115    if (level == lldb::eDescriptionLevelBrief)
116    {
117        if (num_addresses == 0)
118        {
119            s->Printf ("run to address with no addresses given.");
120            return;
121        }
122        else if (num_addresses == 1)
123            s->Printf ("run to address: ");
124        else
125            s->Printf ("run to addresses: ");
126
127        for (size_t i = 0; i < num_addresses; i++)
128        {
129            s->Address (m_addresses[i], sizeof (addr_t));
130            s->Printf(" ");
131        }
132    }
133    else
134    {
135        if (num_addresses == 0)
136        {
137            s->Printf ("run to address with no addresses given.");
138            return;
139        }
140        else if (num_addresses == 1)
141            s->Printf ("Run to address: ");
142        else
143        {
144            s->Printf ("Run to addresses: ");
145        }
146
147        for (size_t i = 0; i < num_addresses; i++)
148        {
149            if (num_addresses > 1)
150            {
151                s->Printf("\n");
152                s->Indent();
153            }
154
155            s->Address(m_addresses[i], sizeof (addr_t));
156            s->Printf (" using breakpoint: %d - ", m_break_ids[i]);
157            Breakpoint *breakpoint = m_thread.CalculateTarget()->GetBreakpointByID (m_break_ids[i]).get();
158            if (breakpoint)
159                breakpoint->Dump (s);
160            else
161                s->Printf ("but the breakpoint has been deleted.");
162        }
163    }
164}
165
166bool
167ThreadPlanRunToAddress::ValidatePlan (Stream *error)
168{
169    // If we couldn't set the breakpoint for some reason, then this won't
170    // work.
171    bool all_bps_good = true;
172    size_t num_break_ids = m_break_ids.size();
173
174    for (size_t i = 0; i < num_break_ids; i++)
175    {
176        if (m_break_ids[i] == LLDB_INVALID_BREAK_ID)
177        {
178            all_bps_good = false;
179            if (error)
180            {
181                error->Printf ("Could not set breakpoint for address: ");
182                error->Address (m_addresses[i], sizeof (addr_t));
183                error->Printf ("\n");
184            }
185        }
186    }
187    return all_bps_good;
188}
189
190bool
191ThreadPlanRunToAddress::DoPlanExplainsStop (Event *event_ptr)
192{
193    return AtOurAddress();
194}
195
196bool
197ThreadPlanRunToAddress::ShouldStop (Event *event_ptr)
198{
199    return false;
200}
201
202bool
203ThreadPlanRunToAddress::StopOthers ()
204{
205    return m_stop_others;
206}
207
208void
209ThreadPlanRunToAddress::SetStopOthers (bool new_value)
210{
211    m_stop_others = new_value;
212}
213
214StateType
215ThreadPlanRunToAddress::GetPlanRunState ()
216{
217    return eStateRunning;
218}
219
220bool
221ThreadPlanRunToAddress::WillStop ()
222{
223    return true;
224}
225
226bool
227ThreadPlanRunToAddress::MischiefManaged ()
228{
229    Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
230
231    if (AtOurAddress())
232    {
233        // Remove the breakpoint
234        size_t num_break_ids = m_break_ids.size();
235
236        for (size_t i = 0; i < num_break_ids; i++)
237        {
238            if (m_break_ids[i] != LLDB_INVALID_BREAK_ID)
239            {
240                m_thread.CalculateTarget()->RemoveBreakpointByID (m_break_ids[i]);
241                m_break_ids[i] = LLDB_INVALID_BREAK_ID;
242            }
243        }
244        if (log)
245            log->Printf("Completed run to address plan.");
246        ThreadPlan::MischiefManaged ();
247        return true;
248    }
249    else
250        return false;
251}
252
253bool
254ThreadPlanRunToAddress::AtOurAddress ()
255{
256    lldb::addr_t current_address = m_thread.GetRegisterContext()->GetPC();
257    bool found_it = false;
258    size_t num_addresses = m_addresses.size();
259    for (size_t i = 0; i < num_addresses; i++)
260    {
261        if (m_addresses[i] == current_address)
262        {
263            found_it = true;
264            break;
265        }
266    }
267    return found_it;
268}
269