1 //===-- DNBBreakpoint.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 //  Created by Greg Clayton on 6/29/07.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "DNBBreakpoint.h"
15 #include <algorithm>
16 #include "DNBLog.h"
17 
18 
19 #pragma mark -- DNBBreakpoint
20 DNBBreakpoint::DNBBreakpoint(nub_addr_t addr, nub_size_t byte_size, nub_thread_t tid, bool hardware) :
21     m_breakID(GetNextID()),
22     m_tid(tid),
23     m_byte_size(byte_size),
24     m_opcode(),
25     m_addr(addr),
26     m_enabled(0),
27     m_hw_preferred(hardware),
28     m_is_watchpoint(0),
29     m_watch_read(0),
30     m_watch_write(0),
31     m_hw_index(INVALID_NUB_HW_INDEX),
32     m_hit_count(0),
33     m_ignore_count(0),
34     m_callback(NULL),
35     m_callback_baton(NULL)
36 {
37 }
38 
39 DNBBreakpoint::~DNBBreakpoint()
40 {
41 }
42 
43 nub_break_t
44 DNBBreakpoint::GetNextID()
45 {
46     static uint32_t g_nextBreakID = 0;
47     return ++g_nextBreakID;
48 }
49 
50 void
51 DNBBreakpoint::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 
61 bool
62 DNBBreakpoint::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 
75 void
76 DNBBreakpoint::Dump() const
77 {
78     if (IsBreakpoint())
79     {
80         DNBLog("DNBBreakpoint %u: tid = %4.4x  addr = %8.8p  state = %s  type = %s breakpoint  hw_index = %i  hit_count = %-4u  ignore_count = %-4u  callback = %8.8p baton = %8.8p",
81             m_breakID,
82             m_tid,
83             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 = %8.8p  size = %u  state = %s  type = %s watchpoint (%s%s)  hw_index = %i  hit_count = %-4u  ignore_count = %-4u  callback = %8.8p baton = %8.8p",
95             m_breakID,
96             m_tid,
97             m_addr,
98             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 
113 DNBBreakpointList::DNBBreakpointList()
114 {
115 }
116 
117 DNBBreakpointList::~DNBBreakpointList()
118 {
119 }
120 
121 
122 nub_break_t
123 DNBBreakpointList::Add(const DNBBreakpoint& bp)
124 {
125     m_breakpoints.push_back(bp);
126     return m_breakpoints.back().GetID();
127 }
128 
129 bool
130 DNBBreakpointList::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 
145 nub_break_t
146 DNBBreakpointList::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 
158 bool
159 DNBBreakpointList::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 
171 class BreakpointIDMatches
172 {
173 public:
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 
183 class BreakpointAddressMatches
184 {
185 public:
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 
195 DNBBreakpointList::iterator
196 DNBBreakpointList::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 
202 DNBBreakpointList::const_iterator
203 DNBBreakpointList::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 
209 DNBBreakpoint *
210 DNBBreakpointList::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 
219 const DNBBreakpoint *
220 DNBBreakpointList::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 
229 DNBBreakpoint *
230 DNBBreakpointList::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 
241 const DNBBreakpoint *
242 DNBBreakpointList::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 
253 bool
254 DNBBreakpointList::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 
266 void
267 DNBBreakpointList::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 
276 DNBBreakpoint *
277 DNBBreakpointList::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 
290 const DNBBreakpoint *
291 DNBBreakpointList::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