DNBBreakpoint.cpp revision 851e30ec6a1b1d2c154bb7d69ed0d05b5fd14705
1bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant//===-- DNBBreakpoint.cpp ---------------------------------------*- C++ -*-===//
2bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant//
3f5256e16dfc425c1d466f6308d4026d529ce9e0bHoward Hinnant//                     The LLVM Compiler Infrastructure
4bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant//
5b64f8b07c104c6cc986570ac8ee0ed16a9f23976Howard Hinnant// This file is distributed under the University of Illinois Open Source
6b64f8b07c104c6cc986570ac8ee0ed16a9f23976Howard Hinnant// License. See LICENSE.TXT for details.
7bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant//
8bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant//===----------------------------------------------------------------------===//
9bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant//
10bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant//  Created by Greg Clayton on 6/29/07.
11bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant//
12bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant//===----------------------------------------------------------------------===//
13bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant
14bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant#include "DNBBreakpoint.h"
15bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant#include <algorithm>
16bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant#include "DNBLog.h"
17bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant
18bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant
19061d0cc4db18d17bf01ed14c5db0be098205bd47Marshall Clow#pragma mark -- DNBBreakpoint
2070342b99e227912742972b754ad86e75c5d7eefbHoward HinnantDNBBreakpoint::DNBBreakpoint(nub_addr_t addr, nub_size_t byte_size, nub_thread_t tid, bool hardware) :
21bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant    m_breakID(GetNextID()),
22bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant    m_tid(tid),
2370342b99e227912742972b754ad86e75c5d7eefbHoward Hinnant    m_byte_size(byte_size),
24bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant    m_opcode(),
25bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant    m_addr(addr),
26bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant    m_enabled(0),
27bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant    m_hw_preferred(hardware),
28bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant    m_is_watchpoint(0),
29bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant    m_watch_read(0),
30bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant    m_watch_write(0),
3170342b99e227912742972b754ad86e75c5d7eefbHoward Hinnant    m_hw_index(INVALID_NUB_HW_INDEX),
3270342b99e227912742972b754ad86e75c5d7eefbHoward Hinnant    m_hit_count(0),
3370342b99e227912742972b754ad86e75c5d7eefbHoward Hinnant    m_ignore_count(0),
3470342b99e227912742972b754ad86e75c5d7eefbHoward Hinnant    m_callback(NULL),
3570342b99e227912742972b754ad86e75c5d7eefbHoward Hinnant    m_callback_baton(NULL)
3670342b99e227912742972b754ad86e75c5d7eefbHoward Hinnant{
3770342b99e227912742972b754ad86e75c5d7eefbHoward Hinnant}
3870342b99e227912742972b754ad86e75c5d7eefbHoward Hinnant
3970342b99e227912742972b754ad86e75c5d7eefbHoward HinnantDNBBreakpoint::~DNBBreakpoint()
4070342b99e227912742972b754ad86e75c5d7eefbHoward Hinnant{
4170342b99e227912742972b754ad86e75c5d7eefbHoward Hinnant}
4270342b99e227912742972b754ad86e75c5d7eefbHoward Hinnant
43bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnantnub_break_t
44DNBBreakpoint::GetNextID()
45{
46    static uint32_t g_nextBreakID = 0;
47    return ++g_nextBreakID;
48}
49
50void
51DNBBreakpoint::SetCallback(DNBCallbackBreakpointHit callback, void *callback_baton)
52{
53    m_callback = callback;
54    m_callback_baton = callback_baton;
55}
56
57
58// RETURNS - true if we should stop at this breakpoint, false if we
59// should continue.
60
61bool
62DNBBreakpoint::BreakpointHit(nub_process_t pid, nub_thread_t tid)
63{
64    m_hit_count++;
65
66    if (m_hit_count > m_ignore_count)
67    {
68        if (m_callback)
69            return m_callback(pid, tid, GetID(), m_callback_baton);
70        return true;
71    }
72    return false;
73}
74
75void
76DNBBreakpoint::Dump() const
77{
78    if (IsBreakpoint())
79    {
80        DNBLog ("DNBBreakpoint %u: tid = %4.4x  addr = 0x%llx  state = %s  type = %s breakpoint  hw_index = %i  hit_count = %-4u  ignore_count = %-4u  callback = %p baton = %p",
81                m_breakID,
82                m_tid,
83                (uint64_t)m_addr,
84                m_enabled ? "enabled " : "disabled",
85                IsHardware() ? "hardware" : "software",
86                GetHardwareIndex(),
87                GetHitCount(),
88                GetIgnoreCount(),
89                m_callback,
90                m_callback_baton);
91    }
92    else
93    {
94        DNBLog ("DNBBreakpoint %u: tid = %4.4x  addr = 0x%llx  size = %llu  state = %s  type = %s watchpoint (%s%s)  hw_index = %i  hit_count = %-4u  ignore_count = %-4u  callback = %p baton = %p",
95                m_breakID,
96                m_tid,
97                (uint64_t)m_addr,
98                (uint64_t)m_byte_size,
99                m_enabled ? "enabled " : "disabled",
100                IsHardware() ? "hardware" : "software",
101                m_watch_read ? "r" : "",
102                m_watch_write ? "w" : "",
103                GetHardwareIndex(),
104                GetHitCount(),
105                GetIgnoreCount(),
106                m_callback,
107                m_callback_baton);
108    }
109}
110
111#pragma mark -- DNBBreakpointList
112
113DNBBreakpointList::DNBBreakpointList()
114{
115}
116
117DNBBreakpointList::~DNBBreakpointList()
118{
119}
120
121
122nub_break_t
123DNBBreakpointList::Add(const DNBBreakpoint& bp)
124{
125    m_breakpoints.push_back(bp);
126    return m_breakpoints.back().GetID();
127}
128
129bool
130DNBBreakpointList::ShouldStop(nub_process_t pid, nub_thread_t tid, nub_break_t breakID)
131{
132    DNBBreakpoint *bp = FindByID (breakID);
133    if (bp)
134    {
135        // Let the breakpoint decide if it should stop here (could not have
136        // reached it's target hit count yet, or it could have a callback
137        // that decided it shouldn't stop (shared library loads/unloads).
138        return bp->BreakpointHit(pid, tid);
139    }
140    // We should stop here since this breakpoint isn't valid anymore or it
141    // doesn't exist.
142    return true;
143}
144
145nub_break_t
146DNBBreakpointList::FindIDByAddress (nub_addr_t addr)
147{
148    DNBBreakpoint *bp = FindByAddress (addr);
149    if (bp)
150    {
151        DNBLogThreadedIf(LOG_BREAKPOINTS, "DNBBreakpointList::%s ( addr = 0x%16.16llx ) => %u", __FUNCTION__, (uint64_t)addr, bp->GetID());
152        return bp->GetID();
153    }
154    DNBLogThreadedIf(LOG_BREAKPOINTS, "DNBBreakpointList::%s ( addr = 0x%16.16llx ) => NONE", __FUNCTION__, (uint64_t)addr);
155    return INVALID_NUB_BREAK_ID;
156}
157
158bool
159DNBBreakpointList::Remove (nub_break_t breakID)
160{
161    iterator pos = GetBreakIDIterator(breakID);    // Predicate
162    if (pos != m_breakpoints.end())
163    {
164        m_breakpoints.erase(pos);
165        return true;
166    }
167    return false;
168}
169
170
171class BreakpointIDMatches
172{
173public:
174    BreakpointIDMatches (nub_break_t breakID) : m_breakID(breakID) {}
175    bool operator() (const DNBBreakpoint& bp) const
176    {
177        return m_breakID == bp.GetID();
178    }
179 private:
180   const nub_break_t m_breakID;
181};
182
183class BreakpointAddressMatches
184{
185public:
186    BreakpointAddressMatches (nub_addr_t addr) : m_addr(addr) {}
187    bool operator() (const DNBBreakpoint& bp) const
188    {
189        return m_addr == bp.Address();
190    }
191 private:
192   const nub_addr_t m_addr;
193};
194
195DNBBreakpointList::iterator
196DNBBreakpointList::GetBreakIDIterator (nub_break_t breakID)
197{
198    return std::find_if(m_breakpoints.begin(), m_breakpoints.end(), // Search full range
199                        BreakpointIDMatches(breakID));              // Predicate
200}
201
202DNBBreakpointList::const_iterator
203DNBBreakpointList::GetBreakIDConstIterator (nub_break_t breakID) const
204{
205    return std::find_if(m_breakpoints.begin(), m_breakpoints.end(), // Search full range
206                        BreakpointIDMatches(breakID));              // Predicate
207}
208
209DNBBreakpoint *
210DNBBreakpointList::FindByID (nub_break_t breakID)
211{
212    iterator pos = GetBreakIDIterator(breakID);
213    if (pos != m_breakpoints.end())
214        return &(*pos);
215
216    return NULL;
217}
218
219const DNBBreakpoint *
220DNBBreakpointList::FindByID (nub_break_t breakID) const
221{
222    const_iterator pos = GetBreakIDConstIterator(breakID);
223    if (pos != m_breakpoints.end())
224        return &(*pos);
225
226    return NULL;
227}
228
229DNBBreakpoint *
230DNBBreakpointList::FindByAddress (nub_addr_t addr)
231{
232    iterator end = m_breakpoints.end();
233    iterator pos = std::find_if(m_breakpoints.begin(), end,             // Search full range
234                                BreakpointAddressMatches(addr));        // Predicate
235    if (pos != end)
236        return &(*pos);
237
238    return NULL;
239}
240
241const DNBBreakpoint *
242DNBBreakpointList::FindByAddress (nub_addr_t addr) const
243{
244    const_iterator end = m_breakpoints.end();
245    const_iterator pos = std::find_if(m_breakpoints.begin(), end,       // Search full range
246                                      BreakpointAddressMatches(addr));  // Predicate
247    if (pos != end)
248        return &(*pos);
249
250    return NULL;
251}
252
253bool
254DNBBreakpointList::SetCallback(nub_break_t breakID, DNBCallbackBreakpointHit callback, void *callback_baton)
255{
256    DNBBreakpoint *bp = FindByID (breakID);
257    if (bp)
258    {
259        bp->SetCallback(callback, callback_baton);
260        return true;
261    }
262    return false;
263}
264
265
266void
267DNBBreakpointList::Dump() const
268{
269    const_iterator pos;
270    const_iterator end = m_breakpoints.end();
271    for (pos = m_breakpoints.begin(); pos != end; ++pos)
272        (*pos).Dump();
273}
274
275
276DNBBreakpoint *
277DNBBreakpointList::GetByIndex (uint32_t i)
278{
279    iterator end = m_breakpoints.end();
280    iterator pos;
281    uint32_t curr_i = 0;
282    for (pos = m_breakpoints.begin(), curr_i = 0; pos != end; ++pos, ++curr_i)
283    {
284        if (curr_i == i)
285            return &(*pos);
286    }
287    return NULL;
288}
289
290const DNBBreakpoint *
291DNBBreakpointList::GetByIndex (uint32_t i) const
292{
293    const_iterator end = m_breakpoints.end();
294    const_iterator pos;
295    uint32_t curr_i = 0;
296    for (pos = m_breakpoints.begin(), curr_i = 0; pos != end; ++pos, ++curr_i)
297    {
298        if (curr_i == i)
299            return &(*pos);
300    }
301    return NULL;
302}
303
304