blob: 6d5c0de1478b5d10f98346db4ab5185c473c047a [file] [log] [blame]
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001//===-- 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
20DNBBreakpoint::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
39DNBBreakpoint::~DNBBreakpoint()
40{
41}
42
43nub_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 {
Greg Clayton490fbbe2011-10-28 22:59:14 +000080 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);
Chris Lattner30fdc8d2010-06-08 16:52:24 +000091 }
92 else
93 {
Greg Clayton490fbbe2011-10-28 22:59:14 +000094 DNBLog ("DNBBreakpoint %u: tid = %4.4x addr = 0x%llx size = %zu 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 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);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000108 }
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 {
Greg Claytone2d4f0d2011-01-19 07:54:15 +0000151 DNBLogThreadedIf(LOG_BREAKPOINTS, "DNBBreakpointList::%s ( addr = 0x%16.16llx ) => %u", __FUNCTION__, (uint64_t)addr, bp->GetID());
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000152 return bp->GetID();
153 }
Greg Claytone2d4f0d2011-01-19 07:54:15 +0000154 DNBLogThreadedIf(LOG_BREAKPOINTS, "DNBBreakpointList::%s ( addr = 0x%16.16llx ) => NONE", __FUNCTION__, (uint64_t)addr);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000155 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